/* product_grid.css
 * Styling for product_grid.php's card grid. Swatch appearance itself
 * (round + rectangular, all states) comes from the shared swatch.css —
 * this file just sets the smaller icon size for cards, plus everything
 * specific to the card layout (image, title, price, promo, CTA).
 */

*{margin:0;padding:0;box-sizing:border-box}
html, body{overscroll-behavior:none;}
body{font-family:'Ubuntu',Arial,sans-serif;background:var(--page-bg, #f8f9fa);color:var(--text-dark, #222);}

/* --swatch-size is injected inline by product_grid.php from
   GRID_SWATCH_ICON_SIZE, not hardcoded here — see that file's <style> block. */

.grid-page{max-width:1920px;margin:0 auto;padding:24px}

.grid-toolbar{margin-bottom:20px;max-width:400px}
#filterInput{
    width:100%;
    padding:10px 12px;
    border:1px solid var(--border-grey, #d1d5db);
    border-radius:6px;
    font-size:14px;
    font-family:inherit;
}
#filterInput:focus{outline:none;border-color:var(--brand-red, #DC1F1D)}

.no-results{padding:40px;text-align:center;color:#888;font-size:15px}

/* 6 across at ~1920px (each card ~300px in a max-width:1920px, 24px-
   padded, 20px-gapped grid), responsive down from there. */
.product-grid-container{
    display:grid;
    grid-template-columns:repeat(6, 1fr);
    gap:30px;
}
@media (max-width:1600px){ .product-grid-container{grid-template-columns:repeat(4, 1fr)} }
@media (max-width:1100px){ .product-grid-container{grid-template-columns:repeat(3, 1fr)} }
@media (max-width:768px){  .product-grid-container{grid-template-columns:repeat(2, 1fr)} }
@media (max-width:480px){  .product-grid-container{grid-template-columns:1fr} }

.product-card{
    background:#fff;
    box-shadow: 0 2px 8px rgba(0,0,0,0.15);
    border-radius:10px;
    padding:8px 16px 16px 16px;
    display:flex;
    flex-direction:column;
    position:relative;
    min-width:0; /* lets swatches shrink below their content width instead of overflowing the card */
}
/* No `gap` here any more (2026-08-26 — was gap:10px). It silently added
   10px between EVERY pair of children on top of whatever margin that
   child ALSO had, so every individual gap value in this file had to be
   read as "10 + this margin", not the plain number sitting in front of
   you — genuinely hard to find/trust when you're trying to adjust one
   specific gap (reported: "I'm struggling"). Every gap below is now a
   single, direct, honest margin-top value — what you see is the total
   gap, full stop. The one exception is .promo-badge's own margin-top:
   auto, which was never a fixed gap to begin with — see its own comment
   for why, and .card-swatches' new margin-bottom just below for how to
   actually adjust space before it now. */

.card-image-wrap{
    position:relative;
}
.card-image-link{display:block}
.card-image{
    width:100%;
    aspect-ratio:1/1;
    object-fit:contain;
    background:var(--image-placeholder-bg, #f0f0f0);
    border-radius:6px;
    display:block;
}

.card-title{
    font-size:16px;
    font-weight:600;
    line-height:1.3;
    display:-webkit-box;
    -webkit-line-clamp:3;
    -webkit-box-orient:vertical;
    overflow:hidden;
    margin-top:10px; /* was the implicit parent gap:10px — same total, now explicit here */
}
/* No min-height here (2026-08-26 — was min-height:3.9em, always
   reserving 3 lines' worth of space, even in a row where every title
   actually fit in 1 or 2). -webkit-line-clamp:3 above still CAPS a
   genuinely long title at 3 lines max — it just no longer forces every
   shorter title to pretend to be that tall. .product-grid-container has
   no align-items override, so its default (stretch) already matches
   every card in a row to that row's tallest ACTUAL card — that's what
   keeps a row's cards visually aligned without this min-height doing it
   artificially for every row regardless of what that row needs. */
.card-title a{color:inherit;text-decoration:none}
.card-title a:hover{color:var(--brand-red, #DC1F1D)}

/* Flex column so `gap` provides consistent spacing BETWEEN each group's
   own box, regardless of how many groups there are (the value to change
   for "space between groups" is this gap). */
.card-swatches{
    display:flex;
    flex-direction:column;
    gap:4px;
    margin-top:10px;    /* was the implicit parent gap:10px — same total, now explicit here */
    margin-bottom:15px; /* was ALSO the implicit parent gap:10px, the fixed portion of the swatches→promo-badge space — the REST of that gap (which varies per card) still comes from .promo-badge's own margin-top:auto, unchanged; this is the one part of it you CAN safely tune directly. Raise/lower this to adjust JUST the swatches→promo-badge gap without touching promo-badge's margin-top at all — that property has to stay "auto" for the bottom-anchoring to keep working (see .promo-badge's own comment). */
}
/* margin-top/bottom reserve blank strips above/below the swatch row (the
   "+N more" link floats into the top one); justify-content left-aligns
   every group's row horizontally (2026-08-25: was centred).
   Text and round swatches get DIFFERENT gaps (2026-08-25 feedback: the
   round colour/image swatches' gap needed reducing, but the text
   swatches' own gap already looked right and shouldn't move) — scoped
   via data-swatch-type, set by renderAttributeGroup() in
   product_functions.php. capOneGroup() in product_grid.js reads the
   real computed gap rather than a hardcoded number, so it stays correct
   for both. */
.card-swatches .swatch-container{margin-top:4px;margin-bottom:4px;justify-content:flex-start;}
.card-swatches .swatch-container[data-swatch-type="text"]{gap:8px;}
.card-swatches .swatch-container[data-swatch-type="round"]{gap:5px;}

/* A single-attribute-group card gets the SAME total vertical space a
   two-group card's pair of rows would occupy, rather than leaving that
   second "slot" empty below a short single row — lets flex:1 claim
   whatever leftover height the grid's row-stretching gives this card. */
.card-swatches[data-group-count="1"]{
    flex:1;
    justify-content:flex-start;
}

.swatch-group-wrapper{position:relative;}

/* The "+N more" link is moved inside .swatch-container as a real flex
   item by capOneGroup() in product_grid.js — position:static lets it
   flow with the swatches (row-wrapping, centring); align-self:center
   keeps it vertically centred against the row's height. */
.swatch-container .more-options-link{
    position:static;
    align-self:center;
}

/* Styled as a BUTTON now (2026-08-26 — was a plain underlined text
   link), matching the bordered/rounded look of the swatches it sits
   among rather than reading as a stray hyperlink. Height matches its
   row's own swatch height (--swatch-size for a round-swatch group,
   --swatch-text-height for a text-swatch group — see the override just
   below for the latter) so it lines up neatly; WIDTH is deliberately
   left to size naturally from its own text + padding, since "+12 more"
   and "+3 more" don't need to match any swatch's width, just the row's
   height. Blue text (not black) and no border-radius-matching-fill is
   what still marks it as an action rather than another swatch. */
.more-options-link{
    display:inline-flex;
    align-items:center;
    justify-content:center;
    height:var(--swatch-size, 30px);
    padding:2px 3px;
    box-sizing:border-box;
    border:var(--swatch-border-width) solid #ccc;
    border-radius:var(--swatch-corner-radius);
    background:#fff;
    font-size:13px;
    /*font-weight:500;*/
    color:#000;
    text-decoration:none;
    white-space:nowrap;
    cursor:pointer;
    transition:background .15s;
}
.more-options-link:hover{background:#f5f5f5}
/* Inside a text-swatch group, match THAT group's own (usually shorter)
   height instead of the round-swatch default above. */
.swatch-container[data-swatch-type="text"] .more-options-link{
    height:var(--swatch-text-height, var(--swatch-size, 30px));
}

/* Attribute label ("Size", "Colour", "Bag Size"...) above each icon
   group — brought back 2026-08-25 so a 2-group card's groups read as
   distinct without needing the drop-shadow box that used to separate
   them (see the removed .swatch-group-wrapper:nth-of-type(2) rule this
   replaced). Deliberately understated (small, mid-grey) — tweak here,
   not in product_page.css, which has its own bigger/bolder version for
   the full product page. */
.attribute-group{margin-bottom:2px}
.attribute-label{
    display:block;
    font-size:13px;
    font-weight:400;
    color:#777;
    margin-bottom:6px;
    text-transform:uppercase;
    letter-spacing:.3px;
}
.selected-value{font-weight:400;color:#777;margin-left:3px;text-transform:none}

.promo-overlay{
    position:absolute;
    top:2px;
    left:8px;
    max-width:calc(100% - 16px);
    z-index:2;
}
/* Solid white "sticker" outline that HUGS the PNG's actual visible pixels
   (2026-08-25) — not the previous fading drop-shadow(0 0 5px ...) glow,
   and not a box-shadow either (box-shadow only ever traces the element's
   rectangular BOX, giving a square frame around a transparent PNG rather
   than following its real shape — see the box-shadow attempt this
   replaced).
   There's no native CSS property for "solid outline that follows a PNG's
   alpha shape" — the usual trick is stacking several drop-shadow()s, each
   with 0 blur, offset a small distance in a ring of directions around the
   image. Each one is an exact, hard-edged copy of the artwork's own
   silhouette shifted in one direction; enough directions layered together
   fill in solid, reading as a uniform white border that follows the
   image's real edges rather than its bounding box. 8 compass directions
   (with a 1px blur each, just to soften the seams between them) is a
   good balance of "solid-looking" vs. not overloading the browser with
   filter passes. The distance below (6px) is the border's thickness —
   change all 8 offsets together to adjust it. Ordered white-outermost so
   the original dark depth-shadow (last line) stays visually underneath
   the whole white-bordered result. */
.promo-overlay img{
    max-height:60px;
    max-width:120px;
    /* Heads up — found a bug while I was in here: a stray semicolon after
       the first drop-shadow() was ending the whole `filter` declaration
       right there, so the second (-3px) shadow was actually being
       dropped silently — only the +3px (right-side) shadow was ever
       applying. Removed the semicolon so both sides render; your 3px
       offset/3px blur values themselves are untouched. */
    filter:
        drop-shadow(3px 0 3px #fff)
        drop-shadow(-3px 0 3px #fff);
}

/* Promo TEXT badge — moved out of .promo-overlay (which now holds only
   the promo IMAGE, still top-left over the product photo) into its own
   row between the swatches and the price line. Always a single line now
   (see product_functions.php's renderPromoBadgeHtml()).
   align-self:flex-start (NOT the flex column's default stretch) makes
   the badge shrink to its own text width and sit left-aligned, rather
   than stretching the full card width with the text centred inside it.
   min-height + the .promo-line's own FIXED px line-height (not a
   unitless ratio — see the note on that rule below) mean this row is
   always the same height whether or not a given card actually has a
   promo — invisibleIf()/setVisibleKeepingSpace() in product_functions.php/
   product_swatches.js hide it with visibility:hidden rather than
   display:none for exactly this reason.
   margin-top:auto lives HERE (not on .card-price-row below) — this is
   the anchor that pushes the promo badge + everything after it (price
   range, then the price row) down to the card's bottom edge as ONE
   fixed unit, regardless of how much/little sits above it (a card with
   2 swatch groups vs. one with none) — 2026-08-25 follow-up: previously
   the auto margin was on .card-price-row itself, which pushed the price
   row to the bottom independently of the promo badge above it, so the
   gap between the two stretched or shrank depending on how tall the
   swatches/title happened to be on a given card. */
.promo-badge{
    display:flex;
    align-self:flex-start;
    align-items:center;
    justify-content:flex-start;
    min-height:20px;
    margin-top:auto;
    box-shadow:0 1px 3px rgba(0,0,0,0.25);
}
/* line-height is a FIXED px value, not a unitless ratio — a unitless
   value is recalculated per-element from that element's OWN font-size,
   so the enlarged .promo-number span inside this line (see
   PROMO_NUMBER_SCALE, injected inline by product_grid.php) would get a
   taller computed line-height than the surrounding text, inflating this
   row's height whenever a promo happens to contain a number. A fixed px
   value here is inherited by .promo-number as-is regardless of its own
   font-size, so the row's height stays constant either way. */
.promo-badge .promo-line{font-size:15px;font-weight:600;white-space:nowrap;margin:0;line-height:20px}

/* Small FIXED gap to the price row below — deliberately small, since the
   badge should sit close to the price it relates to. The old 20px
   padding-top (back when this row's own margin-top:auto did the bottom
   anchoring — see .promo-badge's own comment above) is gone; that's also
   why the old data-group-count="1" override right below used to exist
   (it doesn't any more, nothing left to override).
   2026-08-26: this is now a plain, direct total — .product-card no
   longer has its own `gap` (see that rule's own comment for why), so
   there's no hidden "+10" to account for any more. This value IS the
   gap, in full. */
.card-price-row{display:flex;flex-direction:column;margin-top:-1px}
/* Price line: was-price + the current/sale price sit on ONE line,
   bottom-justified (align-items:baseline) — was-price crossed out in
   black at half the sale price's font-size, sale price large and red,
   was-price positioned just before it (order in the markup). Unit price
   (equiv) and the price range keep their own existing formatting, just
   moved to their own line below (.price-meta-line) instead of sharing
   this one. */
.price-line{display:flex;align-items:baseline;gap:6px}
.was-price{font-size:22px;color:var(--text-dark, #222);text-decoration:line-through;}/*font-weight:500}*/
.card-price{font-size:32px;font-weight:700;color:var(--text-dark, #222)}
.card-price.on-sale{color:var(--brand-red, #DC1F1D)}
/* Only equiv-price lives here now — price-range moved out to its own
   row, right after .card-title (2026-08-25 feedback: it "didn't look
   right" sharing this line, bottom-right). justify-content:flex-start
   replaces the old space-between, which existed purely to push
   price-range to the opposite end from equiv-price — nothing left here
   to push apart. */
.price-meta-line{display:flex;align-items:baseline;justify-content:flex-start;gap:8px;margin-top:2px}
/* min-height added 2026-08-26 — equiv-price is empty (no unit price for
   this product) far more often than it isn't, and an empty div has zero
   natural height regardless of anything else on the row. Since this
   whole row sits ABOVE the auto-margin-anchored bottom cluster (see
   .promo-badge's own comment), a shorter .card-price-row here means MORE
   space gets absorbed by that auto margin to compensate — which shifts
   WHERE the entire cluster starts (promo-badge, price-range, the price
   itself), not just this row. That's what was reported as "price and
   price-range float up and down depending if there's a unit price" —
   fixing it here is what stops the whole cluster's position from
   depending on whether any individual card happens to have a unit price
   or not. */
.equiv-price{font-size:13px;color:#777;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-height:1.2em}
/* Moved 2026-08-26 — now sits BETWEEN .promo-badge and .card-price-row
   (was between .card-title and .card-swatches, moved there 2026-08-25 —
   see git history/this doc's own numbered sections for the full story),
   formatting itself still unchanged either way.
   margin-top:4px — a plain, direct total (.product-card no longer has
   its own `gap`, see that rule's own comment for why, so there's no
   hidden "+10" to account for). Tweak this value alone to change JUST
   the promo-badge→price-range gap; .card-price-row's own margin-top
   controls price-range→price-row independently.
   min-height:1.2em — this row is now ALWAYS rendered (see
   renderGridCard() in product_functions.php), hidden with
   visibility:hidden rather than omitted for a single-price product, so
   swatches/price/button still line up across a row that mixes varying-
   and single-price products. visibility:hidden keeps an element's
   natural layout space, but a genuinely CONTENT-EMPTY block-level div
   has zero natural height regardless — min-height is what actually
   reserves the space in the empty case; 1.2em ≈ this font-size's normal
   line-height, matching the populated case closely so there's no visible
   jump between the two. */
.price-range{font-size:13px;font-weight:400;color:#555;white-space:nowrap;min-height:1.2em;margin-top:10px}

.btn-view-product{
    display:block;
    text-align:center;
    background:var(--brand-red, #DC1F1D);
    color:#fff;
    border:0;
    padding:10px 0;
    border-radius:6px;
    font-size:18px;
    font-weight:600;
    text-decoration:none;
    margin-top:8px; /* was 4px + the implicit parent gap:10px — same total (14px), now a plain direct value */
    transition:background .2s;
}
.btn-view-product:hover{background:var(--brand-red-hover, #C84444)}

.btn-view-product.out-of-stock{background:var(--brand-red-dark, #7A0D0D)}
.btn-view-product.out-of-stock:hover{background:var(--brand-red-dark-hover, #8F1A1A)}

.product-card.highlighted{
    border-color:var(--brand-red, #DC1F1D);
    box-shadow:0 0 0 3px rgba(200,17,17,0.25);
}