/* ============================================================================
   Cape Coast Mall 2.0 — storefront
   ----------------------------------------------------------------------------
   The customer-facing shop. Shares the locked brand palette with app.css
   (docs/BRAND-TOKENS.md) and adds nothing to it — every colour below is a
   token taken from the live capecoastmall.com.

   Mobile is the primary design target (SRS 3): Ghanaian customers shop on
   phones, so every layout here starts single-column and widens.
   ============================================================================ */

:root {
    --ccm-amber:     #FCB800;
    --ccm-amber-ink: #000000;
    --ccm-red:       #FF3300;
    --ccm-red-band:  #F60202;
    --ccm-orange:    #F14705;
    --ccm-badge-ink: #FFFFFF;
    --ccm-mint:      #EFFFF2;
    --ccm-link:      #0066CC;
    --ccm-ink:       #000000;
    --ccm-body:      #666666;
    --ccm-bg:        #FFFFFF;
    --ccm-rule:      #E1E1E1;
    --ccm-surface:   #FAFAFA;
    --ccm-rule-soft: #EDEDED;
    --ccm-muted:     #8A8A8A;

    --ccm-font: "Work Sans", Arial, Helvetica, sans-serif;
    --ccm-container: 1170px;   /* matches the live site */
    --ccm-radius: 4px;
}

* { box-sizing: border-box; }

body {
    margin: 0;
    font-family: var(--ccm-font);
    font-size: 14px;
    line-height: 1.6;
    color: var(--ccm-body);
    background: var(--ccm-bg);
    -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4 { color: var(--ccm-ink); margin: 0; font-weight: 600; }
a { color: var(--ccm-link); text-decoration: none; }
/* Underline links in prose, not designed components.
   -----------------------------------------------------------------------------
   `a:hover` is more specific than `.dept-link`, so this rule beat every
   component that had carefully set `text-decoration: none` — the department
   bar grew an underline on hover, and so did anything else shaped like a
   button or a card. Patching each one as it was noticed is how a stylesheet
   ends up with a dozen `text-decoration: none !important`.
   `:not([class])` draws the line where it belongs: a bare <a> in a sentence is
   a link and should look like one; an <a> that carries a class is a component
   and decides its own hover. Components that do want an underline — the
   breadcrumbs, the document pages — set it explicitly. */
a:not([class]):hover { text-decoration: underline; }
img { max-width: 100%; }
:focus-visible { outline: 2px solid var(--ccm-link); outline-offset: 2px; }

.shell { max-width: var(--ccm-container); margin: 0 auto; padding: 0 16px; }

/* -------------------------------------------------------------------- hero */
.hero { background: var(--ccm-mint); border-bottom: 1px solid var(--ccm-rule); padding: 44px 0; }
.hero .shell { display: grid; grid-template-columns: 1fr; gap: 22px; align-items: center; }
.hero h1 { font-size: clamp(28px, 5vw, 44px); line-height: 1.1; letter-spacing: -.02em; }
.hero h1 .accent { color: var(--ccm-red); }
.hero p { font-size: 16px; margin: 14px 0 0; max-width: 46ch; }
.hero-actions { display: flex; gap: 12px; flex-wrap: wrap; margin-top: 22px; }

.promise-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 14px; margin-top: 30px; }
.promise { background: var(--ccm-bg); border: 1px solid var(--ccm-rule); border-radius: var(--ccm-radius); padding: 14px 16px; }
.promise strong { display: block; color: var(--ccm-ink); font-size: 13.5px; }
.promise span { font-size: 12.5px; color: var(--ccm-muted); }

/* --------------------------------------------------------------- offer band */
.offer-band {
    background: var(--ccm-red-band); color: var(--ccm-badge-ink);
    text-align: center; padding: 15px 0;
    font-size: clamp(20px, 3.4vw, 30px); font-weight: 600; letter-spacing: -.01em;
}
.delivery-band {
    background: var(--ccm-mint); text-align: center; padding: 13px 0;
    font-size: 12.5px; color: var(--ccm-ink); border-bottom: 1px solid var(--ccm-rule);
}
.delivery-band strong { letter-spacing: .04em; text-transform: uppercase; font-size: 11.5px; }

/* ------------------------------------------------------------------ buttons */
.btn {
    display: inline-flex; align-items: center; justify-content: center; gap: 8px;
    padding: 11px 20px; font: inherit; font-weight: 600; cursor: pointer;
    border: 1px solid transparent; border-radius: var(--ccm-radius);
}
.btn:hover { text-decoration: none; filter: brightness(.96); }
.btn-primary { background: var(--ccm-amber); color: var(--ccm-amber-ink); }
.btn-ghost { background: var(--ccm-bg); color: var(--ccm-ink); border-color: var(--ccm-rule); }
.btn-danger { background: var(--ccm-red); color: var(--ccm-badge-ink); }
.btn-block { width: 100%; }
.btn:disabled { opacity: .5; cursor: not-allowed; }
.btn-sm { padding: 7px 12px; font-size: 12.5px; }

/* -------------------------------------------------------------- section head */
section.row { padding: 34px 0; }
.row-head {
    display: flex; align-items: baseline; justify-content: space-between;
    gap: 14px; border-bottom: 1px solid var(--ccm-rule);
    padding-bottom: 12px; margin-bottom: 20px;
}
.row-head h2 { font-size: 19px; }
.row-head a { font-size: 13px; }

/* ------------------------------------------------------------- product grid */
.grid { display: grid; gap: 14px; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); }
.card {
    border: 1px solid var(--ccm-rule); border-radius: var(--ccm-radius);
    background: var(--ccm-bg); display: flex; flex-direction: column;
    position: relative; overflow: hidden;
}
.card:hover { border-color: var(--ccm-amber); }
/* A fixed square, whatever the vendor uploaded.
   `aspect-ratio: 1` fixes the box and `object-fit: contain` fits the picture
   inside it, so nothing a vendor uploads can change the size of a card. Every
   image in this catalogue is 1800x1200 or 720x1200 -- not one is square -- and
   under the `cover` this used to have, a third of every wide photograph was
   cropped away. A shopper cannot judge a product whose edges have been cut off,
   and a row of cards that are all exactly the same size is worth more than a
   picture that fills its box.
   The max-width/max-height pair is belt to that braces: even with object-fit
   unsupported or overridden, the image cannot exceed its container. */
.card-media {
    display: block;
    aspect-ratio: 1;
    background: var(--ccm-bg);
    overflow: hidden;
}

.card-media img {
    width: 100%;
    height: 100%;
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
    object-position: center;
    display: block;
    /* A little air, so a photograph shot edge-to-edge does not touch the
       card's border and read as clipped. */
    padding: 6px;
    box-sizing: border-box;
}
.card-body { padding: 11px 12px 13px; display: flex; flex-direction: column; gap: 6px; flex: 1; }
.card-name { font-size: 13.5px; color: var(--ccm-ink); line-height: 1.35; }
.card-name:hover { color: var(--ccm-link); }
.card-cat { font-size: 11.5px; color: var(--ccm-muted); }
.card-price { margin-top: auto; }
.price { color: var(--ccm-red); font-weight: 700; font-size: 15px; }
.price-was { color: var(--ccm-muted); text-decoration: line-through; font-size: 12.5px; margin-left: 6px; }

.badge {
    position: absolute; top: 8px; left: 8px; z-index: 1;
    background: var(--ccm-orange); color: var(--ccm-badge-ink);
    font-size: 11px; font-weight: 700; padding: 3px 7px; border-radius: 2px;
}
.badge-out { background: var(--ccm-ink); }


/* -------------------------------------------------------------- product page */
.pdp { display: grid; gap: 28px; grid-template-columns: 1fr; padding: 28px 0; }
.pdp-gallery { display: flex; flex-direction: column; gap: 10px; }
/* White, not the surface grey.
   Fitting a landscape photograph into a square leaves a band above and below
   it. On grey that band draws a frame around the product; on white it is
   invisible against the white backdrop nearly all product photography is shot
   on, so the picture simply looks the shape it is. */
.pdp-main {
    border: 1px solid var(--ccm-rule); border-radius: var(--ccm-radius);
    background: var(--ccm-bg); aspect-ratio: 1; overflow: hidden;
}
/* The whole product, inside a fixed square. See .card-media above: this is
   the screen where cropping matters most, because it is the one where somebody
   decides whether to buy the thing. */
.pdp-main img {
    width: 100%;
    height: 100%;
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
    object-position: center;
    display: block;
    padding: 10px;
    box-sizing: border-box;
}
.pdp-thumbs { display: grid; grid-template-columns: repeat(auto-fill, minmax(64px, 1fr)); gap: 8px; }
.pdp-thumbs img {
    width: 100%; aspect-ratio: 1;
    max-width: 100%; max-height: 100%;
    object-fit: contain; display: block;
    padding: 3px; box-sizing: border-box;
    border: 1px solid var(--ccm-rule); border-radius: 3px; background: var(--ccm-bg);
}
.pdp h1 { font-size: clamp(21px, 3vw, 27px); line-height: 1.25; }
.pdp-price { font-size: 27px; }
.pdp-meta { display: flex; gap: 8px; flex-wrap: wrap; margin: 12px 0; }
.chip { font-size: 11.5px; padding: 4px 9px; border-radius: 2px; border: 1px solid var(--ccm-rule); color: var(--ccm-body); }
.chip-stock { background: var(--ccm-mint); color: var(--ccm-ink); }
.chip-out { background: var(--ccm-ink); color: var(--ccm-badge-ink); border-color: var(--ccm-ink); }
.pdp-desc { border-top: 1px solid var(--ccm-rule); margin-top: 22px; padding-top: 18px; }

.qty-row input {
    width: 76px; padding: 10px; font: inherit; text-align: center;
    border: 1px solid var(--ccm-rule); border-radius: var(--ccm-radius);
    color: var(--ccm-ink); background: var(--ccm-bg);
}

/* --------------------------------------------------------------------- cart */
.cart-layout { display: grid; gap: 22px; grid-template-columns: 1fr; padding: 26px 0; }
.cart-line {
    display: grid; grid-template-columns: 74px 1fr; gap: 14px;
    padding: 15px 0; border-bottom: 1px solid var(--ccm-rule-soft);
}
/* 74 square, fixed. A basket line whose height depends on the shape of a
   photograph makes a list of five items five different heights. */
.cart-line img {
    width: 74px;
    height: 74px;
    max-width: 74px;
    max-height: 74px;
    flex: 0 0 74px;
    object-fit: contain;
    padding: 4px;
    box-sizing: border-box;
    border: 1px solid var(--ccm-rule);
    border-radius: var(--ccm-radius);
    background: var(--ccm-bg);
}
.cart-line.is-unavailable { opacity: .62; }
.cart-line-top { display: flex; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.cart-actions input {
    width: 62px; padding: 6px 8px; font: inherit; text-align: center;
    border: 1px solid var(--ccm-rule); border-radius: var(--ccm-radius);
}

.summary {
    border: 1px solid var(--ccm-rule); border-radius: var(--ccm-radius);
    padding: 20px; background: var(--ccm-bg); align-self: start;
}
.summary-line { display: flex; justify-content: space-between; gap: 12px; padding: 7px 0; font-size: 13.5px; }
.summary-total {
    border-top: 1px solid var(--ccm-rule); margin-top: 10px; padding-top: 13px;
    font-size: 17px; font-weight: 700; color: var(--ccm-ink);
}
.vendor-group { border: 1px solid var(--ccm-rule-soft); border-radius: var(--ccm-radius); padding: 12px 14px; margin-bottom: 12px; }
.vendor-group h4 { font-size: 12.5px; color: var(--ccm-muted); font-weight: 600; }

/* ------------------------------------------------------------------- alerts */
.notice { padding: 12px 15px; border-radius: var(--ccm-radius); font-size: 13.5px; margin: 16px 0; border: 1px solid var(--ccm-rule); }
.notice-ok { background: var(--ccm-mint); color: var(--ccm-ink); }
.notice-bad { background: var(--ccm-bg); border-left: 3px solid var(--ccm-red); color: var(--ccm-ink); }
.notice-info { background: var(--ccm-surface); color: var(--ccm-ink); }

/* A condition somebody has to act on, so it carries the amber edge that means
   exactly that everywhere else on this site. */
.notice-warn { background: var(--ccm-bg); border-left: 3px solid var(--ccm-amber); color: var(--ccm-ink); }

.empty-state { text-align: center; padding: 56px 20px; color: var(--ccm-muted); border: 1px dashed var(--ccm-rule); border-radius: var(--ccm-radius); }

/* -------------------------------------------------------------- browse page */
.browse { display: grid; gap: 24px; grid-template-columns: 1fr; padding: 24px 0; }
/* ------------------------------------------------------------ browse sidebar
   One panel, sectioned by rules rather than three separate boxes: a stack of
   equally-weighted cards makes every filter look like a heading of its own,
   and the eye has nowhere to start.

   The links are plain markup and always on screen. An earlier version wrapped
   them in a <details> so a phone could collapse them, which nobody asked for
   and which hid the whole sidebar: browsers hide a closed <details>'s content
   in a way that `display: block` on the child does not override, so on desktop
   — where the summary was hidden too — the panel rendered empty with no way to
   open it. Navigation is the point of this column; it stays visible.

   Rows are full-width targets, not bare text links. A 13px word is a poor
   thing to hit with a thumb, and the old list gave no feedback at all on
   hover — you could not tell a category apart from a caption. */
.browse-side { align-self: start; }

.side-shell {
    border: 1px solid var(--ccm-rule);
    border-radius: var(--ccm-radius);
    background: var(--ccm-bg);
    overflow: hidden;
}

.side-head {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 13px 16px;
    background: var(--ccm-surface);
    border-bottom: 1px solid var(--ccm-rule);
    font-size: 13px;
    font-weight: 700;
    letter-spacing: .02em;
    color: var(--ccm-ink);
}
.side-head svg { width: 16px; height: 16px; color: var(--ccm-orange); }

/* Pushed to the far edge so it reads as an escape from the filters rather
   than another one of them. */
.side-clear {
    margin-left: auto;
    font-size: 12px;
    font-weight: 600;
    color: var(--ccm-orange);
}
.side-clear:hover { text-decoration: underline; }

.filters-panel { padding: 16px; }
.filters-panel + .filters-panel { border-top: 1px solid var(--ccm-rule); }
.filters-panel h3 {
    margin-bottom: 8px;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .09em;
    text-transform: uppercase;
    color: var(--ccm-muted);
}

.filter-list { list-style: none; margin: 0 -6px; padding: 0; }

.filter-row {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 8px 10px;
    border-radius: var(--ccm-radius);
    font-size: 13.5px;
    line-height: 1.3;
    color: var(--ccm-body);
    transition: background .14s ease, color .14s ease;
}
.filter-row:hover { background: var(--ccm-surface); color: var(--ccm-ink); }

/* Children are indented with a guide rule rather than the "— " prefix the
   markup used to print. Punctuation standing in for structure reads as part
   of the category name, and it does not survive a screen reader. */
.filter-item { list-style: none; }

/* The department name and its fold control are two separate targets on one
   line. They used to be one link with a decorative caret drawn inside it,
   which is why tapping the caret only ever navigated: there was nothing
   underneath it to click. */
.filter-line { display: flex; align-items: stretch; gap: 2px; }
.filter-line .filter-row { flex: 1; min-width: 0; }
.filter-row.is-parent { font-weight: 600; color: var(--ccm-ink); }

.filter-branch {
    flex: none;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    border-radius: var(--ccm-radius);
    color: var(--ccm-muted);
    transition: background .14s ease, color .14s ease;
}
.filter-branch:hover { background: var(--ccm-surface); color: var(--ccm-ink); }
.filter-branch.is-open { color: var(--ccm-orange); }

/* On a phone this is a 30px square holding a 14px arrow, sitting immediately
   beside the category link it folds. Two small targets side by side is the
   arrangement most likely to be mis-hit, and here the two do different things
   — one navigates away, the other expands in place — so a miss costs a page
   load and the loss of your place in the list. The comment above says the
   caret was split out precisely so it could be tapped; this gives it the size
   that makes that true. */
@media (max-width: 767px) {
    .filter-branch { min-width: 44px; min-height: 44px; }
}

/* Points down when the branch below it is open, right when it is folded —
   the arrow indicates the direction the list will move. */
.filter-caret {
    width: 14px;
    height: 14px;
    transition: transform .18s ease;
}
.filter-branch.is-open .filter-caret { transform: rotate(90deg); }

.filter-kids { list-style: none; margin: 0; padding: 0; }
.filter-row.is-child { padding-left: 30px; font-size: 13px; }
/* A guide rule under the open department, rather than the "\2014 " that the
   markup used to print into the name — punctuation standing in for structure
   reads as part of the category and does not survive a screen reader. */
.filter-row.is-child::before {
    content: "";
    position: absolute;
    left: 14px;
    top: 0;
    bottom: 0;
    width: 1px;
    background: var(--ccm-rule);
}
.filter-list li:last-child .filter-row.is-child::before { bottom: 50%; }

.filter-row.is-active {
    background: var(--ccm-mint);
    color: var(--ccm-ink);
    font-weight: 600;
}
/* The accent bar is what makes the selection findable at a glance in a long
   list; the tint alone is too quiet next to a hover. */
.filter-row.is-active::after {
    content: "";
    position: absolute;
    left: 0;
    top: 6px;
    bottom: 6px;
    width: 3px;
    border-radius: 0 2px 2px 0;
    background: var(--ccm-orange);
}
.filter-row.is-child.is-active::before { background: var(--ccm-orange); }

.filter-label { flex: 1; min-width: 0; overflow-wrap: anywhere; }

.filter-row .count {
    flex: none;
    padding: 1px 6px;
    border-radius: 8px;
    background: var(--ccm-surface);
    color: var(--ccm-muted);
    font-size: 11px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}
.filter-row:hover .count, .filter-row.is-active .count { background: var(--ccm-bg); }

/* Show only — toggles, because these two are on/off and a plain link gave no
   sign of which state a click would leave you in. */
.filter-toggles { display: flex; flex-wrap: wrap; gap: 7px; }
.filter-toggle {
    padding: 6px 13px;
    border: 1px solid var(--ccm-rule);
    border-radius: 999px;
    font-size: 12.5px;
    color: var(--ccm-body);
    transition: border-color .14s ease, background .14s ease, color .14s ease;
}
.filter-toggle:hover { border-color: var(--ccm-body); color: var(--ccm-ink); }
.filter-toggle.is-on {
    border-color: var(--ccm-orange);
    background: var(--ccm-orange);
    color: var(--ccm-badge-ink);
    font-weight: 600;
}

.browse-head { display: flex; justify-content: space-between; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 16px; }
.browse-head select, .price-filter input {
    padding: 8px 10px; font: inherit; font-size: 13px;
    border: 1px solid var(--ccm-rule); border-radius: var(--ccm-radius);
    color: var(--ccm-ink); background: var(--ccm-bg);
}
.price-filter { display: flex; flex-direction: column; gap: 10px; }
.price-row { display: flex; align-items: center; gap: 7px; }
.price-box {
    flex: 1;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 3px;
    padding: 0 9px;
    border: 1px solid var(--ccm-rule);
    border-radius: var(--ccm-radius);
    background: var(--ccm-bg);
}
.price-box:focus-within { border-color: var(--ccm-orange); }
.price-cue { flex: none; font-size: 12.5px; color: var(--ccm-muted); }
/* The box owns the border now, so the input inside must give its own up —
   otherwise the field reads as a box drawn inside a box. */
.price-filter .price-box input {
    width: 100%;
    min-width: 0;
    padding: 8px 0;
    border: 0;
    background: none;
    font-size: 13px;
}
.price-filter .price-box input:focus { outline: none; }
.price-dash { flex: none; color: var(--ccm-muted); font-size: 12px; }

/* On a phone the sidebar sits above the products. Only one department is
   expanded at a time, so the list is short enough to read without a scroll
   box of its own; the cap is a guard for a shop that grows a lot of
   departments, not the normal case. */
@media (max-width: 767px) {
    .filters-panel .filter-list { max-height: 340px; overflow-y: auto; }
}

.pager { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 26px; }
.pager a, .pager span {
    padding: 7px 12px; border: 1px solid var(--ccm-rule);
    border-radius: var(--ccm-radius); font-size: 13px; color: var(--ccm-body);
}
.pager .is-current { background: var(--ccm-mint); color: var(--ccm-ink); font-weight: 600; }
.pager .is-disabled { opacity: .45; }

/* ------------------------------------------------------------------- footer */
.shop-foot { background: var(--ccm-surface); border-top: 1px solid var(--ccm-rule); margin-top: 44px; padding: 34px 0 0; }
.foot-cols { display: grid; gap: 26px; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); }
.foot-cols h4 { font-size: 13px; margin-bottom: 11px; }
.foot-cols ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 7px; font-size: 13px; }
/* .foot-bottom is defined with the rest of the footer further down: it is a
   full-bleed light band now, not a rule inside the shell. */

/* --------------------------------------------------------------- responsive */
/* Tablet and up: side-by-side layouts. Aligned to the same 768px the header
   bands use — two nearly-equal breakpoints 8px apart is how a layout ends up
   reflowing twice on the way through a tablet. */
@media (min-width: 768px) {
    .hero .shell { grid-template-columns: 1.15fr .85fr; }
    .pdp { grid-template-columns: 1fr 1fr; gap: 36px; }
    .cart-layout { grid-template-columns: 1fr 320px; }
    .browse { grid-template-columns: 248px 1fr; gap: 28px; }
    /* Follows the page down, so the categories are still reachable when a
       shopper is forty products into a long listing. */
    .browse-side { position: sticky; top: 16px; max-height: calc(100vh - 32px); overflow-y: auto; }
    .cart-line { grid-template-columns: 92px 1fr; }
    .cart-line img { width: 92px; height: 92px; }
}

@media (min-width: 1024px) {
    .grid { grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); }
}
@media (prefers-reduced-motion: reduce) { * { transition: none !important; animation: none !important; } }

/* Breadcrumb and the inline saving chip on the product page. Separate classes
   rather than inline styles, because the CSP forbids style attributes. */
.breadcrumb { font-size: 11.5px; color: var(--ccm-muted); padding: 14px 0 0; }
.save-chip {
    display: inline-block; margin-left: 8px; vertical-align: middle;
    background: var(--ccm-orange); color: var(--ccm-badge-ink);
    font-size: 11px; font-weight: 700; padding: 3px 7px; border-radius: 2px;
}
.visually-hidden {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* Cart line details. */
.breadcrumb-title { font-size: 24px; margin: 22px 0 4px; }
.cart-line-noimage {
    display: block; width: 74px; height: 74px;
    border: 1px solid var(--ccm-rule); border-radius: var(--ccm-radius);
    background: var(--ccm-surface);
}
.cart-line-price { text-align: right; }
.line-issue { color: var(--ccm-red); font-size: 12.5px; font-weight: 600; margin-top: 4px; }
.cart-clear { margin-top: 16px; }
.summary h2 { font-size: 16px; margin-bottom: 10px; }
.summary .card-cat { margin-top: 12px; }
.notice ul { margin: 8px 0 0; padding-left: 20px; }

/* =============================================================================
   Homepage slider
   -----------------------------------------------------------------------------
   Every slide occupies ONE grid cell and they cross-fade. That means the cell
   is as tall as the tallest slide, so unless every slide fills it, a shorter
   one leaves the backing showing — which is exactly the dark band that
   appeared under an image slide sitting beside a taller text slide.

   The fix is to give the band one height and make both kinds of slide fill it:
   the text slide by centring its content, the image by covering. No slide is
   allowed to size the band on its own.

   The first slide is visible with no JavaScript at all; the script only adds
   movement.
   ========================================================================== */

.hero-slider {
    position: relative;
    display: grid;
    /* One height for the whole band, at every width. Scales with the viewport
       rather than jumping between two fixed sizes. */
    min-height: clamp(280px, 42vw, 440px);
    background: var(--ccm-mint);
    overflow: hidden;
}

.hero-track {
    display: grid;
    grid-template-areas: "slide";
    min-height: inherit;
}

.hero-slide {
    grid-area: slide;
    min-height: inherit;
    opacity: 0;
    visibility: hidden;
    transition: opacity .45s ease;
}

.hero-slide.is-current { opacity: 1; visibility: visible; }

/* --- Text slide ----------------------------------------------------------- */

.hero-slide.is-text { display: flex; align-items: center; }
.hero-slide.is-text .hero { width: 100%; background: transparent; border: 0; padding: 32px 0; }

/* --- Image slide ---------------------------------------------------------- */

/* No dark backing. If the artwork ever fails to cover, the brand mint shows
   through, which is a background rather than a hole. */
.hero-slide.is-image { display: block; }

.hero-slide.is-image picture,
.hero-image-link {
    display: block;
    width: 100%;
    height: 100%;
}

.hero-image {
    display: block;
    width: 100%;
    height: 100%;
    /* cover, so the band is filled at every aspect ratio; centre, so a banner
       whose subject sits in the middle survives the crop on a narrow screen. */
    object-fit: cover;
    object-position: center;
}

/* --- Arrows and dots ------------------------------------------------------ */

.hero-nav {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    z-index: 2;
    width: 36px;
    height: 36px;
    display: flex;
    align-items: center;
    justify-content: center;
    border: 0;
    border-radius: 50%;
    background: var(--ccm-bg);
    color: var(--ccm-ink);
    box-shadow: 0 2px 10px rgba(0, 0, 0, .18);
    cursor: pointer;
    opacity: .9;
}
.hero-nav:hover { opacity: 1; }
.hero-nav svg { width: 16px; height: 16px; }
.hero-prev { left: 14px; }
.hero-next { right: 14px; }

.hero-dots {
    position: absolute;
    left: 0; right: 0; bottom: 12px;
    z-index: 2;
    display: flex;
    justify-content: center;
    gap: 7px;
}
.hero-dot {
    width: 9px; height: 9px;
    border: 0; padding: 0;
    border-radius: 50%;
    background: var(--ccm-bg);
    opacity: .55;
    cursor: pointer;
    box-shadow: 0 1px 3px rgba(0, 0, 0, .3);
}
.hero-dot.is-current { opacity: 1; background: var(--ccm-amber); }

@media (prefers-reduced-motion: reduce) {
    .hero-slide { transition: none; }
}

/* --- Phone ---------------------------------------------------------------- */

@media (max-width: 767px) {
    .hero-slider { min-height: clamp(200px, 56vw, 300px); }

    /* The four promise boxes are hidden on a phone. They are reassurance, not
       navigation, and on a small screen they push the actual products a full
       screen further down. The same promises are in the footer, where someone
       who wants them will look. */
    .promise-row { display: none; }

    .hero-slide.is-text .hero { padding: 22px 0; }
    .hero h1 { font-size: clamp(24px, 7vw, 32px); }
    .hero p  { font-size: 14px; }
    .hero-actions { margin-top: 16px; }

    /* 44px, not 30px. These were the smallest controls on the homepage and
       they sit over a moving image, which is the worst combination: a missed
       tap on a carousel arrow usually lands on the slide and navigates away
       from the page instead. */
    .hero-nav { width: 44px; height: 44px; }
    .hero-nav svg { width: 18px; height: 18px; }

    /* The dots stay 9px to look at — a row of big circles over the artwork
       would be louder than the artwork. What grows is only the area that
       answers a finger, via a transparent overlay.

       The overlay is 34px wide and the gap is 25px, so each target is exactly
       as wide as the spacing between two dot centres. That is deliberate:
       make the overlay any wider and adjacent targets overlap, at which point
       the later sibling wins the tap and aiming at one dot selects its
       neighbour — which is worse than the small target it replaced. */
    .hero-dots { gap: 25px; }

    .hero-dot { position: relative; }

    .hero-dot::before {
        content: '';
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        width: 34px;
        height: 44px;
    }
}

/* =============================================================================
   Header and departments — the responsive rules
   -----------------------------------------------------------------------------
   These come last on purpose: they supersede the earlier masthead and deptbar
   blocks, which were written before the client supplied the desktop reference.

   Three bands, and every one of them is a real device:

     up to 767px    phone      two stacked rows, icons only
     768–1023px     tablet     the desktop arrangement, tightened
     1024px and up  desktop    the client's reference, at full size

   The desktop arrangement is the default and phones are the override, rather
   than the other way round, because the department bar and the support block
   are the parts that need the most room and it is clearer to take things away
   than to bolt them on.
   ========================================================================== */

/* --- Masthead ------------------------------------------------------------- */

.masthead { border-bottom: 1px solid var(--ccm-rule); background: var(--ccm-bg); padding: 12px 0; }

.masthead .shell {
    display: flex;
    align-items: center;
    gap: 18px;
    flex-wrap: nowrap;
}

.brand { flex: none; }
.brand img { display: block; width: 200px; max-width: 100%; height: auto; }

/* The department control. Three bars, no library. */
.menu-toggle {
    flex: none;
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 5px;
    width: 40px;
    height: 40px;
    padding: 0 6px;
    border: 0;
    background: transparent;
    cursor: pointer;
}
.menu-toggle span {
    display: block;
    height: 2.5px;
    border-radius: 2px;
    background: var(--ccm-ink);
    transition: background .15s;
}
.menu-toggle:hover span { background: var(--ccm-red); }

/* --- Search --------------------------------------------------------------- */

.searchbar { flex: 1 1 auto; display: flex; min-width: 0; }

.searchbar input {
    flex: 1 1 auto;
    min-width: 0;
    border: 1px solid var(--ccm-rule);
    border-right: 0;
    border-radius: 3px 0 0 3px;
    padding: 12px 14px;
    font-family: inherit;
    font-size: 14px;
    color: var(--ccm-ink);
    background: var(--ccm-bg);
    outline: none;
}
.searchbar input:focus { border-color: var(--ccm-muted); }

.searchbar button {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 7px;
    border: 0;
    border-radius: 0 3px 3px 0;
    background: var(--ccm-amber);
    color: var(--ccm-ink);
    padding: 0 26px;
    cursor: pointer;
}
.searchbar button:hover { filter: brightness(.94); }
.searchbar button svg { width: 20px; height: 20px; }

/* --- Customer support ----------------------------------------------------- */

.head-support {
    flex: none;
    display: inline-flex;
    align-items: center;
    gap: 10px;
    color: var(--ccm-ink);
    text-decoration: none;
}
.head-support svg { width: 30px; height: 30px; color: var(--ccm-body); flex: none; }
.head-support-text { display: flex; flex-direction: column; line-height: 1.25; }
.head-support-text small {
    font-size: 11px;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--ccm-body);
}
.head-support-text strong { font-size: 15px; color: var(--ccm-amber); }
.head-support:hover .head-support-text strong { color: var(--ccm-red); }

/* --- Basket and account --------------------------------------------------- */

.head-actions { display: flex; align-items: center; gap: 20px; flex: none; }

.head-link {
    display: inline-flex;
    align-items: center;
    gap: 9px;
    font-size: 13px;
    color: var(--ccm-ink);
    text-decoration: none;
}

.head-glyph { position: relative; display: inline-flex; flex: none; }
.head-glyph svg { width: 28px; height: 28px; }

.cart-pill {
    position: absolute;
    top: -5px;
    right: -8px;
    min-width: 19px;
    height: 19px;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0 5px;
    border-radius: 10px;
    background: var(--ccm-amber);
    color: var(--ccm-ink);
    font-size: 11px;
    font-weight: 700;
    line-height: 1;
}

.head-stack { display: flex; flex-direction: column; line-height: 1.3; }
.head-stack strong { font-size: 13.5px; font-weight: 600; }
.head-stack small { font-size: 11.5px; color: var(--ccm-body); }
.head-stack a { color: var(--ccm-ink); text-decoration: none; }
.head-stack a:hover { color: var(--ccm-red); }

/* =============================================================================
   Department bar
   -----------------------------------------------------------------------------
   White ground, dark text, an amber underline on the current department — the
   live site's treatment, and the client's reference.
   ========================================================================== */

.deptbar { border-bottom: 1px solid var(--ccm-rule); background: var(--ccm-bg); }
.deptbar .shell { display: flex; align-items: stretch; gap: 2px; flex-wrap: wrap; }

.dept { position: relative; }

.dept-link {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 13px 14px;
    font-size: 14px;
    font-weight: 400;
    color: var(--ccm-ink);
    text-decoration: none;
    white-space: nowrap;
    cursor: pointer;
    list-style: none;
    border-bottom: 2px solid transparent;
    background: transparent;
}

/* Safari still paints a disclosure triangle without both of these. */
.dept-link::-webkit-details-marker { display: none; }
.dept-link::marker { content: ''; }

.dept-link:hover,
.dept-link:focus-visible { color: var(--ccm-red); border-bottom-color: var(--ccm-amber); background: transparent; }
.dept-link.is-active { border-bottom-color: var(--ccm-amber); font-weight: 600; }

.dept-home svg { width: 19px; height: 19px; }
.dept-caret { width: 12px; height: 12px; color: var(--ccm-body); transition: transform .15s; }
.dept[open] .dept-caret { transform: rotate(180deg); }

.dept-panel {
    position: absolute;
    top: 100%;
    left: 0;
    z-index: 40;
    min-width: 250px;
    background: var(--ccm-bg);
    border: 1px solid var(--ccm-rule);
    border-top: 2px solid var(--ccm-amber);
    border-radius: 0 0 4px 4px;
    box-shadow: 0 10px 28px rgba(0, 0, 0, .14);
    padding: 10px 0;
}

.dept-all {
    display: block;
    padding: 7px 18px 9px;
    margin-bottom: 4px;
    border-bottom: 1px solid var(--ccm-rule-soft);
    font-size: 13px;
    font-weight: 700;
    color: var(--ccm-ink);
    text-decoration: none;
}
.dept-all:hover { color: var(--ccm-red); }
.dept-all .count { color: var(--ccm-muted); font-weight: 400; }

.dept-panel ul { list-style: none; margin: 0; padding: 0; }
.dept-panel li a {
    display: block;
    padding: 8px 18px;
    font-size: 13px;
    color: var(--ccm-body);
    text-decoration: none;
}
.dept-panel li a:hover { background: var(--ccm-mint); color: var(--ccm-ink); }

/* A mouse gets hover. Touch gets the <details> toggle, which needs no script —
   a menu that only opens on hover is a menu half the customers cannot open. */
@media (hover: hover) and (pointer: fine) {
    .dept:hover > .dept-panel { display: block; }
}

/* =============================================================================
   Tablet — 768px to 1023px
   -----------------------------------------------------------------------------
   The desktop arrangement, tightened. Everything the client's reference shows
   is still present; it is only narrower.
   ========================================================================== */

@media (min-width: 768px) and (max-width: 1023px) {
    .masthead .shell { gap: 12px; }
    .brand img { width: 168px; }

    .searchbar input  { padding: 10px 12px; font-size: 13.5px; }
    .searchbar button { padding: 0 18px; }

    /* The support label goes; the number stays, because the number is the
       part anybody actually uses. */
    .head-support svg { width: 26px; height: 26px; }
    .head-support-text small { display: none; }
    .head-support-text strong { font-size: 14px; }

    .head-actions { gap: 14px; }
    .head-glyph svg { width: 26px; height: 26px; }
    .head-word { display: none; }

    .dept-link { padding: 12px 10px; font-size: 13px; }
    .deptbar .shell { overflow-x: auto; flex-wrap: nowrap; }
}

/* =============================================================================
   Phone — up to 767px
   -----------------------------------------------------------------------------
   Two rows, as in the client's mobile reference: logo with the basket and
   account icons, then the menu button beside a full-width amber search.
   ========================================================================== */

@media (max-width: 767px) {
    .masthead .shell {
        display: grid;
        /* Four columns, and every action icon has a home.
           This had three areas for what is always four things — the logo, the
           tracking van, the basket and the account — so the account icon was
           left unplaced and the grid dropped it onto a row of its own under
           the search box. The user's icon now sits beside the search, which is
           where the client asked for it, and adding a fifth action would need
           a column rather than silently wrapping. */
        grid-template-columns: auto 1fr auto auto;
        grid-template-areas:
            "brand brand  track  cart"
            "menu  search search account";
        gap: 12px 10px;
        align-items: center;
    }

    .brand     { grid-area: brand; }
    .brand img { width: 165px; }

    .menu-holder  { grid-area: menu; }
    .menu-toggle  { width: 34px; padding: 0; }
    .searchbar    { grid-area: search; }
    .head-actions { display: contents; }

    /* The support block belongs on a phone's dialler, not its header. The
       number is one tap away in the footer and on every product page. */
    .head-support { display: none; }

    /* Placed by position, because that is what the markup guarantees:
       tracking, then the basket, then the account block — which is a link when
       somebody is signed in and a log-in/register pair when they are not. */
    .head-actions > :nth-child(1) { grid-area: track;   justify-self: end; }
    .head-actions > :nth-child(2) { grid-area: cart;    justify-self: end; }
    .head-actions > :nth-child(3) { grid-area: account; justify-self: end; }

    .head-word { display: none; }
    .head-glyph svg { width: 26px; height: 26px; }

    .searchbar input  { padding: 11px 12px; font-size: 13.5px; }
    .searchbar button { padding: 0 20px; }

    /* The department strip becomes a drawer. */
    .deptbar { display: none; border-top: 1px solid var(--ccm-rule); }
    .deptbar.is-open { display: block; }
    .deptbar .shell { flex-direction: column; align-items: stretch; gap: 0; flex-wrap: nowrap; }

    .dept-link {
        justify-content: space-between;
        width: 100%;
        padding: 13px 4px;
        border-bottom: 1px solid var(--ccm-rule-soft);
    }
    .dept-link.is-active { border-bottom-color: var(--ccm-amber); }
    .dept-home { justify-content: flex-start; }

    .dept-panel {
        position: static;
        border: 0;
        border-radius: 0;
        box-shadow: none;
        background: var(--ccm-surface);
        padding: 4px 0 8px 14px;
    }

}

/* Very small phones: give the search its own row rather than crushing it. */
@media (max-width: 380px) {
    .brand img { width: 140px; }
    .head-actions { gap: 12px; }
    .head-glyph svg { width: 24px; height: 24px; }
}

/* =============================================================================
   Something a thumb can actually hit (2026-09-12)
   -----------------------------------------------------------------------------
   The header icons draw at 28px, and shrink to 26px below 768px and 24px below
   381px. The anchor around them has no padding, so the *tappable* area was the
   icon itself — a 24px target on the three controls a phone user reaches for
   most: track an order, the basket, and sign in. Both platform guidelines put
   the minimum at 44px (Apple) / 48dp (Google), and the gap is not academic:
   a 24px target is missed often enough that people tap twice, and on the
   basket that reads as the site being broken.

   The fix is padding on the link, not a bigger icon. The mark stays the size
   it was designed to be — only the area that responds to a finger grows, so
   nothing on screen moves. `.head-glyph` deliberately keeps its natural size
   because `.cart-pill` is positioned against it; inflating it instead would
   push the basket count away from the basket.
   ========================================================================== */
@media (max-width: 767px) {
    .head-link,
    .head-glyph-link {
        min-width: 44px;
        min-height: 44px;
        justify-content: center;
    }

    /* The departments control, which is the same size problem. */
    .menu-toggle {
        min-width: 44px;
        min-height: 44px;
    }
}

/* =============================================================================
   Topbar
   -----------------------------------------------------------------------------
   Two facts, each with its own icon: where we deliver, and when. Dark ground so
   it separates cleanly from the white masthead below it without a rule.
   ========================================================================== */

.topbar {
    background: var(--ccm-ink);
    color: var(--ccm-bg);
    font-size: 12.5px;
    padding: 8px 0;
}

.topbar .shell {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
}

.topbar a { color: var(--ccm-amber); text-decoration: none; }
.topbar a:hover { text-decoration: underline; }

.topbar-item {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    line-height: 1.4;
}

.topbar-item svg {
    width: 16px;
    height: 16px;
    flex: none;
    color: var(--ccm-amber);
}

.topbar-item strong { font-weight: 600; color: var(--ccm-bg); }
.topbar-sep { color: var(--ccm-muted); padding: 0 3px; }

/* =============================================================================
   Shop by category
   -----------------------------------------------------------------------------
   The tile carries an initial as its mark. Not decoration: with no per-category
   artwork in the system yet, a row of identical grey boxes is harder to scan
   than a row of distinct letters, and inventing placeholder imagery would mean
   shipping pictures that promise something the catalogue does not have.
   ========================================================================== */

.cat-grid {
    display: grid;
    gap: 14px;
    grid-template-columns: repeat(auto-fill, minmax(158px, 1fr));
}

.cat-tile {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    border: 1px solid var(--ccm-rule);
    border-radius: var(--ccm-radius);
    padding: 20px 14px 16px;
    text-align: center;
    background: var(--ccm-bg);
    color: var(--ccm-ink);
    text-decoration: none;
    transition: border-color .15s, box-shadow .15s, transform .15s;
}

.cat-tile:hover,
.cat-tile:focus-visible {
    border-color: var(--ccm-amber);
    box-shadow: 0 6px 18px rgba(0, 0, 0, .08);
    transform: translateY(-2px);
    text-decoration: none;
}

.cat-tile-mark {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 46px;
    height: 46px;
    margin-bottom: 8px;
    border-radius: 50%;
    background: var(--ccm-mint);
    color: var(--ccm-red);
    font-size: 20px;
    font-weight: 700;
    line-height: 1;
    transition: background .15s, color .15s;
}

.cat-tile:hover .cat-tile-mark { background: var(--ccm-amber); color: var(--ccm-ink); }

.cat-tile strong { display: block; font-size: 13.5px; line-height: 1.3; font-weight: 600; }
.cat-tile-count { font-size: 11.5px; color: var(--ccm-muted); }

/* An empty department is still listed — a shopper looking for Fashion should
   find the word Fashion — but it is visibly quieter than a stocked one. */
.cat-tile.is-empty .cat-tile-mark { background: var(--ccm-rule-soft); color: var(--ccm-muted); }
.cat-tile.is-empty strong { color: var(--ccm-body); }

/* The section heading gained a subtitle, so its row aligns to the top. */
.row-head { align-items: flex-start; }
.row-head a { white-space: nowrap; padding-top: 4px; }

@media (max-width: 767px) {
    .topbar { font-size: 11.5px; padding: 7px 0; }
    .topbar .shell { justify-content: center; text-align: center; gap: 4px 14px; }
    .topbar-item svg { width: 14px; height: 14px; }

    .cat-grid { grid-template-columns: repeat(auto-fill, minmax(132px, 1fr)); gap: 10px; }
    .cat-tile { padding: 16px 10px 12px; }
    .cat-tile-mark { width: 40px; height: 40px; font-size: 17px; }
}

/* =============================================================================
   Password reveal
   -----------------------------------------------------------------------------
   A password nobody can read is a password typed wrong, especially on a phone
   keyboard. The toggle is a real <button> so it is reachable by keyboard, and
   it never submits the form.
   ========================================================================== */

.password-field { position: relative; display: block; }

.password-field input { width: 100%; padding-right: 44px; }

.password-toggle {
    position: absolute;
    top: 50%;
    right: 6px;
    transform: translateY(-50%);
    display: flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    padding: 0;
    border: 0;
    border-radius: 4px;
    background: transparent;
    color: var(--ccm-muted);
    cursor: pointer;
}

.password-toggle:hover { color: var(--ccm-ink); }
.password-toggle:focus-visible { outline: 2px solid var(--ccm-link); outline-offset: 1px; }
.password-toggle svg { width: 19px; height: 19px; }

/* Two icons, one shown at a time — swapped by the button's aria-pressed state,
   so the visual and the announced state cannot drift apart. */
.password-toggle .icon-hide { display: none; }
.password-toggle[aria-pressed="true"] .icon-show { display: none; }
.password-toggle[aria-pressed="true"] .icon-hide { display: block; }

/* =============================================================================
   The department panel behind the button beside the logo
   -----------------------------------------------------------------------------
   Departments down the left; the one under the pointer opens its
   sub-categories on the right. Only department names are listed by default,
   because thirty sub-categories on screen at once is a wall of text to read
   rather than a menu to use.

   It reveals on hover and on keyboard focus, in CSS. The script only handles
   opening and closing the panel itself.
   ========================================================================== */

.menu-holder { position: relative; flex: none; }

.mega-panel {
    display: none;
    position: absolute;
    top: calc(100% + 10px);
    left: 0;
    z-index: 60;
    width: 268px;
    background: var(--ccm-bg);
    border: 1px solid var(--ccm-rule);
    border-top: 3px solid var(--ccm-amber);
    border-radius: 0 0 6px 6px;
    box-shadow: 0 16px 40px rgba(0, 0, 0, .16);
    padding: 8px 0 0;
}

.mega-panel.is-open { display: block; }

/* Bridges the gap between button and panel, so crossing it does not close the
   menu. Invisible, and it moves nothing. */
.mega-panel::before {
    content: '';
    position: absolute;
    top: -13px;
    left: 0;
    right: 0;
    height: 13px;
}

.mega-list { list-style: none; margin: 0; padding: 0; }

.mega-dept { position: relative; }

.mega-dept-link {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 11px 16px;
    font-size: 13.5px;
    font-weight: 500;
    color: var(--ccm-ink);
    text-decoration: none;
    border-left: 3px solid transparent;
    transition: background .12s, border-color .12s, color .12s;
}

.mega-dept:hover > .mega-dept-link,
.mega-dept:focus-within > .mega-dept-link {
    background: var(--ccm-mint);
    border-left-color: var(--ccm-amber);
    color: var(--ccm-red);
}

.mega-caret { width: 13px; height: 13px; flex: none; color: var(--ccm-muted); }
.mega-dept:hover .mega-caret { color: var(--ccm-red); }

/* --- The flyout ----------------------------------------------------------- */

.mega-subs {
    display: none;
    position: absolute;
    top: -9px;
    left: 100%;
    min-width: 260px;
    max-width: 340px;
    background: var(--ccm-bg);
    border: 1px solid var(--ccm-rule);
    border-top: 3px solid var(--ccm-amber);
    border-radius: 0 6px 6px 0;
    box-shadow: 0 16px 40px rgba(0, 0, 0, .16);
    padding: 12px 0;
}

.mega-dept.has-subs:hover > .mega-subs,
.mega-dept.has-subs:focus-within > .mega-subs { display: block; }

.mega-subs-all {
    display: flex;
    align-items: baseline;
    gap: 7px;
    padding: 4px 18px 10px;
    margin-bottom: 6px;
    border-bottom: 1px solid var(--ccm-rule-soft);
    font-size: 13px;
    font-weight: 700;
    color: var(--ccm-ink);
    text-decoration: none;
}

.mega-subs-all:hover { color: var(--ccm-red); }
.mega-subs-all .count { font-size: 11px; font-weight: 400; color: var(--ccm-muted); }

.mega-subs ul { list-style: none; margin: 0; padding: 0; }

.mega-subs li a {
    display: block;
    padding: 6px 18px;
    font-size: 12.5px;
    line-height: 1.45;
    color: var(--ccm-body);
    text-decoration: none;
}

.mega-subs li a:hover { background: var(--ccm-mint); color: var(--ccm-ink); }

/* --- Footer --------------------------------------------------------------- */

.mega-foot {
    display: block;
    margin-top: 6px;
    padding: 11px 16px;
    border-top: 1px solid var(--ccm-rule-soft);
    background: var(--ccm-surface);
    border-radius: 0 0 6px 6px;
    font-size: 12.5px;
    font-weight: 600;
    color: var(--ccm-red);
    text-decoration: none;
}

.mega-foot:hover { background: var(--ccm-mint); }

/* If the panel would run off the right edge, flip the flyout to the left. */
@media (max-width: 1100px) {
    .mega-subs { left: auto; right: 100%; border-radius: 6px 0 0 6px; }
}

/* On a phone the button opens the department bar as a drawer instead, so the
   panel never appears — one list, reached two ways, rather than two lists. */
@media (max-width: 767px) {
    .mega-panel,
    .mega-panel.is-open { display: none; }

    .menu-holder { grid-area: menu; }
}

/* A folded department's own children sit one step in, so "Mens Fashion" reads
   as belonging to "Fashion" rather than sitting beside it. */
.mega-subs li.is-nested a { padding-left: 32px; color: var(--ccm-muted); }
.mega-subs li.is-nested a:hover { color: var(--ccm-ink); }

/* =============================================================================
   Checkout — the professional treatment
   -----------------------------------------------------------------------------
   Rewritten over the first pass. This is the screen where a shopper decides
   whether to trust the shop with money, so it is the one screen where the
   visual work is doing a job rather than decorating.

   Three decisions:

     * Numbered steps. A checkout that looks like one long form reads as
       long; the same fields under "1 Delivery / 2 Contact / 3 Payment" read as
       three short ones.
     * A summary that follows you down the page on a desktop, so the total is
       never scrolled off while you fill in an address.
     * The total set apart in the brand amber. It is the single number the
       customer is actually deciding about.
   ========================================================================== */

.checkout-layout {
    display: grid;
    grid-template-columns: 1fr;
    gap: 26px;
    align-items: start;
    padding: 8px 0 48px;
}

/* --- Page heading --------------------------------------------------------- */

.checkout-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
    padding: 26px 0 18px;
    border-bottom: 1px solid var(--ccm-rule);
    margin-bottom: 22px;
}

.checkout-head h1 { font-size: 26px; letter-spacing: -.02em; margin: 0; }
.checkout-head .sub { font-size: 13px; color: var(--ccm-muted); margin-top: 4px; }

.checkout-secure {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    font-size: 12.5px;
    font-weight: 600;
    color: var(--ccm-body);
}
.checkout-secure svg { width: 16px; height: 16px; color: var(--ccm-red); }

/* --- Panels as numbered steps --------------------------------------------- */

.panel {
    background: var(--ccm-bg);
    border: 1px solid var(--ccm-rule);
    border-radius: 6px;
    padding: 22px 24px 24px;
    margin-bottom: 18px;
}

.panel h2 {
    display: flex;
    align-items: center;
    gap: 11px;
    font-size: 16px;
    margin: 0 0 6px;
    letter-spacing: -.01em;
}

/* The step number. A counter rather than markup, so reordering the panels
   renumbers them automatically and no template carries a hard-coded "2". */
.checkout-layout { counter-reset: step; }

.panel-step h2::before {
    counter-increment: step;
    content: counter(step);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    flex: none;
    border-radius: 50%;
    background: var(--ccm-amber);
    color: var(--ccm-ink);
    font-size: 13px;
    font-weight: 700;
}

.panel > .card-cat { margin: 0 0 16px; }

/* --- Fields --------------------------------------------------------------- */

.field-row { display: grid; grid-template-columns: 1fr; gap: 0 16px; }

.checkout-layout .field { margin-bottom: 14px; }

.checkout-layout label {
    display: block;
    font-size: 12.5px;
    font-weight: 600;
    color: var(--ccm-ink);
    margin-bottom: 5px;
}

.checkout-layout input[type="text"],
.checkout-layout input[type="tel"],
.checkout-layout input[type="email"],
.checkout-layout select,
.checkout-layout textarea {
    width: 100%;
    border: 1px solid var(--ccm-rule);
    border-radius: 4px;
    padding: 11px 13px;
    font-family: inherit;
    font-size: 14px;
    color: var(--ccm-ink);
    background: var(--ccm-bg);
    outline: none;
    transition: border-color .12s, box-shadow .12s;
}

.checkout-layout input:focus,
.checkout-layout select:focus,
.checkout-layout textarea:focus {
    border-color: var(--ccm-amber);
    box-shadow: 0 0 0 3px var(--ccm-mint);
}

.checkout-layout input[aria-invalid="true"] { border-color: var(--ccm-red); }
.checkout-layout textarea { resize: vertical; min-height: 62px; }

/* --- Choosing an address or a payment method ------------------------------ */

.pick {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    border: 1px solid var(--ccm-rule);
    border-radius: 5px;
    padding: 13px 15px;
    margin-bottom: 9px;
    cursor: pointer;
    transition: border-color .12s, background .12s, box-shadow .12s;
}

.pick:hover { border-color: var(--ccm-muted); }
.pick input { margin-top: 3px; flex: none; accent-color: var(--ccm-red); }
.pick span { display: block; line-height: 1.5; }
.pick .card-cat { display: block; margin-top: 3px; }

.pick:has(input:checked) {
    border-color: var(--ccm-red);
    background: var(--ccm-mint);
    box-shadow: inset 0 0 0 1px var(--ccm-red);
}

.pick.is-disabled { opacity: .5; cursor: not-allowed; }
.pick.is-disabled:hover { border-color: var(--ccm-rule); }

/* --- The summary ---------------------------------------------------------- */

.summary {
    background: var(--ccm-bg);
    border: 1px solid var(--ccm-rule);
    border-radius: 6px;
    padding: 22px 24px;
}

.summary h2 {
    font-size: 15px;
    margin: 0 0 14px;
    padding-bottom: 12px;
    border-bottom: 1px solid var(--ccm-rule-soft);
    letter-spacing: -.01em;
}

.summary-line {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 14px;
    font-size: 13.5px;
    padding: 6px 0;
}

.summary-line > span:first-child { color: var(--ccm-body); }
.summary-line > span:last-child { font-weight: 600; text-align: right; }

.summary-rule {
    border-top: 1px solid var(--ccm-rule-soft);
    margin-top: 10px;
    padding-top: 12px;
}

/* The one number the customer is deciding about. */
.summary-total {
    margin-top: 12px;
    padding-top: 14px;
    border-top: 2px solid var(--ccm-ink);
    font-size: 17px;
}
.summary-total > span:first-child { color: var(--ccm-ink); font-weight: 700; }
.summary-total > span:last-child { font-weight: 700; font-size: 20px; }

.summary .btn-block { margin-top: 18px; }
.summary .card-cat { display: block; margin-top: 10px; line-height: 1.55; }

/* --- Reassurance under the button ----------------------------------------- */

.checkout-assure {
    list-style: none;
    margin: 16px 0 0;
    padding: 16px 0 0;
    border-top: 1px solid var(--ccm-rule-soft);
}

.checkout-assure li {
    display: flex;
    align-items: flex-start;
    gap: 9px;
    font-size: 12px;
    line-height: 1.5;
    color: var(--ccm-body);
    padding: 5px 0;
}

.checkout-assure svg { width: 15px; height: 15px; flex: none; margin-top: 1px; color: var(--ccm-red); }

/* --- Wide screens --------------------------------------------------------- */

@media (min-width: 900px) {
    .checkout-layout { grid-template-columns: minmax(0, 1fr) 360px; }

    /* The total stays in view while the address is filled in. */
    .checkout-layout .summary { position: sticky; top: 18px; }
}

@media (max-width: 767px) {
    .panel { padding: 18px 16px 20px; border-radius: 5px; }
    .summary { padding: 18px 16px; }
    .checkout-head { padding: 18px 0 14px; }
    .checkout-head h1 { font-size: 22px; }
    .summary-total > span:last-child { font-size: 18px; }
}

/* --- Confirmation --------------------------------------------------------- */

.order-done { text-align: center; padding: 34px 0 8px; }

.order-done-mark {
    width: 62px;
    height: 62px;
    margin: 0 auto 16px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background: var(--ccm-mint);
    color: var(--ccm-red);
}
.order-done-mark svg { width: 30px; height: 30px; }

.order-done h1 { font-size: 26px; margin: 0 0 8px; }
.order-done-sub { margin: 0 0 16px; font-size: 15px; }

/* The guest's link back to their order, with Copy and Open beside it.
   A readonly input rather than a <span>: it can be tapped, selected and
   copied by hand on a phone, which a span cannot. */
.track-link-row {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    margin-top: 8px;
}

.track-link {
    flex: 1 1 260px;
    min-width: 0;
    padding: 8px 10px;
    background: var(--ccm-bg);
    border: 1px solid var(--ccm-rule);
    border-radius: 6px;
    font-size: 12px;
    font-family: var(--ccm-mono, monospace);
    color: var(--ccm-ink);
    text-overflow: ellipsis;
}

.track-link:focus { outline: 2px solid var(--ccm-link); outline-offset: 1px; }

/* Set by ccm copy-button script when the copy lands. */
.is-copied { background: var(--ccm-mint); }

/* --- Status pill ---------------------------------------------------------- */

.order-pill {
    display: inline-block;
    padding: 3px 9px;
    border-radius: 11px;
    font-size: 11.5px;
    font-weight: 700;
    line-height: 1.5;
    white-space: nowrap;
}

.order-pill-ok   { background: var(--ccm-mint);      color: var(--ccm-ink); }
.order-pill-wait { background: var(--ccm-rule-soft); color: var(--ccm-body); }
.order-pill-bad  { background: var(--ccm-red);       color: var(--ccm-bg); }

/* --- Timeline ------------------------------------------------------------- */

.timeline { list-style: none; margin: 10px 0 0; padding: 0 0 0 16px; border-left: 2px solid var(--ccm-rule); }

.timeline li {
    position: relative;
    padding: 0 0 14px 12px;
    font-size: 13px;
    line-height: 1.5;
}

.timeline li::before {
    content: '';
    position: absolute;
    left: -21px;
    top: 5px;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--ccm-amber);
}

.timeline li:last-child { padding-bottom: 0; }

.timeline-when {
    display: block;
    font-size: 11.5px;
    color: var(--ccm-muted);
}

@media (min-width: 768px) {
    .checkout-layout { grid-template-columns: 1fr 340px; }
    .field-row { grid-template-columns: 1fr 1fr; }
}

/* =============================================================================
   Quantity stepper and icon buttons
   -----------------------------------------------------------------------------
   A stepper rather than a bare number field: on a phone, tapping plus is one
   action where typing into a spinner is three. The field itself stays, because
   it is what submits and what a keyboard user edits.
   ========================================================================== */

.stepper {
    display: inline-flex;
    align-items: stretch;
    border: 1px solid var(--ccm-rule);
    border-radius: 4px;
    overflow: hidden;
    background: var(--ccm-bg);
}

.stepper-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 38px;
    border: 0;
    background: var(--ccm-surface);
    color: var(--ccm-ink);
    cursor: pointer;
    padding: 0;
    transition: background .12s, color .12s;
}

.stepper-btn:hover { background: var(--ccm-amber); }
.stepper-btn:focus-visible { outline: 2px solid var(--ccm-link); outline-offset: -2px; }

.stepper-btn svg {
    width: 15px;
    height: 15px;
    stroke: currentColor;
    stroke-width: 2;
    stroke-linecap: round;
    fill: none;
}

.stepper input[type="number"] {
    width: 52px;
    border: 0;
    border-left: 1px solid var(--ccm-rule);
    border-right: 1px solid var(--ccm-rule);
    text-align: center;
    font-family: inherit;
    font-size: 14px;
    font-weight: 600;
    color: var(--ccm-ink);
    background: var(--ccm-bg);
    padding: 9px 0;
    outline: none;
    /* The browser's own spinner would sit beside our buttons doing the same
       job, half the size and in the wrong place. */
    -moz-appearance: textfield;
    appearance: textfield;
}

.stepper input[type="number"]::-webkit-outer-spin-button,
.stepper input[type="number"]::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

/* While a change is being sent, the control dims rather than jumping. */
.stepper[aria-busy="true"] { opacity: .55; pointer-events: none; }

/* --- Icon buttons --------------------------------------------------------- */

.icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 42px;
    height: 42px;
    border: 1px solid var(--ccm-rule);
    border-radius: 4px;
    background: var(--ccm-bg);
    color: var(--ccm-ink);
    cursor: pointer;
    text-decoration: none;
    padding: 0;
    transition: border-color .12s, background .12s, color .12s;
}

.icon-btn:hover {
    border-color: var(--ccm-amber);
    background: var(--ccm-amber);
    color: var(--ccm-ink);
}

.icon-btn svg { width: 20px; height: 20px; }

/* The quiet variant, for a destructive action that should not shout. */
.icon-btn-quiet {
    width: 34px;
    height: 34px;
    border-color: transparent;
    color: var(--ccm-muted);
}
.icon-btn-quiet:hover {
    background: transparent;
    border-color: var(--ccm-red);
    color: var(--ccm-red);
}
.icon-btn-quiet svg { width: 17px; height: 17px; }

/* An icon sitting inside a normal text button. */
.btn-icon {
    width: 15px;
    height: 15px;
    vertical-align: -2px;
    margin-right: 5px;
}

.qty-row {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    margin: 18px 0 0;
}

.cart-actions {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    margin-top: 10px;
}

@media (max-width: 767px) {
    .stepper-btn { width: 42px; }
    .stepper input[type="number"] { width: 48px; padding: 11px 0; }
    .qty-row .btn { flex: 1 1 auto; }
}

/* A failed payment gets the same mark as a successful one, in the other tone. */
.order-done-mark.is-bad { background: var(--ccm-rule-soft); color: var(--ccm-red); }
.mono { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 12.5px; }

/* =============================================================================
   Add to basket — the in-place control
   -----------------------------------------------------------------------------
   The button and the stepper occupy the same slot, so swapping between them
   does not move anything else on the page. On a listing that matters: a card
   that changed height on add would shove the rest of the grid around under the
   shopper's finger.
   ========================================================================== */

.add-control { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin: 18px 0 0; }
.add-control.is-compact { margin: 0; gap: 8px; }

.add-live { display: flex; align-items: center; gap: 8px; }
.add-live[aria-busy="true"] { opacity: .55; pointer-events: none; }

.add-qty {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 46px;
    padding: 9px 4px;
    border-left: 1px solid var(--ccm-rule);
    border-right: 1px solid var(--ccm-rule);
    font-size: 14px;
    font-weight: 700;
    color: var(--ccm-ink);
    background: var(--ccm-bg);
}

.add-note {
    flex: 1 1 100%;
    font-size: 11.5px;
    color: var(--ccm-muted);
    min-height: 15px;
    line-height: 1.3;
}
.add-note.is-bad { color: var(--ccm-red); font-weight: 600; }

/* On a card the control fills the width, and the basket icon shrinks so the
   stepper keeps its target size. */
.add-control.is-compact .btn { flex: 1 1 100%; }
.add-control.is-compact .add-live { width: 100%; }
.add-control.is-compact .stepper { flex: 1 1 auto; }
.add-control.is-compact .add-qty { flex: 1 1 auto; }
.add-control.is-compact .icon-btn { width: 38px; height: 38px; flex: none; }
.add-control.is-compact .stepper-btn { width: 34px; }

/* -----------------------------------------------------------------------------
   [hidden] must actually hide.
   -----------------------------------------------------------------------------
   Any rule that sets `display` on an element beats the browser's built-in
   `[hidden] { display: none }`, because that default has the lowest possible
   precedence. `.add-live { display: flex }` therefore showed every quantity
   stepper on every product at once, whether the shopper had added it or not.
   This one line makes the attribute mean what it says, everywhere.
   -------------------------------------------------------------------------- */
[hidden] { display: none !important; }

/* =============================================================================
   Product image lightbox
   -----------------------------------------------------------------------------
   Tapping a product image opens it large, growing out of the thumbnail rather
   than appearing from nowhere — so it is obvious which picture opened and
   where it will go back to.

   The whole thing is one element appended to <body>, not a copy per image: a
   listing of forty products would otherwise carry forty hidden dialogs.
   ========================================================================== */

.lightbox {
    position: fixed;
    inset: 0;
    z-index: 200;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px;
    background: rgba(0, 0, 0, .82);
    opacity: 0;
    transition: opacity .22s ease;
}

.lightbox.is-open { opacity: 1; }

.lightbox-figure {
    position: relative;
    max-width: min(920px, 100%);
    max-height: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
    /* Grows from 92% as it opens: small enough to read as a zoom, large enough
       not to feel like a bounce. */
    transform: scale(.92);
    opacity: 0;
    transition: transform .26s cubic-bezier(.2, .8, .3, 1), opacity .2s ease;
}

.lightbox.is-open .lightbox-figure { transform: scale(1); opacity: 1; }

.lightbox-figure img {
    display: block;
    max-width: 100%;
    max-height: calc(100vh - 140px);
    object-fit: contain;
    border-radius: 6px;
    background: var(--ccm-bg);
    cursor: zoom-in;
    transition: transform .3s cubic-bezier(.2, .8, .3, 1);
    transform-origin: center;
}

/* A second tap zooms further, and the image can then be dragged by scrolling
   its container — the plain way, which works on every phone. */
.lightbox-figure img.is-zoomed { transform: scale(1.9); cursor: zoom-out; }

.lightbox-caption {
    color: var(--ccm-bg);
    font-size: 13.5px;
    text-align: center;
    max-width: 60ch;
    line-height: 1.5;
}

.lightbox-close {
    position: absolute;
    top: -14px;
    right: -14px;
    width: 38px;
    height: 38px;
    display: flex;
    align-items: center;
    justify-content: center;
    border: 0;
    border-radius: 50%;
    background: var(--ccm-bg);
    color: var(--ccm-ink);
    cursor: pointer;
    box-shadow: 0 2px 10px rgba(0, 0, 0, .35);
}
.lightbox-close svg { width: 17px; height: 17px; }

/* Anything the lightbox can open gets the cursor that says so. */
/* Only the product page zooms. A card image showed a magnifier cursor
   too, which promised a zoom that quick view took over. */
.pdp-main img, .pdp-thumbs img { cursor: zoom-in; }

@media (prefers-reduced-motion: reduce) {
    .lightbox, .lightbox-figure, .lightbox-figure img { transition: none; }
}

@media (max-width: 767px) {
    .lightbox { padding: 14px; }
    .lightbox-close { top: -6px; right: -6px; }
    .lightbox-figure img { max-height: calc(100vh - 120px); }
}

/* The way back to the product page, for a picture opened from a listing. */
.lightbox-more {
    display: inline-block;
    padding: 9px 20px;
    border-radius: 20px;
    background: var(--ccm-amber);
    color: var(--ccm-ink);
    font-size: 13px;
    font-weight: 700;
    text-decoration: none;
}
.lightbox-more:hover { filter: brightness(.94); }

/* The magnifier badge that sat in the bottom-right corner of every card
   picture was removed at the client's request: the eye in the middle of the
   image already means "look closer", and two glyphs promising the same thing
   on one photograph read as two different actions.

   It was drawn as a ::after pseudo-element with an inline SVG, which is why
   it is worth saying so here — nothing in the markup mentions it, and a
   search of the templates for a zoom icon finds nothing.

   `position: relative` stays: .quick-view is absolutely positioned against
   this box and would otherwise centre itself on the page. */
.card-media { position: relative; }

/* =============================================================================
   Quick view
   -----------------------------------------------------------------------------
   An eye on the picture, and the add-to-basket controls kept out of the way
   until the shopper shows interest in that card.

   The actions are hidden with opacity rather than display, and the card
   reserves their height either way — so revealing them does not reflow the
   grid under the pointer, which on a touch screen means tapping the wrong
   thing.
   ========================================================================== */

.quick-view {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%) scale(.8);
    z-index: 2;
    width: 46px;
    height: 46px;
    display: flex;
    align-items: center;
    justify-content: center;
    border: 0;
    border-radius: 50%;
    background: var(--ccm-bg);
    color: var(--ccm-ink);
    cursor: pointer;
    opacity: 0;
    box-shadow: 0 4px 16px rgba(0, 0, 0, .25);
    transition: opacity .18s ease, transform .18s cubic-bezier(.2, .8, .3, 1), background .15s;
}

.quick-view svg { width: 21px; height: 21px; }

.card:hover .quick-view,
.card:focus-within .quick-view {
    opacity: 1;
    transform: translate(-50%, -50%) scale(1);
}

.quick-view:hover { background: var(--ccm-amber); }
.quick-view:focus-visible { opacity: 1; transform: translate(-50%, -50%) scale(1); outline: 2px solid var(--ccm-link); }

/* --- The card's action area ----------------------------------------------- */

.card-actions {
    opacity: 0;
    transform: translateY(4px);
    transition: opacity .18s ease, transform .18s ease;
}

.card:hover .card-actions,
.card:focus-within .card-actions { opacity: 1; transform: none; }

/* A card holding something already in the basket keeps its stepper visible —
   hiding the quantity a shopper has chosen would be hiding information, not
   tidying it away. */
.card-actions:has(.add-live:not([hidden])) { opacity: 1; transform: none; }

/* Touch screens have no hover, so the actions are simply always there. */
@media (hover: none) {
    .card-actions { opacity: 1; transform: none; }
    .quick-view { opacity: .92; transform: translate(-50%, -50%) scale(1); }
}

/* =============================================================================
   The quick-view panel
   ========================================================================== */

.qv-figure {
    display: grid;
    grid-template-columns: 1fr;
    gap: 0;
    width: min(940px, 100%);
    max-height: calc(100vh - 48px);
    background: var(--ccm-bg);
    border-radius: 8px;
    overflow: hidden;
    transform: scale(.92);
    opacity: 0;
    transition: transform .28s cubic-bezier(.2, .8, .3, 1), opacity .2s ease;
}

.lightbox.is-open .qv-figure { transform: scale(1); opacity: 1; }

.qv-image {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px;
    background: var(--ccm-surface);
    min-height: 220px;
}
.qv-image img { max-width: 100%; max-height: 46vh; object-fit: contain; }

.qv-body { padding: 26px 28px 28px; overflow-y: auto; }

.qv-body h2 {
    font-size: 22px;
    line-height: 1.25;
    letter-spacing: -.02em;
    margin: 0 0 16px;
    padding-bottom: 16px;
    border-bottom: 1px solid var(--ccm-rule);
}

.qv-price {
    font-size: 28px;
    font-weight: 700;
    color: var(--ccm-ink);
    display: block;
    margin-bottom: 6px;
}
.qv-price-was {
    font-size: 16px;
    color: var(--ccm-muted);
    text-decoration: line-through;
    margin-left: 8px;
    font-weight: 400;
}

.qv-meta {
    display: flex;
    align-items: center;
    gap: 14px;
    flex-wrap: wrap;
    padding: 14px 0;
    margin-bottom: 6px;
    border-top: 1px solid var(--ccm-rule);
    border-bottom: 1px solid var(--ccm-rule);
    font-size: 13.5px;
    color: var(--ccm-body);
}
.qv-meta strong { color: var(--ccm-link); }
.qv-meta .in-stock { color: var(--ccm-red); font-weight: 700; }
.qv-meta .out-stock { color: var(--ccm-muted); font-weight: 700; }
.qv-sep { color: var(--ccm-rule); }

.qv-actions { margin-top: 20px; }
.qv-actions .add-control { margin: 0; }

/* The panel borrows the card's own add control rather than cloning it, so a
   quantity set here is the quantity on the card behind the panel. It arrives
   at card size and is scaled up to suit the larger surface. */
.qv-control-slot .add-control { width: 100%; }
.qv-control-slot .add-live { justify-content: flex-start; }
.qv-control-slot .stepper-btn { width: 40px; height: 40px; }
.qv-control-slot .add-qty { min-width: 46px; font-size: 16px; }
.qv-actions .btn { padding: 13px 34px; font-size: 15px; }

.qv-more {
    display: inline-block;
    margin-top: 16px;
    font-size: 13px;
    color: var(--ccm-link);
}

.qv-close {
    position: absolute;
    top: 12px;
    right: 12px;
    z-index: 3;
    width: 34px;
    height: 34px;
    display: flex;
    align-items: center;
    justify-content: center;
    border: 0;
    border-radius: 50%;
    background: transparent;
    color: var(--ccm-body);
    cursor: pointer;
}
.qv-close:hover { color: var(--ccm-ink); }
.qv-close svg { width: 20px; height: 20px; }

.qv-loading { padding: 60px; text-align: center; color: var(--ccm-muted); font-size: 14px; }

@media (min-width: 768px) {
    .qv-figure { grid-template-columns: 1fr 1fr; }
    .qv-image { min-height: 380px; padding: 30px; }
    .qv-image img { max-height: 60vh; }
}

@media (prefers-reduced-motion: reduce) {
    .quick-view, .card-actions, .qv-figure { transition: none; }
}

/* ------------------------------------------------------- CMS sections (Phase 12)
   These render whatever the homepage layout asks for, so they have to look
   right anywhere on the page rather than only in the position they were
   originally written into. */

/* A preview is unmistakable on purpose. Someone looking at a draft must never
   wonder whether shoppers can see it too. */
.preview-band {
    background: var(--ccm-amber);
    color: var(--ccm-amber-ink);
    font-size: 13px;
    padding: 9px 0;
}
.preview-band a { color: var(--ccm-amber-ink); text-decoration: underline; }

.promo-banner {
    position: relative;
    border-radius: var(--ccm-radius);
    overflow: hidden;
    background: var(--ccm-surface);
}
.promo-banner img { display: block; width: 100%; height: auto; }
.promo-body { padding: 22px; }
.promo-body h2 { margin: 0 0 6px; font-size: 20px; }
.promo-body p { margin: 0 0 14px; color: var(--ccm-body); font-size: 14px; }

/* A banner with artwork puts its words over the picture from a tablet up,
   where there is room. On a phone they stack, because text over a photograph
   at that width is unreadable however carefully it is placed. */
@media (min-width: 768px) {
    .promo-banner:has(img) .promo-body {
        position: absolute;
        inset: 0;
        display: flex;
        flex-direction: column;
        justify-content: center;
        max-width: 52%;
        padding: 30px;
    }
}

.rich-text { max-width: 68ch; color: var(--ccm-body); font-size: 15px; line-height: 1.7; }

/* --------------------------------------------------- support dock and chat
   Two launchers, bottom right, in the tawk.to arrangement the client asked
   for. WhatsApp is a plain link so it works with no script at all; chat opens
   a panel that keeps the shopper on the site.

   The dock sits above everything except the lightbox, and clear of the safe
   area on phones with a home indicator — a support button under the gesture
   bar is a support button nobody can press. */
.support-dock {
    position: fixed;
    right: 16px;
    bottom: calc(16px + env(safe-area-inset-bottom, 0px));
    z-index: 90;
    display: flex;
    flex-direction: column-reverse;
    gap: 10px;
    align-items: flex-end;
}

.support-btn {
    display: inline-flex;
    align-items: center;
    gap: 9px;
    height: 52px;
    padding: 0 18px 0 15px;
    border: 0;
    border-radius: 26px;
    font: inherit;
    font-size: 14px;
    font-weight: 600;
    cursor: pointer;
    box-shadow: 0 4px 16px rgba(0, 0, 0, .18);
    transition: transform .16s ease, filter .16s ease;
}
.support-btn:hover { transform: translateY(-1px); filter: brightness(.96); text-decoration: none; }
.support-btn svg { width: 22px; height: 22px; flex: none; }

/* Both buttons are in the Cape Coast palette, by client instruction: no colour
   on the storefront that is not the brand's own.
   
   That is a real trade-off worth naming. WhatsApp's green is how people
   recognise the button at a glance, and amber is not it — the icon's shape has
   to do that work alone here. The shape is the official mark and is unaltered,
   so it is still recognisable; it is simply quieter than it would be in green. */
.support-btn-wa   { background: var(--ccm-amber);  color: var(--ccm-amber-ink); }
.support-btn-chat { background: var(--ccm-orange); color: var(--ccm-badge-ink); }

/* On a phone the labels go and the buttons become discs. Two full-width pills
   stacked in the corner of a small screen cover the product a shopper is
   trying to read. */
@media (max-width: 767px) {
    .support-btn-label { display: none; }
    .support-btn { width: 52px; padding: 0; justify-content: center; }
}

.chat-panel {
    position: fixed;
    right: 16px;
    bottom: calc(82px + env(safe-area-inset-bottom, 0px));
    z-index: 91;
    width: min(370px, calc(100vw - 32px));
    max-height: min(560px, calc(100vh - 140px));
    display: flex;
    flex-direction: column;
    background: var(--ccm-bg);
    border: 1px solid var(--ccm-rule);
    border-radius: 14px;
    overflow: hidden;
    box-shadow: 0 12px 40px rgba(0, 0, 0, .22);
}

.chat-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 14px 16px;
    background: var(--ccm-orange);
    color: var(--ccm-badge-ink);
}
.chat-head-sub { font-size: 12px; opacity: .9; margin-top: 2px; }
.chat-close {
    border: 0; background: none; color: var(--ccm-badge-ink);
    cursor: pointer; padding: 4px; line-height: 0;
}
.chat-close svg { width: 20px; height: 20px; }

.chat-log {
    flex: 1;
    min-height: 180px;
    overflow-y: auto;
    padding: 16px;
    background: var(--ccm-surface);
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.chat-msg { display: flex; flex-direction: column; max-width: 82%; }
.chat-msg-visitor { align-self: flex-end; align-items: flex-end; }
.chat-msg-staff, .chat-msg-system { align-self: flex-start; }

.chat-bubble {
    padding: 10px 13px;
    border-radius: 14px;
    font-size: 13.5px;
    line-height: 1.5;
    /* A pasted order number or a long URL must wrap rather than stretch the
       panel off the side of the screen. */
    overflow-wrap: anywhere;
}
.chat-msg-visitor .chat-bubble {
    background: var(--ccm-orange);
    color: var(--ccm-badge-ink);
    border-bottom-right-radius: 4px;
}
.chat-msg-staff .chat-bubble {
    background: var(--ccm-bg);
    color: var(--ccm-ink);
    border: 1px solid var(--ccm-rule);
    border-bottom-left-radius: 4px;
}
/* A system line is not a person and must not look like one. */
.chat-msg-system .chat-bubble {
    background: transparent;
    color: var(--ccm-body);
    border: 1px dashed var(--ccm-rule);
    font-size: 13px;
}
.chat-who { font-size: 11px; color: var(--ccm-muted); margin: 0 4px 3px; }

.chat-note {
    align-self: center;
    font-size: 12px;
    color: var(--ccm-muted);
    text-align: center;
}

.chat-form {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 10px 12px;
    border-top: 1px solid var(--ccm-rule);
    background: var(--ccm-bg);
}
.chat-form input {
    flex: 1;
    min-width: 0;
    padding: 10px 12px;
    border: 1px solid var(--ccm-rule);
    border-radius: 20px;
    font: inherit;
    font-size: 13.5px;
}
.chat-form input:focus { outline: none; border-color: var(--ccm-orange); }
.chat-send {
    flex: none;
    width: 40px; height: 40px;
    display: inline-flex; align-items: center; justify-content: center;
    border: 0; border-radius: 50%;
    background: var(--ccm-orange); color: var(--ccm-badge-ink);
    cursor: pointer;
}
.chat-send svg { width: 18px; height: 18px; }

.chat-foot {
    margin: 0;
    padding: 0 14px 12px;
    font-size: 12px;
    color: var(--ccm-muted);
    background: var(--ccm-bg);
}

/* Visible to a screen reader, invisible on the page. */
.u-sr-only {
    position: absolute; width: 1px; height: 1px;
    padding: 0; margin: -1px; overflow: hidden;
    clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ---------------------------------------------- chat suggestions and handover
   Tappable common questions, and the way out to a person.

   The chips sit between the log and the composer rather than inside the log,
   so they do not scroll away with the conversation — somebody who has read two
   canned answers and still needs help must be able to find "talk to a person"
   without scrolling back up. */
.chat-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 7px;
    padding: 12px 14px 0;
    background: var(--ccm-bg);
}

.chat-chip {
    padding: 7px 13px;
    border: 1px solid var(--ccm-rule);
    border-radius: 999px;
    background: var(--ccm-bg);
    color: var(--ccm-body);
    font: inherit;
    font-size: 12.5px;
    cursor: pointer;
    transition: border-color .14s ease, color .14s ease;
}
.chat-chip:hover { border-color: var(--ccm-orange); color: var(--ccm-ink); }

.chat-human {
    padding: 10px 14px 0;
    background: var(--ccm-bg);
}

/* Quieter than the send button on purpose. It is an escape hatch, not the
   thing we are steering people towards — but it is never hidden behind
   anything either, because somebody who wants a person should not have to
   hunt. */
.chat-human-btn {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 8px 14px;
    border: 1px solid var(--ccm-orange);
    border-radius: 999px;
    background: var(--ccm-bg);
    color: var(--ccm-orange);
    font: inherit;
    font-size: 12.5px;
    font-weight: 600;
    cursor: pointer;
}
.chat-human-btn:hover { background: var(--ccm-orange); color: var(--ccm-badge-ink); }
.chat-human-btn:disabled { opacity: .5; cursor: default; }
.chat-human-btn svg { width: 15px; height: 15px; }

/* ------------------------------------------------------ dialogs and toasts
   The SweetAlert experience, in the project's own markup.

   Not SweetAlert2 itself: this site runs `style-src 'self'` with no
   `unsafe-inline`, and that library sets inline style attributes on the nodes
   it creates. Bundling it would have meant weakening the CSP for a dialog box.

   No inline styles here, and every colour is a token. */
.ccm-dialog-backdrop {
    position: fixed;
    inset: 0;
    z-index: 200;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 20px;
    background: rgba(0, 0, 0, .45);
    opacity: 0;
    transition: opacity .18s ease;
}
.ccm-dialog-backdrop.is-open { opacity: 1; }

.ccm-dialog {
    width: min(420px, 100%);
    background: var(--ccm-bg);
    border-radius: 16px;
    padding: 28px 26px 22px;
    text-align: center;
    box-shadow: 0 18px 50px rgba(0, 0, 0, .28);
    transform: scale(.94);
    transition: transform .18s ease;
}
.ccm-dialog-backdrop.is-open .ccm-dialog { transform: scale(1); }

.ccm-dialog-mark {
    width: 62px; height: 62px;
    margin: 0 auto 16px;
    border-radius: 50%;
    display: flex; align-items: center; justify-content: center;
}
.ccm-dialog-mark svg { width: 30px; height: 30px; }
.ccm-dialog-mark-warning { background: var(--ccm-amber); color: var(--ccm-amber-ink); }
.ccm-dialog-mark-danger  { background: var(--ccm-red-band); color: var(--ccm-badge-ink); }
.ccm-dialog-mark-success { background: var(--ccm-mint); color: var(--ccm-ink); }
.ccm-dialog-mark-info    { background: var(--ccm-surface); color: var(--ccm-body); }

.ccm-dialog-title { margin: 0 0 8px; font-size: 20px; font-weight: 700; color: var(--ccm-ink); }
.ccm-dialog-text  { margin: 0 0 20px; font-size: 14px; line-height: 1.6; color: var(--ccm-body); }
.ccm-dialog-actions { display: flex; gap: 10px; justify-content: center; flex-wrap: wrap; }
.ccm-dialog-actions .btn { min-width: 128px; }

/* Nothing scrolls behind an open dialog. */
body.ccm-dialog-lock { overflow: hidden; }

.ccm-toasts {
    position: fixed;
    right: 16px;
    bottom: 16px;
    z-index: 210;
    display: flex;
    flex-direction: column-reverse;
    gap: 10px;
    max-width: min(380px, calc(100vw - 32px));
}

.ccm-toast {
    display: flex;
    align-items: flex-start;
    gap: 11px;
    padding: 13px 14px;
    border-radius: 12px;
    background: var(--ccm-bg);
    border: 1px solid var(--ccm-rule);
    box-shadow: 0 8px 26px rgba(0, 0, 0, .16);
    font-size: 13.5px;
    line-height: 1.5;
    color: var(--ccm-ink);
    opacity: 0;
    transform: translateY(8px);
    transition: opacity .2s ease, transform .2s ease;
}
.ccm-toast.is-open { opacity: 1; transform: none; }
.ccm-toast .ccm-dialog-mark { width: 26px; height: 26px; margin: 0; flex: none; }
.ccm-toast .ccm-dialog-mark svg { width: 15px; height: 15px; }
.ccm-toast-success { border-left: 3px solid var(--ccm-mint); }
.ccm-toast-error   { border-left: 3px solid var(--ccm-red-band); }

.ccm-toast-x {
    margin-left: auto;
    border: 0; background: none; cursor: pointer;
    color: var(--ccm-muted); font-size: 18px; line-height: 1;
    padding: 0 2px;
}
.ccm-toast-x:hover { color: var(--ccm-ink); }

/* On a phone the toasts span the width, above the support dock. */
@media (max-width: 767px) {
    .ccm-toasts { left: 16px; right: 16px; bottom: 82px; max-width: none; }
}

/* ------------------------------------------------------------ product gallery
   Arrows sit on the picture rather than under it, so moving between
   photographs does not move the eye away from the photograph. */
.pdp-main { position: relative; }

.pdp-arrow {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    z-index: 2;
    width: 40px;
    height: 40px;
    display: flex;
    align-items: center;
    justify-content: center;
    border: 0;
    border-radius: 50%;
    background: var(--ccm-bg);
    color: var(--ccm-ink);
    cursor: pointer;
    box-shadow: 0 2px 10px rgba(0, 0, 0, .18);
    opacity: 0;
    transition: opacity .16s ease, background .16s ease;
}
.pdp-main:hover .pdp-arrow { opacity: 1; }
.pdp-arrow:hover  { background: var(--ccm-orange); color: var(--ccm-badge-ink); }
.pdp-arrow:focus-visible { opacity: 1; }
.pdp-arrow svg { width: 20px; height: 20px; }
.pdp-arrow-prev { left: 10px; }
.pdp-arrow-next { right: 10px; }

/* A phone has no hover, so the arrows are simply always there. A control that
   only appears on hover is a control a touch user does not have. */
@media (hover: none) {
    .pdp-arrow { opacity: 1; }
}

.pdp-count {
    position: absolute;
    right: 10px;
    bottom: 10px;
    z-index: 2;
    padding: 3px 9px;
    border-radius: 999px;
    background: rgba(0, 0, 0, .55);
    color: var(--ccm-bg);
    font-size: 11.5px;
    font-variant-numeric: tabular-nums;
}

/* The thumbnails are buttons now, not bare images. */
.pdp-thumb {
    padding: 0;
    border: 2px solid transparent;
    border-radius: var(--ccm-radius);
    background: none;
    cursor: pointer;
    line-height: 0;
    overflow: hidden;
    transition: border-color .14s ease, opacity .14s ease;
}
.pdp-thumb img {
    display: block;
    width: 100%;
    height: 100%;
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
    padding: 3px;
    box-sizing: border-box;
}
.pdp-thumb:hover { opacity: .85; }
.pdp-thumb.is-current { border-color: var(--ccm-orange); }

/* =============================================================================
   Search suggestions
   =============================================================================
   The panel hangs off the search form, which is why the form is the
   positioning context. It sits above the sticky header, so its z-index has to
   clear the header's — a suggestion list that appears *behind* the thing it
   drops out of is a bug that only shows up on a real page.
   ========================================================================== */

.searchbar { position: relative; }

.suggest {
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    right: 0;
    z-index: 300;
    max-height: min(70vh, 480px);
    overflow-y: auto;
    background: #FFFFFF;
    border: 1px solid var(--ccm-rule);
    border-radius: 3px;
    box-shadow: 0 10px 30px rgba(0, 0, 0, .14);
    padding: 4px;
}

.suggest-head {
    font-size: 10.5px;
    letter-spacing: .07em;
    text-transform: uppercase;
    color: var(--ccm-muted);
    padding: 9px 10px 5px;
}

.suggest-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 7px 10px;
    border-radius: 3px;
    color: var(--ccm-ink);
    text-decoration: none;
}

/* Hover and keyboard selection look identical on purpose: there is one
   highlighted row at a time, however it got that way. */
.suggest-row:hover,
.suggest-row.is-cursor { background: var(--ccm-mint); }

.suggest-thumb {
    width: 38px; height: 38px;
    max-width: 38px; max-height: 38px;
    flex: 0 0 38px;
    object-fit: contain;
    padding: 2px;
    box-sizing: border-box;
    border: 1px solid var(--ccm-rule);
    border-radius: 2px;
    background: #FFFFFF;
}

.suggest-text { display: flex; flex-direction: column; min-width: 0; flex: 1 1 auto; }

.suggest-text strong {
    font-size: 13px; font-weight: 500; line-height: 1.3;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.suggest-text small { font-size: 11px; color: var(--ccm-muted); }

.suggest-tail {
    font-size: 12.5px; font-weight: 600; color: var(--ccm-red);
    flex: 0 0 auto; white-space: nowrap;
}

.suggest-none {
    padding: 16px 12px; font-size: 13px; color: var(--ccm-muted); text-align: center;
}

.suggest-all {
    border-top: 1px solid var(--ccm-rule-soft);
    margin-top: 4px;
    justify-content: center;
}

.suggest-all strong { font-size: 12.5px; color: var(--ccm-link); font-weight: 600; }

@media (max-width: 720px) {
    .suggest-thumb { width: 32px; height: 32px; }
}

/* =============================================================================
   Order tracking
   ========================================================================== */

.track-form { max-width: 460px; }

.track-list { display: flex; flex-direction: column; gap: 12px; margin-top: 14px; }

.track-card {
    display: block;
    padding: 15px 17px;
    border: 1px solid var(--ccm-rule);
    border-radius: 3px;
    text-decoration: none;
    color: inherit;
    background: #FFFFFF;
}

.track-card:hover { border-color: var(--ccm-amber); }

.track-card-head {
    display: flex; align-items: flex-start; justify-content: space-between;
    gap: 12px; flex-wrap: wrap;
}

/* The road, including the parts not yet travelled. Horizontal on a wide
   screen; on a phone it becomes a vertical list, because five labels across
   360px is five illegible labels. */
.track-rail {
    display: flex;
    list-style: none;
    margin: 16px 0 0;
    padding: 0;
    counter-reset: step;
}

.track-step {
    flex: 1 1 0;
    min-width: 0;
    position: relative;
    padding-top: 20px;
    text-align: center;
}

/* The connecting line, drawn behind the dots. */
.track-step::before {
    content: "";
    position: absolute;
    top: 5px;
    left: -50%;
    width: 100%;
    height: 2px;
    background: var(--ccm-rule);
}

.track-step:first-child::before { display: none; }
.track-step.is-done::before { background: var(--ccm-amber); }

.track-dot {
    position: absolute;
    top: 0;
    left: 50%;
    transform: translateX(-50%);
    width: 12px; height: 12px;
    border-radius: 50%;
    background: #FFFFFF;
    border: 2px solid var(--ccm-rule);
}

.track-step.is-done .track-dot { background: var(--ccm-amber); border-color: var(--ccm-amber); }

/* The step the order is actually on gets a ring, so "reached here" is
   distinguishable from "passed through here" at a glance. */
.track-step.is-now .track-dot {
    box-shadow: 0 0 0 4px rgba(252, 184, 0, .28);
}

.track-step-label {
    font-size: 11px;
    color: var(--ccm-muted);
    display: block;
    padding: 0 4px;
    line-height: 1.35;
}

.track-step.is-done .track-step-label { color: var(--ccm-body); }
.track-step.is-now .track-step-label  { color: var(--ccm-ink); font-weight: 600; }

@media (max-width: 640px) {
    .track-rail { flex-direction: column; gap: 10px; }

    .track-step { text-align: left; padding: 0 0 0 24px; }
    .track-step::before {
        left: 5px; top: -10px; width: 2px; height: 10px;
    }
    .track-dot { left: 0; transform: none; top: 2px; }
    .track-step-label { padding: 0; font-size: 12.5px; }
}

/* Reusing the last delivery address. */
.reuse-address { border-color: var(--ccm-amber); }

.reuse-card {
    display: block;
    padding: 13px 15px;
    background: var(--ccm-mint);
    border: 1px solid var(--ccm-rule);
    border-radius: 3px;
    margin: 12px 0 14px;
    font-size: 13.5px;
}

.reuse-card .card-cat { display: block; margin-top: 3px; }

.reuse-actions { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }

/* A button that reads as a link. It is a <button> because it acts on this
   page rather than navigating, and an <a href="#"> that runs script is a link
   that lies about what it does. */
.btn-link {
    background: none;
    border: 0;
    padding: 0;
    font: inherit;
    color: var(--ccm-link);
    text-decoration: underline;
    cursor: pointer;
}

.btn-link:hover { color: var(--ccm-red); }

/* Discount code at checkout. */
.coupon-box { margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--ccm-rule); }
.coupon-box label { display: block; font-size: 12.5px; margin-bottom: 6px; color: var(--ccm-body); }

.coupon-row { display: flex; gap: 8px; }
.coupon-row input { flex: 1 1 auto; min-width: 0; text-transform: uppercase; }
.coupon-row .btn { flex: 0 0 auto; }

.coupon-applied {
    margin: 0; font-size: 13px; color: var(--ccm-body);
    background: var(--ccm-mint); border: 1px solid var(--ccm-rule);
    border-radius: 3px; padding: 9px 11px;
}

.coupon-applied strong { color: var(--ccm-ink); }
.coupon-applied a { margin-left: 6px; font-size: 12px; }

.coupon-error { margin: 7px 0 0; font-size: 12.5px; color: var(--ccm-red); }

/* A line that takes money off reads differently from one that adds it. */
.summary-line.is-saving span:last-child { color: var(--ccm-ink); font-weight: 700; }
.summary-line.is-saving small { display: block; font-size: 11px; color: var(--ccm-muted); }

/* ---------------------------------------------------------------------------
   Public order tracking  (/orders/track/{number})

   The page somebody opens from a text message when they want to know where
   their parcel is. Built entirely from the tokens already defined at the top
   of app.css -- amber for the live state, the brand red for a failed one, mint
   for a delivered one -- so it inherits the site's colours and its dark theme
   without introducing either.
   --------------------------------------------------------------------------- */

.trk-hero {
    display: flex; align-items: center; justify-content: space-between; gap: 20px;
    background: var(--ccm-surface);
    border: 1px solid var(--ccm-rule);
    border-left: 5px solid var(--ccm-amber);
    border-radius: var(--ccm-radius);
    padding: 22px 24px;
    margin: 18px 0 14px;
}

/* Delivered and cancelled are the two states worth recognising before
   reading. Everything in between is "on its way", and shares one look. */
.trk-hero.is-done   { border-left-color: var(--ccm-amber); background: var(--ccm-mint); }
.trk-hero.is-failed { border-left-color: var(--ccm-red); }

.trk-hero-main { min-width: 0; }

.trk-eyebrow {
    margin: 0 0 4px; font-size: 12.5px; letter-spacing: .04em;
    text-transform: uppercase; color: var(--ccm-muted);
}

.trk-eyebrow .mono { text-transform: none; letter-spacing: 0; color: var(--ccm-body); }

.trk-status {
    margin: 0; font-size: 26px; line-height: 1.15; color: var(--ccm-ink);
}

.trk-hero.is-failed .trk-status { color: var(--ccm-red); }

.trk-detail { margin: 6px 0 0; color: var(--ccm-body); font-size: 14px; }

.trk-facts {
    display: flex; flex-wrap: wrap; gap: 22px;
    list-style: none; margin: 16px 0 0; padding: 0;
}

.trk-fact-label {
    display: block; font-size: 11px; text-transform: uppercase;
    letter-spacing: .05em; color: var(--ccm-muted);
}

.trk-fact-value { display: block; font-size: 15px; font-weight: 600; color: var(--ccm-ink); }

/* Large enough to read at arm's length on a phone held in daylight, which is
   where this page is actually opened. */
.trk-hero-mark {
    flex: 0 0 auto;
    display: flex; align-items: center; justify-content: center;
    width: 76px; height: 76px; border-radius: 50%;
    background: var(--ccm-amber); color: var(--ccm-amber-ink);
    font-size: 26px; font-weight: 700; line-height: 1;
}

.trk-hero.is-failed .trk-hero-mark { background: var(--ccm-red); color: var(--ccm-badge-ink); }
.trk-of { font-size: 14px; font-weight: 500; opacity: .7; }

.trk-rail-panel { padding-top: 22px; padding-bottom: 18px; }

/* The date each stage was reached, under its label. A rail of ticks says how
   far along you are; the dates say whether anything has moved today. */
.trk-when {
    display: block; margin-top: 3px; font-size: 11px; color: var(--ccm-muted);
    min-height: 14px;
}

/* --- the history ------------------------------------------------------- */

.trk-log { list-style: none; margin: 14px 0 0; padding: 0; }

.trk-log-row {
    position: relative; display: flex; gap: 12px;
    padding: 0 0 16px 18px;
}

/* One continuous line down the left, stopping at the last entry so it does
   not trail off into nothing. */
.trk-log-row::before {
    content: ""; position: absolute; left: 4px; top: 6px; bottom: -6px;
    width: 1px; background: var(--ccm-rule);
}

.trk-log-row:last-child { padding-bottom: 0; }
.trk-log-row:last-child::before { display: none; }

.trk-log-dot {
    position: absolute; left: 0; top: 5px;
    width: 9px; height: 9px; border-radius: 50%;
    background: var(--ccm-rule); border: 2px solid var(--ccm-bg);
}

/* The most recent entry is the one somebody is looking for. */
.trk-log-row:first-child .trk-log-dot { background: var(--ccm-amber); }

.trk-log-body { min-width: 0; }
.trk-log-what { font-size: 14px; color: var(--ccm-ink); }
.trk-log-when { font-size: 12px; color: var(--ccm-muted); margin-top: 2px; }

/* --- what is in it ------------------------------------------------------ */

.trk-items { list-style: none; margin: 14px 0 0; padding: 0; }

.trk-item {
    display: flex; align-items: center; gap: 12px;
    padding: 10px 0; border-bottom: 1px solid var(--ccm-rule-soft);
}

.trk-item:last-child { border-bottom: 0; }

.trk-item-pic {
    flex: 0 0 auto; width: 56px; height: 56px;
    display: flex; align-items: center; justify-content: center;
    background: var(--ccm-surface); border: 1px solid var(--ccm-rule);
    border-radius: var(--ccm-radius); overflow: hidden;
}

.trk-item-pic img {
    width: 100%;
    height: 100%;
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
    padding: 4px;
    box-sizing: border-box;
    display: block;
}

/* No picture: the quantity, which is the next most useful thing that square
   can say. */
.trk-item-qty { font-size: 16px; font-weight: 700; color: var(--ccm-body); }

.trk-item-body { flex: 1 1 auto; min-width: 0; }
.trk-item-name {
    font-size: 14px; color: var(--ccm-ink);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.trk-item-meta  { font-size: 12.5px; color: var(--ccm-muted); margin-top: 2px; }
.trk-item-total { flex: 0 0 auto; font-size: 14px; font-weight: 600; color: var(--ccm-ink); }

/* --- the sidebar -------------------------------------------------------- */

.trk-address { font-size: 14px; color: var(--ccm-body); line-height: 1.6; margin: 8px 0 0; }
.trk-address strong { color: var(--ccm-ink); }

.trk-help, .trk-keep {
    margin-top: 22px; padding-top: 18px; border-top: 1px solid var(--ccm-rule);
}

.btn-block { display: block; width: 100%; text-align: center; }

@media (max-width: 640px) {
    .trk-hero { flex-direction: column; align-items: flex-start; padding: 18px; }
    .trk-hero-mark { width: 56px; height: 56px; font-size: 20px; }
    .trk-status { font-size: 22px; }
    .trk-facts { gap: 16px; }
    /* The rail is already stacked below 640px by the .track-rail rules above;
       the dates go beside the label rather than under it so the column does
       not become a very tall list of two-line steps. */
    .trk-when { display: inline; margin-left: 8px; }
}

/* ---------------------------------------------------------------------------
   The "you might also like" rail

   Six product cards on screen, the rest reachable with the arrows. A grid was
   the wrong shape for this: it either wraps onto a second line, which competes
   with the page below it, or it caps at four and hides the other fourteen
   behind a text link nobody clicks.

   Built from the tokens in app.css, so it inherits the site's colours and its
   dark theme without introducing either.
   --------------------------------------------------------------------------- */

.rail-head { align-items: center; gap: 16px; flex-wrap: wrap; }
.rail-title h2 { margin: 0; }

/* Naming the category is not decoration -- it is the promise the rail keeps.
   Every card below it is in that category. */
.rail-sub { margin: 2px 0 0; font-size: 13px; color: var(--ccm-body); }
.rail-sub strong { color: var(--ccm-ink); }

.rail-tools { display: flex; align-items: center; gap: 8px; margin-left: auto; }

.rail-arrow {
    width: 34px; height: 34px; flex: 0 0 auto;
    display: inline-flex; align-items: center; justify-content: center;
    background: var(--ccm-bg); color: var(--ccm-ink);
    border: 1px solid var(--ccm-rule); border-radius: 50%;
    font-size: 20px; line-height: 1; cursor: pointer;
    transition: background .12s ease, border-color .12s ease;
}

.rail-arrow:hover:not(:disabled) { background: var(--ccm-amber); border-color: var(--ccm-amber); color: var(--ccm-amber-ink); }
.rail-arrow:focus-visible        { outline: 2px solid var(--ccm-link); outline-offset: 2px; }

/* Disabled rather than hidden: a control that disappears at the end of a list
   moves everything beside it, and the row jumps as you use it. */
.rail-arrow:disabled { opacity: .35; cursor: default; }

/* "See all Kitchen Ware" — a button, because it is the thing somebody wants
   when the rail has not shown them what they were after, and a 13px text link
   beside a heading was not something anybody found. */
.rail-more { white-space: nowrap; }
.rail-more span { margin-left: 4px; }

.rail { position: relative; margin-top: 14px; }

.rail-track {
    display: grid;
    grid-auto-flow: column;
    /* Exactly six across, so the rail is a full row and not a ragged one.
       Expressed as a custom property so the breakpoints below change one
       number rather than restating the whole calc(). */
    --rail-cols: 6;
    grid-auto-columns: calc((100% - ((var(--rail-cols) - 1) * 14px)) / var(--rail-cols));
    gap: 14px;
    overflow-x: auto;
    scroll-behavior: smooth;
    scroll-snap-type: x mandatory;
    /* Room for the focus ring, and for a card's shadow, without clipping. */
    padding: 4px 2px 8px;
    /* The scrollbar is redundant next to the arrows and takes a row of height
       on Windows; the rail is still scrollable by wheel, touch and keyboard. */
    scrollbar-width: none;
}

.rail-track::-webkit-scrollbar { display: none; }
.rail-track:focus-visible { outline: 2px solid var(--ccm-link); outline-offset: 2px; }

.rail-item { scroll-snap-align: start; min-width: 0; }

/* The arrows at the two ends, over the rail itself. These are the ones the
   brief asked for; the pair beside the heading do the same job for a reader
   who is already up there. */
.rail-edge {
    position: absolute; top: 50%; transform: translateY(-50%); z-index: 2;
    width: 38px; height: 38px;
    display: none; align-items: center; justify-content: center;
    background: var(--ccm-bg); color: var(--ccm-ink);
    border: 1px solid var(--ccm-rule); border-radius: 50%;
    font-size: 22px; line-height: 1; cursor: pointer;
    box-shadow: var(--ccm-shadow-sm, 0 1px 2px rgba(0,0,0,.05));
}

.rail-edge:hover { background: var(--ccm-amber); border-color: var(--ccm-amber); color: var(--ccm-amber-ink); }
.rail-edge-prev  { left: -19px; }
.rail-edge-next  { right: -19px; }

/* Shown only when there is somewhere to go. `is-scrollable` is set by the
   script once it knows the track overflows, so a rail of three products on a
   wide screen has no arrows to press and nothing to disappoint. */
.rail.is-scrollable .rail-edge { display: flex; }
.rail-edge:disabled { display: none; }

@media (max-width: 1100px) {
    /* Off the ends and inside the rail, where there is room for them. */
    .rail-edge-prev { left: 4px; }
    .rail-edge-next { right: 4px; }
}

@media (max-width: 900px) {
    .rail-track { --rail-cols: 4; }
}

@media (max-width: 700px) {
    .rail-track { --rail-cols: 2.2; }
    .rail-head  { gap: 10px; }
    .rail-tools { width: 100%; margin-left: 0; }
    .rail-more  { margin-left: auto; }
    /* On a phone the thumb does this better than a button can. */
    .rail.is-scrollable .rail-edge { display: none; }
}

/* ===========================================================================
   THE FOOTER

   A dark ground, and that is the one real decision here.

   A footer the same white as the page has no edge, so the shop appears to
   trail off rather than end — and a visitor who has scrolled to the bottom
   looking for a telephone number has to hunt for it in the same visual weight
   as everything above. Grounding it in `--ccm-ink` gives the page a floor,
   pushes the amber support strip forward as the brightest thing on the screen,
   and costs nothing: black is already the site's heading colour, so no new
   colour enters the palette.

   Above it sits the support strip, in amber. It is the loudest element in the
   footer on purpose — "call us" is the most useful thing this shop can say to
   somebody who has read all the way down.
   =========================================================================== */

.shop-foot {
    margin-top: 48px;
    background: var(--ccm-ink);
    color: rgba(255, 255, 255, .72);
    font-size: 13.5px;
    line-height: 1.65;
}

/* --------------------------------------------------------- support strip */

.foot-support {
    background: var(--ccm-amber);
    color: var(--ccm-amber-ink);
}

/* The number on the left, the hours on the right, and the row centred in the
   band's height.
   Two columns rather than three: the support block takes the space it needs at
   the leading edge, the hours sit against the trailing edge, and `align-items:
   center` with equal padding puts both on the band's optical centre line.
   Centring the block horizontally was tried and is wrong — it leaves the band
   empty at both ends and the telephone number floating, when the thing a
   reader's eye looks for at the foot of a page is a left edge to start from. */
.foot-support-inner {
    display: grid;
    grid-template-columns: auto 1fr;
    align-items: center;
    gap: 16px 24px;
    padding: 14px 0;
    min-height: 62px;
}

.foot-support-block {
    grid-column: 1;
    display: flex;
    align-items: center;
    gap: 14px;
}

.foot-support-mark {
    flex: 0 0 auto;
    width: 44px;
    height: 44px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(0, 0, 0, .1);
}

.foot-support-mark svg { width: 21px; height: 21px; }

.foot-support-label {
    display: block;
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: .1em;
    text-transform: uppercase;
    opacity: .7;
}

.foot-support-phone {
    display: block;
    font-size: 22px;
    font-weight: 700;
    line-height: 1.15;
    letter-spacing: -.01em;
    color: var(--ccm-amber-ink);
    text-decoration: none;
}

.foot-support-phone:hover { text-decoration: underline; }

/* The trailing edge, on the same centre line as the number beside it.
   Dropped onto its own line on a narrow screen rather than squeezed — trading
   hours that wrap into three words per line read as broken. */
.foot-support-hours {
    grid-column: 2;
    justify-self: end;
    margin: 0;
    font-size: 12.5px;
    font-weight: 500;
    line-height: 1.4;
    opacity: .82;
    text-align: right;
}

/* --------------------------------------------------------------- columns */

/* `>`, not a descendant selector.
   The support strip's container carries `shell` too, so a descendant rule put
   40px of padding on top of it and pushed the telephone number twenty pixels
   below the centre line of its own band — while every measurement of the band
   itself looked correct. Only the columns block is a direct child of the
   footer, which is exactly the element this padding is for. */
.shop-foot > .shell { padding-top: 40px; padding-bottom: 0; }

.foot-cols {
    display: grid;
    gap: 32px 28px;
    align-items: start;
    /* The brand column is wider than the link columns because it carries a
       paragraph; the rest share what is left equally. */
    grid-template-columns: 1.6fr repeat(4, 1fr);
    padding-bottom: 36px;
}

.foot-cols h4 {
    margin: 0 0 14px;
    font-size: 12px;
    font-weight: 700;
    letter-spacing: .09em;
    text-transform: uppercase;
    color: #FFFFFF;
}

.foot-cols ul { list-style: none; margin: 0; padding: 0; }
.foot-cols li { margin-bottom: 9px; }

.foot-cols a {
    color: rgba(255, 255, 255, .72);
    text-decoration: none;
    transition: color .12s ease;
}

/* Amber is the feedback; an underline on top of it is noise. These have no
   class of their own, so the prose rule at the top of this file would give
   them one. */
.foot-cols a:hover { color: var(--ccm-amber); text-decoration: none; }

.foot-cols a:focus-visible {
    outline: 2px solid var(--ccm-amber);
    outline-offset: 2px;
    border-radius: 2px;
}

/* Footer links on a phone were 15px tall with 9px between them — close enough
   together that a thumb aiming at "Track your order" lands on "Sell on this
   platform" instead. The text stays 13px; the row it sits in becomes 44px, and
   the margin goes because the padding now provides the separation. Desktop is
   untouched: a mouse pointer is precise and the tighter list reads better. */
@media (max-width: 767px) {
    .foot-cols a {
        display: inline-flex;
        align-items: center;
        min-height: 44px;
    }

    .foot-cols li { margin-bottom: 0; }
}

/* --------------------------------------------------------------- brand */

.foot-brand p {
    margin: 14px 0 0;
    max-width: 34ch;
    font-size: 13px;
    line-height: 1.7;
    color: rgba(255, 255, 255, .62);
}

/* The logo is a dark-on-light mark, so it needs a light plate to sit on
   rather than being inverted — inverting a brand mark is a change to the
   brand, and the client asked for their logo, not a version of it. */
.foot-logo {
    display: block;
    height: auto;
    max-width: 152px;
    padding: 9px 12px;
    background: #FFFFFF;
    border-radius: var(--ccm-radius);
}

.foot-social {
    display: flex;
    gap: 9px;
    list-style: none;
    margin: 18px 0 0;
    padding: 0;
}

.foot-social a {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    border-radius: 50%;
    border: 1px solid rgba(255, 255, 255, .22);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .02em;
    color: rgba(255, 255, 255, .8);
    transition: background .12s ease, border-color .12s ease, color .12s ease;
}

.foot-social a:hover {
    background: var(--ccm-amber);
    border-color: var(--ccm-amber);
    color: var(--ccm-amber-ink);
}

/* --------------------------------------------------------------- contact */

/* Label above value, not beside it. "Kotokuraba Market BFS026, Cape Coast,
   Ghana" does not fit on one line next to the word Address on any phone, and
   an address that wraps around its own label reads as two addresses. */
.foot-contact li { margin-bottom: 13px; }

.foot-contact-label {
    display: block;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: .09em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, .42);
    margin-bottom: 2px;
}

.foot-contact span:not(.foot-contact-label) { color: rgba(255, 255, 255, .72); }

/* ---------------------------------------------------------- what we take */

/* The delivery note, which the bottom bar used to carry. */
.foot-note {
    padding: 16px 0 20px;
    border-top: 1px solid rgba(255, 255, 255, .12);
    font-size: 12.5px;
    color: rgba(255, 255, 255, .5);
}

/* ---------------------------------------------------------- bottom bar

   Built to the client's reference: a light band across the full width, the
   copyright on the left, the accepted methods on the right.

   Light on purpose, under a dark footer: the payment marks are the point of
   the strip and they are drawn for a light ground. The artwork was supplied
   on #F6F6F6, which is not a brand colour, so that ground is keyed out of the
   image and the band uses the approved neutral instead.

   The same in one direction at every width: the reference shows one row, and
   the client asked for it on all devices, so this deliberately does not stack
   on a phone. It scrolls its marks instead — see .foot-pay-marks. */
.foot-bottom {
    background: var(--ccm-surface);
    color: var(--ccm-body);
    border-top: 1px solid rgba(255, 255, 255, .12);
}

.foot-bottom-inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding-top: 14px;
    padding-bottom: 14px;
}

.foot-copy {
    font-size: 12.5px;
    color: var(--ccm-body);
    flex: 0 1 auto;
    min-width: 0;
}

.foot-pay {
    display: flex;
    align-items: center;
    gap: 14px;
    min-width: 0;
}

.foot-pay-label {
    font-size: 12px;
    color: var(--ccm-muted);
    white-space: nowrap;
}

/* The marks keep their aspect and never dictate the page width: on a narrow
   screen the strip scrolls inside itself rather than pushing the body
   sideways, which is the one thing a full-bleed bar must never do. */
.foot-pay-marks {
    display: block;
    min-width: 0;
    overflow-x: auto;
    scrollbar-width: none;
}

.foot-pay-marks::-webkit-scrollbar { display: none; }

.foot-pay-marks img {
    display: block;
    height: 30px;
    width: auto;
    max-width: none;
}

/* Below 640px the row stops being possible rather than stopping being
   desirable: the copyright alone is about 215px at a readable size and the
   marks another 210px, inside a 358px shell. Something has to give, and
   making either of them too small to read is worse than putting them on two
   lines. Same content, same order, centred. */
@media (max-width: 639px) {
    .foot-bottom-inner {
        flex-direction: column;
        align-items: center;
        gap: 10px;
        text-align: center;
    }

    .foot-copy { font-size: 11.5px; }

    /* The label goes above the marks rather than beside them. Side by side,
       the pair measured 407px inside a 358px shell and pushed the whole page
       sideways — a full-bleed bar is the last thing that should do that. */
    .foot-pay {
        flex-direction: column;
        gap: 6px;
        max-width: 100%;
    }

    .foot-pay-marks { max-width: 100%; }
    .foot-pay-marks img { height: 26px; }
}

/* The phone's tab bar is fixed over the bottom of every page, so the last
   thing in the document has to get out from under it. */
@media (max-width: 767px) {
    .foot-bottom-inner {
        padding-bottom: calc(74px + env(safe-area-inset-bottom, 0px));
    }
}

@media (max-width: 1023px) {
    .foot-cols { grid-template-columns: 1fr 1fr 1fr; }
    .foot-brand { grid-column: 1 / -1; }
    .foot-brand p { max-width: 52ch; }
}

@media (max-width: 767px) {
    .shop-foot { margin-top: 32px; }
    .shop-foot > .shell { padding-top: 30px; }
    .foot-cols { grid-template-columns: 1fr 1fr; gap: 26px 20px; }

    /* One column on a phone: there is no room to hold a left edge against a
       right one, and the hours below the number is the reading order anyway. */
    .foot-support-inner { grid-template-columns: 1fr; gap: 8px; min-height: 0; }
    .foot-support-block { grid-column: 1; }
    .foot-support-hours { grid-column: 1; justify-self: start; text-align: left; }
    .foot-support-phone { font-size: 19px; }
}

@media (max-width: 380px) {
    .foot-cols { grid-template-columns: 1fr; }
}

/* ===========================================================================
   DOCUMENT PAGES — about, terms, sell on this platform

   Three pages that are read rather than shopped, and they need a different
   discipline from a product grid: a measure short enough to read, a hierarchy
   you can skim, and — for the terms, which are long — a way to get to clause
   nine without scrolling past eight.
   =========================================================================== */

.page-shell { padding-top: 20px; padding-bottom: 8px; }

/* --------------------------------------------------------------- crumbs */

.crumbs {
    display: flex;
    gap: 8px;
    align-items: center;
    font-size: 12.5px;
    color: var(--ccm-muted);
    margin-bottom: 18px;
}

.crumbs a { color: var(--ccm-body); text-decoration: none; }
.crumbs a:hover { color: var(--ccm-link); text-decoration: underline; }
.crumbs span[aria-hidden] { color: var(--ccm-rule); }

/* ----------------------------------------------------------------- hero */

/* A band rather than a headline on white. It separates "what this page is"
   from "what it says", which is the distinction a reader makes first — and on
   the terms it is where the last-updated date belongs, because that is the
   thing a returning reader checks before anything else. */
.page-doc-head {
    padding: 34px 36px;
    margin-bottom: 34px;
    background: var(--ccm-surface);
    border: 1px solid var(--ccm-rule);
    border-left: 4px solid var(--ccm-amber);
    border-radius: var(--ccm-radius);
}

.page-doc-head h1 {
    margin: 0 0 10px;
    font-size: 32px;
    line-height: 1.15;
    letter-spacing: -.015em;
}

.page-doc-lede {
    margin: 0;
    max-width: 62ch;
    font-size: 16.5px;
    line-height: 1.65;
    color: var(--ccm-body);
}

.page-doc-head .btn { margin-top: 20px; }

/* ------------------------------------------------------------- the body */

/* Roughly 70 characters. Terms nobody can read are terms nobody reads, and a
   full-width line of legal text on a desktop is exactly that.
   Centred, so a document page is a column on the page rather than a column
   pinned to its left edge. */
.page-doc { max-width: 72ch; margin-inline: auto; }

/* Inside the two-column terms layout the article is already placed by the
   grid, so it must not centre itself a second time. */
.doc-layout .page-doc { margin-inline: 0; }

.page-doc h2 {
    margin: 38px 0 12px;
    padding-top: 22px;
    font-size: 19px;
    line-height: 1.3;
    letter-spacing: -.01em;
    border-top: 1px solid var(--ccm-rule-soft);
}

.page-doc-head + h2,
.page-doc > h2:first-of-type { margin-top: 0; }

.page-doc h3 { margin: 22px 0 8px; font-size: 15px; }

/* `--ccm-body`, like everything else on the site.
   A darker grey was tried here and reverted: the client's palette is closed,
   and the brand rule in the Phase 5 suite enforces it. It was also not needed
   -- #666 on white at 15px is about 5.7:1, comfortably past the 4.5:1 that
   normal text has to clear. What actually makes a long document readable is
   the size and the leading, and both are set generously here. */
.page-doc p {
    margin: 0 0 15px;
    font-size: 15px;
    line-height: 1.78;
    color: var(--ccm-body);
}

/* Underlined, because an unmarked link in a paragraph of legal text is a link
   nobody sees. Buttons are exempt: a button that is also underlined reads as
   broken, and it is already unmistakably a control. */
.page-doc a:not(.btn) {
    color: var(--ccm-link);
    text-decoration: underline;
    text-underline-offset: 2px;
}

.page-doc .btn { text-decoration: none; }
.page-doc strong { color: var(--ccm-ink); font-weight: 600; }

/* Numbered steps, with the number as a mark rather than a list bullet — it
   makes a four-step process read as a process instead of as a list. */
.page-steps {
    counter-reset: step;
    list-style: none;
    margin: 0 0 18px;
    padding: 0;
}

.page-steps li {
    counter-increment: step;
    position: relative;
    margin-bottom: 16px;
    padding-left: 44px;
    font-size: 15px;
    line-height: 1.72;
    color: var(--ccm-body);
}

.page-steps li::before {
    content: counter(step);
    position: absolute;
    left: 0;
    top: 1px;
    width: 28px;
    height: 28px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background: var(--ccm-amber);
    color: var(--ccm-amber-ink);
    font-size: 13px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.page-steps strong,
.sell-list strong { color: var(--ccm-ink); font-weight: 600; }

/* A closing note, in the soft panel colour so it reads as an aside rather
   than as another clause. */
.page-doc-foot {
    margin-top: 34px;
    padding: 18px 20px;
    background: var(--ccm-mint);
    border: 1px solid var(--ccm-rule);
    border-radius: var(--ccm-radius);
    font-size: 14.5px;
    line-height: 1.7;
}

.page-doc-foot p:last-child { margin-bottom: 0; }

/* --------------------------------------------------------------- contact */

/* Four facts, and the grid must not care how many columns they land in.
   The first version drew its dividing rules by showing a grey container
   through one-pixel gaps, which is a neat trick until the item count does not
   divide by the column count — then the leftover cells show as grey blocks
   with nothing in them, which is exactly what happened with four facts in
   three columns. Borders on the cells themselves have no such failure mode:
   where there is no cell there is nothing to see. */
.page-contact {
    display: grid;
    margin: 6px 0 18px;
    /* Two columns, not auto-fit.
       There are four facts, and four divides evenly by two and by four but
       not by three — which is what auto-fit chose at this measure, leaving the
       fourth alone on a row beside a stretch of nothing. A fixed two keeps
       every row full at every width the document column can take, and each
       fact gets enough room that the address does not wrap into three lines. */
    grid-template-columns: repeat(2, minmax(0, 1fr));
    border: 1px solid var(--ccm-rule);
    border-radius: var(--ccm-radius);
    overflow: hidden;
    background: var(--ccm-bg);
}

/* One per row on a phone: two columns of an address at 160px each is worse
   than four rows anybody can read. */
@media (max-width: 480px) {
    .page-contact { grid-template-columns: 1fr; }
}

.page-contact > div {
    padding: 16px 18px;
    border-right: 1px solid var(--ccm-rule);
    border-bottom: 1px solid var(--ccm-rule);
}

/* Every cell draws a right and a bottom rule, which doubles up against the
   container's own border on the last column and the last row. Shifting the
   grid one pixel down-right and clipping it hides exactly those two, without
   the stylesheet ever needing to know how many columns auto-fit chose. */
.page-contact > div { margin: 0 -1px -1px 0; }

.page-contact p { margin: 0; font-size: 14.5px; line-height: 1.55; color: var(--ccm-ink); }

.page-contact-label {
    display: block;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: .09em;
    text-transform: uppercase;
    color: var(--ccm-muted);
    margin-bottom: 5px;
}

@media (max-width: 767px) {
    .page-doc-head { padding: 24px 20px; margin-bottom: 26px; }
    .page-doc-head h1 { font-size: 25px; }
    .page-doc-lede { font-size: 15px; }
    .page-doc h2 { font-size: 17px; margin-top: 30px; }
    .page-steps li { padding-left: 38px; }
}

/* ===========================================================================
   SELL ON THIS PLATFORM

   The one page here that has to persuade rather than inform, so it gets a
   landing-page shape: the cost answered in the first screen, the process as
   numbered steps, and the same call to action at both ends — a trader who is
   convinced by the third paragraph should not have to scroll back up.
   =========================================================================== */

/* Wide enough for three cost cards, and no wider.
   The first version let this run the full 1170px while capping the prose at
   72ch, which put every paragraph in the left two-thirds and left the right
   third empty on every screen — the text looked misaligned rather than
   measured. Constraining the whole article to a little over the width three
   cards want makes the prose and the cards share one edge. */
.page-doc.is-wide { max-width: 940px; margin-inline: auto; }

.page-doc.is-wide > p,
.page-doc.is-wide > h2,
.page-doc.is-wide > .page-steps,
.page-doc.is-wide > .sell-list { max-width: 74ch; }

.sell-grid {
    display: grid;
    gap: 16px;
    margin: 6px 0 24px;
    grid-template-columns: repeat(auto-fit, minmax(212px, 1fr));
}

.sell-card {
    padding: 22px;
    background: var(--ccm-bg);
    border: 1px solid var(--ccm-rule);
    border-top: 3px solid var(--ccm-amber);
    border-radius: var(--ccm-radius);
}

/* The figure is the answer to the question the trader actually came with, so
   it is the biggest thing on the card and the heading beneath it is the
   caption — not the other way round. */
.sell-card-figure {
    display: block;
    font-size: 26px;
    font-weight: 700;
    line-height: 1.1;
    letter-spacing: -.02em;
    color: var(--ccm-ink);
}

.sell-card h3 {
    margin: 6px 0 8px;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .09em;
    text-transform: uppercase;
    color: var(--ccm-muted);
}

.sell-card p { margin: 0; font-size: 13.5px; line-height: 1.68; color: var(--ccm-body); }

/* A tick rather than a bullet: every line in these lists is something the
   platform gives or asks, and a tick says so at a glance. */
.sell-list { list-style: none; margin: 0 0 18px; padding: 0; }

.sell-list li {
    position: relative;
    margin-bottom: 11px;
    padding-left: 28px;
    font-size: 15px;
    line-height: 1.72;
    color: var(--ccm-body);
}

.sell-list li::before {
    content: "";
    position: absolute;
    left: 0;
    top: 8px;
    width: 15px;
    height: 9px;
    border-left: 2px solid var(--ccm-amber);
    border-bottom: 2px solid var(--ccm-amber);
    transform: rotate(-45deg);
}

.sell-cta {
    margin-top: 30px;
    padding: 28px;
    background: var(--ccm-surface);
    border: 1px solid var(--ccm-rule);
    border-left: 4px solid var(--ccm-amber);
    border-radius: var(--ccm-radius);
}

.sell-cta p:last-child { margin-bottom: 0; }
.sell-cta .muted { font-size: 13.5px; color: var(--ccm-muted); }

/* ===========================================================================
   TERMS — a contents rail

   Thirteen clauses is a long page, and the reader who opens it usually wants
   one of them: what happens if I return something, what happens to my
   information. Scrolling past twelve to find the thirteenth is the difference
   between terms that are published and terms that are read.

   Sticky on a desktop, a plain list on a phone — a sticky sidebar on a narrow
   screen eats the screen.
   =========================================================================== */

/* Centred as a unit, not stretched across the shell.
   The contents rail plus a 72ch column is about 900px. Letting the grid fill
   the full 1170px container put the document hard against the rail with 250px
   of nothing to its right, which reads as a layout that failed rather than one
   that chose its measure. */
.doc-layout {
    display: grid;
    gap: 44px;
    align-items: start;
    grid-template-columns: 210px minmax(0, 72ch);
    justify-content: center;
    margin: 0 auto;
}

.doc-toc { position: sticky; top: 20px; }

.doc-toc-title {
    margin: 0 0 12px;
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: .09em;
    text-transform: uppercase;
    color: var(--ccm-muted);
}

.doc-toc ol { list-style: none; margin: 0; padding: 0; counter-reset: toc; }

.doc-toc li { counter-increment: toc; }

.doc-toc a {
    display: block;
    padding: 6px 10px 6px 0;
    font-size: 13px;
    line-height: 1.45;
    color: var(--ccm-body);
    text-decoration: none;
    border-left: 2px solid var(--ccm-rule);
    padding-left: 12px;
    transition: color .12s ease, border-color .12s ease;
}

.doc-toc a:hover {
    color: var(--ccm-ink);
    border-left-color: var(--ccm-amber);
}

/* Anchored headings must not slide under the sticky header when jumped to. */
.page-doc h2[id] { scroll-margin-top: 24px; }

@media (max-width: 1023px) {
    .doc-layout { grid-template-columns: 1fr; gap: 24px; }

    .doc-toc {
        position: static;
        padding: 18px 20px;
        background: var(--ccm-surface);
        border: 1px solid var(--ccm-rule);
        border-radius: var(--ccm-radius);
    }

    /* Two columns of links on a tablet, so the contents does not become a
       screen of its own before the document starts. */
    .doc-toc ol { columns: 2; column-gap: 20px; }
    .doc-toc a { border-left: 0; padding-left: 0; }
}

@media (max-width: 767px) {
    /* Capped and scrollable, not a full screen of links.
       Thirteen clauses in one column is 400px of navigation before the
       document begins -- which is the failure a contents rail exists to
       prevent, arriving one screen earlier. Five visible and the rest a short
       scroll keeps every clause reachable and gives the page back to the
       terms. */
    .doc-toc ol {
        /* `columns: auto`, not `columns: 1`.
           A multi-column box under a max-height overflows sideways rather than
           down -- it makes a second column outside the box -- so the capped
           list grew a horizontal scrollbar and hid clauses 5 to 13 off the
           right edge. Turning the column formatting off entirely is what makes
           overflow-y mean what it says. */
        columns: auto;
        max-height: 168px;
        overflow-y: auto;
        overflow-x: hidden;
        -webkit-overflow-scrolling: touch;
    }

    /* Something to scroll towards: without it a clipped list looks like a
       complete list that happens to end at "5. Paying". */
    .doc-toc {
        position: relative;
        padding-bottom: 22px;
    }

    .doc-toc::after {
        content: "";
        position: absolute;
        left: 1px;
        right: 1px;
        bottom: 1px;
        height: 30px;
        pointer-events: none;
        background: linear-gradient(to bottom, transparent, var(--ccm-surface));
        border-radius: 0 0 var(--ccm-radius) var(--ccm-radius);
    }

    .sell-card-figure { font-size: 22px; }
    .sell-cta { padding: 20px; }
}

.foot-social svg { width: 17px; height: 17px; display: block; }

/* ===========================================================================
   FORM FIELDS ON THE STOREFRONT

   `.field` was styled only inside `.checkout-layout`, so every other form on
   the shop — order tracking among them — rendered with its label inline
   against its input and its hint wrapped around the box. The rules were always
   general; only their selector was not.
   =========================================================================== */

/* Unscoped, deliberately.
   shop.css is loaded by the storefront layout and by nothing else, so the file
   itself is the scope. The first version qualified these with `.shop-main` and
   `.page-shell`, which missed the order-tracking form — and missing one form is
   how a rule like this comes to be written a second time somewhere else.
   `.checkout-layout` has its own, more specific rules and still wins. */
.field { margin-bottom: 16px; }

.field label {
    display: block;
    margin-bottom: 6px;
    font-size: 12.5px;
    font-weight: 600;
    color: var(--ccm-ink);
}

.field input,
.field select,
.field textarea {
    display: block;
    width: 100%;
    padding: 11px 13px;
    font: inherit;
    font-size: 14.5px;
    color: var(--ccm-ink);
    background: var(--ccm-bg);
    border: 1px solid var(--ccm-rule);
    border-radius: var(--ccm-radius);
}

/* Checkboxes and radios must not inherit the full-width block sizing above. */
.field input[type="checkbox"],
.field input[type="radio"] {
    display: inline-block;
    width: auto;
    padding: 0;
    accent-color: var(--ccm-link);
}

.field input:focus,
.field select:focus,
.field textarea:focus {
    border-color: var(--ccm-link);
    outline: 2px solid rgba(0, 102, 204, .18);
    outline-offset: 0;
}

/* A hint belongs under its field on its own line. Inline, it wraps around the
   input and reads as part of the next control. */
.field > .muted,
.field > .text-sm,
.field > .field-hint {
    display: block;
    margin-top: 6px;
    font-size: 12.5px;
    line-height: 1.55;
    color: var(--ccm-muted);
}

/* ===========================================================================
   TRACK YOUR ORDER — the lookup

   The page a customer opens when they are anxious about a parcel. It should
   look like one job: a box, a button, and nothing competing with them.
   =========================================================================== */

.track-hub { max-width: 720px; margin: 0 auto; }

.track-hub .page-head { margin-bottom: 22px; }
.track-hub .page-head h1 { font-size: 28px; letter-spacing: -.015em; }
.track-hub .page-head .sub { margin-top: 6px; font-size: 14.5px; color: var(--ccm-body); }

.track-hub .panel {
    padding: 26px 28px;
    background: var(--ccm-bg);
    border: 1px solid var(--ccm-rule);
    border-radius: var(--ccm-radius);
}

/* The lookup card is the one thing on the page worth doing, so it carries the
   amber edge and the panel below it does not. */
.track-hub .panel.is-primary { border-left: 4px solid var(--ccm-amber); }

.track-hub .panel h2 { font-size: 17px; margin-bottom: 6px; }
.track-hub .panel > .muted { font-size: 14px; line-height: 1.65; color: var(--ccm-body); }

/* Two fields side by side above 560px: an order number and a short code are
   both narrow, and stacking them makes the form look longer than the work it
   asks for. */
.track-form { margin-top: 18px; }

.track-form .track-form-row {
    display: grid;
    gap: 0 16px;
    grid-template-columns: 1fr;
}

@media (min-width: 560px) {
    .track-form .track-form-row { grid-template-columns: 1fr 1fr; }
}

.track-form .btn { margin-top: 2px; }
.track-form input { font-variant-numeric: tabular-nums; letter-spacing: .01em; }

/* The signed-in alternative, quieter than the form above it. */
.track-alt {
    margin-top: 16px;
    padding: 18px 20px;
    background: var(--ccm-surface);
    border: 1px solid var(--ccm-rule);
    border-radius: var(--ccm-radius);
    font-size: 14px;
    line-height: 1.65;
    color: var(--ccm-body);
}

.track-alt h2 { font-size: 15px; margin-bottom: 4px; }
.track-alt p { margin: 0; }

@media (max-width: 767px) {
    .track-hub .panel { padding: 20px; }
    .track-hub .page-head h1 { font-size: 23px; }
}

/* ===========================================================================
   NEED A HAND?

   The last thing on the homepage before the footer, and what somebody who has
   scrolled this far without finding what they wanted is looking for. Three
   things a person can act on, each with a tap target big enough for a thumb.
   =========================================================================== */

.help-strip {
    display: grid;
    gap: 22px;
    align-items: center;
    grid-template-columns: minmax(200px, 260px) 1fr;
    padding: 24px 26px;
    background: var(--ccm-surface);
    border: 1px solid var(--ccm-rule);
    border-left: 4px solid var(--ccm-amber);
    border-radius: var(--ccm-radius);
}

.help-intro h2 { margin: 0 0 5px; font-size: 19px; letter-spacing: -.01em; }
.help-intro p  { margin: 0; font-size: 13px; line-height: 1.6; color: var(--ccm-body); }

.help-ways {
    display: grid;
    gap: 10px;
    list-style: none;
    margin: 0;
    padding: 0;
    /* 230, not 210: at the smaller figure a card was too narrow for
       hello@capecoastmall.com and the address broke across two lines in the
       middle of a word. An email split as "…capecoastmall.co / m" is one
       nobody can read back to somebody over the telephone. */
    grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
}

.help-way {
    display: flex;
    align-items: center;
    gap: 12px;
    height: 100%;
    padding: 13px 15px;
    text-decoration: none;
    background: var(--ccm-bg);
    border: 1px solid var(--ccm-rule);
    border-radius: var(--ccm-radius);
    transition: border-color .12s ease, transform .12s ease;
}

.help-way:hover { border-color: var(--ccm-amber); transform: translateY(-1px); }

/* The address is not a link, so it must not behave like one. */
.help-way.is-static { cursor: default; }
.help-way.is-static:hover { border-color: var(--ccm-rule); transform: none; }

/* `flex: 0 0 auto` and a fixed box.
   Without it the circle is a flex item that can grow, and the SVG inside it
   has a viewBox and no width — so it takes the width offered and scales its
   height to match. On the homepage that rendered these three icons at
   1098 x 1098 pixels each. An inline SVG must always be given a size by
   something; a viewBox is a coordinate system, not a dimension. */
.help-way-mark {
    flex: 0 0 auto;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--ccm-amber);
    color: var(--ccm-amber-ink);
}

.help-way-mark svg {
    width: 18px;
    height: 18px;
    flex: 0 0 auto;
    display: block;
}

.help-way-body { min-width: 0; }

.help-way-label {
    display: block;
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: .07em;
    text-transform: uppercase;
    color: var(--ccm-muted);
}

/* Wraps rather than truncates: an address cut off mid-word is worse than one
   on two lines, and a telephone number must never be clipped. */
.help-way-value {
    display: block;
    margin-top: 1px;
    font-size: 13.5px;
    font-weight: 600;
    line-height: 1.35;
    color: var(--ccm-ink);
    /* `break-word`, not `anywhere`: it breaks only when a word genuinely
       cannot fit, and prefers a sensible point when it must. */
    overflow-wrap: break-word;
}

@media (max-width: 767px) {
    .help-strip { grid-template-columns: 1fr; padding: 18px; }
}

/* ===========================================================================
   PEOPLE ARE BUYING

   A small panel that appears once somebody has scrolled. It gets out of the
   way of the footer, and it closes.
   =========================================================================== */

.buzz {
    position: fixed;
    right: 18px;
    bottom: 18px;
    z-index: 40;
    width: 340px;
    max-width: calc(100vw - 24px);
    background: var(--ccm-bg);
    border: 1px solid var(--ccm-rule);
    border-radius: var(--ccm-radius);
    box-shadow: 0 8px 24px rgba(0, 0, 0, .12);
    overflow: hidden;
}

.buzz-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding: 10px 12px;
    border-bottom: 1px solid var(--ccm-rule-soft);
}

.buzz-title { margin: 0; font-size: 13px; }

/* A real button, sized for a thumb. A 12-pixel cross only a mouse can hit is
   how a dismissible panel becomes an undismissable one on a phone. */
.buzz-close {
    flex: 0 0 auto;
    width: 30px;
    height: 30px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: none;
    border: 0;
    border-radius: 50%;
    font-size: 20px;
    line-height: 1;
    color: var(--ccm-muted);
    cursor: pointer;
}

.buzz-close:hover { background: var(--ccm-surface); color: var(--ccm-ink); }
.buzz-close:focus-visible { outline: 2px solid var(--ccm-link); outline-offset: 1px; }

/* Two across, and short. This is a nudge, not a second listing page. */
.buzz-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 1px;
    background: var(--ccm-rule-soft);
    max-height: 46vh;
    overflow-y: auto;
}

.buzz-item {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 9px 10px;
    background: var(--ccm-bg);
    text-decoration: none;
    min-width: 0;
}

.buzz-item:hover { background: var(--ccm-surface); }

.buzz-item-pic {
    flex: 0 0 40px;
    width: 40px;
    height: 40px;
    max-width: 40px;
    max-height: 40px;
    object-fit: contain;
    padding: 2px;
    box-sizing: border-box;
    border-radius: var(--ccm-radius);
    background: var(--ccm-bg);
}

.buzz-item-body { min-width: 0; }

.buzz-item-name {
    display: block;
    font-size: 12.5px;
    color: var(--ccm-ink);
    line-height: 1.3;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.buzz-item-meta {
    display: block;
    margin-top: 1px;
    font-size: 11px;
    color: var(--ccm-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

@media (max-width: 520px) {
    .buzz { right: 10px; left: 10px; bottom: 10px; width: auto; }
    .buzz-grid { grid-template-columns: 1fr; max-height: 38vh; }
}

@media (prefers-reduced-motion: reduce) {
    .help-way:hover { transform: none; }
}

/* ---------------------------------------------------------------------------
   A safety net for every inline icon.

   An <svg> with a viewBox and no width is not "24 pixels" — it is a shape with
   a coordinate system, and it will take whatever width its container offers
   and scale its height to match. Where a container is a flex or grid item that
   can grow, that is however wide the page is. This caps any icon nobody has
   sized explicitly at something recognisably an icon, so the failure is a
   slightly wrong glyph rather than a picture the size of the screen.
   --------------------------------------------------------------------------- */
svg:not([width]):not([height]) { max-width: 100%; max-height: 100%; }

/* ===========================================================================
   Signing up, phase two — vendor and rider applications
   ===========================================================================
   Long forms on the storefront, filled in once by somebody who has never seen
   the admin. Wider spacing and larger type than an admin screen, because this
   is the first real thing they do on the site and it decides whether they
   finish. Every colour is a brand token. */

.ob-head { max-width: 62ch; margin: 6px 0 26px; }

.ob-step {
    display: inline-block;
    margin-bottom: 10px;
    padding: 5px 11px;
    border-radius: 999px;
    background: var(--ccm-mint);
    color: var(--ccm-ink);
    font-size: 12px;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
}

.ob-head h1 {
    margin: 0;
    font-size: 30px;
    font-weight: 700;
    letter-spacing: -.02em;
    line-height: 1.15;
    color: var(--ccm-ink);
}
.ob-head p { margin: 10px 0 0; font-size: 16px; line-height: 1.6; color: var(--ccm-body); }

/* --- one section of the form ---------------------------------------------- */
.ob-card {
    margin: 0 0 18px;
    background: var(--ccm-bg);
    border: 1px solid var(--ccm-rule);
    border-radius: var(--ccm-radius-lg);
    overflow: hidden;
}

.ob-card-head {
    display: flex;
    align-items: flex-start;
    gap: 14px;
    padding: 20px 22px 16px;
    border-bottom: 1px solid var(--ccm-rule);
    background: var(--ccm-surface);
}
.ob-card-head > div { min-width: 0; }
.ob-card-head h2 {
    margin: 0;
    font-size: 18px;
    font-weight: 700;
    letter-spacing: -.01em;
    color: var(--ccm-ink);
}
.ob-card-head p { margin: 4px 0 0; font-size: 14.5px; line-height: 1.55; color: var(--ccm-body); }

.ob-icon {
    flex: none;
    width: 40px; height: 40px;
    display: grid; place-items: center;
    border-radius: 10px;
    background: var(--ccm-bg);
    border: 1px solid var(--ccm-rule);
    color: var(--ccm-ink);
}
.ob-icon svg { width: 20px; height: 20px; }

.ob-body { padding: 20px 22px 22px; }
.ob-body .field { margin-bottom: 16px; }
.ob-body .field:last-child { margin-bottom: 0; }

/* Two fields side by side, stacking on a phone. */
.ob-body .field-row {
    display: grid;
    gap: 0 16px;
    grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr));
}

/* A document already uploaded. */
.ob-have {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-top: 6px;
    font-size: 13px;
    font-weight: 600;
    color: var(--ccm-ink);
}
.ob-have svg { width: 15px; height: 15px; flex: none; }

/* --- the terms ------------------------------------------------------------ */
.ob-terms {
    margin: 0 0 18px;
    padding-left: 20px;
    display: grid;
    gap: 11px;
    font-size: 14.5px;
    line-height: 1.6;
    color: var(--ccm-body);
}
.ob-terms strong { color: var(--ccm-ink); }
.ob-terms li::marker { color: var(--ccm-muted); font-weight: 700; }

/* --- actions -------------------------------------------------------------- */
.ob-actions {
    display: flex;
    align-items: center;
    gap: 14px;
    flex-wrap: wrap;
    margin: 4px 0 26px;
}

/* --- the fee -------------------------------------------------------------- */
.ob-fee { border-color: var(--ccm-amber); }

.ob-fee-amount {
    display: flex;
    align-items: baseline;
    gap: 10px;
    flex-wrap: wrap;
    margin-bottom: 16px;
}
.ob-fee-value {
    font-size: 34px;
    font-weight: 700;
    letter-spacing: -.02em;
    color: var(--ccm-ink);
    font-variant-numeric: tabular-nums;
}

.ob-paid { display: flex; align-items: center; gap: 13px; }
.ob-paid-mark {
    flex: none;
    width: 40px; height: 40px;
    display: grid; place-items: center;
    border-radius: 50%;
    background: var(--ccm-mint);
    color: var(--ccm-ink);
}
.ob-paid-mark svg { width: 21px; height: 21px; }

/* --- the closing note ----------------------------------------------------- */
.ob-foot {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    margin: 0 0 40px;
    padding: 15px 17px;
    border-radius: var(--ccm-radius-lg);
    background: var(--ccm-surface);
    font-size: 14px;
    line-height: 1.6;
    color: var(--ccm-body);
}
.ob-foot svg { width: 18px; height: 18px; flex: none; margin-top: 2px; color: var(--ccm-muted); }

/* --- the "we have it" page ------------------------------------------------ */
.ob-done {
    max-width: 58ch;
    margin: 22px auto 48px;
    text-align: center;
}
.ob-done-mark {
    width: 68px; height: 68px;
    margin: 0 auto 18px;
    display: grid; place-items: center;
    border-radius: 50%;
    background: var(--ccm-surface);
    color: var(--ccm-muted);
}
.ob-done-mark svg { width: 32px; height: 32px; }
.ob-done-mark.is-good { background: var(--ccm-mint); color: var(--ccm-ink); }
.ob-done-mark.is-bad  { color: var(--ccm-red); }

.ob-done h1 {
    margin: 0 0 12px;
    font-size: 28px;
    font-weight: 700;
    letter-spacing: -.02em;
    color: var(--ccm-ink);
}
.ob-done p { margin: 0 0 14px; font-size: 16px; line-height: 1.65; color: var(--ccm-body); }
.ob-done .ob-reason {
    padding: 13px 16px;
    border-radius: var(--ccm-radius-lg);
    background: var(--ccm-surface);
    color: var(--ccm-ink);
    font-weight: 600;
}

.ob-summary {
    display: grid;
    gap: 1px;
    margin: 22px 0;
    text-align: left;
    background: var(--ccm-rule);
    border: 1px solid var(--ccm-rule);
    border-radius: var(--ccm-radius-lg);
    overflow: hidden;
}
.ob-summary > div {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 14px;
    padding: 13px 17px;
    background: var(--ccm-bg);
}
.ob-summary dt { font-size: 14px; color: var(--ccm-body); }
.ob-summary dd { margin: 0; font-size: 14.5px; font-weight: 600; color: var(--ccm-ink); }

.ob-done-actions { margin-top: 22px; }

@media (max-width: 640px) {
    .ob-head h1 { font-size: 25px; }
    .ob-card-head { padding: 16px 16px 13px; }
    .ob-body { padding: 16px; }
    .ob-fee-value { font-size: 28px; }
    .ob-done h1 { font-size: 24px; }
}

/* --- "Check cart", under the stepper ---------------------------------------
   The control is a wrapping flex row, so giving this a full-width basis puts
   it on its own line beneath the − / + rather than squeezed beside it. */
.add-check {
    flex: 1 0 100%;
    justify-content: center;
    margin-top: 8px;
}
.add-control.is-compact .add-check { margin-top: 6px; }

/* The plus, once the shelf is empty.
   It is disabled rather than merely refusing on click, so a shopper learns
   they have taken the last one before pressing rather than after. */
.stepper-btn:disabled {
    opacity: .4;
    cursor: not-allowed;
    background: var(--ccm-surface);
}
.stepper-btn:disabled:hover { background: var(--ccm-surface); }

/* --- how many are left -----------------------------------------------------
   Shown on the product page beside the stepper. A number, because "in stock"
   and "only 3 left" are different facts and a shopper buying for a party needs
   the second one. */
.stock-line {
    display: flex;
    align-items: center;
    gap: 7px;
    margin: 12px 0 0;
    font-size: 14px;
    color: var(--ccm-body);
}
.stock-line svg { width: 16px; height: 16px; flex: none; }
.stock-line strong { color: var(--ccm-ink); font-variant-numeric: tabular-nums; }
.stock-line.is-low { color: var(--ccm-red); }
.stock-line.is-low strong { color: var(--ccm-red); }

/* --- who is selling it, on a card -----------------------------------------
   The vendor sits beside the category in the same small line. It is a link
   inside a card whose title is also a link, so it gets its own colour and a
   hover to make clear it goes somewhere different. */
.card-cat a.card-vendor {
    color: var(--ccm-body);
    font-weight: 600;
    text-decoration: none;
}
.card-cat a.card-vendor:hover { color: var(--ccm-link); text-decoration: underline; }
.card-cat-sep { opacity: .5; margin: 0 1px; }

/* --- confirmations, at the top ---------------------------------------------
   Storefront only. The admin keeps its bottom-right stack, where it sits out
   of the way of a table somebody is reading.

   A shopper is looking at the product they just pressed Add on, which is in
   the middle of the page, and a message in the bottom corner was missed. This
   lands at the top centre, over the header, where the eye already is. */
.ccm-toasts {
    top: 14px;
    bottom: auto;
    left: 50%;
    right: auto;
    transform: translateX(-50%);
    flex-direction: column;
    align-items: center;
    width: max-content;
    max-width: min(420px, calc(100vw - 24px));
}

.ccm-toast {
    box-shadow: 0 10px 30px rgba(0, 0, 0, .14), 0 2px 6px rgba(0, 0, 0, .06);
}

@media (max-width: 640px) {
    .ccm-toasts {
        top: 10px;
        left: 12px;
        right: 12px;
        bottom: auto;
        transform: none;
        width: auto;
        max-width: none;
    }
}

/* The live-chat launcher, kept off phones.
   The panel covers most of a small screen, and WhatsApp is right beside it —
   an app the shopper already has. An administrator can switch this back on,
   which removes the class rather than overriding the rule. */
@media (max-width: 767px) {
    .support-btn-chat.is-desktop-only { display: none; }
}

/* --- quick view, on a phone ------------------------------------------------
   The panel is a grid with a max-height and `overflow: hidden`. Both its rows
   were sized `auto`, so the body grew to its content, the grid overran the cap,
   and the hidden overflow *clipped* the bottom — which is where the price, the
   stepper and "Add to cart" live. The controls were not off-screen; they had
   been cut off.

   Sizing the second row `minmax(0, 1fr)` gives it the space that is left and a
   zero minimum, which is what lets its own `overflow-y: auto` scroll instead of
   the parent clipping. A track whose minimum is `auto` cannot shrink, and that
   is the whole bug. */
.qv-figure { grid-template-rows: auto minmax(0, 1fr); }
.qv-body { min-height: 0; }

@media (max-width: 767px) {
    /* Nearly the full screen, deliberately: at this width a centred card with
       margins leaves too little room for the picture and the controls at once. */
    .qv-figure {
        width: 100%;
        max-height: calc(100dvh - 24px);
        border-radius: 12px;
    }

    /* A smaller picture, so the part that does something is above the fold. */
    .qv-image { min-height: 0; padding: 16px; }
    .qv-image img { max-height: 30vh; }

    .qv-body { padding: 18px 18px 22px; }
    .qv-body h2 { font-size: 19px; }

    /* The action row stays put while the description scrolls behind it, so
       "Add to cart" is reachable without hunting for it. */
    .qv-actions {
        position: sticky;
        bottom: -22px;
        margin-top: 16px;
        padding: 12px 0 14px;
        background: var(--ccm-bg);
        box-shadow: 0 -10px 14px -8px rgba(0, 0, 0, .12);
    }

    .qv-close {
        top: 8px; right: 8px;
        width: 38px; height: 38px;
        background: var(--ccm-bg);
        border-radius: 50%;
        box-shadow: 0 1px 4px rgba(0, 0, 0, .18);
    }
}

/* --- a department's face ---------------------------------------------------
   The mark holds a picture, an icon, or the first letter — whichever the
   administrator set, in that order. Same circle either way, so a row of tiles
   stays even however they are decorated. */
.cat-tile-mark { overflow: hidden; }
.cat-tile-mark svg { width: 23px; height: 23px; stroke-width: 1.7; }

/* A photograph fills the circle rather than sitting inside it. */
.cat-tile-mark.has-image { background: var(--ccm-surface); padding: 0; }
.cat-tile-mark.has-image img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

/* Slightly larger tiles now that they can carry artwork, and an even grid at
   every width rather than a ragged last row. */
.cat-grid { grid-template-columns: repeat(auto-fill, minmax(min(148px, 100%), 1fr)); }
.cat-tile-mark { width: 52px; height: 52px; }

/* "Check cart" sits directly beneath the − / + , full width and in the brand
   amber, so the way to the basket is the most obvious thing in the control
   once something is in it. `order` puts it after the stepper regardless of
   where it falls in the source. */
.add-control { row-gap: 0; }
.add-check {
    order: 3;
    flex: 1 0 100%;
    margin-top: 10px;
    padding: 11px 16px;
    font-weight: 700;
}
.add-control.is-compact .add-check { margin-top: 8px; }

/* A payment chip now carries an icon beside its name. */

/* ===========================================================================
   The basket, as a table
   =========================================================================== */

.cart-table-wrap { border-radius: var(--ccm-radius-lg); }

.cart-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 14.5px;
}

.cart-table thead th {
    text-align: left;
    padding: 14px 16px;
    background: var(--ccm-surface);
    border-bottom: 1px solid var(--ccm-rule);
    font-size: 12px;
    font-weight: 700;
    letter-spacing: .07em;
    text-transform: uppercase;
    color: var(--ccm-body);
    white-space: nowrap;
}

.cart-table td {
    padding: 18px 16px;
    border-bottom: 1px solid var(--ccm-rule-soft);
    vertical-align: middle;
}
.cart-table tbody tr:last-child td { border-bottom: 0; }

/* A line whose product went away while it sat here. */
.cart-table tr.is-unavailable { background: var(--ccm-surface); }
.cart-table tr.is-unavailable .cart-name { color: var(--ccm-muted); }

.cart-cell-thumb { width: 88px; }
.cart-cell-thumb img {
    width: 64px; height: 64px;
    object-fit: contain;
    display: block;
    border: 1px solid var(--ccm-rule-soft);
    border-radius: 6px;
    background: var(--ccm-bg);
}

.cart-name { font-weight: 600; color: var(--ccm-link); }
.cart-name:hover { text-decoration: underline; }
.cart-meta { margin-top: 3px; font-size: 13px; color: var(--ccm-body); }
.cart-meta strong { color: var(--ccm-ink); font-weight: 600; }

.cart-cell-price, .cart-cell-total { white-space: nowrap; font-variant-numeric: tabular-nums; }
.cart-cell-total strong { font-size: 15px; color: var(--ccm-ink); }
.cart-cell-qty .stepper { margin: 0; }
.cart-cell-remove { width: 56px; text-align: right; }

/* Remove a line. A bin in its own quiet button, red when pointed at, because
   it is the only control on the row that destroys something. */
.cart-remove {
    display: inline-grid;
    place-items: center;
    width: 36px; height: 36px;
    padding: 0;
    border: 1px solid var(--ccm-rule);
    border-radius: 8px;
    background: var(--ccm-bg);
    color: var(--ccm-muted);
    cursor: pointer;
    transition: color .12s ease, border-color .12s ease, background .12s ease;
}
.cart-remove svg { width: 18px; height: 18px; }
.cart-remove:hover {
    color: var(--ccm-badge-ink);
    background: var(--ccm-red-band);
    border-color: var(--ccm-red-band);
}
.cart-remove:focus-visible { outline: 2px solid var(--ccm-link); outline-offset: 2px; }

/* --- the bar under the table ---------------------------------------------- */
.cart-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 14px;
    flex-wrap: wrap;
    margin-top: 18px;
}
.cart-bar-right { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }

/* The one thing this page exists for. Brand red, so it is not mistaken for the
   amber "keep shopping" button at the other end of the same bar. */
.btn-checkout {
    background: var(--ccm-red-band);
    color: var(--ccm-badge-ink);
    border-color: var(--ccm-red-band);
    font-weight: 700;
}
.btn-checkout:hover { filter: brightness(.93); color: var(--ccm-badge-ink); text-decoration: none; }
.btn-checkout:disabled { opacity: .45; cursor: not-allowed; filter: none; }

/* --- on a phone -----------------------------------------------------------
   Five columns will not fit, so each row becomes a card and every cell carries
   its own label. A horizontally scrolling basket is a basket whose totals are
   off-screen. */
@media (max-width: 720px) {
    .cart-table-wrap { overflow: visible; border: 0; }
    .cart-table thead { display: none; }

    .cart-table, .cart-table tbody, .cart-table tr, .cart-table td { display: block; width: auto; }

    .cart-table tr {
        position: relative;
        margin-bottom: 12px;
        padding: 14px 14px 10px 92px;
        min-height: 92px;
        border: 1px solid var(--ccm-rule);
        border-radius: var(--ccm-radius-lg);
        background: var(--ccm-bg);
    }

    .cart-table td { padding: 0; border: 0; }

    .cart-cell-thumb { position: absolute; top: 14px; left: 14px; width: 64px; }

    .cart-cell-price, .cart-cell-total {
        display: flex;
        justify-content: space-between;
        margin-top: 8px;
        font-size: 14px;
    }
    .cart-cell-price::before, .cart-cell-total::before {
        content: attr(data-label);
        color: var(--ccm-body);
        font-weight: 500;
    }

    .cart-cell-qty { margin-top: 10px; }
    .cart-cell-remove {
        position: absolute;
        top: 10px; right: 10px;
        width: auto;
    }

    .cart-bar { flex-direction: column; align-items: stretch; }
    .cart-bar-right { flex-direction: column; }
    .cart-bar .btn, .cart-bar-right .btn, .cart-bar form { width: 100%; }
    .cart-bar .btn { justify-content: center; }
}

/* --- checkout: billing details --------------------------------------------- */
.req { color: var(--ccm-red); font-weight: 700; }

/* "Ship to a different address?" — a checkbox that reveals a second set of
   fields.

   A real checkbox with a sibling selector, not a <details>: a closed <details>
   still submits every input inside it, so the flag would have been sent on
   every order whether or not anybody ticked it. This way the browser decides,
   and it works with JavaScript off. */
.ship-elsewhere {
    margin: 4px 0 18px;
    padding: 4px 0;
    border-top: 1px solid var(--ccm-rule-soft);
    border-bottom: 1px solid var(--ccm-rule-soft);
}

.ship-toggle {
    position: absolute;
    width: 1px; height: 1px;
    opacity: 0;
    margin: 0;
}

/* Scoped to the layout it lives in, because `.checkout-layout label` sets
   `display: block` at a higher specificity and was winning. That mattered more
   than it looks: with the label blockified the ::before stayed inline, width
   and height did not apply to it, and the box collapsed to nothing — the
   wording was on screen with no checkbox beside it. */
.ship-label,
.checkout-layout .ship-label {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 12px 2px;
    margin-bottom: 0;
    cursor: pointer;
    /* Safari and every browser on iOS still need the prefix; without it a
       long press on these controls selects the label text instead of acting
       on the control, which on a phone reads as the tap not registering. */
    -webkit-user-select: none;
    user-select: none;
    font-size: 14.5px;
    font-weight: 600;
    color: var(--ccm-ink);
}

.ship-label::before {
    content: '';
    /* Stated rather than inherited from being a flex item, so the box keeps
       its size wherever this component is dropped. */
    display: block;
    flex: none;
    width: 18px; height: 18px;
    border: 1px solid var(--ccm-rule);
    border-radius: 4px;
    background: var(--ccm-bg);
    transition: background .12s ease, border-color .12s ease;
}

.ship-toggle:checked + .ship-label::before {
    background: var(--ccm-red);
    border-color: var(--ccm-red);
}

/* The tick, drawn rather than fetched — the CSP allows no inline styles and a
   data: URI here would be one more thing to maintain. */
.ship-toggle:checked + .ship-label::after {
    content: '';
    position: absolute;
    margin-left: 6px;
    width: 5px; height: 10px;
    border: solid var(--ccm-badge-ink);
    border-width: 0 2px 2px 0;
    transform: rotate(45deg) translate(-1px, -1px);
}

.ship-toggle:focus-visible + .ship-label::before {
    outline: 2px solid var(--ccm-link);
    outline-offset: 2px;
}

/* Hidden until asked for. */
.ship-toggle:not(:checked) ~ .ship-body { display: none; }
.ship-body { padding: 4px 0 16px; }

/* --- room for the floating support buttons --------------------------------
   A little clearance at the end of a page so the dock never rests on the last
   line of content. It cannot solve the general case — a fixed button will
   overlap something at some scroll position, which is why the dock can now be
   dismissed; see .support-close. */
.shop-main,
body > .shell:last-of-type { padding-bottom: 96px; }

/* ===========================================================================
   The phone's bottom bar
   ===========================================================================
   Mobile only. Above 767px the masthead and the department strip already put
   Home, Category, Search and Cart within reach, and a fixed bar there would
   just take a strip off the bottom of every page for nothing.

   Everything below is inside the media query on purpose: this must not change
   a single pixel of the desktop layout. */

.tabbar { display: none; }

@media (max-width: 767px) {
    .tabbar {
        position: fixed;
        left: 0; right: 0; bottom: 0;
        z-index: 95;
        display: grid;
        grid-template-columns: repeat(4, 1fr);
        background: var(--ccm-bg);
        border-top: 1px solid var(--ccm-rule);
        /* Clear of the home indicator on a modern phone. */
        padding-bottom: env(safe-area-inset-bottom, 0px);
        box-shadow: 0 -2px 12px rgba(0, 0, 0, .06);
    }

    .tabbar-item {
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: 4px;
        /* 56px is a comfortable target on the smallest phone still in use. */
        min-height: 56px;
        padding: 8px 4px;
        border: 0;
        background: none;
        font: inherit;
        font-size: 11.5px;
        font-weight: 600;
        color: var(--ccm-body);
        text-decoration: none;
        cursor: pointer;
        -webkit-tap-highlight-color: transparent;
    }
    .tabbar-item svg { width: 22px; height: 22px; }
    .tabbar-item:active { background: var(--ccm-surface); }
    .tabbar-item.is-current { color: var(--ccm-red); }
    .tabbar-item:focus-visible { outline: 2px solid var(--ccm-link); outline-offset: -3px; }

    .tabbar-cart { position: relative; display: inline-flex; }
    .tabbar-count {
        position: absolute;
        top: -5px; right: -9px;
        min-width: 17px; height: 17px;
        padding: 0 4px;
        display: grid; place-items: center;
        border-radius: 999px;
        background: var(--ccm-amber);
        color: var(--ccm-amber-ink);
        font-size: 10.5px;
        font-weight: 700;
        font-variant-numeric: tabular-nums;
    }

    /* Nothing may end underneath the bar. */
    .shop-main,
    body > .shell:last-of-type { padding-bottom: calc(84px + env(safe-area-inset-bottom, 0px)); }

    footer { padding-bottom: calc(72px + env(safe-area-inset-bottom, 0px)); }

    /* The dock sits above the bar rather than on it. */
    .support-dock { bottom: calc(76px + env(safe-area-inset-bottom, 0px)); }
    .support-restore { bottom: calc(76px + env(safe-area-inset-bottom, 0px)); }
}

/* --- putting the dock away -------------------------------------------------
   A small cross on the corner of the dock, and a tab to bring it back. Both
   are always available: a floating button will overlap something at some
   scroll position, and the reader is better placed than we are to decide when
   that matters. */
.support-dock { position: fixed; }

.support-close {
    position: absolute;
    top: -8px; right: -6px;
    z-index: 2;
    width: 24px; height: 24px;
    display: grid; place-items: center;
    padding: 0;
    border: 1px solid var(--ccm-rule);
    border-radius: 50%;
    background: var(--ccm-bg);
    color: var(--ccm-body);
    cursor: pointer;
    box-shadow: 0 1px 4px rgba(0, 0, 0, .16);
}
.support-close svg { width: 12px; height: 12px; }
.support-close:hover { background: var(--ccm-ink); color: var(--ccm-bg); border-color: var(--ccm-ink); }
.support-close:focus-visible { outline: 2px solid var(--ccm-link); outline-offset: 2px; }

.support-restore {
    position: fixed;
    right: 16px;
    bottom: calc(16px + env(safe-area-inset-bottom, 0px));
    z-index: 90;
    width: 40px; height: 40px;
    display: grid; place-items: center;
    padding: 0;
    border: 1px solid var(--ccm-rule);
    border-radius: 50%;
    background: var(--ccm-bg);
    color: var(--ccm-body);
    cursor: pointer;
    box-shadow: var(--ccm-shadow-sm);
}
.support-restore svg { width: 19px; height: 19px; }
.support-restore:hover { color: var(--ccm-ink); border-color: var(--ccm-muted); }

/* The dock and its restore tab, above the phone's bottom bar.
   These repeat the offsets set earlier because the base .support-restore rule
   is declared after that media block, and at equal specificity the later rule
   wins — so the tab was landing underneath the bar and could not be pressed. */
@media (max-width: 767px) {
    .support-dock,
    .support-restore { bottom: calc(76px + env(safe-area-inset-bottom, 0px)); }

    /* Above the bar, so a dismissed dock can always be brought back. */
    .support-restore { z-index: 96; }
    .support-dock { z-index: 96; }
}

/* --- the hero band: the whole picture, sized to the device ------------------
   Two problems, one rule.
   
   `min-height` set a floor and nothing set a ceiling, so a tall image could
   push the band past the viewport. And `object-fit: cover` filled that band by
   *cropping* — which on a banner carrying words means the words go missing,
   and differently at every width.

   So the band takes the shape of the artwork instead. `aspect-ratio` is the
   1920x620 the upload form asks for, so a correctly sized banner fills it
   exactly; anything else is fitted whole against the brand mint rather than
   trimmed. Capped at 70vh so it can never take the whole screen. */
.hero-slider {
    aspect-ratio: 1920 / 620;
    height: auto;
    min-height: 0;
    max-height: 70vh;
}
.hero-track, .hero-slide { min-height: 0; height: 100%; }

/* contain, not cover: every part of the picture is on screen. */
.hero-image {
    width: 100%;
    height: 100%;
    object-fit: contain;
    object-position: center;
}

@media (max-width: 767px) {
    /* A phone gets the portrait artwork where there is one, so the band is
       taller and squarer. Still the whole picture, still capped. */
    .hero-slider { aspect-ratio: 16 / 11; max-height: 56vh; }
}

/* The blurred backdrop behind a hero image.
   Fills a full-width band whose artwork is not the band's shape, so the space
   beside a square banner carries the picture's own colours instead of reading
   as a failed load. The real artwork sits on top of it, whole. */
.hero-slide.is-image picture { position: relative; overflow: hidden; }

.hero-image-fill {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center;
    filter: blur(28px) saturate(1.15);
    /* Scaled up so the blur's soft edge never shows at the band's border. */
    transform: scale(1.12);
    opacity: .55;
    pointer-events: none;
}

.hero-image { position: relative; z-index: 1; }

@media (prefers-reduced-motion: reduce) {
    .hero-image-fill { filter: blur(20px); transform: none; }
}

/* ===========================================================================
   The shop toolbar — how many, in what order, shown how
   =========================================================================== */

.shop-toolbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 14px;
    flex-wrap: wrap;
    margin: 0 0 18px;
    padding: 12px 16px;
    background: var(--ccm-surface);
    border: 1px solid var(--ccm-rule);
    border-radius: var(--ccm-radius-lg);
}

.shop-count { margin: 0; font-size: 14.5px; color: var(--ccm-body); }
.shop-count strong { color: var(--ccm-ink); font-variant-numeric: tabular-nums; }

.shop-sort { display: flex; align-items: center; gap: 8px; margin: 0; }
.shop-sort select {
    min-width: 210px;
    height: 40px;
    padding: 0 12px;
    border: 1px solid var(--ccm-rule);
    border-radius: 6px;
    background: var(--ccm-bg);
    font: inherit;
    font-size: 14px;
    color: var(--ccm-ink);
}

.shop-view { display: flex; align-items: center; gap: 8px; }
.shop-view-label { font-size: 14px; color: var(--ccm-body); }

.shop-view-btn {
    display: grid;
    place-items: center;
    width: 36px; height: 36px;
    border: 1px solid var(--ccm-rule);
    border-radius: 6px;
    background: var(--ccm-bg);
    color: var(--ccm-muted);
}
.shop-view-btn svg { width: 18px; height: 18px; }
.shop-view-btn:hover { color: var(--ccm-ink); border-color: var(--ccm-muted); text-decoration: none; }
.shop-view-btn.is-current {
    background: var(--ccm-ink);
    border-color: var(--ccm-ink);
    color: var(--ccm-bg);
}

/* --- list view -------------------------------------------------------------
   The same cards, one per row, with the picture beside the words instead of
   above them. A separate template would be a second card to keep in step with
   the first. */
.grid.is-list { display: grid; grid-template-columns: 1fr; gap: 12px; }

.grid.is-list .card {
    display: grid;
    grid-template-columns: 180px 1fr;
    align-items: center;
    gap: 18px;
    padding: 14px;
}
.grid.is-list .card-media { margin: 0; }
.grid.is-list .card-body { padding: 0; }
.grid.is-list .card-name { font-size: 16px; }
.grid.is-list .card-actions { opacity: 1; transform: none; max-width: 260px; }

@media (max-width: 560px) {
    .grid.is-list .card { grid-template-columns: 110px 1fr; gap: 12px; }
    .shop-toolbar { gap: 10px; }
    .shop-sort { flex: 1 1 100%; }
    .shop-sort select { width: 100%; min-width: 0; }
}

/* --- how to pay, under the total ------------------------------------------- */
.pay-choice { display: grid; gap: 10px; margin: 18px 0; }

.pay-option {
    display: grid;
    grid-template-columns: 20px 1fr;
    align-items: start;
    gap: 12px;
    padding: 14px;
    border: 1px solid var(--ccm-rule);
    border-radius: var(--ccm-radius-lg);
    background: var(--ccm-bg);
    cursor: pointer;
    transition: border-color .12s ease, background .12s ease;
}
.pay-option:hover { border-color: var(--ccm-muted); }
.pay-option:has(input:checked) { border-color: var(--ccm-red); background: var(--ccm-surface); }
.pay-option:has(input:focus-visible) { outline: 2px solid var(--ccm-link); outline-offset: 2px; }
.pay-option.is-disabled { opacity: .55; cursor: not-allowed; }

.pay-option input { margin: 3px 0 0; accent-color: var(--ccm-red); }

.pay-option-body { display: block; min-width: 0; }
.pay-option-title {
    display: block;
    font-size: 14.5px;
    font-weight: 700;
    color: var(--ccm-ink);
}
.pay-option-note {
    display: block;
    margin-top: 5px;
    font-size: 12.5px;
    line-height: 1.5;
    color: var(--ccm-body);
}

/* The methods, as the panel of marks the client supplied.
   The image runs edge to edge inside the frame rather than sitting on a
   padded background: its own ground is #F6F6F6, and any padding colour that
   was not exactly that would draw a seam around it. The whitespace baked
   into the artwork is the padding. */
.pay-brands {
    display: block;
    max-width: 384px;
    margin-top: 9px;
    border: 1px solid var(--ccm-rule);
    border-radius: 8px;
    overflow: hidden;
}
.pay-brands img {
    display: block;
    width: 100%;
    height: auto;
}

/* ===========================================================================
   Searchable select (ccm-select.js)
   ---------------------------------------------------------------------------
   Copied verbatim from app.css, where this component has lived since the admin
   needed it. The storefront now needs it too — the checkout's country list is
   249 entries — and the two sheets are loaded independently, so the rules have
   to exist in both. Every value is a token both sheets already define, so the
   copy cannot drift into a different colour; if the shape ever changes, it
   changes in both.
   =========================================================================== */

.ccm-select { position: relative; }

/* Hidden from sight, still in the form. `display: none` would take it out of
   the submission on some browsers; this does not. */
.ccm-select-native {
    position: absolute;
    width: 1px; height: 1px;
    opacity: 0;
    pointer-events: none;
}

.ccm-select-button {
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 10px 12px;
    border: 1px solid var(--ccm-rule);
    border-radius: 8px;
    background: var(--ccm-bg);
    color: var(--ccm-ink);
    font: inherit;
    font-size: 13.5px;
    text-align: left;
    cursor: pointer;
}
.ccm-select-button::after {
    content: "";
    flex: none;
    width: 8px; height: 8px;
    border-right: 2px solid var(--ccm-muted);
    border-bottom: 2px solid var(--ccm-muted);
    transform: rotate(45deg) translateY(-2px);
}
.ccm-select-button:hover { border-color: var(--ccm-body); }
.ccm-select-button.is-placeholder { color: var(--ccm-muted); }

.ccm-select-panel {
    position: absolute;
    z-index: 40;
    left: 0; right: 0; top: calc(100% + 4px);
    background: var(--ccm-bg);
    border: 1px solid var(--ccm-rule);
    border-radius: 10px;
    box-shadow: 0 10px 30px rgba(0, 0, 0, .14);
    overflow: hidden;
}

.ccm-select-search {
    width: 100%;
    padding: 10px 12px;
    border: 0;
    border-bottom: 1px solid var(--ccm-rule);
    font: inherit;
    font-size: 13.5px;
}
.ccm-select-search:focus { outline: none; }

.ccm-select-list { max-height: 260px; overflow-y: auto; }

.ccm-select-option {
    display: block;
    width: 100%;
    padding: 9px 12px;
    border: 0;
    background: none;
    font: inherit;
    font-size: 13.5px;
    color: var(--ccm-ink);
    text-align: left;
    cursor: pointer;
}
.ccm-select-option:hover,
.ccm-select-option:focus { background: var(--ccm-surface); outline: none; }
.ccm-select-option.is-selected { background: var(--ccm-mint); font-weight: 600; }

.ccm-select-empty { padding: 12px; font-size: 13px; color: var(--ccm-muted); }

/* ===========================================================================
   A button that is working
   ---------------------------------------------------------------------------
   Drawn in currentColor so it inherits whatever button it sits on and adds no
   colour of its own — the palette is locked, and a spinner is not a good
   reason to widen it.
   =========================================================================== */

.btn.is-busy {
    cursor: progress;
    opacity: .85;
}

.btn-spinner {
    display: inline-block;
    width: 14px;
    height: 14px;
    margin-right: 8px;
    vertical-align: -2px;
    border: 2px solid currentColor;
    border-right-color: transparent;
    border-radius: 50%;
    animation: ccm-spin .6s linear infinite;
}

@keyframes ccm-spin {
    to { transform: rotate(360deg); }
}

/* Somebody who has asked for less motion still needs to see that the button
   is busy; a pulse says so without spinning. */
@media (prefers-reduced-motion: reduce) {
    .btn-spinner { animation: ccm-fade 1s ease-in-out infinite alternate; }
    @keyframes ccm-fade { to { opacity: .3; } }
}

/* The product code, when the shop has chosen to show it. Monospaced because
   it is a code somebody may be reading out or typing, not a word. */
.chip-code {
    font-family: ui-monospace, Consolas, monospace;
    letter-spacing: .02em;
}

/* The signed-out account glyph is a link in its own right. It inherits the
   header's colour and lays out exactly as the bare glyph did, so the desktop
   row is unchanged — what it adds is a tap target on a phone, where the
   "Log in" and "Register" words beside it are hidden. */
.head-glyph-link {
    display: inline-flex;
    align-items: center;
    color: inherit;
    text-decoration: none;
}

.head-glyph-link:hover { color: var(--ccm-red); }

/* =============================================================================
   Add to basket — saying so on the button
   =============================================================================
   The press used to be answered somewhere else: a toast in the corner and a
   number in the masthead. On a listing, where the button is often the only
   thing under the thumb and the toast can be off the top of a scrolled page,
   that reads as a button that did nothing — so people press it again.

   Four states, all on the button itself, where the finger already is:

     pressed  the moment of contact, before any network
     adding   the request is in flight
     added    it worked, held long enough to be read
     failed   it did not, and the button says so rather than only the note

   No new colours: the button is already amber with black on it, and the states
   are drawn with the palette's mint, ink and red. Every animation is switched
   off under prefers-reduced-motion, where the state still changes — somebody
   who asked for less motion still needs to know their press landed.
   ========================================================================== */

/* The press itself. Instant, and independent of the request: on a slow
   connection this is the only feedback for the first few hundred milliseconds. */
.add-control .btn[data-add-button] {
    position: relative;
    overflow: hidden;
    transition: transform .12s ease, background-color .16s ease, color .16s ease;
}

.add-control .btn[data-add-button]:active { transform: scale(.97); }

.add-control .btn.is-pressed { animation: ccm-add-press .22s ease; }

@keyframes ccm-add-press {
    40% { transform: scale(.95); }
    to  { transform: scale(1); }
}

/* A ring that travels out from the button, so a tap on a phone — where there
   is no hover and the :active state is gone in a frame — leaves something the
   eye can catch up with. */
.add-control .btn.is-pressed::after {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: inherit;
    border: 2px solid var(--ccm-ink);
    opacity: .45;
    animation: ccm-add-ring .45s ease-out forwards;
    pointer-events: none;
}

@keyframes ccm-add-ring {
    to { transform: scale(1.06); opacity: 0; }
}

/* In flight. The spinner is the shared one; what this adds is a button that
   cannot be pressed twice while the first press is still travelling.

   `.btn:disabled` drops every button to half opacity, which is right for a
   control you cannot use and wrong for one that is working on your behalf: it
   made "Adding…" and the tick read as greyed-out rather than as an answer. The
   button stays genuinely disabled — a second press would add a second one —
   and only the look is overridden. */
.add-control .btn.is-adding,
.add-control .btn.is-added {
    opacity: 1;
}

.add-control .btn.is-adding {
    cursor: progress;
}

/* It worked. Mint with the ink on it — the same pair the "Free" and "Paid"
   pills use — held for long enough to read, then returned to normal. */
.add-control .btn.is-added {
    background: var(--ccm-mint);
    border-color: var(--ccm-mint);
    color: var(--ccm-ink);
    animation: ccm-add-pop .32s ease;
}

@keyframes ccm-add-pop {
    35% { transform: scale(1.04); }
    to  { transform: scale(1); }
}

/* The tick draws itself rather than appearing, which is what makes it read as
   a confirmation rather than as another icon. */
.add-control .btn.is-added .btn-icon path {
    stroke-dasharray: 26;
    stroke-dashoffset: 26;
    animation: ccm-add-tick .34s ease-out .06s forwards;
}

@keyframes ccm-add-tick {
    to { stroke-dashoffset: 0; }
}

/* It did not work. A short shake, because a message that only appears below
   the button is a message on a listing nobody sees. */
.add-control .btn.is-failed {
    animation: ccm-add-shake .34s ease;
    border-color: var(--ccm-red);
}

@keyframes ccm-add-shake {
    20%, 60% { transform: translateX(-3px); }
    40%, 80% { transform: translateX(3px); }
    to       { transform: translateX(0); }
}

/* The stepper that replaces the button on a product page: it slides up into
   the space the button leaves rather than appearing from nowhere, so the eye
   follows the change instead of hunting for it. */
.add-control .add-live.is-arriving,
.add-control .add-check.is-arriving {
    animation: ccm-add-rise .26s ease-out;
}

@keyframes ccm-add-rise {
    from { opacity: 0; transform: translateY(6px); }
    to   { opacity: 1; transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
    .add-control .btn[data-add-button],
    .add-control .btn[data-add-button]:active { transition: none; transform: none; }

    .add-control .btn.is-pressed,
    .add-control .btn.is-added,
    .add-control .btn.is-failed,
    .add-control .add-live.is-arriving,
    .add-control .add-check.is-arriving { animation: none; }

    /* The ring and the drawn tick go; the colour change stays, because it is
       the part that carries the meaning. */
    .add-control .btn.is-pressed::after { display: none; }
    .add-control .btn.is-added .btn-icon path { stroke-dashoffset: 0; animation: none; }
}

/* =============================================================================
   Choosing a size and a colour
   =============================================================================
   A row of pressable values per option, not a dropdown. A shopper deciding
   between three sizes wants to see the three; a <select> hides two of them
   behind a tap and tells them nothing about which are in stock.
   ========================================================================== */

.pdp-options { margin: 18px 0 4px; display: grid; gap: 16px; }

.pdp-option-head {
    display: flex;
    align-items: baseline;
    gap: 8px;
    margin-bottom: 8px;
}

.pdp-option-name {
    font-size: 13px;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--ccm-body);
}

/* What they picked, beside the label — so the choice is readable without
   hunting for which button looks pressed. */
.pdp-option-chosen {
    font-size: 14px;
    font-weight: 700;
    color: var(--ccm-ink);
}

.pdp-swatches { display: flex; flex-wrap: wrap; gap: 8px; }

.swatch {
    min-width: 52px;
    padding: 9px 14px;
    border: 1px solid var(--ccm-rule);
    border-radius: var(--ccm-radius);
    background: var(--ccm-bg);
    color: var(--ccm-ink);
    font: inherit;
    font-size: 14px;
    font-weight: 600;
    cursor: pointer;
    transition: border-color .12s ease, background .12s ease, transform .1s ease;
}

.swatch:hover { border-color: var(--ccm-ink); }
.swatch:active { transform: scale(.97); }

.swatch.is-chosen {
    border-color: var(--ccm-ink);
    background: var(--ccm-ink);
    color: var(--ccm-bg);
}

/* Not available in what they have already chosen. Struck through rather than
   hidden: a size that vanishes reads as a page that lost something, and the
   shopper cannot tell they would need to change colour to get it back. */
.swatch.is-gone {
    color: var(--ccm-muted);
    border-style: dashed;
    text-decoration: line-through;
    cursor: not-allowed;
}

.swatch.is-gone:hover { border-color: var(--ccm-rule); }

.swatch:focus-visible { outline: 2px solid var(--ccm-link); outline-offset: 2px; }

/* Before a full choice is made the Add button still works — it adds the
   default — but it says the choice is what is expected next. */
.add-control.is-undecided .btn[data-add-button] { opacity: .92; }

@media (max-width: 480px) {
    .swatch { flex: 1 1 auto; text-align: center; }
}

/* =============================================================================
   The shops
   =============================================================================
   A marketplace is a building full of shops, and until now this storefront
   only ever showed goods. Three pieces, all drawn from one circle: the rail of
   faces near the top of the homepage, the showcase of windows below it, and
   the directory at /shops.
   ========================================================================== */

.shop-circle {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    text-align: center;
    text-decoration: none;
    color: inherit;
    width: 100%;
}

.shop-disc {
    display: grid;
    place-items: center;
    width: 96px;
    height: 96px;
    border-radius: 50%;
    overflow: hidden;
    border: 1px solid var(--ccm-rule);
    transition: transform .14s ease, border-color .14s ease;
}

.shop-circle:hover .shop-disc {
    transform: translateY(-2px);
    border-color: var(--ccm-ink);
}

.shop-disc img { width: 100%; height: 100%; object-fit: cover; }

/* Five tints from the locked palette, picked by the shop's own id so a shop
   keeps its colour between visits. A row of identical grey discs tells a
   shopper nothing about who trades here. */
.shop-initials {
    font-size: 30px;
    font-weight: 700;
    letter-spacing: .02em;
    color: var(--ccm-ink);
}

.tint-0 { background: var(--ccm-mint); }
.tint-1 { background: var(--ccm-surface); }
.tint-2 { background: var(--ccm-amber); }
.tint-3 { background: var(--ccm-rule-soft); }
.tint-4 { background: var(--ccm-mint); }

.tint-2 .shop-initials { color: var(--ccm-amber-ink); }

.shop-circle-name {
    font-size: 13.5px;
    font-weight: 600;
    color: var(--ccm-ink);
    line-height: 1.35;
    /* Two lines at most: a long trading name must not make one item in the
       rail twice the height of its neighbours. */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.shop-circle-count { font-size: 12px; color: var(--ccm-muted); }

/* The rail item is sized for a product card; a circle needs far less. */
.rail-item:has(.shop-circle) { width: 132px; flex: 0 0 132px; }

/* ------------------------------------------------------------- the windows */
.shops-row .shop-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(320px, 100%), 1fr));
    gap: 16px;
    margin-top: 16px;
}

.shop-card {
    border: 1px solid var(--ccm-rule);
    border-radius: var(--ccm-radius);
    background: var(--ccm-bg);
    padding: 16px;
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.shop-card-head { text-decoration: none; }
.shop-card-head .shop-circle { flex-direction: row; gap: 12px; text-align: left; }
.shop-card-head .shop-disc { width: 56px; height: 56px; flex: none; }
.shop-card-head .shop-initials { font-size: 18px; }

/* What they have out: a strip of small pictures with their prices, which is
   what a shop window actually shows. */
.shop-card-items {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 8px;
}

.shop-thumb {
    position: relative;
    display: block;
    border: 1px solid var(--ccm-rule-soft);
    border-radius: var(--ccm-radius);
    overflow: hidden;
    aspect-ratio: 1;
    background: var(--ccm-surface);
}

.shop-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.shop-thumb-blank { display: block; width: 100%; height: 100%; background: var(--ccm-rule-soft); }

.shop-thumb-price {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    padding: 3px 6px;
    font-size: 11.5px;
    font-weight: 700;
    color: var(--ccm-bg);
    background: rgba(0, 0, 0, .62);
    text-align: center;
}

.shop-card-more {
    margin-top: auto;
    font-size: 13.5px;
    font-weight: 600;
    color: var(--ccm-link);
    text-decoration: none;
}

.shop-card-more:hover { text-decoration: underline; }

/* ----------------------------------------------------------- the directory */
.shop-directory {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(160px, 100%), 1fr));
    gap: 18px;
    margin-top: 18px;
}

.shop-tile {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    padding: 18px 12px;
    border: 1px solid var(--ccm-rule);
    border-radius: var(--ccm-radius);
    background: var(--ccm-bg);
    text-align: center;
}

.shop-tile-cat {
    font-size: 11.5px;
    font-weight: 700;
    letter-spacing: .05em;
    text-transform: uppercase;
    color: var(--ccm-body);
}

.shop-tile-where { font-size: 12px; color: var(--ccm-muted); }

.shop-search { display: flex; gap: 8px; align-items: center; }

.shop-search input {
    padding: 9px 12px;
    border: 1px solid var(--ccm-rule);
    border-radius: var(--ccm-radius);
    font: inherit;
    font-size: 13.5px;
    min-width: 200px;
}

.shop-search input:focus { outline: none; border-color: var(--ccm-orange); }

/* -------------------------------------------------------- one shop's page */
.shop-head {
    display: flex;
    align-items: center;
    gap: 18px;
    flex-wrap: wrap;
    padding: 20px 0 8px;
    border-bottom: 1px solid var(--ccm-rule);
    margin-bottom: 20px;
}

.shop-head .shop-circle { flex-direction: row; width: auto; gap: 14px; text-align: left; }
.shop-head .shop-disc { width: 76px; height: 76px; flex: none; }
.shop-head .shop-circle-name { display: none; }
.shop-head .shop-circle-count { display: none; }

.shop-head-body h1 { margin: 0 0 4px; }
.shop-head-meta { margin: 0; font-size: 13.5px; color: var(--ccm-body); }
.shop-head-about { margin: 8px 0 0; font-size: 14px; color: var(--ccm-body); max-width: 70ch; }

@media (max-width: 640px) {
    .shop-disc { width: 76px; height: 76px; }
    .shop-initials { font-size: 24px; }
    .rail-item:has(.shop-circle) { width: 108px; flex: 0 0 108px; }
    .shop-card-items { grid-template-columns: repeat(3, 1fr); }
    .shop-search input { min-width: 0; flex: 1 1 auto; }
}

/* =============================================================================
   The product page, to the client's reference
   =============================================================================
   Who it is sold by and how many are left, a way to share it, the quantity
   chosen before adding rather than corrected after, and a tab strip carrying
   the specification — including the size-and-price table for a product that
   comes in more than one.
   ========================================================================== */

.pdp-sold-by {
    margin: 6px 0 14px;
    font-size: 13.5px;
    color: var(--ccm-body);
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}

.pdp-sold-by a { font-weight: 700; color: var(--ccm-link); }
/* The separator and the stock word that used to share this line have gone:
   the count lives under the button, where it follows the chosen size. */

/* ------------------------------------------------------------------ share */
.pdp-share {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 16px 0 6px;
    flex-wrap: wrap;
}

.pdp-share-label {
    font-size: 12px;
    font-weight: 700;
    letter-spacing: .05em;
    text-transform: uppercase;
    color: var(--ccm-muted);
}

.share-btn {
    display: grid;
    place-items: center;
    width: 34px;
    height: 34px;
    border-radius: var(--ccm-radius);
    border: 1px solid var(--ccm-rule);
    color: var(--ccm-body);
    text-decoration: none;
    transition: border-color .12s ease, color .12s ease, background .12s ease;
}

.share-btn svg { width: 17px; height: 17px; }

/* No brand colours: the palette is locked, and four coloured chips on a
   product page would be the loudest thing on it. They take the ink on hover,
   which is enough to say they are pressable. */
.share-btn:hover { border-color: var(--ccm-ink); color: var(--ccm-ink); background: var(--ccm-surface); }

/* The "Quantity" picker that used to sit above Add has gone, along with its
   rules. How many exist is the vendor's number, stated on the page; how many
   to buy is the − / + on the cart line afterwards. */

.pdp-cats {
    margin: 16px 0 0;
    font-size: 13px;
    color: var(--ccm-body);
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
}

.pdp-cats-label { font-weight: 700; }
.pdp-cats a { color: var(--ccm-link); }

/* ------------------------------------------------------------------ tabs */
/* Radios and labels, no script: the tabs work with JavaScript off, the arrow
   keys move between them because that is what a radio group does, and there is
   no inline handler for the CSP to refuse. */
.pdp-tabs { margin-top: 34px; }

.pdp-tabstrip {
    display: flex;
    flex-wrap: wrap;
    gap: 0 6px;
    border-bottom: 1px solid var(--ccm-rule);
}

.pdp-tab-radio {
    position: absolute;
    opacity: 0;
    width: 1px;
    height: 1px;
}

.pdp-tab {
    padding: 12px 16px;
    font-size: 14.5px;
    font-weight: 600;
    color: var(--ccm-body);
    cursor: pointer;
    border-bottom: 3px solid transparent;
    margin-bottom: -1px;
    white-space: nowrap;
}

.pdp-tab:hover { color: var(--ccm-ink); }

.pdp-tab-radio:checked + .pdp-tab {
    color: var(--ccm-ink);
    font-weight: 700;
    border-bottom-color: var(--ccm-amber);
}

.pdp-tab-radio:focus-visible + .pdp-tab { outline: 2px solid var(--ccm-link); outline-offset: -2px; }

/* Each panel is a sibling after all the radios, so the checked one can be
   addressed by position. Hidden rather than removed, so the content is in the
   page for search engines and for a reader with the script off. */
.pdp-panel {
    display: none;
    width: 100%;
    order: 99;
    padding: 22px 2px 0;
}

#pdp-tab-spec:checked ~ #panel-spec,
#pdp-tab-shop:checked ~ #panel-shop,
#pdp-tab-more:checked ~ #panel-more { display: block; }

.pdp-panel h3 { margin: 18px 0 8px; font-size: 16px; }
.pdp-panel h3:first-child { margin-top: 0; }
.pdp-panel p { margin: 0 0 12px; color: var(--ccm-body); line-height: 1.65; max-width: 78ch; }

/* The size-and-price table the client asked for. */
.table-scroll { overflow-x: auto; margin: 10px 0 18px; }

.spec-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 14px;
    min-width: 420px;
}

.spec-table th, .spec-table td {
    padding: 11px 14px;
    border: 1px solid var(--ccm-rule);
    text-align: left;
}

.spec-table thead th {
    background: var(--ccm-surface);
    font-size: 12px;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--ccm-body);
}

.spec-table td.ta-right, .spec-table th.ta-right { text-align: right; }
.spec-table tbody th { background: var(--ccm-surface); width: 30%; font-weight: 700; }

.pdp-vendor { display: flex; gap: 18px; align-items: flex-start; flex-wrap: wrap; }
.pdp-vendor .shop-circle { width: auto; }
.pdp-vendor .shop-circle-name, .pdp-vendor .shop-circle-count { display: none; }
.pdp-vendor h3 { margin-top: 0; }

@media (max-width: 640px) {
    .pdp-tab { padding: 11px 12px; font-size: 13.5px; }
}

/* ==========================================================================
   Flash sale
   --------------------------------------------------------------------------
   A band that only exists while a sale is running, so it is allowed to be
   louder than the rows around it -- the site's own red, which is what the
   live site already uses for a price cut, against the ordinary white page.

   No new colours: --ccm-red-band and --ccm-amber are the two the brand
   already owns, and the clock uses amber-on-black because that pairing is
   everywhere else on this site already.
   ========================================================================== */

.flash-band {
    background: var(--ccm-red-band);
    border-radius: var(--ccm-radius);
    padding: 16px 18px 18px;
    margin: 0 0 26px;
}

.flash-head {
    display: flex;
    align-items: center;
    gap: 14px;
    flex-wrap: wrap;
    margin: 0 0 14px;
}

.flash-title {
    display: flex;
    align-items: center;
    gap: 14px;
    flex-wrap: wrap;
    min-width: 0;
}

.flash-title h2 {
    margin: 0;
    font-size: 20px;
    line-height: 1.2;
    color: #FFFFFF;
}

/* The clock. Reads as a fact until the last hour, when it turns amber. */
.flash-clock {
    display: inline-flex;
    align-items: baseline;
    gap: 7px;
    padding: 5px 11px;
    border-radius: 999px;
    background: rgba(0, 0, 0, .22);
    color: #FFFFFF;
    font-size: 13px;
    white-space: nowrap;
}

.flash-clock-label { opacity: .85; }

.flash-clock-value {
    /* Tabular figures so the seconds do not shuffle the row as they tick. */
    font-variant-numeric: tabular-nums;
    font-weight: 700;
    font-size: 15px;
    letter-spacing: .3px;
}

.flash-clock.is-soon {
    background: var(--ccm-amber);
    color: var(--ccm-amber-ink);
}

.flash-clock.is-soon .flash-clock-label { opacity: 1; }

.flash-clock.is-over {
    background: rgba(0, 0, 0, .3);
    opacity: .8;
}

/* The arrows sit on the red, so they invert rather than keeping the grey
   border they wear on a white row. */
.flash-band .rail-arrow {
    background: rgba(255, 255, 255, .16);
    border-color: rgba(255, 255, 255, .45);
    color: #FFFFFF;
}

.flash-band .rail-arrow:hover:not(:disabled) {
    background: var(--ccm-amber);
    border-color: var(--ccm-amber);
    color: var(--ccm-amber-ink);
}

.flash-band .rail-arrow:disabled { opacity: .4; }

/* The rail inside the band gets a gutter at each end, so the round edge
   arrows land beside the cards rather than on top of their titles. On a white
   row they can hang off the ends into the page margin; here the band's own
   edge is in the way. */
.flash-band .rail { padding: 0 44px; }
.flash-band .rail-edge-prev { left: 3px; }
.flash-band .rail-edge-next { right: 3px; }

@media (max-width: 640px) {
    .flash-band { padding: 14px 12px 16px; }
    .flash-band .rail { padding: 0; }
    .flash-title h2 { font-size: 17px; }
    /* The edge arrows would overhang the band on a phone; the header pair
       above them does the same job and is already in the flow. */
    .flash-band .rail-edge { display: none; }
}

/* A disc showing a real photograph drops its tint: the tint exists to make
   lettering legible, and behind a picture it only shows through the corners
   of a transparent PNG as a coloured halo. */
.shop-disc.has-photo { background: var(--ccm-bg); }

/* ==========================================================================
   The shop directory on a phone
   --------------------------------------------------------------------------
   A directory of shops is a list, not a grid of squares. On a wide screen the
   tiles read well because there is room for four across; on a 390px phone the
   same tiles become two thin columns of centred text, the heading breaks in
   half beside the search box, and the address under each shop has nowhere to
   go.

   So below 700px the whole thing turns into what a phone wants: one shop a
   row, picture on the left, name and detail to the right, chevron at the end,
   hairlines between. The markup is the same markup — one tile to keep correct
   rather than a desktop set and a mobile set that drift apart.
   ========================================================================== */

/* The search box, on every width: a bordered field with the glyph inside it,
   rather than a naked input sitting next to a button. */
.shop-search-field {
    position: relative;
    display: flex;
    align-items: center;
    flex: 1 1 auto;
    min-width: 0;
}

.shop-search-icon {
    position: absolute;
    left: 11px;
    width: 17px;
    height: 17px;
    color: var(--ccm-muted);
    pointer-events: none;
}

.shop-search input {
    width: 100%;
    padding-left: 34px;
}

@media (max-width: 700px) {
    /* Heading over search, each on its own line and full width. */
    .shops-head {
        display: block;
        padding-bottom: 14px;
    }

    .shops-head .rail-title h1 { font-size: 22px; line-height: 1.2; margin: 0; }
    .shops-head .rail-sub { margin: 4px 0 0; }

    .shops-head .shop-search {
        margin-top: 12px;
        width: 100%;
    }

    /* 44px high: the smallest thing a thumb reliably hits. */
    .shops-head .shop-search input,
    .shops-head .shop-search .btn { min-height: 44px; }

    /* One card holding the whole list, hairlines between the rows. */
    .shop-directory {
        grid-template-columns: 1fr;
        gap: 0;
        margin-top: 14px;
        border: 1px solid var(--ccm-rule);
        border-radius: var(--ccm-radius);
        overflow: hidden;
        background: var(--ccm-bg);
    }

    .shop-tile {
        display: block;
        align-items: stretch;
        padding: 0;
        border: 0;
        border-bottom: 1px solid var(--ccm-rule-soft);
        border-radius: 0;
    }

    .shop-tile:last-child { border-bottom: 0; }
    .shop-tile:active { background: var(--ccm-surface); }

    /*
     * The link becomes the row. A grid rather than a flex line, so the name
     * and the item count stack beside the picture instead of sitting in three
     * columns across.
     */
    .shop-tile .shop-circle {
        display: grid;
        grid-template-columns: auto minmax(0, 1fr) auto;
        grid-template-areas:
            "disc name chev"
            "disc count chev";
        align-items: center;
        column-gap: 13px;
        text-align: left;
        padding: 12px 14px;
        width: 100%;
    }

    .shop-tile .shop-disc {
        grid-area: disc;
        width: 54px;
        height: 54px;
        flex: none;
    }

    .shop-tile .shop-initials { font-size: 19px; }

    .shop-tile .shop-circle-name {
        grid-area: name;
        align-self: end;
        font-size: 15px;
        line-height: 1.25;
    }

    .shop-tile .shop-circle-count {
        grid-area: count;
        align-self: start;
        margin-top: 2px;
    }

    /* The chevron. Drawn from two borders rather than a character, so a screen
       reader is not handed a stray "›" at the end of every shop's name. */
    .shop-tile .shop-circle::after {
        content: "";
        grid-area: chev;
        width: 9px;
        height: 9px;
        margin-right: 2px;
        border-right: 2px solid var(--ccm-muted);
        border-top: 2px solid var(--ccm-muted);
        transform: rotate(45deg);
    }

    /* Nothing lifts on touch: there is no hover, and a row that moves under a
       finger reads as a mis-tap. */
    .shop-circle:hover .shop-disc { transform: none; }

    /* Trade and address, aligned under the name rather than under the picture. */
    .shop-tile-meta {
        display: block;
        padding: 0 14px 12px 81px;
        margin-top: -6px;
    }

    .shop-tile-cat { display: inline; }

    .shop-tile-where {
        display: block;
        margin-top: 2px;
    }
}

/* ==========================================================================
   Shop by category
   --------------------------------------------------------------------------
   Departments as cards with a picture, and the subcategories under each one
   as links. The old tiles were a letter on a coloured disc and a name, which
   grouped nothing: a shopper after a phone charger had to guess that it lives
   under Electricals and then hunt once they got there.

   The picture is whatever the department has — the artwork an administrator
   uploaded, or a photograph of something on sale inside it. Both arrive as
   `.catcard-pic img` and are cropped to the same square, so a card looks the same
   whichever it got.
   ========================================================================== */

.catgrid {
    display: grid;
    gap: 14px;
    grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
}

.catcard {
    display: flex;
    flex-direction: column;
    border: 1px solid var(--ccm-rule);
    border-radius: var(--ccm-radius);
    background: var(--ccm-bg);
    padding: 14px 14px 12px;
    transition: border-color .15s, box-shadow .15s;
}

.catcard:hover { border-color: var(--ccm-amber); box-shadow: 0 6px 18px rgba(0, 0, 0, .07); }

.catcard-face {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 3px;
    text-align: center;
    color: var(--ccm-ink);
    text-decoration: none;
}

.catcard-face:hover { text-decoration: none; }

.catcard-pic {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 84px;
    height: 84px;
    margin-bottom: 9px;
    border-radius: 50%;
    overflow: hidden;
    background: var(--ccm-mint);
    color: var(--ccm-red);
    font-size: 27px;
    font-weight: 700;
    line-height: 1;
}

.catcard-pic img { width: 100%; height: 100%; object-fit: cover; }
.catcard-pic svg { width: 34px; height: 34px; }

/* A photograph brings its own colour; the mint ground behind it would only
   show at the edges of a transparent PNG. */
.catcard-pic.has-image { background: var(--ccm-bg); border: 1px solid var(--ccm-rule-soft); }

.catcard-name { font-size: 14.5px; font-weight: 700; line-height: 1.25; }
.catcard-count { font-size: 11.5px; color: var(--ccm-muted); }

/* The subcategories: the actual grouping the client asked for. */
.catcard-subs {
    list-style: none;
    margin: 11px 0 0;
    padding: 11px 0 0;
    border-top: 1px solid var(--ccm-rule-soft);
    display: flex;
    flex-direction: column;
    gap: 5px;
}

.catcard-subs a {
    display: block;
    font-size: 12.5px;
    color: var(--ccm-body);
    text-decoration: none;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.catcard-subs a:hover { color: var(--ccm-link); text-decoration: underline; }

.catcard-all {
    margin-top: auto;
    padding-top: 10px;
    font-size: 12.5px;
    font-weight: 700;
    color: var(--ccm-link);
    text-decoration: none;
    align-self: flex-start;
}

/* An empty department stays on the page and stays quiet. */
.catcard.is-empty .catcard-pic { background: var(--ccm-rule-soft); color: var(--ccm-muted); }
.catcard.is-empty .catcard-name { color: var(--ccm-body); }

@media (max-width: 767px) {
    /* Two across on a phone, which keeps the picture big enough to read. */
    .catgrid { grid-template-columns: repeat(2, 1fr); gap: 10px; }
    .catcard { padding: 12px 10px 10px; }
    .catcard-pic { width: 66px; height: 66px; }
    .catcard-name { font-size: 13px; }
    /* The subcategory list is the first thing to go: on a 160px-wide card it
       is four truncated words under a picture. The department itself is one
       tap away and lists them properly. */
    .catcard-subs { display: none; }
}

/* ==========================================================================
   Adverts
   --------------------------------------------------------------------------
   Four shapes on one strip: words on one of the site's colours, a picture, a
   short video, and a YouTube video shown as its thumbnail.

   The grounds are named rather than free: the client's standing instruction is
   that nothing on this site uses a colour it does not already use, so an
   administrator picks amber, red, mint, black or plain, and these five rules
   are the whole of what those words can mean.
   ========================================================================== */

.ad-strip { display: grid; gap: 14px; }
.ad-strip.is-split { grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }

.ad-card {
    border-radius: var(--ccm-radius);
    overflow: hidden;
    background: var(--ccm-bg);
}

/* ------------------------------------------------------- words on a colour */
.ad-text { padding: 26px 24px; }

/* `color: inherit` on purpose: headings elsewhere on the site are black, and
   a black headline on the red or black ground is unreadable. The card's own
   ground decides the ink for everything in it. */
.ad-words h3 { margin: 0 0 6px; font-size: 21px; line-height: 1.2; color: inherit; }
.ad-words p  { margin: 0 0 14px; font-size: 14.5px; max-width: 60ch; }
.ad-words .btn { margin-top: 2px; }

.ad-ground-amber { background: var(--ccm-amber); color: var(--ccm-amber-ink); }
.ad-ground-red   { background: var(--ccm-red-band); color: #FFFFFF; }
.ad-ground-mint  { background: var(--ccm-mint); color: var(--ccm-ink); }
.ad-ground-ink   { background: var(--ccm-ink); color: #FFFFFF; }
.ad-ground-plain { background: var(--ccm-bg); color: var(--ccm-ink); border: 1px solid var(--ccm-rule); }

/* On a coloured ground the amber button disappears into it, so the button
   inverts instead of restating the background. */
.ad-ground-amber .btn-primary {
    background: var(--ccm-ink);
    border-color: var(--ccm-ink);
    color: #FFFFFF;
}

.ad-ground-red .btn-primary,
.ad-ground-ink .btn-primary {
    background: var(--ccm-amber);
    border-color: var(--ccm-amber);
    color: var(--ccm-amber-ink);
}

/* ------------------------------------------------------------ the pictures */
.ad-image img,
.ad-youtube img {
    display: block;
    width: 100%;
    height: auto;
}

.ad-image,
.ad-video,
.ad-youtube { border: 1px solid var(--ccm-rule); }

.ad-video video {
    display: block;
    width: 100%;
    max-height: 420px;
    background: var(--ccm-ink);
}

.ad-caption { padding: 13px 15px 15px; }
.ad-caption h3 { margin: 0 0 4px; font-size: 16px; line-height: 1.25; color: inherit; }
.ad-caption p  { margin: 0 0 10px; font-size: 13.5px; color: var(--ccm-body); }

/* -------------------------------------------------------------- YouTube */
.ad-play { position: relative; display: block; background: var(--ccm-ink); }

/* The thumbnail could not be copied: keep the shape so the card does not
   collapse to a line of text. */
.ad-noshot { display: block; width: 100%; aspect-ratio: 16 / 9; background: var(--ccm-surface); }

.ad-play-badge {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 62px;
    color: rgba(0, 0, 0, .72);
    transition: color .15s, transform .15s;
    pointer-events: none;
}

.ad-play-badge svg { display: block; width: 100%; height: auto; }

/* The site's own red on hover, not YouTube's #FF0000: the standing
   instruction is that nothing here uses a colour the site does not already
   have, and the two are close enough that nobody would tell them apart. */
.ad-play:hover .ad-play-badge {
    color: var(--ccm-red);
    transform: translate(-50%, -50%) scale(1.06);
}

.ad-watch { font-size: 13px; font-weight: 700; color: var(--ccm-link); text-decoration: none; }
.ad-watch:hover { text-decoration: underline; }

@media (max-width: 640px) {
    .ad-text { padding: 20px 16px; }
    .ad-words h3 { font-size: 18px; }
    .ad-play-badge { width: 52px; }
}

/* ==========================================================================
   Sections that load as you scroll
   --------------------------------------------------------------------------
   The homepage carries a dozen bands of cards. Every one of them used to be
   measured, laid out and painted before the first screen appeared, even though
   a visitor sees two of them.

   `content-visibility: auto` tells the browser it may skip all of that for a
   band that is nowhere near the viewport, and do it when the band approaches.
   The HTML is all still there — nothing is fetched later — so a reader with
   JavaScript off, a search engine, and Ctrl+F all still find everything.

   `contain-intrinsic-size: auto 520px` is the height to assume for a band it
   has not measured yet. The `auto` keyword makes the browser remember the real
   height once it has seen it, so the scrollbar settles after the first pass
   instead of jumping about on every scroll.
   ========================================================================== */

.band {
    content-visibility: auto;
    contain-intrinsic-size: auto 520px;
}

/* Printing lays out the whole document at once, and a band the browser was
   allowed to skip would come out as a blank rectangle of its guessed height. */
@media print {
    .band {
        content-visibility: visible;
        contain-intrinsic-size: auto;
    }
}

/*
 * The fade as a band arrives.
 *
 * Only under `.ccm-reveal` — a class ccm-reveal.js puts on <html> when it
 * starts. Without the script nothing is ever transparent, which is the whole
 * point: a page that hides its own contents until JavaScript runs is a page
 * that is sometimes blank.
 */
.ccm-reveal .band[data-reveal] {
    opacity: 0;
    transform: translateY(14px);
    transition: opacity .45s ease, transform .45s ease;
}

.ccm-reveal .band[data-reveal].is-in {
    opacity: 1;
    transform: none;
}

/* Somebody who has asked their system for less motion gets the content and
   none of the movement. */
@media (prefers-reduced-motion: reduce) {
    .ccm-reveal .band[data-reveal] {
        opacity: 1;
        transform: none;
        transition: none;
    }
}

/* ===========================================================================
   The cart, and the checkout summary
   ---------------------------------------------------------------------------
   A cart line dims while a change is on its way to the server. The checkout
   summary carries no quantity controls at all (client, 2026-09-12): it lists
   what is being bought, and the cart is where that is changed.
   =========================================================================== */
.cart-table tr.is-busy { opacity: .55; }

.summary-line small { display: block; font-size: 12px; color: var(--ccm-body); }

/* Why a payment option was taken away: the area decides. */
.pay-rule-note {
    margin: 10px 0 0;
    padding: 9px 12px;
    border-left: 3px solid var(--ccm-amber);
    background: var(--ccm-surface);
    font-size: 13px;
    line-height: 1.5;
    color: var(--ccm-ink);
}

/* An asterisk or a note switched off stays off, whatever its display rule. */
.req[hidden],
.pay-rule-note[hidden],
.line-issue[hidden] { display: none; }
