/* ==========================================================================
   Wristband category page - v2 design
   --------------------------------------------------------------------------
   Design system translated 1:1 from the approved reference prototype
   (Tailwind + oklch tokens -> plain CSS). Everything is scoped under .wcv2 so
   it cannot leak into, or be clobbered by, the legacy Bootstrap 3 + dash.css
   globals that the rest of the storefront relies on.

   Token values are the reference's exact oklch() triplets. Each declaration
   ships a pre-computed sRGB hex first so browsers without oklch() support
   (pre-2023 Safari/Firefox) still get the intended colour rather than an
   unstyled fallback.
   ========================================================================== */

.wcv2 {
    /* primary - teal/green */
    --wcv2-primary-50:  #eafaf0;  --wcv2-primary-50:  oklch(.97 .02 160);
    --wcv2-primary-100: #d9f7e5;  --wcv2-primary-100: oklch(.95 .04 160);
    --wcv2-primary-300: #92e2b7;  --wcv2-primary-300: oklch(.85 .10 160);
    --wcv2-primary-500: #008b52;  --wcv2-primary-500: oklch(.55 .15 160);
    --wcv2-primary-600: #007441;  --wcv2-primary-600: oklch(.48 .14 160);
    --wcv2-primary-700: #005a30;  --wcv2-primary-700: oklch(.40 .12 160);
    /* secondary - burnt orange (top-left "Popular" card badge) */
    --wcv2-secondary-500: #bb3800; --wcv2-secondary-500: oklch(.53 .18 42.12);
    /* accent - amber (stars + "No Setup" pill) */
    --wcv2-accent-500: #d19200;   --wcv2-accent-500: oklch(.70 .18 85);
    /* background - warm neutrals */
    /* bg-50 carries alpha, so the fallback is rgba() rather than hex - it is the
       page/card surface and is also used as foreground on the coloured pills. */
    --wcv2-bg-50:  rgba(245, 245, 245, .81); --wcv2-bg-50:  oklch(.97 0 0 / .81);
    --wcv2-bg-100: #dad2d4;       --wcv2-bg-100: oklch(.87 .01 .07);
    --wcv2-bg-200: #f6ede0;       --wcv2-bg-200: oklch(.95 .02 80);
    --wcv2-bg-300: #e5ddd0;       --wcv2-bg-300: oklch(.90 .02 80);
    /* foreground - cool greys */
    --wcv2-fg-400: #8a8f9c;       --wcv2-fg-400: oklch(.65 .02 270);
    --wcv2-fg-500: #6d717e;       --wcv2-fg-500: oklch(.55 .02 270);
    --wcv2-fg-600: #515561;       --wcv2-fg-600: oklch(.45 .02 270);
    --wcv2-fg-700: #363a45;       --wcv2-fg-700: oklch(.35 .02 270);
    --wcv2-fg-900: #0e111b;       --wcv2-fg-900: oklch(.18 .02 270);
    --wcv2-fg-950: #050609;       --wcv2-fg-950: oklch(.12 .01 270);

    /* Borders in the reference are always the token at reduced alpha. Kept as
       standalone rgba so we don't need colour-mix() for the /70 and /60 steps. */
    --wcv2-border: rgba(215, 200, 178, .7);   /* bg-200 / 70 */
    --wcv2-border-soft: rgba(199, 186, 166, .6); /* bg-300 / 60 */

    --wcv2-font-body: "Inter", system-ui, -apple-system, "Segoe UI", sans-serif;
    --wcv2-font-heading: "DM Sans", system-ui, -apple-system, "Segoe UI", sans-serif;

    /* Tailwind shadow scale, verbatim */
    --wcv2-shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, .05);
    --wcv2-shadow-md: 0 4px 6px -1px rgba(0, 0, 0, .1), 0 2px 4px -2px rgba(0, 0, 0, .1);
    --wcv2-shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, .1), 0 4px 6px -4px rgba(0, 0, 0, .1);

    background: var(--wcv2-bg-50);
    font-family: var(--wcv2-font-body);
    color: var(--wcv2-fg-700);
    -webkit-font-smoothing: antialiased;
}

/* Hard reset inside the island: Bootstrap 3 sets margins on headings, bolds
   every <label>, and dash.css styles .rating/.count_rating. Reset rather than
   fight it rule-by-rule. */
/* style.correct.css:9 sets `*{margin:0 auto}` site-wide. Inside a flex or grid
   container those auto margins absorb the free space and shove every item
   toward the centre, so the island has to zero margins for ALL descendants,
   not just the usual suspects. Component margins are declared further down the
   file at equal specificity, so source order lets them win. */
.wcv2,
.wcv2 *,
.wcv2 *::before,
.wcv2 *::after {
    box-sizing: border-box;
    margin: 0;
}

/* Element resets are wrapped in :where() so they contribute ZERO specificity
   beyond the .wcv2 root (0,1,0). Written as plain descendant selectors
   (`.wcv2 button`) they score (0,1,1) and silently outrank every single-class
   component rule below - which is exactly what happened: .wcv2-btn-outline
   lost its border, background and padding, and .wcv2-page lost its border.
   Keep new resets inside :where(). */
.wcv2 :where(h1, h2, h3, h4, p, ul, li) {
    padding: 0;
    list-style: none;
}
.wcv2 :where(label) { font-weight: 400; }
.wcv2 :where(button) {
    font: inherit;
    color: inherit;
    background: none;
    border: 0;
    padding: 0;
    cursor: pointer;
}
.wcv2 :where(a) { text-decoration: none; }
.wcv2 :where(img) { display: block; max-width: 100%; }

.wcv2-shell {
    max-width: 1440px;
    margin: 0 auto;
    padding: 0 16px;
}
@media (min-width: 768px) { .wcv2-shell { padding: 0 24px; } }
@media (min-width: 1024px) { .wcv2-shell { padding: 0 32px; } }

/* ==========================================================================
   Toolbar: breadcrumb, title, sort, result count
   ========================================================================== */

.wcv2-toolbar {
    background: var(--wcv2-bg-50);
    border-bottom: 1px solid var(--wcv2-border);
    padding: 16px 0;
}

/* !important is required, not sloppiness: style.correct.css:2957 declares
   `nav{display:block!important}` globally, which a plain class cannot outrank.
   Applies to both <nav> elements in this island (breadcrumb + pager). */
.wcv2-crumbs {
    display: flex !important;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
    font-size: 14px;
    margin-bottom: 12px;
}
.wcv2-crumbs a {
    color: var(--wcv2-fg-500);
    transition: color .15s ease;
}
.wcv2-crumbs a:hover { color: var(--wcv2-primary-600); }
.wcv2-crumbs .wcv2-crumb-sep { color: var(--wcv2-fg-400); display: flex; }
.wcv2-crumbs .wcv2-crumb-current { color: var(--wcv2-fg-950); font-weight: 500; }

/* Title then full-width description, stacked. The sort control and the result
   count no longer live here - they sit on their own row below (.wcv2-toolbar-foot),
   so the description always spans the full content width. */
.wcv2-toolbar-main {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

/* Result count (left) and sort control (right), on one line beneath the
   description. Wraps to two lines on narrow screens rather than squashing. */
.wcv2-toolbar-foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 12px 16px;
    margin-top: 18px;
}

.wcv2-title {
    font-family: var(--wcv2-font-heading);
    font-weight: 700;
    font-size: 24px;
    line-height: 1.2;
    letter-spacing: -.025em;
    color: var(--wcv2-fg-950);
}
@media (min-width: 768px) { .wcv2-title { font-size: 30px; } }

.wcv2-subtitle {
    font-size: 16px;
    color: var(--wcv2-fg-600);
    max-width: none;      /* spans the full content width, not a 42rem column */
    line-height: 1.65;
}

/* Sort control ------------------------------------------------------------ */

.wcv2-sort { position: relative; flex-shrink: 0; }

.wcv2-btn-outline {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 10px 16px;
    border-radius: 8px;
    border: 1px solid var(--wcv2-border);
    background: var(--wcv2-bg-50);
    font-size: 14px;
    font-weight: 500;
    color: var(--wcv2-fg-700);
    transition: border-color .15s ease;
}
.wcv2-btn-outline:hover { border-color: var(--wcv2-primary-300); }

/* Chevron rotates 180deg over 200ms, exactly as the reference does when the
   dropdown / filter section is open. */
.wcv2-chevron { transition: transform .2s ease; display: flex; }
[aria-expanded="true"] > .wcv2-chevron { transform: rotate(180deg); }

/* --- The "light box" -----------------------------------------------------
   A glass panel around the sort trigger. It wraps ONLY the button, never the
   dropdown, because it needs overflow:hidden to clip the sheen sweep - the
   menu is a sibling so it can still escape the box.
   Easing is cubic-bezier(.16,1,.3,1) (ease-out-expo) throughout: a fast start
   settling gently, which is what reads as "expensive" rather than springy. */
.wcv2-sort-box {
    position: relative;
    overflow: hidden;
    border-radius: 12px;
    border: 1px solid var(--wcv2-border);
    background: linear-gradient(180deg, rgba(255, 255, 255, .92), rgba(255, 255, 255, .55));
    -webkit-backdrop-filter: blur(10px) saturate(1.35);
    backdrop-filter: blur(10px) saturate(1.35);
    box-shadow: var(--wcv2-shadow-sm), inset 0 1px 0 rgba(255, 255, 255, .75);
    transition: transform .45s cubic-bezier(.16, 1, .3, 1),
                box-shadow .45s cubic-bezier(.16, 1, .3, 1),
                border-color .3s ease;
}
.wcv2-sort-box:hover {
    transform: translateY(-1px);
    border-color: var(--wcv2-primary-300);
    box-shadow: var(--wcv2-shadow-md), inset 0 1px 0 rgba(255, 255, 255, .9);
}
/* Keyboard parity with the hover state, plus a visible focus ring. */
.wcv2-sort-box:focus-within {
    border-color: var(--wcv2-primary-500);
    box-shadow: var(--wcv2-shadow-md), 0 0 0 3px var(--wcv2-primary-100);
}

/* Sheen: a diagonal highlight that sweeps across once per hover. Driven by an
   animation rather than a transition so it never rewinds backwards when the
   pointer leaves. */
@keyframes wcv2-sheen {
    from { transform: translateX(-130%); }
    to   { transform: translateX(130%); }
}
.wcv2-sort-box::after {
    content: "";
    position: absolute;
    inset: -1px;
    pointer-events: none;
    background: linear-gradient(105deg,
                transparent 38%, rgba(255, 255, 255, .85) 50%, transparent 62%);
    transform: translateX(-130%);
}
.wcv2-sort-box:hover::after {
    animation: wcv2-sheen .9s cubic-bezier(.16, 1, .3, 1);
}

.wcv2-sort-trigger {
    position: relative;
    z-index: 1;                     /* above the sheen layer */
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 11px 16px;
    font-size: 14px;
    white-space: nowrap;
}
.wcv2-sort-caption {
    color: var(--wcv2-fg-500);
    font-weight: 400;
}
.wcv2-sort-value {
    color: var(--wcv2-fg-950);
    font-weight: 600;
    transition: color .3s ease;
}
.wcv2-sort-box:hover .wcv2-sort-value { color: var(--wcv2-primary-600); }
.wcv2-sort-trigger .wcv2-chevron { color: var(--wcv2-fg-500); }

/* --- Dropdown ----------------------------------------------------------- */

@keyframes wcv2-menu-in {
    from { opacity: 0; transform: translateY(-8px) scale(.96); }
    to   { opacity: 1; transform: translateY(0) scale(1); }
}
@keyframes wcv2-menu-item-in {
    from { opacity: 0; transform: translateX(8px); }
    to   { opacity: 1; transform: none; }
}

.wcv2-sort-menu {
    position: absolute;
    right: 0;
    top: 100%;
    margin-top: 10px;
    width: 15rem;
    background: linear-gradient(180deg, rgba(255, 255, 255, .97), rgba(255, 255, 255, .9));
    -webkit-backdrop-filter: blur(14px) saturate(1.3);
    backdrop-filter: blur(14px) saturate(1.3);
    border-radius: 14px;
    border: 1px solid var(--wcv2-border);
    box-shadow: var(--wcv2-shadow-lg), 0 0 0 1px rgba(0, 0, 0, .02);
    z-index: 20;
    padding: 6px;
    transform-origin: top right;
    /* Runs on every un-hide, since [hidden] toggles display. */
    animation: wcv2-menu-in .32s cubic-bezier(.16, 1, .3, 1) both;
}
.wcv2-sort-menu[hidden] { display: none; }
.wcv2-sort-menu button {
    display: block;
    width: 100%;
    text-align: left;
    padding: 10px 12px;
    border-radius: 9px;
    font-size: 14px;
    color: var(--wcv2-fg-700);
    transition: background-color .2s ease, color .2s ease, padding-left .2s ease;
    animation: wcv2-menu-item-in .3s cubic-bezier(.16, 1, .3, 1) both;
}
/* Staggered reveal - the options cascade in rather than appearing as a slab. */
.wcv2-sort-menu button:nth-child(1) { animation-delay: .04s; }
.wcv2-sort-menu button:nth-child(2) { animation-delay: .08s; }
.wcv2-sort-menu button:nth-child(3) { animation-delay: .12s; }
.wcv2-sort-menu button:nth-child(4) { animation-delay: .16s; }
.wcv2-sort-menu button:nth-child(5) { animation-delay: .20s; }
.wcv2-sort-menu button:hover {
    background: var(--wcv2-primary-50);
    color: var(--wcv2-primary-700);
    padding-left: 16px;
}
.wcv2-sort-menu button[aria-selected="true"] {
    background: var(--wcv2-primary-50);
    color: var(--wcv2-primary-700);
    font-weight: 600;
}

/* Click-catcher that closes the menu, mirroring the reference's fixed inset-0 */
.wcv2-backdrop { position: fixed; inset: 0; z-index: 10; }
.wcv2-backdrop[hidden] { display: none; }

.wcv2-count {
    font-size: 14px;
    color: var(--wcv2-fg-500);
}
.wcv2-count strong { font-weight: 600; color: var(--wcv2-fg-700); }

/* ==========================================================================
   Body layout: sidebar + grid
   ========================================================================== */

.wcv2-body { padding: 24px 0 40px; }

.wcv2-layout {
    display: flex;
    flex-direction: column;
    gap: 32px;
}
@media (min-width: 1024px) { .wcv2-layout { flex-direction: row; } }

.wcv2-filter-toggle { margin-bottom: 16px; }
@media (min-width: 1024px) { .wcv2-filter-toggle { display: none; } }

.wcv2-filter-badge {
    margin-left: 4px;
    width: 20px;
    height: 20px;
    border-radius: 9999px;
    background: var(--wcv2-primary-500);
    color: var(--wcv2-bg-50);
    font-size: 10px;
    font-weight: 700;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
.wcv2-filter-badge[hidden] { display: none; }

.wcv2-aside { width: 100%; flex-shrink: 0; }
.wcv2-aside[hidden] { display: none; }
@media (min-width: 1024px) {
    .wcv2-aside,
    .wcv2-aside[hidden] { display: block; width: 16rem; }
    .wcv2-aside-inner { position: sticky; top: 24px; }
}

.wcv2-results { flex: 1; min-width: 0; }

/* Filter panel ----------------------------------------------------------- */

.wcv2-filter-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 16px;
}
.wcv2-filter-head h3 {
    font-family: var(--wcv2-font-heading);
    font-weight: 600;
    font-size: 16px;
    color: var(--wcv2-fg-950);
}
.wcv2-reset {
    font-size: 12px;
    color: var(--wcv2-primary-600);
    font-weight: 500;
}
.wcv2-reset:hover { color: var(--wcv2-primary-700); }
.wcv2-reset[hidden] { display: none; }

.wcv2-fgroup { border-bottom: 1px solid var(--wcv2-border); }

.wcv2-fgroup-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    padding: 12px 0;
    text-align: left;
}
.wcv2-fgroup-head span {
    font-family: var(--wcv2-font-heading);
    font-weight: 600;
    font-size: 14px;
    color: var(--wcv2-fg-950);
}
.wcv2-fgroup-head .wcv2-chevron { color: var(--wcv2-fg-500); }

.wcv2-fgroup-body { padding-bottom: 16px; display: grid; gap: 8px; }
.wcv2-fgroup-body[hidden] { display: none; }

.wcv2-check {
    display: flex;
    align-items: center;
    gap: 10px;
    cursor: pointer;
}
.wcv2-check input {
    width: 16px;
    height: 16px;
    flex-shrink: 0;
    margin: 0;
    cursor: pointer;
    accent-color: var(--wcv2-primary-500);
}
.wcv2-check span {
    font-size: 14px;
    color: var(--wcv2-fg-700);
    transition: color .15s ease;
}
.wcv2-check:hover span { color: var(--wcv2-fg-900); }

/* Checkbox-square look-alike for a .wcv2-check used as a real <a> link
   instead of a checkbox input - webparts/wmoreproducts-v2.php's Category
   list uses this: those rows navigate to a different page/product set
   entirely, so an actual checkbox (implying an in-page multi-select filter)
   would misrepresent what clicking it does. Purely additive, new class name,
   doesn't touch any existing .wcv2-check usage. */
.wcv2-check-dot {
    width: 16px;
    height: 16px;
    flex-shrink: 0;
    border-radius: 4px;
    border: 1.5px solid var(--wcv2-bg-100);
    background: #fff;
    transition: .15s;
}
.wcv2-check:hover .wcv2-check-dot { border-color: var(--wcv2-primary-500); }
.wcv2-check-dot.is-active {
    background: var(--wcv2-primary-500);
    border-color: var(--wcv2-primary-500);
}

.wcv2-rating-opt {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    padding: 6px 8px;
    border-radius: 8px;
    transition: background-color .15s ease, color .15s ease;
}
.wcv2-rating-opt:hover { background: var(--wcv2-bg-100); }
.wcv2-rating-opt[aria-pressed="true"] {
    background: var(--wcv2-primary-50);
    color: var(--wcv2-primary-700);
}
.wcv2-rating-opt .wcv2-stars { gap: 0; }
.wcv2-rating-opt span { font-size: 14px; color: var(--wcv2-fg-700); }

/* Stars: filled = accent, empty = bg-300 */
.wcv2-stars { display: inline-flex; align-items: center; }
.wcv2-stars svg { display: block; color: var(--wcv2-bg-300); }
.wcv2-stars svg.is-on { color: var(--wcv2-accent-500); }

/* ==========================================================================
   Product grid + card
   ========================================================================== */

/* 2 / 2 / 3 / 4 columns. Two-up on phones with a tighter gutter - at a 390px
   viewport that leaves ~173px per card, so the card internals are scaled down
   in the max-width:639px block further down rather than left at desktop sizes. */
.wcv2-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 12px;
}
@media (min-width: 640px)  { .wcv2-grid { gap: 20px; } }
@media (min-width: 1024px) { .wcv2-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 1280px) { .wcv2-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

.wcv2-card {
    position: relative;
    display: flex;
    flex-direction: column;
    background: var(--wcv2-bg-50);
    border-radius: 12px;
    border: 1px solid var(--wcv2-border);
    overflow: hidden;
    /* reference: transition-all duration-300 */
    transition: box-shadow .3s ease, transform .3s ease;
}
.wcv2-card[hidden] { display: none; }
.wcv2-card:hover,
.wcv2-card:focus-within {
    box-shadow: var(--wcv2-shadow-lg);
    transform: translateY(-4px);
}

/* Media -------------------------------------------------------------------
   4/3 box + 500ms scale(1.05) zoom, per the reference. `contain` rather than
   `cover` because these are cut-out product PNGs, not full-bleed photos -
   cover would slice the top and bottom off every wristband. */
.wcv2-card-media {
    position: relative;
    aspect-ratio: 4 / 3;
    overflow: hidden;
    background: var(--wcv2-bg-100);
}
/* White card image background - moreproducts.php/combineproducts.php only
   (see webparts/wmoreproducts-v2.php and webparts/wmoreproducts1-v2.php,
   the only two files that add .wcv2-mp to the .wcv2 root). Deliberately not
   a change to the base .wcv2-card-media rule above - webparts/wristband-home-v2.php
   and webparts/badge-holders.php keep the warm neutral background. */
.wcv2-mp .wcv2-card-media {
    background: #fff;
}
.wcv2-card-media img {
    width: 100%;
    height: 100%;
    object-fit: contain;
    padding: 10px;
    transition: transform .5s ease;
}
.wcv2-card:hover .wcv2-card-media img { transform: scale(1.05); }

/* Badge holders image fill - webparts/badge-holders.php only (the one file that
   adds .wcv2-bh to the .wcv2 root). Most of that catalogue's art is square
   (800x800 or 1400x1400), so the 4/3 box above left a wide empty gutter down
   both sides of every product. Squaring the box is what makes those fill edge
   to edge; contain rather than cover is deliberate, because roughly a dozen
   products in the two source categories are shot tall or wide instead - the
   badge reels run as narrow as 74x230 - and cover sliced up to 68% off them.
   Contain costs the square majority nothing (in a square box it resolves
   identically) and letterboxes only the odd-ratio minority.

   Deliberately not a change to the base rules above - the other pages on this
   stylesheet keep the 4/3 box. */
.wcv2-bh .wcv2-card-media { aspect-ratio: 1 / 1; }
.wcv2-bh .wcv2-card-media img {
    object-fit: contain;
    padding: 0;
}

/* Top-left badge */
.wcv2-card-flags {
    position: absolute;
    top: 12px;
    left: 12px;
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    z-index: 2;
}
.wcv2-flag {
    padding: 4px 10px;
    font-size: 11px;
    font-weight: 600;
    border-radius: 9999px;
    letter-spacing: .025em;
    background: var(--wcv2-secondary-500);
    /* Solid white, not var(--wcv2-bg-50): that token carries .81 alpha, which
       composites to only 3.92:1 against the burnt orange - under AA for 11px
       text. Opaque white gives 5.70:1. */
    color: #fff;
    line-height: 1.4;
}

/* Wishlist button - fades in on card hover */
.wcv2-heart {
    position: absolute;
    top: 12px;
    right: 12px;
    width: 36px;
    height: 36px;
    border-radius: 9999px;
    background: rgba(255, 251, 244, .9);
    -webkit-backdrop-filter: blur(4px);
    backdrop-filter: blur(4px);
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: var(--wcv2-shadow-sm);
    color: var(--wcv2-fg-500);
    opacity: 0;
    transition: opacity .3s ease, background-color .3s ease, color .3s ease;
    z-index: 3;
}
.wcv2-card:hover .wcv2-heart,
.wcv2-card:focus-within .wcv2-heart { opacity: 1; }
.wcv2-heart:hover { background: var(--wcv2-bg-50); }
.wcv2-heart[aria-pressed="true"] { color: var(--wcv2-accent-500); opacity: 1; }
/* outline icon hidden once saved, and vice-versa */
.wcv2-heart[aria-pressed="true"] .wcv2-heart-off,
.wcv2-heart[aria-pressed="false"] .wcv2-heart-on { display: none; }

/* Bottom scrim, fades in with the Quick View button */
.wcv2-card-scrim {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: 50%;
    background: linear-gradient(to top, rgba(0, 0, 0, .5), transparent);
    opacity: 0;
    transition: opacity .3s ease;
    pointer-events: none;
    z-index: 1;
}
.wcv2-card:hover .wcv2-card-scrim,
.wcv2-card:focus-within .wcv2-card-scrim { opacity: 1; }

/* Quick View: rises 12px into place while fading in, 300ms */
.wcv2-quick {
    position: absolute;
    bottom: 16px;
    left: 50%;
    transform: translate(-50%, 12px);
    opacity: 0;
    transition: opacity .3s ease, transform .3s ease, background-color .3s ease, color .3s ease;
    background: var(--wcv2-bg-50);
    color: var(--wcv2-fg-950);
    padding: 10px 20px;
    border-radius: 8px;
    font-weight: 500;
    font-size: 14px;
    box-shadow: var(--wcv2-shadow-md);
    white-space: nowrap;
    z-index: 3;
}
.wcv2-card:hover .wcv2-quick,
.wcv2-card:focus-within .wcv2-quick {
    opacity: 1;
    transform: translate(-50%, 0);
}
.wcv2-quick:hover {
    background: var(--wcv2-primary-500);
    color: var(--wcv2-bg-50);
}

/* Card body -------------------------------------------------------------- */

.wcv2-card-body { padding: 16px; display: flex; flex-direction: column; flex: 1; }

/* Stars + review count on the left, pills on the right. The reference fits
   both on one line because its accent pill reads "Sale"; ours reads "No Setup"
   and the German/Arabic brands translate longer still, which overflowed the
   review count underneath the pills. Wrapping drops the pills to their own
   row when the card is too narrow instead of clipping the count. */
.wcv2-card-meta {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 6px 8px;
    margin-bottom: 8px;
}
.wcv2-card-rating { display: flex; align-items: center; gap: 6px; min-width: 0; }
.wcv2-card-rating .wcv2-reviews {
    font-size: 13px;
    color: var(--wcv2-fg-500);
    white-space: nowrap;
}

.wcv2-pills { display: flex; align-items: center; gap: 4px; flex-shrink: 0; }
.wcv2-pill {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    padding: 2px 6px;
    font-size: 9px;
    font-weight: 700;
    border-radius: 9999px;
    letter-spacing: .025em;
    text-transform: uppercase;
    line-height: 1.6;
    white-space: nowrap;
}
.wcv2-pill-accent { background: var(--wcv2-accent-500); color: var(--wcv2-bg-50); }
.wcv2-pill-primary { background: var(--wcv2-primary-500); color: var(--wcv2-bg-50); }

/* The reference's signature micro-animation: the delivery truck nudges
   forward and back, forever, on the free-shipping pill. */
@keyframes wcv2-truck-drive {
    0%   { transform: translateX(0); }
    50%  { transform: translateX(3px); }
    100% { transform: translateX(0); }
}
.wcv2-truck {
    display: inline-block;
    animation: wcv2-truck-drive 1.4s ease-in-out infinite;
}

.wcv2-card-title {
    font-weight: 500;
    color: var(--wcv2-fg-900);
    font-size: 15px;
    line-height: 1.375;
    margin-bottom: 8px;
    transition: color .2s ease;
    /* Two-line clamp. Deliberately only the -webkit-* form: adding the modern
       `line-clamp` shorthand alongside it makes Chrome resolve display to
       flow-root, which silently disables the clamp. */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.wcv2-card:hover .wcv2-card-title { color: var(--wcv2-primary-600); }

.wcv2-swatches {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-bottom: 12px;
}
.wcv2-swatch {
    width: 16px;
    height: 16px;
    border-radius: 9999px;
    border: 1px solid var(--wcv2-border-soft);
    flex-shrink: 0;
}
.wcv2-swatch-more { font-size: 10px; color: var(--wcv2-fg-500); margin-left: 2px; }

.wcv2-price-row {
    display: flex;
    align-items: baseline;
    gap: 8px;
    margin-top: auto;
}
.wcv2-price {
    font-size: 20px;
    font-weight: 700;
    color: var(--wcv2-primary-600);
}
.wcv2-price-was {
    font-size: 14px;
    color: var(--wcv2-fg-400);
    text-decoration: line-through;
}
/* Sits immediately right of the price, sharing its baseline, so the two read as
   one line. Replaces the old "As low as X ea / Min. qty N" caption, which
   repeated the price already shown in green directly above it. */
.wcv2-minqty {
    font-size: 13px;
    color: var(--wcv2-fg-500);
    white-space: nowrap;
}

/* Phone sizing for the 2-up grid. Everything here is proportional trimming so
   two cards fit a ~358px content width without the meta row wrapping or the
   footnote running to three lines. Scoped inside .wcv2-card so the sidebar's
   rating-filter stars keep their own size. */
@media (max-width: 639px) {
    .wcv2-card-body { padding: 12px; }
    .wcv2-card-meta { gap: 4px 6px; margin-bottom: 6px; }
    .wcv2-card .wcv2-stars svg { width: 13px; height: 13px; }
    .wcv2-card .wcv2-reviews { font-size: 12px; }
    /* On a 320px screen the card is only ~138px wide and the two pills together
       exceed the content box, so let them wrap instead of spilling out. */
    .wcv2-pills { flex-wrap: wrap; }
    .wcv2-pill { font-size: 8.5px; padding: 2px 5px; }
    .wcv2-card-title { font-size: 14px; margin-bottom: 6px; }
    .wcv2-swatches { gap: 5px; margin-bottom: 9px; }
    .wcv2-swatch { width: 14px; height: 14px; }
    .wcv2-price { font-size: 18px; }
    .wcv2-price-was { font-size: 13px; }
    /* On a 320px screen the card is ~138px wide, where price + "Min. qty 100"
       exceeds the content box - wrap rather than spill. */
    .wcv2-price-row { flex-wrap: wrap; row-gap: 2px; }
    .wcv2-minqty { font-size: 12px; }
    /* Quick View has to fit inside a ~173px card. */
    .wcv2-quick { padding: 8px 14px; font-size: 13px; bottom: 12px; }
    .wcv2-heart { width: 32px; height: 32px; top: 8px; right: 8px; }
    .wcv2-card-flags { top: 8px; left: 8px; }
    .wcv2-flag { font-size: 10px; padding: 3px 8px; }
}

/* Whole-card link overlay: keeps the card a single click target without
   nesting the Quick View / wishlist buttons inside an <a>. */
.wcv2-card-link {
    position: absolute;
    inset: 0;
    z-index: 2;
}
.wcv2-card-link span {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/* ==========================================================================
   Pagination + empty state
   ========================================================================== */

/* Infinite scroll footer. The visible button is deliberate, not a fallback:
   pure scroll-loading strands keyboard users and makes the footer unreachable,
   so the same action is always available as an explicit control. */
.wcv2-more {
    margin-top: 32px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
}
.wcv2-more[hidden] { display: none; }
.wcv2-more-count { font-size: 13px; color: var(--wcv2-fg-500); }

/* Spinner shown while the next batch is being revealed. */
@keyframes wcv2-spin { to { transform: rotate(360deg); } }
.wcv2-more-spin {
    width: 22px;
    height: 22px;
    border-radius: 50%;
    border: 2px solid var(--wcv2-bg-300);
    border-top-color: var(--wcv2-primary-500);
    animation: wcv2-spin .7s linear infinite;
}
.wcv2-more-spin[hidden] { display: none; }

/* Zero-height probe below the grid; crossing it triggers the next batch. */
.wcv2-sentinel { width: 100%; height: 1px; }

/* Real cross-page pagination (webparts/badge-holders-v2.php only) - separate
   from .wcv2-more above, which only ever reveals within one already-fetched
   page. Site-wide Bootstrap .pagination styling still applies to the <li>/<a>
   inside; this just centers it and gives it island-consistent spacing. */
.wcv2-pagination-wrap { display: flex; justify-content: center; padding: 32px 0 8px; }

.wcv2-empty { text-align: center; padding: 80px 0; }
.wcv2-empty[hidden] { display: none; }
.wcv2-empty-icon {
    width: 64px;
    height: 64px;
    border-radius: 9999px;
    background: var(--wcv2-bg-100);
    display: flex;
    align-items: center;
    justify-content: center;
    margin: 0 auto 16px;
    color: var(--wcv2-fg-400);
}
.wcv2-empty h3 {
    font-family: var(--wcv2-font-heading);
    font-weight: 600;
    font-size: 18px;
    color: var(--wcv2-fg-950);
    margin-bottom: 8px;
}
.wcv2-empty p { font-size: 14px; color: var(--wcv2-fg-500); margin-bottom: 16px; }
.wcv2-btn-primary {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 10px 20px;
    border-radius: 8px;
    background: var(--wcv2-primary-500);
    color: var(--wcv2-bg-50);
    font-size: 14px;
    font-weight: 500;
    transition: background-color .15s ease;
}
.wcv2-btn-primary:hover { background: var(--wcv2-primary-600); color: var(--wcv2-bg-50); }

/* ==========================================================================
   SEO copy block (kept from the previous page so the category keeps its
   indexable body text and internal links)
   ========================================================================== */

.wcv2-copy {
    border-top: 1px solid var(--wcv2-border);
    margin-top: 48px;
    padding: 32px 0 8px;
}
.wcv2-copy h2 {
    font-family: var(--wcv2-font-heading);
    font-weight: 600;
    font-size: 24px;
    color: var(--wcv2-fg-950);
    margin-bottom: 14px;
}
.wcv2-copy p {
    font-size: 16px;
    line-height: 1.7;
    color: var(--wcv2-fg-600);
    margin-bottom: 14px;
    max-width: none;      /* full content width, not a 70ch measure */
}

/* Tokens for the out-of-island overrides below (banner + review widget). Same
   values as the .wcv2 block at the top of this file, re-declared on the page
   root because custom properties on .wcv2 are not visible to shared chrome that
   sits outside it. --wcv2-ease is the ease-out-expo curve used page-wide. */
body.wcv2-doc {
    --wcv2-primary-300: oklch(.85 .10 160);
    --wcv2-primary-500: oklch(.55 .15 160);
    --wcv2-fg-500:      oklch(.55 .02 270);
    --wcv2-fg-950:      oklch(.12 .01 270);
    --wcv2-border:      rgba(215, 200, 178, .7);
    --wcv2-font-heading: "DM Sans", system-ui, -apple-system, "Segoe UI", sans-serif;
    --wcv2-ease: cubic-bezier(.16, 1, .3, 1);
}

/* ==========================================================================
   Customer review widget - premium makeover, THIS PAGE ONLY
   --------------------------------------------------------------------------
   webparts/customer-reviews-section.php is shared chrome styled by
   css/popular.css, so every rule here is scoped to body.wcv2-doc and leaves
   the widget untouched on every other page. Existing rules are as specific as
   `.customer_slideOuter .rvw_bx` (0,2,0), so the body class is what buys us
   the specificity to override them.
   ========================================================================== */

/* Quieter ground so the white cards read as genuinely raised off it. */
body.wcv2-doc .customer_rvwArea {
    background: linear-gradient(180deg, #f7f5f2 0%, #fffdfa 100%);
    padding: 60px 0 72px;
}
body.wcv2-doc .rvw_hdng { margin-bottom: 38px; }
body.wcv2-doc .rvw_hdng h2 {
    font-family: var(--wcv2-font-heading);
    font-size: 30px;
    font-weight: 700;
    letter-spacing: -.02em;
    text-transform: none;      /* 35px all-caps reads shouty next to the v2 type */
    color: var(--wcv2-fg-950);
}

/* Vertical breathing room inside the slick viewport so the lifted card and its
   shadow are not clipped by .slick-list{overflow:hidden}. Vertical only -
   horizontal padding here would corrupt slick's slide-width maths. */
body.wcv2-doc .customer_slideOuter .slick-list {
    padding-top: 14px;
    padding-bottom: 30px;
}

/* --- The cards ---------------------------------------------------------- */
body.wcv2-doc .rvw_bx,
body.wcv2-doc .customer_slideOuter .rvw_bx {
    position: relative;
    background: linear-gradient(180deg, #ffffff 0%, #fdfcfb 100%);
    border: 1px solid var(--wcv2-border);
    border-radius: 16px;
    padding: 42px 26px 26px;
    box-shadow: 0 1px 2px rgba(0, 0, 0, .04),
                0 8px 20px -12px rgba(0, 0, 0, .10);
    transition: transform .5s var(--wcv2-ease),
                box-shadow .5s var(--wcv2-ease),
                border-color .35s ease;
}
/* The lift. No moving accent line - the card simply rises and grows a fraction,
   the paper warms slightly and the shadow deepens. All opacity/colour/scale,
   nothing that travels across the card, which is what made the earlier sweeping
   line feel busy. */
body.wcv2-doc .rvw_bx:hover {
    transform: translateY(-6px) scale(1.012);
    background: linear-gradient(180deg, #ffffff 0%, #fbf9f6 100%);
    border-color: rgba(0, 0, 0, .07);
    box-shadow: 0 2px 4px rgba(0, 0, 0, .04),
                0 26px 46px -22px rgba(0, 0, 0, .22),
                inset 0 1px 0 rgba(255, 255, 255, .9);
}

/* Quotation mark and avatar respond to the same hover, a beat behind the lift. */
body.wcv2-doc .rvw_txt p:after {
    opacity: .72;
    transition: transform .5s var(--wcv2-ease), opacity .4s ease;
}
body.wcv2-doc .rvw_bx:hover .rvw_txt p:after {
    opacity: 1;
    transform: translateY(-2px) scale(1.04);
}
body.wcv2-doc .cstmr_pic {
    transition: transform .5s var(--wcv2-ease), box-shadow .5s var(--wcv2-ease);
}
body.wcv2-doc .rvw_bx:hover .cstmr_pic {
    transform: scale(1.06);
    box-shadow: 0 0 0 3px rgba(255, 255, 255, .95),
                0 10px 24px rgba(0, 0, 0, .18);
}
body.wcv2-doc .cstmr_details h5 {
    font-family: var(--wcv2-font-heading);
    font-weight: 600;
    color: var(--wcv2-fg-950);
}

/* --- Arrows: circular glass buttons ------------------------------------- */
/* Appearance only - the left/right offsets stay with popular.css so its
   responsive arrow positioning keeps working. */
body.wcv2-doc .customer_slideOuter .slick-arrow {
    width: 42px;
    height: 42px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background: rgba(255, 255, 255, .94);
    border: 1px solid var(--wcv2-border);
    box-shadow: 0 1px 2px rgba(0, 0, 0, .05),
                0 8px 18px -10px rgba(0, 0, 0, .18);
    -webkit-backdrop-filter: blur(8px);
    backdrop-filter: blur(8px);
    transition: transform .4s var(--wcv2-ease),
                box-shadow .4s var(--wcv2-ease),
                border-color .3s ease;
    z-index: 3;
}
body.wcv2-doc .customer_slideOuter .slick-arrow:hover {
    /* translateY(-50%) must be repeated - popular.css uses it for centring. */
    transform: translateY(-50%) scale(1.08);
    border-color: var(--wcv2-primary-300);
    box-shadow: 0 2px 4px rgba(0, 0, 0, .05),
                0 14px 26px -12px rgba(0, 0, 0, .26);
}
/* Symmetric horizontal offsets. popular.css positions the two arrows by
   different amounts at every breakpoint - prev/next are -20/-10 by default,
   -30/-23 under 768px and -15/-8 under 421px - so the left arrow always hung
   ~10px further out than the right. Measured against the slider box: prev sat
   20px outside its left edge, next only 10px outside its right edge. These
   match prev to next at each breakpoint. */
body.wcv2-doc .customer_slideOuter .slick-prev { left: -10px; right: auto; }
body.wcv2-doc .customer_slideOuter .slick-next { right: -10px; left: auto; }
@media (max-width: 767px) {
    body.wcv2-doc .customer_slideOuter .slick-prev { left: -23px; }
    body.wcv2-doc .customer_slideOuter .slick-next { right: -23px; }
}
@media (max-width: 420px) {
    /* .customer_slideOuter drops to 10px padding here, so keep them tucked in. */
    body.wcv2-doc .customer_slideOuter .slick-prev { left: -8px; }
    body.wcv2-doc .customer_slideOuter .slick-next { right: -8px; }
}

/* Re-centre the FontAwesome glyph, which popular.css offsets by top:-15px. */
body.wcv2-doc .customer_slideOuter .slick-arrow:after {
    position: static;
    top: auto;
    font-size: 20px;
    line-height: 1;
    color: var(--wcv2-fg-500);
}
body.wcv2-doc .customer_slideOuter .slick-arrow:hover:after {
    color: var(--wcv2-primary-500);
}

/* --- Entrance: cards rise in as the section scrolls into view ------------
   js/wristband-home-category-v2.js adds .wcv2-rv-armed immediately (so the cards
   start hidden), swaps in .wcv2-rv-ready on intersection, then strips both
   once the run finishes. Removing them matters: animation fill-mode would
   otherwise pin transform:none and kill the hover lift above. */
@keyframes wcv2-rv-in {
    from { opacity: 0; transform: translateY(20px); }
    to   { opacity: 1; transform: none; }
}
body.wcv2-doc .customer_rvwArea.wcv2-rv-armed .rvw_bx { opacity: 0; }
body.wcv2-doc .customer_rvwArea.wcv2-rv-ready .rvw_bx {
    animation: wcv2-rv-in .7s var(--wcv2-ease) both;
}

/* Respect reduced-motion: drop the decorative loop and the lift/zoom, keep
   opacity fades so hover affordances still read. */
@media (prefers-reduced-motion: reduce) {
    .wcv2 * {
        animation-duration: .001ms !important;
        animation-iteration-count: 1 !important;
    }
    .wcv2-card:hover,
    .wcv2-card:focus-within { transform: none; }
    .wcv2-card:hover .wcv2-card-media img { transform: none; }
    .wcv2-quick { transition: opacity .3s ease; transform: translate(-50%, 0); }

    /* The review widget lives outside .wcv2, so it needs its own guard. */
    body.wcv2-doc .customer_rvwArea * {
        animation-duration: .001ms !important;
        animation-iteration-count: 1 !important;
    }
    body.wcv2-doc .rvw_bx:hover { transform: none; }
    body.wcv2-doc .rvw_bx:hover .cstmr_pic { transform: none; }
    body.wcv2-doc .rvw_bx:hover .rvw_txt p:after { transform: none; }
    body.wcv2-doc .customer_slideOuter .slick-arrow:hover { transform: translateY(-50%); }
}
