/* ─────────────────────────────────────────────────────────────────────────────
   Product-grid loading skeleton (T-3494 follow-on).

   Covers the product column while an enhanced navigation to another category or
   subcategory is in flight. It is NOT decoration: until the response lands, the
   nav has already moved (order-enhanced-nav.js applies the selection, the
   subcategory bar and the hero banner AT CLICK TIME) while #divProducts still
   holds the PREVIOUS category's cards — so for the length of the round trip the
   page shows a category heading and a product set that disagree.

   Timing lives in order-enhanced-nav.js (delay before showing, minimum hold);
   this file only describes the two states. See that file for why an
   always-instant skeleton would be worse than none.

   ── GEOMETRY IS SET BY JS, AND THAT IS NOT LAZINESS ──────────────────────────
   top/left/width are written by order-enhanced-nav.js and deliberately NOT fixed
   insets here. Traced on the running app, one category click while scrolled to
   1500px:

     t231  y=1500  #divProducts top = -1057
     t431  y=840   #divProducts top =  -397
     t631  y=141   #divProducts top =   302
     t933  y=0     #divProducts top =   443   (settled)

   Blazor calls window.scrollTo(0, 0) at navigation START (verified by wrapping it:
   the caller is blazor.web.js), and Bootstrap's `scroll-behavior: smooth` turns
   that into a ~500-600ms animation — which lands INSIDE the very window this
   skeleton covers. So the grid's viewport position is a moving target for most of
   the wait, and any constant top would cover the wrong band: too low at the start,
   or over the category bar and hero banner at the end. The JS recomputes it from
   #divProducts on every scroll frame while visible.

   The same call derives left/width from #divProducts rather than hard-coding the
   basket's 333px — measured, the products column is 0-947 at 1280px and full
   width at 390px, and reading the element gets both right at every width in
   between with no breakpoint to keep in step with the layout contract.

   `position: fixed` is what makes tracking possible at all: the visitor is looking
   at the viewport, not at the document, for the whole scroll animation.

   z-index 2 keeps it above the grid (.divMerchandise is z-auto) and below every
   piece of chrome it must not cover: #sidebar (3 desktop / 1200 mobile), .navbar
   (1030), the flyout navs (2000) and the postcode modal.
   ───────────────────────────────────────────────────────────────────────────── */

/* Hidden is the DEFAULT and the server never renders it visible: this is a
   client-side affordance for an in-page navigation, and a cold load has nothing
   to cover. The `is-visible` class is added and removed only by
   order-enhanced-nav.js. */
.bee-grid-skeleton {
    display: none;
}

.bee-grid-skeleton.is-visible {
    display: block;
    position: fixed;
    /* top / left / width come from the JS above. bottom:0 is the one edge that is
       always the viewport's. */
    bottom: 0;
    z-index: 2;
    /* Opaque, and this exact value matters: it is the measured page background
       (body -> rgb(247, 247, 247)). #divProducts and .main-content-products are
       both transparent, so anything less than opaque here leaves the stale grid
       showing through — which is the thing being hidden. */
    background-color: #f7f7f7;
    overflow: hidden;
    /* .divCategory's own padding, so the skeleton's columns line up with the
       real grid's rather than shifting sideways when the content lands. */
    padding: 0 10px;
}

/* The category heading block (.category-header-container is 34px tall with
   margin 25px 5px 15px on desktop — matched so the real heading appears where
   the placeholder was). */
.bee-grid-skeleton__head {
    height: 34px;
    width: min(260px, 60%);
    margin: 25px 5px 15px 5px;
    border-radius: 8px;
}

/* The real grid is .product_container (flex, wrap) with cards that measure
   ~153x328 at 1280px and ~111x285 at 360px — 6 and 3 per row respectively.
   auto-fill with a 150px minimum reproduces that rhythm at every width in
   between without hard-coding a column count. */
.bee-grid-skeleton__cards {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    gap: 2px;
}

@media (max-width: 500px) {
    /* Measured: at 360px the real grid packs 3 cards per row at 111px each,
       which is narrower than the 150px minimum above would allow. */
    .bee-grid-skeleton__cards {
        grid-template-columns: repeat(3, 1fr);
    }
}

.bee-grid-skeleton__card {
    height: 328px;
    padding: 12px;
    /* The card's own silhouette: .product_box_Small is white with
       border-radius 20px 20px 0 0. */
    background-color: #fff;
    border-radius: 20px 20px 0 0;
}

@media (max-width: 500px) {
    .bee-grid-skeleton__card {
        height: 285px;
    }
}

.bee-grid-skeleton__thumb {
    display: block;
    height: 60%;
    border-radius: 12px;
}

.bee-grid-skeleton__line {
    display: block;
    height: 14px;
    margin-top: 12px;
    border-radius: 7px;
}

.bee-grid-skeleton__line--short {
    width: 50%;
}

/* ── The shimmer: one highlight band travelling across every grey block ───────
   The familiar skeleton "wave" — a soft white highlight sweeping left to right,
   repeating.

   ⚠️ THIS REPLACES A SHIMMER THAT RAN AND COULD NOT BE SEEN, which is worth
   recording because "it isn't animating" was the wrong diagnosis. The previous
   version animated `background-position` across
   `linear-gradient(90deg, #ececec 25%, #f5f5f5 37%, #ececec 63%)` at
   `background-size: 400%`. Measured in a browser: 55 animations running,
   background-position sweeping 95.2% -> 6.5% over ~0.9s, and two frames of the
   same block differing at the pixel level. It was live the whole time. The defect
   was CONTRAST and BAND WIDTH: #f5f5f5 over #ececec is 9/255 (~3.5%) of
   luminance, and a band stretched to 4x the element's width means any one block
   only ever shows a shallow slice of that already-shallow ramp. It read as a flat
   grey box.

   So the fix is not "add an animation" — it is a visible highlight (white at 0.85
   alpha over a slightly darker #e3e3e3 base, ~11% luminance at the peak) in a
   band narrower than the element, so a bright edge actually crosses it.

   Driven by `transform` on a pseudo-element rather than by `background-position`:
   transforms are composited, and this runs on up to 55 blocks at once (18 cards x
   3 blocks + the heading). Same reason MUI's Skeleton "wave" is built this way.
   ───────────────────────────────────────────────────────────────────────────── */
.bee-grid-skeleton__head,
.bee-grid-skeleton__thumb,
.bee-grid-skeleton__line {
    position: relative;
    /* The band is clipped to its own block, so each placeholder lights up in turn
       rather than a single bar sliding over the whole panel. */
    overflow: hidden;
    background-color: #e3e3e3;
}

.bee-grid-skeleton__head::after,
.bee-grid-skeleton__thumb::after,
.bee-grid-skeleton__line::after {
    content: "";
    position: absolute;
    inset: 0;
    background-image: linear-gradient(
        90deg,
        rgba(255, 255, 255, 0) 0,
        rgba(255, 255, 255, 0.85) 50%,
        rgba(255, 255, 255, 0) 100%
    );
    animation: bee-grid-skeleton-wave 1.1s linear infinite;
}

/* ⚠️ THE TRAVEL IS ±70%, NOT ±100%, AND THE DIFFERENCE IS THE WHOLE EFFECT.
   The band is the block's own width, so its bright centre only lights the block
   while the transform is roughly within ±50%. Sweeping the full ±100% (or, worse,
   a 150%-wide band across 250% as the first attempt did) parks the highlight OFF
   the block for much of the cycle, and the placeholder sits there as flat grey.

   Measured, four configurations through one instrument — sampling a card's image
   block every 70ms for ~1.7s and taking the luminance spread across its middle
   row (a spread >= 8/255 counts as "you can see a band"):

     150% band, 0 -> 250%, 1.6s ease-in-out   peak 22  median  4   9/24 frames (38%)
     100% band, -100% -> 100%, 1.2s linear    peak 24  median 24  20/24 frames (83%)
     100% band,  -70% ->  70%, 1.1s linear    peak 24  median 24  24/24 frames (100%)
      60% band, 0 -> 266%, 1.1s linear        peak 24  median 24  21/24 frames (88%)

   All four peak at the same brightness; they differ entirely in how much of the
   time anything is happening. That matters here more than on a typical skeleton
   because this one is only on screen for ~300-500ms (see order-enhanced-nav.js) —
   a 38% duty cycle means a large share of visitors would see one static grey
   frame and no shimmer at all. Linear, not ease-in-out, for the same reason: an
   eased sweep spends its time at the ends, which are the parts that are off the
   block. */
@keyframes bee-grid-skeleton-wave {
    0% {
        transform: translateX(-70%);
    }

    100% {
        transform: translateX(70%);
    }
}

/* A skeleton is a waiting indicator, and the WAIT is the information — not the
   movement. With reduced motion the blocks stay, the sweep goes. */
@media (prefers-reduced-motion: reduce) {
    .bee-grid-skeleton__head::after,
    .bee-grid-skeleton__thumb::after,
    .bee-grid-skeleton__line::after {
        display: none;
    }
}
