/* ============================================================================
   Graviteee Mart — design language
   ----------------------------------------------------------------------------
   Loaded LAST, after the theme's style.css, and written as an override layer on
   purpose: style.css is ~57,000 lines of vendor theme and editing it in place is
   how you break a storefront you cannot fully re-test.

   The problem this solves: every surface had border-radius 0 and no shadow, and
   there were THREE competing accents in use at once —
       #EC8951  warm orange   (the logo, and the price)
       #E53935  red           (variant pills)
       #FF3F6C  pink          (card hover)
   Three accents is why it read as generic. The orange is the brand — it is the
   logo and the price — so everything else is brought to it.

   Conventions:
     * tokens first, then components
     * every motion rule is disabled under prefers-reduced-motion at the bottom
     * !important only where the theme's own specificity leaves no alternative
   ========================================================================== */

:root {
    /* Brand ------------------------------------------------------------- */
    /* Sampled from the original logo PNG rather than guessed. The wordmark
       magenta is the dominant brand colour (5,610 opaque px) and the bag
       orange the secondary (2,130 px). The site had been using #EC8951 — a
       muted near-miss of the orange — and the magenta appeared nowhere at all,
       which is why nothing on the page looked related to the logo. */
    --g-brand:         #B62C5F;   /* wordmark magenta */
    --g-brand-deep:    #921F4B;
    --g-brand-soft:    #FCEFF4;

    --g-accent:        #F67E00;   /* bag orange — prices, sale, CTAs */
    --g-accent-deep:   #D96B00;
    --g-accent-soft:   #FFF3E4;
    --g-accent-ring:   rgba(246, 126, 0, 0.26);

    /* Dark chrome. Warm near-black, tinted toward the brand magenta rather
       than neutral grey — neutral black beside a warm palette reads as a
       different design that happens to share a page. */
    --g-chrome:        #1B1114;
    --g-chrome-2:      #2A1C21;
    --g-chrome-ink:    #F6EFF1;
    --g-chrome-ink-2:  #C4B2B8;
    --g-chrome-line:   rgba(246, 239, 241, 0.12);

    /* Neutrals — warm, so they sit with the accent rather than against it */
    --g-ink:           #241C17;
    --g-ink-2:         #5C5149;
    --g-ink-3:         #8A8079;
    --g-line:          #EDE7E1;
    --g-surface:       #FFFFFF;
    --g-surface-2:     #FAF7F4;

    /* Radii — the single biggest change from "boxy" */
    --g-r-xs:  8px;
    --g-r-sm:  12px;
    --g-r-md:  16px;
    --g-r-lg:  22px;
    --g-r-xl:  28px;
    --g-r-pill: 999px;

    /* Shadows — layered and soft. A single hard shadow is what makes a
       design look cheap; these are two-part, tight + wide. */
    --g-shadow-sm: 0 1px 2px rgba(36, 28, 23, .04), 0 2px 8px rgba(36, 28, 23, .05);
    --g-shadow-md: 0 2px 4px rgba(36, 28, 23, .04), 0 8px 24px rgba(36, 28, 23, .07);
    --g-shadow-lg: 0 4px 8px rgba(36, 28, 23, .05), 0 18px 44px rgba(36, 28, 23, .11);
    --g-shadow-accent: 0 6px 18px rgba(236, 137, 81, .32);

    /* Motion */
    --g-ease:      cubic-bezier(.22, .61, .36, 1);
    --g-ease-out:  cubic-bezier(.16, 1, .3, 1);
    --g-fast:      .18s;
    --g-mid:       .32s;
    --g-slow:      .6s;
}

/* ============================================================================
   1. Product cards — the most-repeated object on the site
   ========================================================================== */

.basic-product {
    border-radius: var(--g-r-md);
    background: var(--g-surface);
    box-shadow: var(--g-shadow-sm);
    overflow: hidden;
    transition: transform var(--g-mid) var(--g-ease-out),
                box-shadow var(--g-mid) var(--g-ease-out);
    will-change: transform;
}

.basic-product:hover {
    transform: translateY(-6px);
    box-shadow: var(--g-shadow-lg);
}

/* The image sits inside its own rounded window and eases up on hover. The
   scale is deliberately small — 1.06 reads as responsive, 1.2 reads as a
   screensaver. */
.basic-product .img-wrapper {
    border-radius: var(--g-r-md) var(--g-r-md) 0 0;
    overflow: hidden;
    background: var(--g-surface-2);
}

.basic-product .img-wrapper img,
.basic-product .img-wrapper picture {
    transition: transform var(--g-slow) var(--g-ease-out);
    display: block;
}

.basic-product:hover .img-wrapper img {
    transform: scale(1.06);
}

/* Floating wishlist heart: frosted, circular, lifts on hover. */
.basic-product .mob-heart {
    background: rgba(255, 255, 255, .82);
    -webkit-backdrop-filter: blur(6px);
    backdrop-filter: blur(6px);
    border-radius: var(--g-r-pill);
    width: 34px;
    height: 34px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    box-shadow: var(--g-shadow-sm);
    transition: transform var(--g-fast) var(--g-ease),
                color var(--g-fast) var(--g-ease);
}

.basic-product .mob-heart:hover {
    transform: scale(1.12);
    color: var(--g-accent);
}

.basic-product .product-title:hover { color: var(--g-accent); }

.basic-product .price-discount {
    color: var(--g-accent-deep);
    background: var(--g-accent-soft);
    border-radius: var(--g-r-pill);
    padding: 2px 9px;
    font-weight: 600;
}

/* ============================================================================
   2. Buttons
   ========================================================================== */

.btn,
.btn-solid,
.btn-primary-dash,
.apply-btn,
button.btn {
    border-radius: var(--g-r-pill);
    transition: transform var(--g-fast) var(--g-ease),
                box-shadow var(--g-fast) var(--g-ease),
                background-color var(--g-fast) var(--g-ease);
}

.btn:hover,
.btn-solid:hover,
.btn-primary-dash:hover,
.apply-btn:hover {
    transform: translateY(-2px);
    box-shadow: var(--g-shadow-md);
}

.btn:active,
.btn-solid:active,
.apply-btn:active { transform: translateY(0); }

/* The two product-page actions carry the accent and its glow. */
.product-buttons .btn-solid,
[class*="add-to-cart"],
[class*="buy-now"] {
    box-shadow: var(--g-shadow-accent);
}

/* Quantity stepper reads as one pill rather than three squares. */
.qty-box .input-group,
.quantity-box {
    border-radius: var(--g-r-pill);
    overflow: hidden;
    border: 1px solid var(--g-line);
}
.btn.quantity-left-minus,
.btn.quantity-right-plus { border-radius: 0; box-shadow: none; }
.btn.quantity-left-minus:hover,
.btn.quantity-right-plus:hover {
    transform: none;
    background: var(--g-accent-soft);
    color: var(--g-accent-deep);
}

/* ============================================================================
   3. Variant pills — were red on pink, the site's third accent
   ========================================================================== */

.variant-option,
.size-box li,
[id="dynamic-variants"] button,
[id="dynamic-variants"] .variant-btn {
    border-radius: var(--g-r-pill) !important;
    transition: all var(--g-fast) var(--g-ease);
}

[id="dynamic-variants"] .variant-btn:hover,
.variant-option:hover {
    border-color: var(--g-accent) !important;
    color: var(--g-accent-deep) !important;
    transform: translateY(-1px);
}

/* ============================================================================
   4. Inputs and search
   ========================================================================== */

.nav-search,
.nav-search-field,
input[type="search"],
input[type="text"].form-control,
input[type="email"].form-control,
input[type="tel"].form-control,
input[type="password"].form-control,
select.form-control,
textarea.form-control {
    border-radius: var(--g-r-pill);
    border: 1px solid var(--g-line);
    transition: border-color var(--g-fast) var(--g-ease),
                box-shadow var(--g-fast) var(--g-ease);
}

textarea.form-control { border-radius: var(--g-r-sm); }

.nav-search:focus,
input.form-control:focus,
select.form-control:focus,
textarea.form-control:focus {
    border-color: var(--g-accent);
    box-shadow: 0 0 0 4px var(--g-accent-ring);
    outline: none;
}

/* ============================================================================
   5. Surfaces — banners, tiles, modals, accordions
   ========================================================================== */

.collection-banner,
.category-block,
.home-slider .slide-1 .home,
.delivery-return-box,
.address-card,
.modal-content,
.dash-panel .section-hd,
.product-accordion .accordion-item {
    border-radius: var(--g-r-lg);
    overflow: hidden;
}

.modal-content {
    border: none;
    box-shadow: var(--g-shadow-lg);
}

.product-accordion .accordion-item {
    border: 1px solid var(--g-line);
    margin-bottom: 10px;
    box-shadow: var(--g-shadow-sm);
}
.product-accordion .accordion-button { border-radius: var(--g-r-lg) !important; }
.product-accordion .accordion-button:not(.collapsed) {
    background: var(--g-accent-soft);
    color: var(--g-accent-deep);
    box-shadow: none;
}
.product-accordion .accordion-button:focus {
    box-shadow: 0 0 0 4px var(--g-accent-ring);
    border-color: transparent;
}

/* Category tiles lift like the product cards, so the whole site behaves
   consistently rather than each section inventing its own idiom. */
.collection-banner,
.category-block {
    box-shadow: var(--g-shadow-sm);
    transition: transform var(--g-mid) var(--g-ease-out),
                box-shadow var(--g-mid) var(--g-ease-out);
}
.collection-banner:hover,
.category-block:hover {
    transform: translateY(-5px);
    box-shadow: var(--g-shadow-lg);
}

/* ============================================================================
   5b. Product gallery — main image and the thumbnail strip
   ----------------------------------------------------------------------------
   The strip was a row of square, full-bleed images with no gap and no way to
   tell which one you were looking at. Slick marks the active slide
   .slick-current, which nothing was styling.
   ========================================================================== */

.product-slick,
.product-slick picture,
.product-slick img {
    border-radius: var(--g-r-lg);
    overflow: hidden;
}

.product-slick img { display: block; }

.slider-nav { margin-top: 12px; }

/* Slick lays these out inline, so spacing has to come from the cell. */
.slider-nav .slick-slide { padding: 0 6px; }

.slider-nav .thumb-cell,
.slider-nav .slick-slide > div {
    border-radius: var(--g-r-sm);
    overflow: hidden;
    cursor: pointer;
    background: var(--g-surface-2);
    /* Transparent ring reserved up front so selecting a thumbnail does not
       shift the row by 2px. */
    box-shadow: 0 0 0 2px transparent;
    transition: box-shadow var(--g-fast) var(--g-ease),
                transform var(--g-fast) var(--g-ease);
}

.slider-nav .thumb-cell img,
.slider-nav .slick-slide img {
    border-radius: var(--g-r-sm);
    display: block;
    width: 100%;
}

.slider-nav .slick-slide:hover .thumb-cell,
.slider-nav .thumb-cell:hover {
    transform: translateY(-2px);
    box-shadow: 0 0 0 2px var(--g-line), var(--g-shadow-sm);
}

/* The one you are actually looking at. */
.slider-nav .slick-current .thumb-cell,
.slider-nav .slick-current > div {
    box-shadow: 0 0 0 2px var(--g-accent), 0 4px 12px var(--g-accent-ring);
}

/* Slick's arrows sat as bare glyphs over the photo. */
.product-slick .slick-prev,
.product-slick .slick-next {
    width: 38px;
    height: 38px;
    border-radius: var(--g-r-pill);
    background: rgba(255, 255, 255, .9);
    -webkit-backdrop-filter: blur(6px);
    backdrop-filter: blur(6px);
    box-shadow: var(--g-shadow-sm);
    z-index: 2;
    transition: transform var(--g-fast) var(--g-ease),
                box-shadow var(--g-fast) var(--g-ease);
}
.product-slick .slick-prev:hover,
.product-slick .slick-next:hover {
    transform: scale(1.08);
    box-shadow: var(--g-shadow-md);
}

/* ============================================================================
   6. Floating and fixed furniture
   ========================================================================== */

.whatsapp-float {
    box-shadow: var(--g-shadow-lg);
    transition: transform var(--g-mid) var(--g-ease-out),
                box-shadow var(--g-mid) var(--g-ease-out);
}
.whatsapp-float:hover {
    transform: translateY(-4px) scale(1.06);
    box-shadow: 0 10px 30px rgba(37, 211, 102, .45);
}

/* The two stacked mobile bars get a soft top edge instead of a hard rule. */
.mobile-bottom-bar,
.mobile-fix-option {
    border-radius: var(--g-r-lg) var(--g-r-lg) 0 0;
    box-shadow: 0 -6px 24px rgba(36, 28, 23, .10);
    border-top: none;
}

.dash-avatar { border-radius: var(--g-r-pill); }

/* ============================================================================
   7. Scroll reveal
   ----------------------------------------------------------------------------
   The hidden state is applied by JS (it adds .g-reveal-ready to <html>), never
   by CSS alone. If the JavaScript fails to run, nothing is ever hidden — the
   page just renders normally. Hiding content in CSS and revealing it in JS is
   how a broken script turns into a blank page.
   ========================================================================== */

.g-reveal-ready [data-g-reveal] {
    opacity: 0;
    transform: translateY(22px);
    transition: opacity var(--g-slow) var(--g-ease-out),
                transform var(--g-slow) var(--g-ease-out);
    transition-delay: var(--g-reveal-delay, 0ms);
}

.g-reveal-ready [data-g-reveal].g-revealed {
    opacity: 1;
    transform: none;
}

/* ============================================================================
   9. The header
   ----------------------------------------------------------------------------
   Rebuilt from scratch 2026-09-20, replacing ~270 lines that existed only to
   wrestle the vendor theme's bar into a shape it was never built for. The old
   block fought `.brand-logo { padding: 31px 0 }` (a 38px logo occupying 106px),
   `.icon-nav`'s own padding, a hard-coded 700px search input, and a `<form>`
   that painted its own grey rectangle behind a pill-shaped field. Each fix
   created the next one, and the bar STILL rendered square-cornered at rest
   because the pill styling only ever applied once scrolled.

   `.g-hd-*` markup is ours, so none of that applies. The bar is a pill from
   first paint and only its weight changes on scroll.

   ARCHITECTURE — the one rule that matters:
   the header is `position: fixed` from first paint and NEVER changes position.
   Its height is measured once into --g-header-h and reserved as body padding.
   Only paint properties animate, so no layout moves mid-scroll. The theme used
   to swap static->fixed at 150px AND toggle 90px of body padding at the same
   moment; no easing curve rescues two simultaneous layout changes.

   Three states, set by glass-ui.js on <html>:
       (none)              at the top       strip visible, roomy bar
       .g-scrolled         scrolled         strip folded, bar tightens + darkens
       .g-scrolled.g-min   scrolling down   nav and search collapse away
   Scrolling up by 4px drops .g-min and brings them straight back.

   ⚠️ Never put backdrop-filter, transform, filter or will-change on an ancestor
   of a position:fixed element — each makes that ancestor the containing block.
   That has bitten this project four times. See section 11.
   ========================================================================== */

:root {
    --g-header-h: 150px;   /* measured at runtime by glass-ui.js */
    --g-hd-gap: 16px;      /* the bar's inset from the viewport edge */
}

header.header-2 {
    position: fixed;
    top: 0; left: 0; right: 0;
    z-index: 9999;
    background: transparent;
}

body { padding-top: var(--g-header-h); }
body.checkout-page { padding-top: 0; }

/* ---- announcement strip -------------------------------------------------- */
.g-hd-strip {
    background: var(--g-chrome);
    color: var(--g-chrome-ink-2);
    font-size: 12.5px;
    overflow: hidden;

    /* Only max-height and opacity animate. The old version animated `height`,
       which the browser cannot interpolate cheaply, alongside the bar's
       max-width and the shell's padding — three layout animations firing at
       the same 30px threshold, which is what made the first scroll stutter. */
    will-change: max-height;
}

.g-hd-strip-inner {
    display: flex;
    align-items: center;
    gap: 14px;
    max-width: 1320px;
    margin: 0 auto;
    padding: 9px 26px;
}

.g-hd-strip-item {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    color: var(--g-chrome-ink-2);
    text-decoration: none;
    white-space: nowrap;
    transition: color var(--g-fast) var(--g-ease);
}
a.g-hd-strip-item:hover { color: var(--g-chrome-ink); }
.g-hd-strip-item--end { margin-left: auto; }
.g-hd-strip-sep { width: 1px; height: 12px; background: var(--g-chrome-line); }

/* The strip clips ITSELF while it folds. That matters: the clip used to live on
   .g-hd-card, and from there it also cut off every dropdown panel — see the
   card rules below. */
.g-hd-strip {
    max-height: 40px;
    opacity: 1;
    overflow: hidden;
    transition: max-height var(--g-mid) var(--g-ease-out),
                opacity var(--g-fast) var(--g-ease-out);
}

.g-scrolled .g-hd-strip {
    max-height: 0;
    opacity: 0;
}

@media (max-width: 767px) {
    /* Two of the three items are noise on a phone; the phone number is not. */
    .g-hd-strip-inner { padding: 7px 16px; justify-content: center; }
    .g-hd-strip-item:not([href]) { display: none; }
    .g-hd-strip-sep { display: none; }
    .g-hd-strip-item--end { display: none; }
}

/* ---- the bar ------------------------------------------------------------- */
.g-hd-shell { padding: var(--g-hd-gap); }

/* One floating card holding both rows. The strip used to be a full-bleed dark
   band above a floating pill, so the two read as unrelated objects with a hard
   edge between them. Two rows in one card; when the strip folds away the card
   is left as a single-row pill, and the radius travels with it. */
/* ⚠️ TWO STATES, ONE TRANSITION — and no per-frame JavaScript.
   ----------------------------------------------------------------------------
   The previous version wrote a --g-shrink number on EVERY scroll frame and
   interpolated the card's max-width, the strip's height and the bar's padding
   from it. Three layout properties recomputed per frame, on a card that is
   `margin: 0 auto` — so every width change moved BOTH its edges inward and the
   logo slid horizontally a pixel at a time. That is what read as "the logo
   shrinking with a jitter" and "shifting pixel by pixel instead of a keyframe".

   Now the card never changes width on scroll. Only its surface changes — radius,
   background, shadow, blur, all paint-only — and the strip folds. The one real
   layout change in the whole interaction is the .g-min compress, which is a
   single class with a single transition, and which is the part that already
   looked right.

   Do not reintroduce a scroll-driven width. If the card must resize with the
   scroll position, resize it with a transform, not a layout property, and do
   not centre it while it does. */

.g-hd-card {
    max-width: 1320px;
    margin: 0 auto;

    /* ⚠️ VISIBLE, and this is load-bearing. `overflow: hidden` lived here to
       clip the folding strip, and it also clipped every navigation dropdown out
       of existence. The card's box ends at y=118; the panels run to y=340, so
       all but 5px of each panel was cut away. They opened correctly the whole
       time — .g-open was set, opacity 1, visibility visible — and drew nothing,
       which is why hovering felt like it "went somewhere else" and clicking just
       followed the category link.

       Proven live by A/B: elementFromPoint at the panel's centre returned the
       page content behind it, and returned .g-panel-link the moment overflow was
       set to visible. The strip now clips itself instead.

       This is the same bug as the category row in 2026-09-20. Any ancestor of a
       dropdown with `overflow: hidden` will do this, silently, at HTTP 200. */
    overflow: visible;

    border-radius: var(--g-r-xl);
    background: rgba(255, 255, 255, .94);
    box-shadow:
        inset 0 0 0 1px rgba(36, 28, 23, .05),
        0 6px 24px rgba(36, 28, 23, .08);

    transition: max-width var(--g-mid) var(--g-ease-out),
                border-radius var(--g-mid) var(--g-ease-out),
                background-color var(--g-mid) var(--g-ease-out),
                box-shadow var(--g-mid) var(--g-ease-out);
}

/* Scrolled: the surface becomes glass. Paint only — nothing here moves. */
.g-scrolled .g-hd-card {
    border-radius: 999px;
    background: rgba(255, 255, 255, .88);
    box-shadow:
        inset 0 0 0 1px rgba(36, 28, 23, .05),
        0 12px 34px rgba(36, 28, 23, .14);
}

/* Scrolling DOWN: the compress. One property, one transition. */
.g-scrolled.g-min .g-hd-card {
    max-width: 760px;
    /* Safe to clip here and nowhere else: a panel held open forces the header
       out of .g-min (glass-ui.js), so there is never a panel to cut off. */
    overflow: hidden;
}

/* ⚠️ Desktop only, and NOT for taste. backdrop-filter establishes a containing
   block for position: fixed descendants, and the mobile search and cart icons
   are fixed elements that live inside this header — blurring it on a phone
   re-anchors them to the card and throws them off the top of the screen. */
@media (min-width: 992px) {
    .g-scrolled .g-hd-card {
        -webkit-backdrop-filter: blur(24px) saturate(180%);
        backdrop-filter: blur(24px) saturate(180%);
    }
}

.g-hd-bar {
    position: relative;
    z-index: 2;
    display: flex;
    align-items: center;
    gap: 18px;
    /* Constant. This used to shrink with the scroll, which moved the logo a
       second time on top of the card's own width change. */
    padding: 10px 12px 10px 22px;
    background: transparent;   /* .g-hd-card paints the surface */
}

/* The shell padding deliberately does NOT change on scroll. Animating it moved
   the card while its own size was animating, and two moving boxes at once is
   what read as jitter. The card alone changes. */

/* ---- logo ---------------------------------------------------------------- */
.g-hd-logo {
    display: inline-flex;
    align-items: center;
    flex: none;
    text-decoration: none;
}

/* The logo was squashed before because the box had a fixed height and the
   image inside it had no aspect control. */
.g-hd-logo img,
.g-hd-logo svg {
    display: block;
    width: auto;
    height: auto;
    max-height: 42px;
    object-fit: contain;
    transition: max-height var(--g-slow) var(--g-ease-out);
}
.g-scrolled .g-hd-logo img,
.g-scrolled .g-hd-logo svg { max-height: 36px; }

/* ---- nav ----------------------------------------------------------------- */
.g-hd-nav {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    justify-content: center;
}

.g-hd-nav > ul#main-menu {
    display: flex;
    align-items: center;
    gap: 2px;
    margin: 0;
    padding: 0;
    list-style: none;
    background: transparent;
}

.g-hd-nav > ul#main-menu > li { position: relative; }

.g-hd-nav > ul#main-menu > li > a {
    display: inline-flex;
    align-items: center;
    padding: 9px 13px !important;
    border-radius: var(--g-r-pill);
    color: var(--g-ink) !important;
    font-size: 14.5px;
    font-weight: 600;
    letter-spacing: -.005em;
    line-height: 1.2;
    text-transform: none !important;
    white-space: nowrap;
    transition: background-color var(--g-fast) var(--g-ease),
                color var(--g-fast) var(--g-ease);
}

.g-hd-nav > ul#main-menu > li > a:hover,
.g-hd-nav > ul#main-menu > li.g-open > a {
    background: var(--g-brand-soft);
    color: var(--g-brand-deep) !important;
}

/* SmartMenus' own caret. Kept because on a phone it is the tap target that
   expands the drawer; adding one of our own gave every item two chevrons. */
.g-hd-nav .sub-arrow {
    transition: transform var(--g-fast) var(--g-ease);
    display: inline-block;
}
.g-hd-nav li.g-open > a .sub-arrow { transform: rotate(180deg); }

/* The drawer's own header row is desktop-invisible. */
.g-hd-nav .mobile-box { display: none; }

@media (max-width: 1199px) {
    /* Below this the links no longer fit beside the logo, search and icons, so
       the drawer takes over. */
    .g-hd-nav { display: none; }
}

/* ---- actions ------------------------------------------------------------- */
.g-hd-actions {
    display: flex;
    align-items: center;
    gap: 6px;
    flex: none;
    margin-left: auto;
}

.g-hd-search {
    position: relative;
    display: flex;
    align-items: center;
    width: 230px;
    background: transparent !important;   /* the theme's form paints its own grey box */
    border: 0 !important;
    padding: 0 !important;
    box-shadow: none !important;
    transition: width var(--g-mid) var(--g-ease-out),
                opacity var(--g-fast) var(--g-ease);
}

.g-hd-search-icon {
    position: absolute;
    left: 14px;
    font-size: 16px;
    color: var(--g-ink-3);
    pointer-events: none;
}

.g-hd-search .nav-search,
.g-hd-search input[type="search"] {
    width: 100%;
    height: 40px;
    padding: 0 16px 0 38px;
    border-radius: var(--g-r-pill) !important;
    border: 1px solid var(--g-line);
    background: var(--g-surface-2);
    font-size: 13.5px;
    color: var(--g-ink);
    transition: border-color var(--g-fast) var(--g-ease),
                box-shadow var(--g-fast) var(--g-ease),
                background-color var(--g-fast) var(--g-ease);
}

.g-hd-search .nav-search:focus {
    outline: none;
    background: var(--g-surface);
    border-color: var(--g-accent);
    box-shadow: 0 0 0 4px var(--g-accent-ring);
}

.g-hd-icon {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 42px;
    height: 42px;
    flex: none;
    padding: 0;
    border: 0;
    border-radius: var(--g-r-pill);
    background: transparent;
    color: var(--g-ink);
    font-size: 20px;
    line-height: 1;
    text-decoration: none;
    cursor: pointer;
    transition: background-color var(--g-fast) var(--g-ease),
                color var(--g-fast) var(--g-ease),
                transform var(--g-fast) var(--g-ease);
}
.g-hd-icon:hover {
    background: var(--g-brand-soft);
    color: var(--g-brand-deep);
    transform: translateY(-1px);
}
.g-hd-icon:active { transform: translateY(0); }

.g-hd-badge {
    position: absolute;
    top: 3px;
    right: 2px;
    min-width: 17px;
    height: 17px;
    padding: 0 4px;
    border-radius: var(--g-r-pill);
    background: var(--g-accent);
    color: #fff;
    font-size: 10px;
    font-weight: 700;
    line-height: 17px;
    text-align: center;
}

/* The magnifier and the hamburger each appear only where their counterpart
   is not available. */
.g-hd-icon--search { display: none; }
.g-hd-icon--menu { display: none; }

@media (max-width: 1199px) {
    .g-hd-icon--menu { display: inline-flex; }
}

@media (max-width: 767px) {
    /* The full field costs more width than a phone has. The magnifier opens
       the same full-screen search modal, which is the better phone pattern. */
    .g-hd-search { display: none; }
    .g-hd-icon--search { display: inline-flex; }

    .g-hd-shell { padding: 10px 12px; }
    .g-hd-bar { gap: 8px; padding: 8px 8px 8px 14px; }
    .g-hd-logo img, .g-hd-logo svg { max-height: 34px; }
    .g-hd-icon { width: 38px; height: 38px; font-size: 19px; }
}

/* Minimised, the bar keeps the thing people actually want from a shop header:
   the search. Only the category nav folds away. Collapsing the search too left
   a pill that could do nothing but go home, which is a worse header than no
   header. */
@media (min-width: 1200px) {
    .g-scrolled.g-min .g-hd-nav {
        opacity: 0;
        max-width: 0;
        overflow: hidden;
        pointer-events: none;
        transition: opacity var(--g-fast) var(--g-ease),
                    max-width var(--g-mid) var(--g-ease-out);
    }
    /* The field takes the width the nav gave up. */
    .g-scrolled.g-min .g-hd-search { width: 360px; }
}

/* ---- the phone drawer ---------------------------------------------------- */
/* SmartMenus + script.js slide #main-menu in from the right by setting
   `right: 0`. That only works while the element is NOT inside a flex row, so
   below 1200px it is taken out of the bar's layout entirely. */
@media (max-width: 1199px) {
    .g-hd-nav > ul#main-menu {
        display: block;
        position: fixed;
        top: 0;
        right: -410px;
        width: 300px;
        max-width: 84vw;
        height: 100vh;
        margin: 0;
        padding: 0;
        overflow-y: auto;
        background: var(--g-surface);
        box-shadow: -8px 0 40px rgba(36, 28, 23, .18);
        z-index: 10000;
        transition: right var(--g-mid) var(--g-ease-out);
    }

    .g-hd-nav { display: block; }   /* the <nav> must stay in the DOM flow */
    .g-hd-nav { position: static; flex: none; }

    .g-hd-nav .mobile-box { display: block; }
    .g-hd-nav .mobile-back {
        display: flex;
        align-items: center;
        justify-content: space-between;
        padding: 18px 20px;
        border-bottom: 1px solid var(--g-line);
        font-size: 15px;
        font-weight: 700;
        color: var(--g-brand);
        cursor: pointer;
    }

    .g-hd-nav > ul#main-menu > li { display: block; }
    .g-hd-nav > ul#main-menu > li > a {
        display: flex;
        justify-content: space-between;
        align-items: center;
        padding: 14px 20px !important;
        border-radius: 0;
        font-size: 15px;
    }
}

/* ---- progress line ------------------------------------------------------- */
.g-progress {
    position: fixed;
    top: 0; left: 0; right: 0;
    height: 3px;
    background: linear-gradient(90deg, var(--g-accent), var(--g-accent-deep));
    transform: scaleX(0);
    transform-origin: 0 50%;
    z-index: 10001;
    pointer-events: none;
    will-change: transform;
}

/* ---- back to top --------------------------------------------------------- */
.g-to-top {
    position: fixed;
    right: 20px;
    bottom: 96px;
    width: 46px;
    height: 46px;
    border: none;
    border-radius: var(--g-r-pill);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 20px;
    color: var(--g-accent-deep);
    background: rgba(255, 255, 255, .78);
    -webkit-backdrop-filter: blur(16px) saturate(180%);
    backdrop-filter: blur(16px) saturate(180%);
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, .9),
        inset 0 0 0 1px rgba(36, 28, 23, .06),
        var(--g-shadow-lg);
    z-index: 9998;
    cursor: pointer;
    opacity: 0;
    visibility: hidden;
    transform: translateY(12px) scale(.9);
    transition: opacity var(--g-mid) var(--g-ease-out),
                transform var(--g-mid) var(--g-ease-out),
                visibility var(--g-mid) linear;
}
.g-to-top.g-show { opacity: 1; visibility: visible; transform: none; }
.g-to-top:hover { transform: translateY(-3px) scale(1.06); color: var(--g-accent); }

@media (max-width: 991px) {
    .g-to-top { bottom: 132px; right: 16px; }
}

/* A floating button that never moves reads as a sticker. 4px, slow enough to
   register as depth rather than as an animation. */
@keyframes g-drift {
    0%, 100% { transform: translateY(0); }
    50%      { transform: translateY(-4px); }
}
.whatsapp-float { animation: g-drift 4.5s var(--g-ease) infinite; }
.whatsapp-float:hover { animation-play-state: paused; }

/* Lenis needs these or it fights the native scrollbar. */
html.lenis, html.lenis body { height: auto; }
.lenis.lenis-smooth { scroll-behavior: auto !important; }
.lenis.lenis-stopped { overflow: hidden; }

/* ============================================================================
   10. Brand mark + dark chrome
   ----------------------------------------------------------------------------
   Owner's direction: dark chrome, light content. The header pill, the floating
   buttons and the mobile bars go near-black; product areas stay white, because
   the photography is bright and jewellery on white is what shoppers expect.

   The near-black is warm and tinted toward the brand magenta. Neutral black
   beside a warm palette reads as a different design sharing the same page.
   ========================================================================== */

/* ---- the mark ------------------------------------------------------------ */
.g-logo { display: inline-flex; align-items: center; line-height: 0; }

.g-logo svg {
    height: 46px;
    width: auto;
    display: block;
    overflow: visible;
    transition: height var(--g-slow) var(--g-ease-out);
}

.g-logo__mark   { fill: var(--g-accent); }
.g-logo__handle { stroke: var(--g-accent); }

.g-logo__word {
    fill: var(--g-brand);
    font-family: Poppins, system-ui, sans-serif;
    font-weight: 700;
    font-size: 46px;
    letter-spacing: -0.6px;
    transition: fill var(--g-mid) var(--g-ease);
}

.g-logo__sub rect { fill: var(--g-accent); }

.g-logo__subtext {
    fill: #fff;
    font-family: Poppins, system-ui, sans-serif;
    font-weight: 700;
    font-size: 11.5px;
    letter-spacing: 1.8px;
    text-anchor: middle;
}

/* .g-logo--light is for genuinely dark surfaces — the footer. The scrolled
   header is no longer one of them, so the wordmark keeps its magenta at every
   scroll position. */
.g-logo--light .g-logo__word { fill: var(--g-chrome-ink); }

/* ---- the bar stays LIGHT at every scroll position -------------------------
   It used to go near-black once scrolled, which forced the magenta wordmark to
   flip to white halfway down the page — the logo changed colour depending on
   how far you had scrolled. A brand mark that does that is not a brand mark.
   The dark chrome stays where it belongs: the strip, the mobile bar and the
   footer. The bar is glass over whatever is behind it.
   -------------------------------------------------------------------------- */

/* The hamburger bars are drawn with background-color, not a font. */
.g-scrolled .toggle-nav .sidebar-overlay,
.g-scrolled .toggle-nav span,
.g-scrolled .toggle-nav .bar { background-color: var(--g-chrome-ink) !important; }

/* ---- floating furniture goes dark too ------------------------------------ */
.g-to-top {
    color: var(--g-chrome-ink);
    background: rgba(27, 17, 20, .78);
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, .12),
        inset 0 0 0 1px rgba(255, 255, 255, .08),
        0 10px 28px rgba(20, 12, 15, .34);
}
.g-to-top:hover { color: var(--g-accent); }

/* Mobile's two stacked bars are chrome, so they follow the same rule. */
@media (max-width: 991px) {
    .mobile-bottom-bar,
    .mobile-fix-option {
        background: var(--g-chrome) !important;
        box-shadow: 0 -8px 28px rgba(20, 12, 15, .30);
    }
    .mobile-bottom-bar *,
    .mobile-fix-option *,
    .mob-bar-btn,
    .mob-bar-btn i { color: var(--g-chrome-ink) !important; }
    .mobile-bottom-bar .mob-bar-btn:active i { color: var(--g-accent) !important; }
}

/* ---- the footer is chrome as well ---------------------------------------- */
footer,
.footer-section,
footer.footer-1 {
    background: var(--g-chrome) !important;
    color: var(--g-chrome-ink-2);
}
footer h4, footer h5, footer .footer-title h4 { color: var(--g-chrome-ink) !important; }
footer a, footer li a, footer p, footer span { color: var(--g-chrome-ink-2) !important; }
footer a:hover, footer li a:hover { color: var(--g-accent) !important; }
footer hr, footer .footer-border { border-color: var(--g-chrome-line) !important; }

/* The black strip above the header was already near-black; warm it to match
   so there are not two different blacks stacked on each other. */
/* .top-header is gone — .g-hd-strip carries its own colours in section 9. */

/* ============================================================================
   11. Motion layer — page transitions
   ----------------------------------------------------------------------------
   The fade-out state is applied by motion.js and always cleared by it, on a
   timeout and on pageshow (bfcache). CSS must never be able to leave the page
   faded on its own.
   ========================================================================== */

/* ----------------------------------------------------------------------------
   OPACITY ONLY. Do not add transform here.

   The first version animated transform on <body> with fill-mode: both. The
   final keyframe was `transform: none`, but a filling animation still resolves
   that to a matrix — so body kept an identity transform permanently. Any
   transform on an ancestor makes position:fixed resolve against that ancestor
   instead of the viewport, which silently broke EVERY fixed element on the
   site: the sticky header scrolled away with the page, and both mobile bottom
   bars ended up thousands of pixels down the document.

   Measured: header.getBoundingClientRect().top was -600 at scrollY 600.

   A 6px rise on the whole page is not worth that. Same reason the leaving
   state no longer translates either.
   -------------------------------------------------------------------------- */
.g-page-ready body {
    animation: g-page-in var(--g-mid) var(--g-ease-out) both;
}

@keyframes g-page-in {
    from { opacity: 0; }
    to   { opacity: 1; }
}

.g-page-leaving body {
    opacity: 0;
    transition: opacity .22s var(--g-ease);
}

/* Magnetic buttons set an inline transform; they need their own transition so
   the release is eased rather than snapping back. */
.btn-solid, .apply-btn, .g-to-top, [class*="add-to-cart"] {
    transition: transform var(--g-mid) var(--g-ease-out),
                box-shadow var(--g-fast) var(--g-ease),
                background-color var(--g-fast) var(--g-ease),
                color var(--g-fast) var(--g-ease);
}

[data-g-parallax] { will-change: transform; }

/* ============================================================================
   8. Reduced motion
   ----------------------------------------------------------------------------
   Not optional. Vestibular disorders are real, and "scroll animations
   everywhere" is exactly the pattern that triggers them.
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
    .basic-product,
    .basic-product .img-wrapper img,
    .collection-banner,
    .category-block,
    .whatsapp-float,
    .btn, .btn-solid, .apply-btn,
    .g-reveal-ready [data-g-reveal] {
        transition: none !important;
        animation: none !important;
    }

    .basic-product:hover,
    .collection-banner:hover,
    .category-block:hover,
    .whatsapp-float:hover,
    .btn:hover, .btn-solid:hover {
        transform: none !important;
    }

    .basic-product:hover .img-wrapper img { transform: none !important; }

    /* Motion layer is disabled wholesale in motion.js under reduced motion;
       these are belt and braces for anything already inline. */
    .g-page-ready body { animation: none !important; }
    .g-page-leaving body { opacity: 1 !important; }
    [data-g-parallax] { transform: none !important; }

    /* Glass chrome: keep the look, drop the movement. */
    .whatsapp-float { animation: none !important; }
    .g-progress { transition: none !important; }
    .g-hd-bar,
    .g-hd-strip,
    .g-to-top { transition: none !important; }
    .g-to-top:hover { transform: none !important; }

    .slider-nav .thumb-cell,
    .slider-nav .thumb-cell:hover,
    .delivery-return-box .dr-col,
    .delivery-return-box .dr-col:hover,
    .product-slick .slick-prev:hover,
    .product-slick .slick-next:hover {
        transition: none !important;
        transform: none !important;
    }

    /* Content must still be visible — reveal without the motion. */
    .g-reveal-ready [data-g-reveal] { opacity: 1 !important; transform: none !important; }
}

/* ============================================================================
   15. Navigation panels
   ----------------------------------------------------------------------------
   The dropdowns on the live site opened on NEITHER hover nor click. SmartMenus
   chooses between the two with isTouchMode(), which is `'ontouchstart' in
   window` — true on touch-capable laptops and on any Chromium with touch
   emulation on. When it guessed touch, the hover handlers were never bound;
   the tap handler wanted a real touch event, which a mouse never sends. Dead
   either way, and it returned HTTP 200 the whole time.

   glass-ui.js now adds .g-open on hover/focus and this rule shows the panel.
   The !important is load-bearing: SmartMenus writes display:none as an INLINE
   style on the same <ul>, and an inline style beats a class rule.
   ========================================================================== */

/* 1200px, matching .g-hd-nav's own breakpoint. Keying these off 992px left a
   992-1199 band where the drawer and the desktop panel rules were both live. */
@media (min-width: 1200px) {
    /* Each panel must anchor to its OWN item. When every li computed to
       `static` — which the theme's `.mega` class forced via !important — all
       four shared one containing block and opened under whichever item sat at
       the centre of the nav. */
    .g-hd-nav li.g-has-panel { position: relative; }

    .g-hd-nav li.g-has-panel > ul.g-panel {
        display: block !important;
        position: absolute;
        top: calc(100% + 10px);
        left: 50%;
        min-width: 260px;
        padding: 0;
        margin: 0;
        background: transparent;
        box-shadow: none;
        border: 0;

        /* Hidden by opacity, not display, so it can animate. visibility keeps
           it out of the tab order and off the pointer while closed. */
        opacity: 0;
        visibility: hidden;
        transform: translate(-50%, -8px) scale(.97);
        transform-origin: 50% 0;
        transition: opacity var(--g-mid) var(--g-ease-out),
                    transform var(--g-mid) var(--g-ease-out),
                    visibility 0s linear var(--g-mid);
        z-index: 60;
    }

    .g-hd-nav li.g-has-panel.g-open > ul.g-panel {
        opacity: 1;
        visibility: visible;
        transform: translate(-50%, 0) scale(1);
        transition: opacity var(--g-mid) var(--g-ease-out),
                    transform var(--g-mid) var(--g-ease-out),
                    visibility 0s;
    }

    /* A bridge across the 10px gap, so moving the pointer from the label down
       into the panel does not cross dead space and close it. */
    .g-hd-nav li.g-has-panel.g-open::after {
        content: "";
        position: absolute;
        top: 100%;
        left: 0;
        right: 0;
        height: 14px;
    }

    .g-panel > li { display: block; padding: 0; }

    .g-panel-inner {
        background: var(--g-surface);
        border-radius: var(--g-r-lg);
        padding: 10px;
        box-shadow:
            inset 0 0 0 1px rgba(36, 28, 23, .07),
            var(--g-shadow-lg);
    }

    .g-panel-links { display: flex; flex-direction: column; gap: 2px; }

    .g-panel-link {
        display: flex !important;
        align-items: center;
        justify-content: space-between;
        gap: 18px;
        padding: 9px 12px !important;
        border-radius: var(--g-r-sm);
        color: var(--g-ink) !important;
        font-size: 14px;
        line-height: 1.3;
        text-transform: none !important;
        letter-spacing: 0;
        transition: background-color var(--g-fast) var(--g-ease),
                    color var(--g-fast) var(--g-ease),
                    transform var(--g-fast) var(--g-ease);
    }

    .g-panel-link:hover {
        background: var(--g-brand-soft);
        color: var(--g-brand-deep) !important;
        transform: translateX(3px);
    }

    /* The count is the honest signal the old nav lacked. "Men" was a top-level
       entry holding one product and nothing said so. */
    .g-panel-link-count {
        flex: none;
        font-size: 11px;
        font-weight: 600;
        color: var(--g-ink-3);
        background: var(--g-surface-2);
        border-radius: var(--g-r-pill);
        padding: 2px 8px;
        transition: background-color var(--g-fast) var(--g-ease),
                    color var(--g-fast) var(--g-ease);
    }
    .g-panel-link:hover .g-panel-link-count {
        background: #fff;
        color: var(--g-brand);
    }

    .g-panel-all {
        display: flex !important;
        align-items: center;
        justify-content: space-between;
        gap: 10px;
        margin-top: 6px;
        padding: 10px 12px !important;
        border-top: 1px solid var(--g-line);
        border-radius: 0 0 var(--g-r-md) var(--g-r-md);
        font-size: 13px;
        font-weight: 600;
        color: var(--g-brand) !important;
        text-transform: none !important;
        letter-spacing: 0;
    }
    .g-panel-all i { transition: transform var(--g-fast) var(--g-ease); }
    .g-panel-all:hover i { transform: translateX(4px); }

    /* SmartMenus' own <span class="sub-arrow"> is absolutely positioned at a
       fixed top offset meant for its own menu metrics, so in this bar it
       floated above the label rather than sitting beside it. On desktop it is
       hidden and the chevron is drawn as a ::after on the link, which sits on
       the text baseline because it is part of the text. It stays visible in the
       drawer, where it is the tap target that expands a submenu. */
    .g-hd-nav .g-has-panel > a .sub-arrow { display: none !important; }

    .g-hd-nav .g-has-panel > a::after {
        content: "";
        display: inline-block;
        width: 7px;
        height: 7px;
        margin-left: 7px;
        border-right: 2px solid currentColor;
        border-bottom: 2px solid currentColor;
        transform: translateY(-2px) rotate(45deg);
        transform-origin: 50% 50%;
        opacity: .55;
        transition: transform var(--g-fast) var(--g-ease),
                    opacity var(--g-fast) var(--g-ease);
    }
    .g-hd-nav .g-has-panel > a:hover::after { opacity: .9; }
    .g-hd-nav .g-has-panel.g-open > a::after {
        transform: translateY(1px) rotate(-135deg);
        opacity: 1;
    }
}

/* The drawer on phones is SmartMenus' own and still works; the panel markup
   must not fight it there. */
@media (max-width: 1199px) {
    /* In the drawer the panel is just an indented list, not a floating card. */
    .g-panel-inner { background: transparent; box-shadow: none; padding: 0; }
    .g-panel-link { justify-content: space-between; padding: 11px 20px 11px 32px !important; }
    .g-panel-all { padding: 12px 20px 12px 32px !important; }
    .g-hd-nav ul.g-panel { padding: 0; background: var(--g-surface-2); }
}

/* ============================================================================
   16. The mobile bottom bar
   ----------------------------------------------------------------------------
   <div class="mobile-fix-option"></div> shipped EMPTY. The theme styles it
   60px tall and position:fixed, so every phone visitor lost a strip of screen
   to a bar containing nothing, and the site had no bottom navigation at all —
   search was reachable only by opening the hamburger drawer first.

   No backdrop-filter here. On this bar specifically it threw the icons off
   screen once already (measured y:-6), because it makes the bar a containing
   block for the fixed children inside it.
   ========================================================================== */

.g-mobile-bar {
    display: none;
    align-items: stretch;
    justify-content: space-around;
    gap: 2px;
    padding: 6px 6px calc(6px + env(safe-area-inset-bottom, 0px));
    background: var(--g-chrome);
    box-shadow: 0 -6px 24px rgba(27, 17, 20, .22);
    z-index: 9997;
}

@media (max-width: 991px) {
    /* The theme pins .mobile-fix-option only up to 577px, so on tablets and
       landscape phones (578-991px) this bar sat at the TOP of the page. */
    .g-mobile-bar { display: flex; position: fixed; left: 0; right: 0; bottom: 0; width: 100%; }
    /* Keep the last of the page clear of the bar. */
    body { padding-bottom: 66px; }
    body.checkout-page { padding-bottom: 0; }
}

.g-mobile-bar-item {
    position: relative;
    flex: 1 1 0;
    min-width: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 3px;
    padding: 6px 2px;
    border: 0;
    background: transparent;
    border-radius: var(--g-r-md);
    color: var(--g-chrome-ink-2);
    font-size: 10px;
    font-weight: 500;
    line-height: 1;
    letter-spacing: .01em;
    text-decoration: none;
    -webkit-tap-highlight-color: transparent;
    transition: color var(--g-fast) var(--g-ease),
                background-color var(--g-fast) var(--g-ease),
                transform var(--g-fast) var(--g-ease);
}

.g-mobile-bar-item i { font-size: 21px; line-height: 1; }
.g-mobile-bar-item:active { transform: scale(.93); }

.g-mobile-bar-item.is-active,
.g-mobile-bar-item:hover {
    color: var(--g-chrome-ink);
    background: rgba(246, 239, 241, .09);
}

.g-mobile-bar-badge {
    position: absolute;
    top: 2px;
    left: 50%;
    margin-left: 4px;
    min-width: 16px;
    height: 16px;
    padding: 0 4px;
    border-radius: var(--g-r-pill);
    background: var(--g-accent);
    color: #fff;
    font-size: 10px;
    font-weight: 700;
    line-height: 16px;
    text-align: center;
}

/* ============================================================================
   17. Section headings
   ----------------------------------------------------------------------------
   The theme's .title1 stacked an <h4> and an <h2> that said different things:
   "special offers" sitting above "Latest Drop", and "Exclusive products" above
   "Special offers". Two promises per section, neither of them the heading.

   One eyebrow, one title, one optional line of supporting copy.
   ========================================================================== */

.g-section-head {
    text-align: center;
    max-width: 640px;
    margin: 0 auto;
    padding: 56px 0 28px;
}

.g-eyebrow {
    display: inline-block;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: var(--g-brand);
    background: var(--g-brand-soft);
    border-radius: var(--g-r-pill);
    padding: 5px 13px;
    margin-bottom: 14px;
}

.g-section-title {
    font-size: clamp(25px, 3.4vw, 38px);
    font-weight: 700;
    letter-spacing: -.02em;
    line-height: 1.12;
    color: var(--g-ink);
    margin: 0;
}

.g-section-sub {
    margin: 12px auto 0;
    max-width: 30em;
    font-size: 15px;
    line-height: 1.6;
    color: var(--g-ink-2);
}

/* ============================================================================
   18. Category tiles
   ----------------------------------------------------------------------------
   Every tile used to be one flat image with its heading, its subtitle and its
   "SHOP NOW" button baked into the pixels. Three tiles, three unrelated art
   directions, three crops — and text that could not be selected, translated,
   resized or read by a crawler, and that softened on any retina screen. Worse,
   the Women tile showed a white shirt and the Men tile a denim jacket, on a
   shop where 290 of 318 products are jewellery and the entire menswear range
   was a single bracelet.

   The text is real HTML now and the image is only ever a background.
   ========================================================================== */

.g-cat-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: 18px;
}

/* Scoped with the section on purpose, NOT with !important.
   The theme ships `.banner-section a { display: block }` — specificity (0,1,1),
   a class plus an element — which quietly beat a bare `.g-cat-card` (0,1,0).
   The card was therefore never a flex container at all: align-items did nothing,
   the label sat at the TOP of the tile, and the scrim that is weighted to the
   BOTTOM was darkening the wrong half. Matching the theme's specificity is the
   fix; escalating to !important only starts a race. */
.g-cat-section .g-cat-card {
    position: relative;
    display: flex;
    align-items: flex-end;
    min-height: 260px;
    padding: 22px;
    border-radius: var(--g-r-xl);
    overflow: hidden;
    isolation: isolate;
    /* The brand gradient is the card's FLOOR, not a special case. Two of the
       four categories point at image files that are not on disk (checked:
       black-flower.jpg and one chatgpt-image png, both 404) — an image can go
       missing at any time, so a tile must look designed when its photograph
       fails, not only when the database field is empty. .is-plain below is the
       same gradient for the empty-field case. */
    background: linear-gradient(145deg, var(--g-brand) 0%, var(--g-brand-deep) 55%, #5E1230 100%);
    text-decoration: none;
    transition: transform var(--g-mid) var(--g-ease-out),
                box-shadow var(--g-mid) var(--g-ease-out);
    box-shadow: var(--g-shadow-sm);
    transition-delay: var(--g-cat-delay, 0ms);
}

.g-cat-section .g-cat-card:hover {
    transform: translateY(-6px);
    box-shadow: var(--g-shadow-lg);
    transition-delay: 0ms;
}

.g-cat-media {
    position: absolute;
    inset: 0;
    z-index: -2;
    display: block;
    overflow: hidden;
}

.g-cat-img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
    transition: transform var(--g-slow) var(--g-ease-out);
}
.g-cat-section .g-cat-card:hover .g-cat-img { transform: scale(1.05); }

/* The scrim. Text over an unknown photograph is only legible if something
   guarantees the contrast — and these photographs are ivory and cream, so a
   generic dark gradient would look like a bruise. This one is the brand
   near-black, heaviest at the bottom where the type sits. */
.g-cat-section .g-cat-card::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    background: linear-gradient(
        to top,
        rgba(27, 17, 20, .86) 0%,
        rgba(27, 17, 20, .44) 38%,
        rgba(27, 17, 20, .06) 72%,
        rgba(27, 17, 20, 0) 100%);
    transition: opacity var(--g-mid) var(--g-ease);
}
.g-cat-section .g-cat-card:hover::before { opacity: .92; }

/* No photograph yet: brand gradient rather than a broken image icon. Two of
   the four top-level categories were only promoted to the top level on
   2026-09-20 and have never had artwork. */
.g-cat-section .g-cat-card.is-plain {
    background: linear-gradient(145deg, var(--g-brand) 0%, var(--g-brand-deep) 55%, #5E1230 100%);
}
.g-cat-section .g-cat-card.is-plain::before {
    background: radial-gradient(120% 90% at 82% 8%, rgba(246, 126, 0, .34) 0%, rgba(246, 126, 0, 0) 60%);
}

.g-cat-body {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 5px;
    width: 100%;
}

.g-cat-name {
    font-size: 21px;
    font-weight: 700;
    letter-spacing: -.015em;
    line-height: 1.15;
    color: #fff;
}

.g-cat-count {
    font-size: 12px;
    font-weight: 500;
    color: rgba(255, 255, 255, .74);
}

.g-cat-cta {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    margin-top: 10px;
    padding: 8px 15px;
    border-radius: var(--g-r-pill);
    background: rgba(255, 255, 255, .15);
    -webkit-backdrop-filter: blur(8px);
    backdrop-filter: blur(8px);
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .26);
    font-size: 12.5px;
    font-weight: 600;
    color: #fff;
    transition: background-color var(--g-fast) var(--g-ease),
                gap var(--g-fast) var(--g-ease);
}
.g-cat-section .g-cat-card:hover .g-cat-cta {
    background: var(--g-accent);
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .32);
    gap: 11px;
}
.g-cat-cta i { font-size: 15px; }

@media (max-width: 575px) {
    .g-cat-grid { grid-template-columns: 1fr 1fr; gap: 12px; }
    .g-cat-card { min-height: 190px; padding: 15px; border-radius: var(--g-r-lg); }
    .g-cat-name { font-size: 16px; }
    .g-cat-cta { padding: 6px 11px; font-size: 11px; margin-top: 7px; }
    .g-section-head { padding: 38px 0 20px; }
}


/* ============================================================================
   20. The hero — real text over a photograph
   ----------------------------------------------------------------------------
   The old banners carried their headline, subtitle and "SHOP NOW" button inside
   the image. This draws them as HTML instead, from the sliders table.

   The artwork is prompted with the left third left deliberately empty, which is
   where the copy sits.
   ========================================================================== */

.g-hero-slide {
    position: relative;
    display: block;
    overflow: hidden;

    /* width:100% is load-bearing, not tidiness.
       With `aspect-ratio` set and width left to `auto`, a binding `max-height`
       makes the browser shrink the box's WIDTH to preserve the ratio rather
       than crop it. On a 1990x1100 window the 68vh cap bound first and the
       slide came out 1758px wide inside a 1990px slick-slide — a 232px band of
       white down the right-hand side. Pinning the width means the ratio only
       ever drives the height, and max-height simply clamps it. */
    width: 100%;
}

/* The theme sizes .home from its own rules; these keep the ratio sane for the
   new 16:9 artwork without letting the hero swallow the whole viewport.
   The old `aspect-ratio: 1600/542` in home.blade.php matched the OLD banner
   crop — it is overridden here and must not be reinstated for this artwork. */
@media (min-width: 768px) {
    #desktop-slider .slide-1 .home,
    #desktop-slider .slide-1 a.home,
    #desktop-slider .g-hero-slide {
        aspect-ratio: 2.35 / 1;
        height: auto !important;
        min-height: 0 !important;
        max-height: 68vh;
        background-size: cover;
        background-position: center;
    }
}

@media (max-width: 767px) {
    #mobile-slider .g-hero-slide {
        aspect-ratio: 4 / 5;
        height: auto !important;
        min-height: 0 !important;
        max-height: 76vh;
        background-size: cover;
        background-position: center;
    }
}

/* ---- the scrim ----------------------------------------------------------- */
/* These photographs are ivory and cream, so dark text on them would be
   unreadable and a flat dark overlay would grey the whole picture. This is a
   horizontal gradient weighted to the left, where the artwork is empty and the
   copy sits — the product side of the frame stays essentially untouched. */
.g-hero-scrim {
    position: absolute;
    inset: 0;
    z-index: 1;
    pointer-events: none;
    background: linear-gradient(
        100deg,
        rgba(247, 241, 234, .78) 0%,
        rgba(247, 241, 234, .52) 30%,
        rgba(247, 241, 234, .12) 52%,
        rgba(247, 241, 234, 0) 68%);
}

@media (max-width: 767px) {
    /* Portrait artwork puts its empty space at the TOP, so the gradient turns
       with it. */
    .g-hero--mobile .g-hero-scrim {
        background: linear-gradient(
            to bottom,
            rgba(247, 241, 234, .82) 0%,
            rgba(247, 241, 234, .52) 32%,
            rgba(247, 241, 234, .10) 56%,
            rgba(247, 241, 234, 0) 72%);
    }
}

/* ---- the copy ------------------------------------------------------------ */
.g-hero-inner {
    position: absolute;
    inset: 0;
    z-index: 2;
    display: flex;
    align-items: center;
    pointer-events: none;   /* only the button is clickable */
}

.g-hero-copy {
    max-width: 30rem;
    pointer-events: auto;
}

.g-hero-title {
    margin: 0;
    color: var(--g-ink);
    font-size: clamp(30px, 4.1vw, 56px);
    font-weight: 700;
    line-height: 1.04;
    letter-spacing: -.028em;
    text-wrap: balance;
}

.g-hero-sub {
    margin: 14px 0 0;
    max-width: 26em;
    color: var(--g-ink-2);
    font-size: clamp(14px, 1.25vw, 17px);
    line-height: 1.55;
}

.g-hero-cta {
    display: inline-flex;
    align-items: center;
    gap: 9px;
    margin-top: 26px;
    padding: 14px 26px;
    border-radius: var(--g-r-pill);
    background: var(--g-accent);
    color: #fff !important;
    font-size: 15px;
    font-weight: 600;
    letter-spacing: .005em;
    text-decoration: none;
    box-shadow: 0 10px 26px rgba(246, 126, 0, .36);
    transition: transform var(--g-fast) var(--g-ease),
                box-shadow var(--g-fast) var(--g-ease),
                background-color var(--g-fast) var(--g-ease),
                gap var(--g-fast) var(--g-ease);
}

.g-hero-cta:hover {
    background: var(--g-accent-deep);
    transform: translateY(-2px);
    box-shadow: 0 14px 32px rgba(246, 126, 0, .44);
    gap: 14px;
    color: #fff !important;
}
.g-hero-cta:active { transform: translateY(0); }
.g-hero-cta i { font-size: 17px; }

@media (max-width: 767px) {
    .g-hero-inner { align-items: flex-start; padding-top: 34px; }
    .g-hero-copy  { max-width: 100%; }
    .g-hero-sub   { margin-top: 10px; }
    .g-hero-cta   { margin-top: 18px; padding: 12px 22px; font-size: 14px; }
}

/* A slide with no copy keeps the whole banner clickable, as before. */
.g-hero-blanket {
    position: absolute;
    inset: 0;
    z-index: 2;
    display: block;
}

/* Slick's own arrows sit under the copy otherwise. */
.g-hero .slick-arrow { z-index: 3; }

/* ---- headline casing ----------------------------------------------------- */
/* The theme uppercases every h1 and h2. The hero headline is written by the
   owner in the admin panel, so whatever casing she types is the casing that
   should appear — the whole point of moving this text out of the image. */
.g-hero-title,
.g-section-title { text-transform: none !important; }

/* ---- screen-reader-only -------------------------------------------------- */
/* Not display:none — that removes it from the accessibility tree too, which
   would defeat the purpose. This keeps it readable to assistive tech and to
   crawlers while taking up no space. */
.g-sr-only {
    position: absolute !important;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* ============================================================================
   21. Mid-page promo strip
   ----------------------------------------------------------------------------
   Replaces offer.png, which had "Stay Hydrated / SPECIAL OFFER / UP TO…" painted
   into it and pointed at water bottles — eleven of 318 products — from the
   middle of a jewellery shop's front page.
   ========================================================================== */

.g-promo-section { padding-top: 0; }

.g-promo {
    position: relative;
    display: flex;
    align-items: center;
    min-height: 210px;
    padding: 34px 40px;
    border-radius: var(--g-r-xl);
    overflow: hidden;
    isolation: isolate;
    background: var(--g-chrome);
    box-shadow: var(--g-shadow-md);
}

.g-promo-img {
    position: absolute;
    inset: 0;
    z-index: -2;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center;
}

/* Same reasoning as the hero: a left-weighted gradient, so the copy is legible
   without flattening a cream photograph into grey. */
.g-promo::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    background: linear-gradient(
        100deg,
        rgba(247, 241, 234, .86) 0%,
        rgba(247, 241, 234, .60) 32%,
        rgba(247, 241, 234, .14) 52%,
        rgba(247, 241, 234, 0) 66%);
}

.g-promo-body { max-width: 30rem; }

.g-promo-eyebrow {
    display: inline-block;
    margin-bottom: 10px;
    padding: 5px 12px;
    border-radius: var(--g-r-pill);
    background: rgba(246, 126, 0, .12);
    box-shadow: inset 0 0 0 1px rgba(246, 126, 0, .4);
    color: var(--g-accent-deep);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .12em;
    text-transform: uppercase;
}

.g-promo-title {
    margin: 0;
    color: var(--g-ink);
    font-size: clamp(21px, 2.3vw, 30px);
    font-weight: 700;
    letter-spacing: -.02em;
    line-height: 1.15;
}

.g-promo-sub {
    margin: 9px 0 0;
    color: var(--g-ink-2);
    font-size: 14px;
    line-height: 1.55;
}

.g-promo-cta {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    margin-top: 18px;
    padding: 11px 20px;
    border-radius: var(--g-r-pill);
    background: rgba(255, 255, 255, .55);
    -webkit-backdrop-filter: blur(8px);
    backdrop-filter: blur(8px);
    box-shadow: inset 0 0 0 1px rgba(36, 28, 23, .18);
    color: var(--g-ink) !important;
    font-size: 13.5px;
    font-weight: 600;
    text-decoration: none;
    transition: background-color var(--g-fast) var(--g-ease),
                gap var(--g-fast) var(--g-ease);
}
.g-promo-cta:hover { background: var(--g-accent); gap: 12px; color: #fff !important; }

@media (max-width: 575px) {
    .g-promo { min-height: 0; padding: 24px 20px; border-radius: var(--g-r-lg); }
    .g-promo::before {
        background: linear-gradient(to top,
            rgba(247, 241, 234, .92) 0%, rgba(247, 241, 234, .80) 55%, rgba(247, 241, 234, .55) 100%);
    }
    .g-promo-sub { font-size: 13px; }
}

/* ---- the carousel arrows must not sit on the copy ------------------------ */
/* Slick centres its arrows vertically on the left and right edges, which is
   exactly where the hero's headline and supporting line live. The "‹" was
   landing on top of the subheading. Moved to a pair in the bottom-right, where
   the artwork is deliberately busiest and the copy never reaches. */
.g-hero .slick-arrow {
    top: auto;
    bottom: 22px;
    transform: none;
    width: 42px;
    height: 42px;
    border-radius: var(--g-r-pill);
    background: rgba(27, 17, 20, .34) !important;
    -webkit-backdrop-filter: blur(10px);
    backdrop-filter: blur(10px);
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .22);
    transition: background-color var(--g-fast) var(--g-ease),
                transform var(--g-fast) var(--g-ease);
    z-index: 4;
}
.g-hero .slick-arrow:hover {
    background: rgba(27, 17, 20, .55) !important;
    transform: scale(1.06);
}

/* The theme leaves these at opacity 0 and only reveals them on its own hover
   rules, which do not apply here — so they were invisible by accident rather
   than by design. Faint at rest, solid when the pointer is over the hero. */
.g-hero .slick-arrow { opacity: .45 !important; }
.g-hero:hover .slick-arrow { opacity: 1 !important; }
.g-hero .slick-prev { left: auto; right: 74px; }
.g-hero .slick-next { right: 22px; }
.g-hero .slick-arrow::before { color: #fff; opacity: .95; }

@media (max-width: 767px) {
    .g-hero .slick-arrow { display: none !important; }  /* swipe instead */
}

/* ⚠️ The theme grows these on hover of the CONTAINER, not of the arrow --------
   `.home-slider:hover .slick-prev` / `.slick-next` (style.css:12819) carry
   `transform: scale(2.5)` plus `left: 100px` / `right: 100px`. Those selectors
   are (0,3,0); everything above here is (0,2,0), so every rule above loses the
   moment the pointer enters the hero — which on arrival is most of the screen.

   Measured on the live page at 1700x950 before this fix: both arrows went from
   42x42 to 105x105, and the left one jumped from x=1584 to x=69, landing across
   the headline as a large grey disc.

   Matching the container-hover specificity is enough on its own — design-system
   .css loads after style.css, so equal specificity wins here. The same rule's
   media-query variants (scale 1.8 / 1.5 / 1.2 / 1.1, left 90/80/70/60/40px)
   lose too, because a media query adds no specificity. */
.g-hero .home-slider:hover .slick-arrow {
    transform: none;
    width: 42px;
    height: 42px;
}
.g-hero .home-slider:hover .slick-prev { left: auto; right: 74px; }
.g-hero .home-slider:hover .slick-next { left: auto; right: 22px; }

/* Last, so that hovering the arrow ITSELF still gets its own small lift. Same
   specificity as the block above, so source order is what decides. */
.g-hero .home-slider .slick-arrow:hover { transform: scale(1.06); }

/* Belt and braces: even if the arrows move again, the copy keeps clear of the
   frame edges so nothing can crowd it. */
.g-hero-copy { padding-right: 12px; }
@media (min-width: 768px) {
    .g-hero-inner { padding-left: 8px; }
}

/* ============================================================================
   22. The WhatsApp button
   ----------------------------------------------------------------------------
   It was a flat #25D366 disc with a hard shadow and a 2s infinite pulse — the
   one element on the page still animating for attention rather than in response
   to anything. Same shape language as everything else now: layered soft shadow,
   a lit rim, and motion only on interaction.
   ========================================================================== */

.whatsapp-float {
    width: 54px !important;
    height: 54px !important;
    font-size: 26px !important;
    background: linear-gradient(145deg, #2EE071 0%, #22C55E 55%, #16A34A 100%) !important;
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, .34),
        0 2px 6px rgba(22, 163, 74, .28),
        0 10px 28px rgba(22, 163, 74, .30) !important;
    animation: none !important;   /* the pulse was pure attention-seeking */
    transition: transform var(--g-fast) var(--g-ease),
                box-shadow var(--g-fast) var(--g-ease) !important;
}

.whatsapp-float:hover {
    transform: translateY(-3px) scale(1.05);
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, .4),
        0 4px 10px rgba(22, 163, 74, .3),
        0 16px 38px rgba(22, 163, 74, .38) !important;
}
.whatsapp-float:active { transform: translateY(0) scale(.97); }

/* ============================================================================
   23. Footer
   ========================================================================== */

/* The credit line is the last thing on the page; it should not be the loudest.
   It also no longer names the contractor who built the site. */
.footer-end p {
    margin: 0;
    font-size: 13px;
    color: var(--g-chrome-ink-2);
    opacity: .82;
}
.footer-end i { margin-right: 5px; }

/* The trust row above it carries more weight than the copyright below. */
.sub-footer,
.dark-subfooter {
    border-top: 1px solid var(--g-chrome-line);
}

/* ============================================================================
   24. Product page
   ========================================================================== */

/* ---- Delivery & Return --------------------------------------------------- */
/* The equal-height fix lives in product_detail.blade.php's own <style> block,
   because that block renders AFTER this file and was setting height:100% on
   .dr-col — an override here could never win. Fixed at the source instead. */

/* ---- the sticky buy bar -------------------------------------------------- */
/* It read as a thin white strip with two small buttons — easy to miss on the
   one screen where the decision gets made. */
.sticky-bottom-bar {
    padding: 12px 20px calc(12px + env(safe-area-inset-bottom, 0px)) !important;
    background: rgba(255, 255, 255, .92) !important;
    -webkit-backdrop-filter: blur(20px) saturate(180%);
    backdrop-filter: blur(20px) saturate(180%);
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, .9),
        0 -2px 8px rgba(36, 28, 23, .06),
        0 -12px 40px rgba(36, 28, 23, .16) !important;
    border-top: 1px solid rgba(36, 28, 23, .06);
}

.sticky-bottom-bar .sticky-product-info img {
    width: 52px !important;
    height: 52px !important;
    border-radius: var(--g-r-sm) !important;
    border: 1px solid var(--g-line) !important;
}

.sticky-bottom-bar .sticky-text .sticky-price {
    color: var(--g-accent-deep) !important;
    font-size: 16px !important;
}

/* The two actions carry real weight: a filled primary and a clear secondary. */
.sticky-bottom-bar .btn,
.sticky-bottom-bar [class*="add-to-cart"],
.sticky-bottom-bar [class*="buy-now"] {
    min-height: 48px;
    padding: 0 26px !important;
    border-radius: var(--g-r-pill) !important;
    font-size: 15px !important;
    font-weight: 600 !important;
    display: inline-flex !important;
    align-items: center;
    justify-content: center;
    gap: 8px;
}

.sticky-bottom-bar [class*="buy-now"] {
    background: var(--g-accent) !important;
    border-color: var(--g-accent) !important;
    color: #fff !important;
    box-shadow: 0 8px 22px rgba(246, 126, 0, .34) !important;
}
.sticky-bottom-bar [class*="buy-now"]:hover {
    background: var(--g-accent-deep) !important;
    transform: translateY(-2px);
}

.sticky-bottom-bar [class*="add-to-cart"] {
    background: var(--g-surface) !important;
    color: var(--g-ink) !important;
    box-shadow: inset 0 0 0 1.5px var(--g-ink) !important;
}
.sticky-bottom-bar [class*="add-to-cart"]:hover {
    background: var(--g-ink) !important;
    color: #fff !important;
    transform: translateY(-2px);
}

/* ⚠️ The WhatsApp button is fixed at bottom-left and sat directly on top of the
   sticky bar's product thumbnail. The bar only exists while it is `.visible`,
   so the button moves only then. */
.sticky-bottom-bar.visible ~ .whatsapp-float,
body:has(.sticky-bottom-bar.visible) .whatsapp-float {
    bottom: calc(92px + env(safe-area-inset-bottom, 0px)) !important;
}

@media (max-width: 767px) {
    .sticky-bottom-bar { gap: 10px !important; }
    .sticky-bottom-bar .sticky-product-info { flex: 0 1 auto; }
    .sticky-bottom-bar .btn,
    .sticky-bottom-bar [class*="add-to-cart"],
    .sticky-bottom-bar [class*="buy-now"] {
        min-height: 44px;
        padding: 0 16px !important;
        font-size: 14px !important;
    }
    /* On a phone the bar sits above the site's own bottom nav. */
    .sticky-bottom-bar.visible { bottom: 60px !important; }

    /* ⚠️ …which means the 92px lift above is not enough here. The bar is itself
       raised 60px, so its top edge is 137px off the bottom of the screen, and a
       button sitting 92px up still crosses it. Measured on the live page at
       375x812: the WhatsApp button occupied 666-720 and the bar started at 675,
       so elementFromPoint on the bar's product thumbnail returned the WhatsApp
       button. 60 (nav) + 77 (bar) + 15 (gap) = 152. */
    .sticky-bottom-bar.visible ~ .whatsapp-float,
    body:has(.sticky-bottom-bar.visible) .whatsapp-float {
        bottom: calc(152px + env(safe-area-inset-bottom, 0px)) !important;
    }
}

/* ============================================================================
   25. .blur-up, without lazysizes
   ----------------------------------------------------------------------------
   style.css ships:
       .blur-up            { filter: blur(5px) }
       .blur-up.lazyloaded { filter: blur(0) }

   The only thing that ever added .lazyloaded was lazysizes, which is no longer
   loaded — images use native loading="lazy" and no view uses data-src, the
   attribute lazysizes actually defers on. Measured before removing it: 31 of
   45 .blur-up elements were still at blur(5px) at any moment, including every
   product card image below the fold. Leaving the theme rule in place with
   nothing to clear it would have blurred all of them permanently.

   So the blur goes. Images appear as they decode, which with WebP at roughly a
   tenth of the original weight is quick — and there is no GPU blur pass on
   every product image, which is the part that mattered on a mid-range phone.
   ========================================================================== */

.blur-up,
.blur-up.lazyload,
.blur-up.lazyloading {
    -webkit-filter: none !important;
    filter: none !important;
}

/* ============================================================================
   26. Checkout trust panels + the last theme 404
   ========================================================================== */

.g-pay-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.g-pay-list li {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 8px 14px;
    border-radius: var(--g-r-pill);
    background: var(--g-surface-2);
    box-shadow: inset 0 0 0 1px var(--g-line);
    font-size: 13px;
    font-weight: 500;
    color: var(--g-ink);
}
.g-pay-list i { font-size: 17px; color: var(--g-accent-deep); }

.g-secure-note {
    display: flex;
    align-items: flex-start;
    gap: 9px;
    margin: 0 0 10px;
    font-size: 13.5px;
    line-height: 1.55;
    color: var(--g-ink-2);
}
.g-secure-note:last-child { margin-bottom: 0; }
.g-secure-note i {
    flex: none;
    margin-top: 2px;
    font-size: 16px;
    color: var(--g-accent-deep);
}

/* slick.css references ../../images/ajax-loader.gif, which is not on disk — a
   404 on every page that carries a carousel. It only ever shows in the brief
   .slick-loading state, so a plain surface is a straight improvement over a
   request that fails. */
.slick-loading .slick-list {
    background: var(--g-surface-2) !important;
}

/* ============================================================================
   27. Collection pages
   ----------------------------------------------------------------------------
   The filter rail and the sort controls were built before the design language
   existed: square corners, hairline borders, and #FF3F6C — the stray third
   accent that appears nowhere in the logo and that this layer exists to remove.
   The pink is replaced at source in collection.blade.php; this brings the
   surfaces into line with the cards and the header.
   ========================================================================== */

/* The rail reads as one card, like everything else on the site. */
.sidebar-filters,
.collection-sidebar,
.sb-wrap {
    background: var(--g-surface);
    border-radius: var(--g-r-lg);
    box-shadow: var(--g-shadow-sm);
    padding: 4px 18px;
}

.sb-title {
    font-size: 12px !important;
    font-weight: 700 !important;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--g-ink-2) !important;
}

.sb-section { border-bottom: 1px solid var(--g-line) !important; }

.sb-select {
    border-radius: var(--g-r-sm) !important;
    border: 1px solid var(--g-line) !important;
    background: var(--g-surface-2);
    font-size: 14px;
    padding: 11px 14px !important;
    transition: border-color var(--g-fast) var(--g-ease),
                box-shadow var(--g-fast) var(--g-ease);
}
.sb-select:focus {
    outline: none;
    border-color: var(--g-accent) !important;
    box-shadow: 0 0 0 4px var(--g-accent-ring);
}

/* The primary action on this page. It was a flat pink rectangle. */
.sb-apply-btn {
    border-radius: var(--g-r-pill) !important;
    background: var(--g-accent) !important;
    color: #fff !important;
    font-weight: 600 !important;
    letter-spacing: .01em !important;
    min-height: 46px;
    box-shadow: 0 8px 22px rgba(246, 126, 0, .30) !important;
    transition: background-color var(--g-fast) var(--g-ease),
                transform var(--g-fast) var(--g-ease),
                box-shadow var(--g-fast) var(--g-ease) !important;
}
.sb-apply-btn:hover {
    background: var(--g-accent-deep) !important;
    transform: translateY(-2px);
    box-shadow: 0 12px 28px rgba(246, 126, 0, .38) !important;
}
.sb-apply-btn:active { transform: translateY(0); }

/* Sort rows behave like the nav panel links. */
.sb-sort-option,
.sort-option {
    border-radius: var(--g-r-sm);
    padding: 9px 10px !important;
    transition: background-color var(--g-fast) var(--g-ease),
                color var(--g-fast) var(--g-ease);
}
.sb-sort-option:hover,
.sort-option:hover { background: var(--g-brand-soft); }

.sb-chip,
.f-chip { border-radius: var(--g-r-pill) !important; }

/* Breadcrumb + page heading */
.collection-breadcrumb a { color: var(--g-ink-3); transition: color var(--g-fast) var(--g-ease); }
.collection-breadcrumb a:hover { color: var(--g-brand); }

.collection-title,
.collection-heading h1,
h1.collection-title {
    font-weight: 700;
    letter-spacing: -.02em;
    text-transform: none !important;
    color: var(--g-ink);
}

/* The mobile SORT / FILTER bar. z-index 999 here vs 8 on the bottom nav is what
   buried search, account and cart on every collection page once before — keep
   it below the bar. */
.mobile-filter-bar,
.collection-mobile-bar { z-index: 7 !important; }

/* ---- product page: the last off-brand colours ---------------------------- */
/* style.css:57455 paints .bottom .bottom_btn:first-child #32589C — a primary
   BLUE, on a site whose palette is magenta and orange. It is the only blue
   surface anywhere. */
.bottom .bottom_btn:first-child {
    background-color: var(--g-ink) !important;
    color: #fff !important;
}

/* The theme's pre-brand orange (#EC8951) still tints the hamburger and a
   heading here. The real accent is #F67E00. */
.sidebar-bar,
.product-page-details h3 { color: var(--g-accent) !important; }

/* Semantic colours stay as they are on purpose: green for in-stock, amber for
   rating stars, red for validation errors. Those are meanings, not branding,
   and recolouring them to the brand would cost more than it gains. */

/* ---- collection page banner ---------------------------------------------- */
.g-collection-banner {
    position: relative;
    margin: 4px 0 18px;
    border-radius: var(--g-r-lg);
    overflow: hidden;
    isolation: isolate;
    background: linear-gradient(145deg, var(--g-brand) 0%, var(--g-brand-deep) 60%, #5E1230 100%);
    box-shadow: var(--g-shadow-sm);
    aspect-ratio: 1774 / 420;
}

/* ⚠️ POSITIVE z-index, deliberately. At z-index:-2 the photograph painted
   BEHIND this element's own gradient background and only the gradient showed —
   the image was loaded, sized and visible, and still invisible. Verified live
   by flipping it to 0. Layering here is explicit: image 0, scrim 1, copy 2. */
.g-collection-banner img {
    position: absolute;
    inset: 0;
    z-index: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center 62%;   /* the artwork's subject sits low-right */
}

/* Left-weighted, same reasoning as the hero: these photographs are cream, so a
   flat overlay would grey the whole thing out. */
.g-collection-banner::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 1;
    background: linear-gradient(100deg,
        rgba(247,241,234,.80) 0%, rgba(247,241,234,.52) 30%,
        rgba(247,241,234,.12) 52%, rgba(247,241,234,0) 68%);
}

.g-collection-banner-body {
    position: absolute;
    inset: 0;
    z-index: 2;
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding: 0 30px;
}

.g-collection-banner-title {
    margin: 0;
    color: var(--g-ink);
    font-size: clamp(19px, 2.2vw, 30px);
    font-weight: 700;
    letter-spacing: -.02em;
    line-height: 1.12;
}

.g-collection-banner-sub {
    margin: 6px 0 0;
    color: var(--g-ink-2);
    font-size: 13px;
}

@media (max-width: 767px) {
    .g-collection-banner { aspect-ratio: 1774 / 620; border-radius: var(--g-r-md); }
    .g-collection-banner-body { padding: 0 18px; }
    .g-collection-banner-sub { font-size: 12px; }
}

/* ============================================================================
   Policy and information pages
   ----------------------------------------------------------------------------
   Long-form reading, so the measure is capped and the type is a size up from
   the storefront's. These pages exist because Razorpay's merchant terms require
   them, but they are also the only place on the site that answers "what happens
   if this goes wrong", so they are built to be read rather than to be ticked
   off a list.
   ========================================================================== */
.g-page {
    max-width: 760px;
    margin: 0 auto;
    padding: 28px 20px 72px;
}

.g-page-kicker {
    display: inline-block;
    font-size: 12px;
    font-weight: 600;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--g-brand);
    background: var(--g-brand-soft);
    border-radius: var(--g-r-pill);
    padding: 5px 12px;
    margin-bottom: 14px;
}

.g-page h1 {
    font-size: clamp(26px, 3.4vw, 38px);
    font-weight: 700;
    letter-spacing: -.02em;
    line-height: 1.15;
    /* The theme uppercases h1. The headings here are sentences. */
    text-transform: none;
    margin: 0 0 8px;
}

.g-page-updated {
    font-size: 13px;
    color: var(--g-ink-3, #7a7069);
    margin: 0 0 28px;
}

.g-page h2 {
    font-size: 19px;
    font-weight: 700;
    text-transform: none;
    letter-spacing: -.01em;
    margin: 34px 0 10px;
}

.g-page h3 {
    font-size: 15px;
    font-weight: 700;
    text-transform: none;
    margin: 22px 0 6px;
}

.g-page p,
.g-page li {
    font-size: 15px;
    line-height: 1.7;
    color: var(--g-ink-2, #4a423d);
}

.g-page p { margin: 0 0 14px; }
.g-page ul { margin: 0 0 16px; padding-left: 22px; }
.g-page li { margin-bottom: 7px; }

.g-page a {
    color: var(--g-brand);
    text-decoration: underline;
    text-underline-offset: 2px;
}

/* A fact the reader is most likely to have come for. */
.g-page-key {
    background: var(--g-brand-soft);
    border-radius: var(--g-r-md);
    padding: 18px 20px;
    margin: 0 0 26px;
}
.g-page-key p:last-child { margin-bottom: 0; }
.g-page-key strong { color: var(--g-brand-deep); }

.g-page-contact {
    border: 1px solid var(--g-line);
    border-radius: var(--g-r-md);
    padding: 18px 20px;
    margin-top: 28px;
}
.g-page-contact p:last-child { margin-bottom: 0; }

/* ============================================================================
   Skeletons
   ----------------------------------------------------------------------------
   One shimmer, used everywhere something is on its way: product photographs,
   the cart drawer, live search. The shape of what is coming is drawn in grey so
   the layout does not jump when the real thing lands.

   Rules that matter:

   * The shimmer NEVER hides content that is already there. Every skeleton is
     either a placeholder element that gets replaced, or a background behind an
     image that covers it on arrival. If the JS fails, the page still works —
     the same principle as reveal.js.
   * It stops. An animation that runs forever on a failed image is a bug that
     looks like a feature; .is-loaded is set on load AND on error.
   * prefers-reduced-motion gets a flat tone, not a moving gradient.
   ========================================================================== */

@keyframes g-shimmer {
    0%   { background-position: -220% 0; }
    100% { background-position: 220% 0; }
}

/* `.is-near` is set by skeleton.js via an IntersectionObserver. Without it the
   shimmer is a plain grey box: an infinite animation on 50 off-screen cards is
   real work on a mid-range phone, and a lazy image below the fold has not even
   been requested yet, so there is nothing to animate the wait for. */
.g-skel,
.g-img-skel.is-near:not(.is-loaded)::before {
    background-color: #efeae6;
    background-image: linear-gradient(
        100deg,
        rgba(255, 255, 255, 0) 28%,
        rgba(255, 255, 255, .72) 48%,
        rgba(255, 255, 255, 0) 68%
    );
    background-size: 220% 100%;
    background-repeat: no-repeat;
    animation: g-shimmer 1.35s linear infinite;
}

/* ---- images -------------------------------------------------------------- */
/* The shimmer sits BEHIND the photo rather than over it, so a slow image fades
   in over a moving placeholder instead of being covered by one. */
.g-img-skel { position: relative; }

.g-img-skel:not(.is-loaded)::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 0;
    border-radius: inherit;
    pointer-events: none;
}

/* ⚠️ The <picture> must NOT be positioned. This rule used to include it, and
   that is what made the owner's category pages look like permanent skeletons.
   ----------------------------------------------------------------------------
   The card markup is  .img-wrapper > picture > img , and the card's own rule is
   `.basic-product .img-wrapper img { position: absolute; inset: 0; height: 100% }`.

   Giving <picture> `position: relative` made IT the containing block for that
   absolute image instead of .img-wrapper. A <picture> whose only child is
   absolutely positioned has no content, so it is zero pixels tall — and
   `height: 100%` of zero is zero.

   Measured on Festive & Gifting: 13 of 13 photos at 126x0. Fully loaded,
   `complete: true`, `naturalWidth: 600`, `opacity: 1` — and invisible. The card
   showed its grey placeholder background and nothing else, which is
   indistinguishable from a skeleton that never resolves.

   Proven by live A/B: setting the <picture> back to `static` returned the image
   to 126x126 in the same frame.

   The <img> alone carries the z-index. In a card it is already absolutely
   positioned so `position: relative` here loses to the card's own rule and only
   the z-index applies; in the product gallery the image is in normal flow, so
   the relative positioning is what lifts it above the shimmer. */
.g-img-skel img { position: relative; z-index: 1; }

/* ⚠️ THE IMAGE IS NEVER HIDDEN. Do not add `opacity: 0` here again.
   ----------------------------------------------------------------------------
   The first version of this faded the photo in: `opacity: 0` until JS added
   `.is-loaded`. It was scoped to `html.g-skel-ready` so a missing script could
   not hide anything, and that guard was not enough — because the script loads
   fine and it is the IMAGE that never arrives.

   Measured on a live collection page: 6 of 50 photos sat at
   `complete: false, naturalWidth: 0, loading: "lazy"`. The browser had simply
   never fetched them, so `load` never fired, so `.is-loaded` was never added,
   so those six products were INVISIBLE — permanently, however long you waited.
   That is the bug the owner reported as "none of the images load, it's just
   skeletons".

   The shimmer works without hiding anything: it sits BEHIND the photo (z-index
   0 against 1), so an opaque photo covers it the moment it paints. JS only
   stops the animation. Nothing this stylesheet does can take a product
   photograph off the page. */

/* ---- generic blocks ------------------------------------------------------ */
.g-skel { border-radius: var(--g-r-sm); display: block; }
.g-skel-line { height: 11px; margin-bottom: 8px; border-radius: 6px; }
.g-skel-line:last-child { margin-bottom: 0; }
.g-skel-line--sm { height: 9px; width: 55%; }
.g-skel-line--lg { height: 14px; }
.g-skel-thumb { width: 54px; height: 54px; border-radius: var(--g-r-sm); flex: none; }

/* ---- cart drawer --------------------------------------------------------- */
.g-skel-cart-row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 0;
    border-bottom: 1px solid var(--g-line);
}
.g-skel-cart-row .g-skel-body { flex: 1; min-width: 0; }

/* ---- live search --------------------------------------------------------- */
.g-skel-search { padding: 10px 12px; }
.g-skel-search-row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 9px 0;
}
.g-skel-search-row .g-skel-thumb { width: 44px; height: 44px; }
.g-skel-search-row .g-skel-body { flex: 1; min-width: 0; }

@media (prefers-reduced-motion: reduce) {
    .g-skel,
    .g-img-skel.is-near:not(.is-loaded)::before {
        animation: none;
        background-image: none;
    }
}

/* ============================================================================
   The search field's two clear buttons
   ----------------------------------------------------------------------------
   Typing in the header search produced TWO crosses and a stray mark outside the
   pill:

   1. `<input type="search">` draws WebKit's own ::-webkit-search-cancel-button.
   2. master.blade.php injects `<span class="clear-search">` as a SIBLING of the
      input and toggles it on input.

   The injected span had no styling at all, so it sat `position: static` in the
   flex row AFTER the field — measured at x=838 against an input ending at 838,
   i.e. just outside the rounded pill, overlapping the form's own padding.

   The theme's span is the one to keep: it is wired to JS that clears the field
   and hides the live-results panel. The native button is switched off.
   ========================================================================== */

.g-hd-search .nav-search::-webkit-search-cancel-button,
.g-hd-search .nav-search::-webkit-search-decoration,
#searchModal input[type="search"]::-webkit-search-cancel-button,
#searchModal input[type="search"]::-webkit-search-decoration {
    -webkit-appearance: none;
    appearance: none;
    display: none;
}

/* Sits inside the pill, vertically centred, on the same muted ink as the
   search icon on the other side. */
/* ⚠️ overflow: visible is load-bearing — the type-ahead panel hangs out of this
   form. The theme's `.form_search` sets `overflow: hidden` (style.css), and the
   form is 45px tall, so a 420px dropdown at y=116 was clipped to nothing.
   Measured: the panel was in the DOM, not hidden, opacity 1, 230x420, with nine
   children — and elementFromPoint at its centre returned the hero behind it.

   Seventh bug in this family. I wrote the warning above this one about the
   header CARD and checked that; the form between them clips too. When a popover
   escapes its parent, check EVERY ancestor up to the stacking context, not the
   one you happen to suspect. */
.g-hd-search { position: relative; overflow: visible; }

.g-hd-search .clear-search {
    position: absolute;
    right: 12px;
    top: 50%;
    transform: translateY(-50%);
    display: none;              /* the JS toggles this to block when there is text */
    width: 22px;
    height: 22px;
    line-height: 22px;
    text-align: center;
    border-radius: 50%;
    cursor: pointer;
    color: var(--g-ink-3, #8A8079);
    font-size: 15px;
    transition: background-color var(--g-fast) var(--g-ease),
                color var(--g-fast) var(--g-ease);
}

.g-hd-search .clear-search:hover {
    background: rgba(36, 28, 23, .07);
    color: var(--g-ink, #241C17);
}

/* Room for it, so a long term does not run underneath. */
.g-hd-search .nav-search { padding-right: 38px; }

/* ============================================================================
   The product gallery holds ONE shape
   ----------------------------------------------------------------------------
   Each slide's image was `width: 100%; height: auto` with the default
   `object-fit: fill`, so its height came from that photograph's own aspect
   ratio. Measured on a live product: 460x537 from a 600x700 original.

   Two consequences, both of which the owner hit:

   * The gallery changed height when you moved between thumbnails, because this
     shop's photos are not a consistent shape — 600x700 next to a square collage
     next to a 4:5. Clicking a thumbnail resized the whole left column.
   * Nothing capped it, so a tall photo made a tall gallery.

   A square box fixes the frame, matching the product cards and the rest of the
   grid. `object-fit: contain` rather than `cover`: this is the view where the
   customer is deciding what to buy, so nothing may be cropped out of it — and
   with a ratio now imposed, the default `fill` would stretch the product.
   ========================================================================== */

.product-slick .slick-slide img,
.product-slick > div img {
    width: 100%;
    height: auto;
    aspect-ratio: 1 / 1;
    object-fit: contain;
    background: var(--g-surface-2, #FAF7F4);
    border-radius: var(--g-r-md);
}

/* The thumbnail strip follows the same shape, so the strip cannot jump either. */
.slider-nav .thumb-cell img {
    width: 100%;
    height: auto;
    aspect-ratio: 1 / 1;
    object-fit: contain;
    background: var(--g-surface-2, #FAF7F4);
}

/* ============================================================================
   Search type-ahead
   ----------------------------------------------------------------------------
   The panel hangs off the search form, which is why .g-hd-search is
   position: relative (set with the clear button above).

   ⚠️ It must NOT be clipped. The header card is `overflow: visible` for exactly
   this reason — the same trap that hid every navigation dropdown. If anything
   in the header ever gets `overflow: hidden` again, this panel disappears with
   the menus, silently, at HTTP 200.
   ========================================================================== */

.g-ac {
    position: absolute;
    top: calc(100% + 8px);
    /* Anchored to the field's right edge and allowed to grow LEFTWARDS over the
       nav. Matching the input's width put the names in a 147px column, so every
       suggestion wrapped to two lines and still truncated — these product names
       run to 110 characters. The max-width keeps it on screen at any width. */
    left: auto;
    right: 0;
    width: 380px;
    max-width: calc(100vw - 32px);
    z-index: 70;
    max-height: min(420px, 70vh);
    overflow-y: auto;
    overscroll-behavior: contain;
    background: #fff;
    border-radius: var(--g-r-md);
    box-shadow:
        inset 0 0 0 1px rgba(36, 28, 23, .07),
        0 14px 40px rgba(36, 28, 23, .16);
    padding: 6px;
}

.g-ac[hidden] { display: none; }

.g-ac-item {
    display: flex;
    align-items: center;
    gap: 11px;
    padding: 8px 9px;
    border-radius: var(--g-r-sm);
    text-decoration: none;
    color: var(--g-ink, #241C17);
}

/* Hover and keyboard share one state, so arrowing down looks the same as
   pointing at a row. */
.g-ac-item.is-active,
.g-ac-item:hover { background: var(--g-brand-soft, #FCEFF4); }

.g-ac-thumb {
    width: 42px;
    height: 42px;
    flex: none;
    border-radius: 8px;
    object-fit: cover;
    background: var(--g-surface-2, #FAF7F4);
}

.g-ac-text { min-width: 0; display: flex; flex-direction: column; gap: 2px; }

.g-ac-name {
    font-size: 13.5px;
    line-height: 1.3;
    /* Two lines: these product names run to 110 characters. */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.g-ac-name mark {
    background: none;
    color: var(--g-brand, #B62C5F);
    font-weight: 700;
    padding: 0;
}

.g-ac-price { font-size: 12.5px; font-weight: 700; color: var(--g-ink-2, #4a423d); }

.g-ac-all {
    display: block;
    margin-top: 4px;
    padding: 10px 9px;
    border-top: 1px solid var(--g-line, #f0f0f0);
    font-size: 12.5px;
    font-weight: 600;
    color: var(--g-brand, #B62C5F);
    text-decoration: none;
    border-radius: var(--g-r-sm);
}
.g-ac-all:hover { background: var(--g-brand-soft, #FCEFF4); }

.g-ac-empty {
    padding: 18px 12px 20px;
    text-align: center;
}
.g-ac-empty strong { display: block; font-size: 14px; color: var(--g-ink, #241C17); }
.g-ac-empty span {
    display: block;
    margin-top: 4px;
    font-size: 12.5px;
    color: var(--g-ink-3, #8A8079);
}

/* The search modal sat at Bootstrap's 1055 while the fixed header is 9999,
   so on a phone the header covered the top of the search field. The cart
   offcanvas already sits at 10000 for the same reason. */
#searchModal { z-index: 10001; }
body:has(#searchModal.show) > .modal-backdrop { z-index: 10000; }

/* Cart drawer: product names were one line with an ellipsis, so most read
   "Fashion Cross Bling M…". Two lines, then clip. Same selector as the
   theme's rule (style.css) so it wins on load order, not on !important. */
.offcanvas.cart-offcanvas .offcanvas-body .cart-product .media .media-body a h4 {
    white-space: normal;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

/* Signed-out "Check Out" opens the sign-in box alongside the cart drawer.
   The drawer was raised to 10000 to clear the 9999 header; the sign-in box
   stayed at Bootstrap's 1055, so it opened BEHIND the drawer and the button
   appeared to do nothing -- for every first-time buyer. */
#loginpopup { z-index: 10002; }
body:has(#loginpopup.show) > .modal-backdrop { z-index: 10001; }

/* Empty-cart "Continue Shopping" was Bootstrap's default blue. */
.cart-offcanvas .btn-primary {
    --bs-btn-bg: var(--g-brand);
    --bs-btn-border-color: var(--g-brand);
    --bs-btn-hover-bg: var(--g-brand-deep);
    --bs-btn-hover-border-color: var(--g-brand-deep);
    --bs-btn-active-bg: var(--g-brand-deep);
    --bs-btn-active-border-color: var(--g-brand-deep);
}

/* Product names in two lines everywhere, not just on collection pages.
   The rule lived in partials/products.blade.php, which only collection
   pages include, so homepage cards kept the theme's one-line nowrap
   ("Gold-Tone Heart …"). min-height keeps a row's cards level. */
.basic-product .product-title {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    white-space: normal;
    overflow: hidden;
    line-height: 1.3;
    min-height: 2.6em;
}

/* The whole card is the link -- also lifted out of partials/products.blade.php,
   which only collection pages include. Homepage and related-product cards had
   only their photo and name clickable. Checked first: on every page these
   cards hold no control other than those two links (same product), so the
   overlay covers nothing. The card is already position: relative. */
.basic-product .product-title::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 1;
}

/* ---- pagination (partials/pagination.blade.php) ------------------------- */
.g-pager {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 14px;
    margin: 36px 0 52px;
}
.g-pager-count { margin: 0; font-size: 13px; color: var(--g-ink-3); }
.g-pager-row { display: flex; align-items: center; gap: 12px; }

.g-pager-pages {
    display: flex;
    align-items: center;
    gap: 2px;
    margin: 0;
    padding: 4px;
    list-style: none;
    background: var(--g-surface);
    border: 1px solid var(--g-line);
    border-radius: var(--g-r-pill);
    box-shadow: var(--g-shadow-sm);
}
.g-pager-num,
.g-pager-gap {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 38px;
    height: 38px;
    padding: 0 6px;
    border-radius: var(--g-r-pill);
    font-size: 14px;
    font-weight: 600;
    color: var(--g-ink-2);
    text-decoration: none;
}
.g-pager-gap { min-width: 22px; color: var(--g-ink-3); }
a.g-pager-num {
    transition: background-color var(--g-fast) var(--g-ease),
                color var(--g-fast) var(--g-ease);
}
a.g-pager-num:hover { background: var(--g-brand-soft); color: var(--g-brand-deep); }
.g-pager-num.is-current {
    background: var(--g-brand);
    color: #fff;
    box-shadow: 0 4px 12px rgba(182, 44, 95, .28);
}

.g-pager-step {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    height: 48px;
    padding: 0 18px 0 12px;
    background: var(--g-surface);
    border: 1px solid var(--g-line);
    border-radius: var(--g-r-pill);
    box-shadow: var(--g-shadow-sm);
    font-size: 14px;
    font-weight: 600;
    color: var(--g-ink);
    text-decoration: none;
    transition: border-color var(--g-fast) var(--g-ease),
                color var(--g-fast) var(--g-ease),
                box-shadow var(--g-fast) var(--g-ease);
}
.g-pager-step--next { padding: 0 12px 0 18px; }
.g-pager-step i { font-size: 20px; line-height: 1; }
a.g-pager-step:hover {
    border-color: var(--g-brand);
    color: var(--g-brand-deep);
    box-shadow: var(--g-shadow-md);
}
.g-pager-step.is-off { visibility: hidden; }

.g-pager-of { display: none; font-size: 14px; font-weight: 600; color: var(--g-ink-2); }

@media (max-width: 575px) {
    .g-pager-row { width: 100%; justify-content: space-between; }
    .g-pager-pages { display: none; }
    .g-pager-of { display: inline; }
}
