/*
 * Stock and offer labels — the pill on the product page, the two ribbons on a card, and the two
 * filter groups.
 *
 * WHY THIS FILE EXISTS. web/css/styles.css is COMPILED Tailwind output and must never be hand-edited,
 * and the compiled output carries exactly two dot colours — `before:bg-green-500` and
 * `before:bg-red-500` — because the theme only ever had two states. There is no third colour in it to
 * reach for, let alone an eighth. Unlayered, like vat-view.css, so it beats the theme's own `@layer`
 * rules whatever their specificity (findings: the Tailwind layer trap).
 *
 * TWO AXES, drawn in opposite corners. `tf-badge--start` is what we are SAYING about the fabric
 * (Sale, Promotion, Remnant, New, Back in stock — staff-set); `tf-badge--end` is how much is LEFT
 * (Nearly gone, Last few metres, Out of stock — derived from quantity). 174 products are both, so a
 * single corner was never going to be enough.
 *
 * EVERY CLASS IS A SLUGIFIED LABEL. "Last few metres" -> `tf-badge--last-few-metres`. So an offer
 * somebody adds in admin renders immediately in the default grey, and giving it a colour is an opt-in
 * below rather than a code change. The failure mode of a label with no rule is "grey", not "invisible".
 *
 * CONTRAST, checked against WCAG AA for small text (4.5:1), label on chip:
 *     white on #8c1d40  9.4    white on #1f4e79  8.6    white on #3f4a52  8.6
 *     black on #aca65b  9.1    white on #1a6b33  6.4    white on #a33a00  6.5
 *     white on #8a5a00  6.3    white on #b3261e  5.9    white on #333333 12.6
 */

:root {
    /* offers — what we are saying */
    --tf-badge-default-bg:      #333333;
    --tf-badge-default-fg:      #ffffff;
    --tf-badge-sale-bg:         #8c1d40;
    --tf-badge-promotion-bg:    #1f4e79;
    --tf-badge-remnant-bg:      #3f4a52;
    --tf-badge-new-bg:          var(--color-primary, #aca65b);
    --tf-badge-new-fg:          #000000;
    --tf-badge-backinstock-bg:  #1a6b33;

    /* stock — how much is left */
    --tf-badge-nearlygone-bg:   #a33a00;
    --tf-badge-lastfew-bg:      #8a5a00;
    --tf-badge-outofstock-bg:   #b3261e;
}

/* ---- the product page's availability line ----------------------------------------------------- */
/*
 * Dark mode is the theme's own mechanism: `.tf-dark` on <html> swaps `--color-white` and
 * `--color-black` rather than restating colours per rule, which is why "In stock" is white on a dark
 * page with no rule of ours. These two follow the same shape — one token, redefined for dark —
 * instead of a fixed hex that would be unreadable in one of the two modes.
 */
:root {
    --tf-stock-lastfew-fg:    #8a5a00;
    --tf-stock-nearlygone-fg: #a33a00;
    --tf-stock-out-fg:        #b3261e;
}

html.tf-dark {
    --tf-stock-lastfew-fg:    #e8b04b;
    --tf-stock-nearlygone-fg: #ff9e5e;
    --tf-stock-out-fg:        #ff8a80;
}

/*
 * The buy box paints its availability with
 *     .tf-product-info .stock.available { color: var(--color-black) }
 * at (0,3,0), and every state below is `.available` except the sold-out one — "Last few metres" IS
 * available, and saying otherwise would contradict an enabled Add to Cart button. So the rule has to
 * be beaten rather than avoided: copy the losing selector, swap one class, prefix `html`. (0,3,1)
 * against (0,3,0), no specificity hack for the next person to decode.
 */
html .tf-stock.tf-stock--last-few-metres,
html .tf-product-info .stock.tf-stock--last-few-metres {
    color: var(--tf-stock-lastfew-fg);
}

html .tf-stock.tf-stock--nearly-gone,
html .tf-product-info .stock.tf-stock--nearly-gone {
    color: var(--tf-stock-nearlygone-fg);
}

html .tf-stock.tf-stock--out-of-stock,
html .tf-product-info .stock.tf-stock--out-of-stock {
    color: var(--tf-stock-out-fg);
}

/* the dot, for the places that show one. The product page hides it; cards and grouped rows do not. */
html .tf-stock::before                     { background-color: var(--color-green-500, #00c950); }
html .tf-stock--last-few-metres::before    { background-color: var(--tf-stock-lastfew-fg); }
html .tf-stock--nearly-gone::before        { background-color: var(--tf-stock-nearlygone-fg); }
html .tf-stock--out-of-stock::before       { background-color: var(--tf-stock-out-fg); }

/* ---- the two ribbons over a card photograph --------------------------------------------------- */
/*
 * WHAT THESE REPLACE. 589 enabled, visible products carry merchandising state in the product NAME —
 * 269 say OUT OF STOCK, 136 LAST PIECE, 133 REMNANT, 51 LIMITED STOCK. The words go into the SERP
 * title, the meta title, the alt text and the structured-data `name`, and Google shows "OUT OF STOCK
 * - Brown Chiffon with..." to somebody who was ready to buy.
 *
 * The staff maintain those titles by hand to about 98.9% accuracy. The argument for taking the job
 * off them is the other 1.1%: three products titled OUT OF STOCK while actually IN stock, one with
 * 10.1 metres on the shelf, invisible to anybody who reads the title. A derived label cannot drift.
 *
 * Two containers, because two card templates exist: `.tf-card-photo` is the Hyvä category card,
 * `.product-item-photo` is Magezon's — its grid, list and slider all share that anchor, which is why
 * one rule covers three home-page components.
 */
html .tf-card-photo,
html .product-item-photo {
    position: relative;
    display: block;
}

html .tf-badge {
    background-color: var(--tf-badge-default-bg);
    color: var(--tf-badge-default-fg);
    position: absolute;
    top: 0.5rem;
    z-index: 1;
    padding: 0.15rem 0.5rem;
    border-radius: 0.25rem;
    font-size: 0.6875rem;
    font-weight: 700;
    line-height: 1.5;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    white-space: nowrap;
    pointer-events: none;
    max-width: calc(50% - 0.75rem);
    overflow: hidden;
    text-overflow: ellipsis;
}

/* offer left, stock right, so the two can never overlap and the eye learns which corner means what */
html .tf-badge--start { left: 0.5rem; }
html .tf-badge--end   { right: 0.5rem; }

/*
 * A PRODUCT CAN CARRY MORE THAN ONE OFFER, so the left corner is a stack, not a slot.
 *
 * Measured on box5 2026-09-24: 443 products carry an offer and 133 carry two, every one of them
 * Remnant + Sale. Only the first was ever drawn, so 133 of the catalogue's 134 remnants showed as
 * SALE and the word Remnant never reached a card. The badges are absolutely positioned, so a second
 * one could only ever land on top of the first; this container takes the positioning and lets them
 * flow inside it.
 *
 * Two is the observed maximum. The stack does not cap, because capping would reintroduce exactly the
 * silent-truncation bug this replaces -- if a third is ever added in admin it should be visible and
 * look crowded, which is a prompt to think, rather than vanish.
 */
html .tf-badges {
    position: absolute;
    top: 0.5rem;
    z-index: 1;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0.25rem;
    max-width: calc(50% - 0.75rem);
}

html .tf-badges--start { left: 0.5rem; }

/* inside the stack the chips are ordinary flow content; the container does the positioning */
html .tf-badges .tf-badge {
    position: static;
    top: auto;
    left: auto;
    right: auto;
    max-width: 100%;
}

/* the same chip in the buy box, where there is no photograph to sit on top of */
html .tf-badge--inline {
    position: static;
    top: auto;
    left: auto;
    right: auto;
    max-width: none;
}

/* offers */
html .tf-badge--sale          { background-color: var(--tf-badge-sale-bg); }
html .tf-badge--promotion     { background-color: var(--tf-badge-promotion-bg); }
html .tf-badge--remnant       { background-color: var(--tf-badge-remnant-bg); }
html .tf-badge--back-in-stock { background-color: var(--tf-badge-backinstock-bg); }
html .tf-badge--new {
    background-color: var(--tf-badge-new-bg);
    color: var(--tf-badge-new-fg);
}

/* stock */
html .tf-badge--nearly-gone     { background-color: var(--tf-badge-nearlygone-bg); }
html .tf-badge--last-few-metres { background-color: var(--tf-badge-lastfew-bg); }
html .tf-badge--out-of-stock    { background-color: var(--tf-badge-outofstock-bg); }

/* ---- the filter groups, drawn as the ribbons they filter for ---------------------------------- */
/*
 * The owner's brief: "make the links look the same as the actual ribbons they represent." So the
 * options are the badges themselves, and the connection between a label on a photograph and a filter
 * in the panel is immediate rather than inferred.
 *
 * NO NEW MARKUP AND NO NEW PHP. Two hooks already existed: `filter.phtml` puts `dm-<slugified label>`
 * on every option `<li>` — added for the colour swatches, so "Sale" becomes `dm-sale` exactly as
 * "Red" becomes `dm-red` — and `view.phtml` carries `tf-filter--<request var>` on the wrapper. The
 * rules below are the only thing that knows these two filters are special.
 *
 * The colours are the same custom properties the badges use, so changing a label's colour moves both
 * and they cannot drift apart.
 */
html .tf-filter--tf_offer .items,
html .tf-filter--tf_stock_level .items {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
}

html .tf-filter--tf_offer .items li,
html .tf-filter--tf_stock_level .items li {
    margin: 0;
}

html .tf-filter--tf_offer .items li > a,
html .tf-filter--tf_offer .items li > span,
html .tf-filter--tf_stock_level .items li > a,
html .tf-filter--tf_stock_level .items li > span {
    background-color: var(--tf-badge-default-bg);
    color: var(--tf-badge-default-fg);
    display: inline-flex;
    align-items: baseline;
    gap: 0.3rem;
    padding: 0.2rem 0.55rem;
    border-radius: 0.25rem;
    font-size: 0.6875rem;
    font-weight: 700;
    line-height: 1.5;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    white-space: nowrap;
}

html .tf-filter--tf_offer .items li .count,
html .tf-filter--tf_stock_level .items li .count {
    font-weight: 400;
    opacity: 0.75;
}

html .tf-filter--tf_offer .items li.dm-sale > a,
html .tf-filter--tf_offer .items li.dm-sale > span          { background-color: var(--tf-badge-sale-bg); }
html .tf-filter--tf_offer .items li.dm-promotion > a,
html .tf-filter--tf_offer .items li.dm-promotion > span     { background-color: var(--tf-badge-promotion-bg); }
html .tf-filter--tf_offer .items li.dm-remnant > a,
html .tf-filter--tf_offer .items li.dm-remnant > span       { background-color: var(--tf-badge-remnant-bg); }
html .tf-filter--tf_offer .items li.dm-back-in-stock > a,
html .tf-filter--tf_offer .items li.dm-back-in-stock > span { background-color: var(--tf-badge-backinstock-bg); }
html .tf-filter--tf_offer .items li.dm-new > a,
html .tf-filter--tf_offer .items li.dm-new > span {
    background-color: var(--tf-badge-new-bg);
    color: var(--tf-badge-new-fg);
}

html .tf-filter--tf_stock_level .items li.dm-nearly-gone > a,
html .tf-filter--tf_stock_level .items li.dm-nearly-gone > span     { background-color: var(--tf-badge-nearlygone-bg); }
html .tf-filter--tf_stock_level .items li.dm-last-few-metres > a,
html .tf-filter--tf_stock_level .items li.dm-last-few-metres > span { background-color: var(--tf-badge-lastfew-bg); }
html .tf-filter--tf_stock_level .items li.dm-out-of-stock > a,
html .tf-filter--tf_stock_level .items li.dm-out-of-stock > span    { background-color: var(--tf-badge-outofstock-bg); }
