/* ---------- Resets (reset.css until 22-10-2026) ----------
   Loaded under EVERY theme, so they live here: one render-blocking file fewer. Theme-specific compatibility lives in
   reset_for_others_themes.css, which is skipped when codbrand is active and still prints just before this file. */

/* Core block buttons must not inherit a link underline. Needed under our own
   theme too: codbrand ships no link styling at all, so without this the browser
   default underlines every block button. */
a.wp-block-button__link {
    text-decoration: none !important;
}

/* GUARD for every heading the plugin renders. A preset or a component's own CSS
   does not always declare margin, size or weight, and the browser's defaults then
   decide them: `margin-block: 1em` (so the space around a title grew with its font
   size), bold, and 1.17em on an h3. A <div> has none of those, so this gives a
   plugin heading the same starting point a <div> title has.
   - Scoped by the heading's OWN class: every plugin heading carries a `cl-` class,
     and page content does not. NOT by ancestor — page content, custom blocks and
     product/category descriptions all render inside plugin wrappers
     (`.cl-boxed-mode-padded`, …), and their headings must stay untouched.
   - ZERO specificity (`:where`), so presets (.cl-preset-N x3), a component's own
     class rule (.cl-instagram-heading, .cl-consent-title) and merchant CSS always
     win. It only replaces the browser defaults; a theme's own heading rules still
     beat it, which is why the two page titles below keep class-level resets.
   - A new plugin heading needs nothing here: a `cl-` class is enough. */
:where(h1, h2, h3, h4, h5, h6):where([class^="cl-"], [class*=" cl-"]) {
    margin: 0;
    font-size: inherit;
    font-weight: inherit;
}

/* Same GUARD for links the plugin renders: an <a> whose preset or style key sets
   no colour (a JS-built link, a footer link whose saved style dropped `color`, the
   WhatsApp button's currentColor icon) otherwise takes the browser's link blue.
   Same scope rule (the link's OWN `cl-` class, so merchant links in page content,
   descriptions and custom blocks keep theirs) and same zero specificity (presets,
   component CSS and merchant CSS win). The underline is already off (`a` below). */
:where(a):where([class^="cl-"], [class*=" cl-"]) {
    color: inherit;
}

/* The two page titles are <h1>s, which themes style (`h1`, `.entry-content h1`).
   These class-level resets keep a theme's h1 margin off them too, as before.
   The category one lived in the category design's generated CSS until 26-09-2026. */
.is_category_block h1.cat-title {
    margin: 0;
}

/* The product title became an <h1> on single product pages (SEO/a11y — the page
   previously contributed no heading at all). The typography preset already wins
   on specificity, because its selector is tripled
   (.cl-preset-N.cl-preset-N.cl-preset-N = 0-3-0) and beats a theme's
   `.single h1` / `.entry-content h1` (0-1-1). The ONE thing it does not declare
   is margin, which every UA stylesheet gives an h1 (~0.67em top and bottom) and
   gives a div none — so without this the title gains vertical space the div
   never had. Loaded under EVERY theme because the UA default applies regardless
   of theme. Scoped to our own class so no other h1 on the page is touched. */
h1.cl-product-title {
    margin-top: 0;
    margin-bottom: 0;
}

* {
  box-sizing: border-box;
}
a {
    text-decoration: none;
}

/* ---------- The codbrand theme's base rules ----------
   Until theme 1.0.5 (22-10-2026) these were the theme's style.css, one render-blocking file more. The theme is only
   used with this plugin, so they live here — but this file loads under EVERY theme, and three of them would break
   another theme's page (body as a flex column, iframes losing their height, wide blocks losing their width). So each
   is scoped to `cl-theme-codbrand`, the body class public-hooks.php adds only when the active theme (or its parent) is
   codbrand. `:where()` keeps each rule's weight as it was in the theme (a bare `img` stays 0,0,1). Task
   tasks/theme-css-into-plugin-public-css-22-10-2026.md (workspace). */

/* Predictable box model — the `*` above covers the elements under every theme; the theme adds the pseudo-elements. */
:where(body.cl-theme-codbrand) *::before,
:where(body.cl-theme-codbrand) *::after,
:where(body.cl-theme-codbrand)::before,
:where(body.cl-theme-codbrand)::after {
    box-sizing: border-box;
}

/* The UA's body{margin:8px} would inset the whole storefront: full-bleed sections stop 8px short of every edge
   (measured on pov.ma 04-09-2026: body 265px wide in a 281px viewport). */
body:where(.cl-theme-codbrand) {
    margin: 0;
}

/* The document is a flex column and the content element fills the rest of the viewport: a page, post or product can
   paint its own content area (the plugin's per-content background), and without this a short page shows a strip of
   the page colour above the footer, and a canvas page stops short of the viewport bottom. `main` is width:100% — the
   width mode lives on its inner element, so the colour is full-bleed in every mode. */
body:where(.cl-theme-codbrand) {
    min-height: 100vh;
    display: flex;
    flex-direction: column;
}
.codbrand-content {
    width: 100%;
    flex: 1 0 auto;
}

/* Pins the mobile text-inflation algorithm (iOS on rotation, Chrome on Android's autosizer). 100%, not `none`, so
   pinch-zoom and the user's own zoom stay; both properties because -webkit- alone misses Chrome/Edge 79+. */
html:where(:has(> body.cl-theme-codbrand)) {
    -webkit-text-size-adjust: 100%;
    text-size-adjust: 100%;
}

/* Media never overflows its container: one wide image would otherwise scroll the page sideways. */
:where(body.cl-theme-codbrand) img,
:where(body.cl-theme-codbrand) video,
:where(body.cl-theme-codbrand) iframe,
:where(body.cl-theme-codbrand) embed,
:where(body.cl-theme-codbrand) object {
    max-width: 100%;
    height: auto;
}

/* WordPress core emits these in block content; with no theme.json layout nothing else defines them, so wide and
   full blocks would render at content width. Logical properties keep RTL right. */
:where(body.cl-theme-codbrand) .aligncenter {
    margin-inline: auto;
}
:where(body.cl-theme-codbrand) .alignwide,
:where(body.cl-theme-codbrand) .alignfull {
    max-width: none;
}

/* One custom property for the content width, so a child theme or the merchant can retune it. */
:root {
    --codbrand-content-width: 1140px;
}

/* Accessibility (WordPress theme handbook, Theme Check): visually hidden, still announced. */
:where(body.cl-theme-codbrand) .screen-reader-text {
    border: 0;
    clip-path: inset(50%);
    height: 1px;
    margin: -1px;
    overflow: hidden;
    padding: 0;
    position: absolute;
    white-space: nowrap;
    width: 1px;
}

/* The skip link becomes visible when focused, or it helps nobody. */
:where(body.cl-theme-codbrand) .skip-link:focus {
    clip-path: none;
    height: auto;
    margin: 0;
    padding: 0.75rem 1rem;
    position: fixed;
    inset-block-start: 0;
    inset-inline-start: 0;
    width: auto;
    z-index: 100000;
    background: #fff;
    color: #000;
}
/*----lightbox-----*/
/* The page does not scroll under the photo lightbox (comps/slider/frontend/assets/js/slider-lightbox.js). */
body.lightbox-active {
    overflow: hidden !important;
}
/* Fixed page chrome must drop BEHIND any full-screen overlay, or it paints on top of it.
   This rule existed for the lightbox but named only 2 of the 5 fixed elements, and the two it
   missed are the two that outrank every overlay:

       .cl_sticky_button.is-visible   9 999 911   (sticky_button/v1/generated_css.php:46)
       .cl_can_be_sticky.is-sticky    1 000 000   (public.css, sticky header — same element as
       .cart_open                     1 000 000    .cl-site-header, so it was already covered)
       .cl-whatsapp-product             100 000   (whatsapp_button/v1/generated_css.php:5)
       ---- overlays sit below all of that ----
       .cl-search-overlay               100 050   (search global_settings/_structural_css.php; search.css until 21-10-2026)
       .cl_gallery.lightbox-active      100 000   (gallery.css, until 11-10-2026)

   So the sticky Add-to-Cart bar painted OVER the fullscreen photo viewer and over the search
   panel, and the WhatsApp button tied with the lightbox. The search overlay and the quickview
   had no demotion rule at ALL — only a body `overflow:hidden`. Extended here to all three
   overlay states x all four chrome elements.
   Written out longhand on purpose: `:is()` would be far shorter, but an engine that does not
   support it discards the ENTIRE selector list, which would silently restore the bug on exactly
   the older Android/Opera Mini devices this plugin targets. Verbose and bulletproof wins.
   Since 11-10-2026 the photo lightbox needs none of it: it is a modal <dialog>, which opens in the top
   layer, above every z-index (task gallery-on-slider-engine), so its four lines went.
   Body classes verified at source (11-10-2026): search.js (`cl-search-overlay-open`),
   product_quickview.js (`cl-quickview-modal-open`). */
body.cl-search-overlay-open .cl-site-header,
body.cl-search-overlay-open .cart_open,
body.cl-search-overlay-open .cl_sticky_button,
body.cl-search-overlay-open .cl-whatsapp-product,
body.cl-quickview-modal-open .cl-site-header,
body.cl-quickview-modal-open .cart_open,
body.cl-quickview-modal-open .cl_sticky_button,
body.cl-quickview-modal-open .cl-whatsapp-product {
    z-index: -1;
}
/*----------*/
/* Prevent horizontal overflow from long unbreakable content
   (encoded HTML entities, long URLs, unspaced text) */
div {
    overflow-wrap: break-word;
    word-break: break-word;
}
/* Buttons keep a whole word as their floor. The rule above is INHERITED, and `word-break: break-word`
   lets min-content fall to one character, so a squeezed button split its label inside a word:
   "بسرعة" became "بسر / عة" on a 2-column phone grid (reported 21-09-2026). `normal` restores the
   floor; the inherited `overflow-wrap: break-word` still breaks a word that cannot fit at all.
   The rule above is deliberately left alone: without it a long URL in a flex row pushed the page
   sideways by 212px at 390px, measured. list.css fixes the filter buttons the same way. */
button {
    word-break: normal;
}
/*----------*/
.cl-hide { display: none !important; }
/* SVG icon wrapper — every icon rendered by IconsManagerSelectorFR is
   wrapped in <span class="cl-icon"><svg>...</svg></span>. The wrapper
   inline-flexes the SVG so it centers cleanly next to text without
   the inline-baseline drop. line-height:1 prevents the wrapper from
   inheriting larger line-heights that would add phantom space.
   Note: a previous version had `padding-top: 2px` here — that caused
   visible vertical offset in tight header layouts and was removed. */
.cl-icon {
    display: inline-flex;
    align-items: center;
    line-height: 1;
}
.cl-icon svg {
    height: 1em !important;
    width: 1em !important;
    display: block;
    vertical-align: middle !important;
}
/* A menu link's own icon (the Menus screen's "Select icon"), before its text in the header menus, the
   More list and the footer menus. Its size and colour are the link's (the two rules above); logical
   margin, so an RTL store puts the gap on the right side. */
.cl-menu-item-icon {
    margin-inline-end: 0.4em;
    vertical-align: middle;
}
/* A link that already spaces its children with a gap — a button design on the link (the More list's
   items, the secondary menu's) or the footer's menu columns — must not add the margin on top (11px
   against 5px on the plain links, measured 04-10-2026). */
a[class*="cl-preset-"] > .cl-menu-item-icon,
.footer-menu-widget a > .cl-menu-item-icon {
    margin-inline-end: 0;
}
/* WhatsApp button with no image uploaded renders the system icon instead (whatsappControllerFR.php).
   The icon is the button's only content, so it has to give the button its height: a circle as
   wide as the container, glyph at half size. It carries its OWN accent background rather than
   relying on the container's: measured 23-09-2026, both woo.local and the demo had customised
   the container style down to no background at all, where a bare glyph was invisible. */
.cl-whatsapp-product .cl-whatsapp-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    aspect-ratio: 1 / 1;
    border-radius: 50%;
    font-size: 28px;
    color: var(--cl-txt-color5);
    background-color: var(--cl-bg-color4);
}
/*---------*/
/* For SOLID icons (like Font Awesome). This makes them inherit text color. */
.cl-icon svg[fill="currentColor"] {
    stroke: none; /* Ensure no unwanted outline appears */
}

/* For OUTLINE icons (like the one you provided). */
.cl-icon svg[fill="none"] {
    fill: none; /* Redundant but safe */
    stroke: currentColor; /* THIS IS THE MAGIC: Inherits text color for the outline */
    stroke-width: 2px; /* A good default thickness. Adjust if needed. */
    stroke-linecap: round; /* Makes line ends look nice */
    stroke-linejoin: round; /* Makes line corners look nice */
}

/*----------------------------*/
/* The theme-compatibility rules that used to live here moved to
   reset_for_others_themes.css, which is enqueued only when the active theme is
   NOT codbrand. What stays is what EVERY theme needs, ours included:
   .elementor-button is a builder rule, .cl-footer-container is our own markup. */

.elementor-button { cursor: pointer;}

.cl-footer-container {
    width: 100%;display: flex;flex-direction: column
}
/*--------------------------*/

/*------notification toast---------*/
/* Above every popup (`.cl_modal` 100000001, a quick view over one 100000002): an add made inside a popup — the cart's
   upsell pop-ups (comps/upsells, L3) — is told by the toast, which sat under the popup's backdrop until 05-11-2026. */
.cl-notification {
    position: fixed;
    bottom: 20px;
    right: 20px;
    z-index: 100000003;
    text-align: left;
    max-width: 320px;
    padding: 12px 20px;
    border-radius: 10px;
    font-size: 13px;
    font-weight: 500;
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
    opacity: 0;
    transform: translateY(10px);
    transition: opacity 0.3s ease, transform 0.3s ease;
    pointer-events: none;
}
.cl-notification.cl-toast-visible {
    opacity: 1;
    transform: translateY(0);
    pointer-events: auto;
}
.cl-error-response {
    background-color: #fff5f5;
    color: #dc3545;
    border: 1px solid #fecdd3;
}
.cl-success-response {
    background-color: #f0fdf4;
    color: #16a34a;
    border: 1px solid #bbf7d0;
}
/* Image-mode toast — flex row [thumbnail | text]. Triggered by the JS adding
   .cl-notification-with-image when showNotification() is called with an
   imageUrl arg. Without that class the toast keeps its legacy text-only
   layout (just .cl-notification with text content). */
.cl-notification.cl-notification-with-image {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 14px;
    max-width: 360px;
}
.cl-notification.cl-notification-with-image .cl-notification-image {
    width: 48px;
    height: 48px;
    object-fit: cover;
    border-radius: 6px;
    flex-shrink: 0;
}
.cl-notification.cl-notification-with-image .cl-notification-content {
    flex: 1;
    min-width: 0;
    line-height: 1.4;
}

/*-------------------*/
.cl-custom-block {
    display: flex;
    justify-content: center;
    flex-direction: column;
    align-items: center;
    overflow-x: hidden;
}
.cl-custom-block .wp-block-group, .cl-custom-block .alignfull {
    max-width: 100% !important;
    margin-inline: 0 !important;
    width: auto !important;
}

.cl-editor-content img {
    max-width: 100%;
    height: auto;
}
.cl-editor-content ul {
    list-style: initial;
    padding: 0 5px 0px 5px;
    margin: 0 15px 0px 15px;
}
.cl-editor-content li {
    line-height: 22px;
    margin-bottom: 0;
}
.cl-editor-content p {
    margin-top: 6px;
    margin-bottom: 6px;
    line-height: 21px;
}

/* The header vertical-padding guard that lived here moved to main_header/v1/generated_css.php on
   11-09-2026: it is now emitted only while the bar has a fixed height, the one case it protects. */
/*----global button------*/
button {
    cursor: pointer;
}
.cl-button {
    display: inline-flex !important;
    align-items: center;
    justify-content: center;
    gap: 8px;
    text-decoration: none !important;
    border-width: 2px;
    border-style: solid;
    border-radius: 6px;
    padding: 4px 6px;
    font-weight: 500;
    font-size: 14px;
    cursor: pointer;
    transition: all 0.2s ease;
}
.cl-button:active {
    transform: translateY(1px);
    box-shadow: none;
}

.cl-primary-btn {
    background-color: #fff;
    border-color: #2196F3;
    color: #2196F3;
}

.cl-primary-btn:hover {
    background-color: #2196F3;
    color: #fff !important;
    box-shadow: 0 2px 4px rgba(33, 150, 243, 0.2);
}

.cl-danger-btn {
    background-color: #d63638;
    border-color: #d63638;
    color: white;
}

.cl-danger-btn:hover {
    background-color: #b32d2e;
    border-color: #b32d2e;
    box-shadow: 0 2px 8px rgba(214, 54, 56, 0.3);
}
/*------buttons-------*/

/*--dont use float left because that can triggere a conflict with the next landing page block if they not also have the flost left -*/
.cl-product-container, .cl-checkout-container {
    display: flex;
    column-gap: 15px;
    width: 100%;
    margin: auto;
    margin-top: 15px;
}
.cl-product-container img,
.cl-product-zone img {
    max-width: 100%;
    height: auto;
}

div[cl-block] {
    width: 100%;
}

/* Override the global div[cl-block]{width:100%} for inner header/footer
   elements that need flex-default sizing. Adding cl-block to these
   inner elements is required for iframe-click routing to their
   respective admin tabs; this override stops the global rule from
   collapsing the flex layouts.
   - Header logo sits flex-aligned next to nav.main-nav and nav.end-menu
     (nav siblings escape the global rule naturally — they're <nav>).
   - Footer branding column + menus column are flex children of
     .cl-footer-main; both need flex-default width to stay side-by-side. */
[cl-compo="header"] [cl-block="logo"],
[cl-compo="footer"] [cl-block="branding"],
[cl-compo="footer"] [cl-block="menus"] {
    width: auto;
}

.cl-checkout-sections {
    /*float: left; this i creating bug in the desktop version so the shipping is not clicked*/
    width: 100%;
    padding-bottom: 20px;
}
/* Let the two product-page columns actually honour `gallery_width_pct`.
   A flex item defaults to `min-width:auto`, which refuses to shrink below its MIN-CONTENT
   width — so the percentages compiled into generated_css hold only while both columns'
   content happens to fit. Put something wide in one side (a long unbreakable heading, a
   table, an embed) and that column sits on its min-content floor while the other absorbs
   the whole loss: gallery_width_pct:50 then renders two visibly UNEQUAL columns, with
   nothing in the admin to explain it. Reported 11-09-2026 by the codbrand.pro build.

   Measured on woo.local, 1240px container, gallery_width_pct:50:
     normal content                 532.4 / 532.6   already equal — nothing to fix
     + a 525px min-content element  525.0 / 540.0   unequal — the bug
     + min-width:0 on both          532.4 / 532.6   equal again
   It only ever releases the floor, so a store that was already correct does not move.

   NOT the `flex-basis` swap that was asked for: flex-basis inherits the same
   `min-width:auto` floor and so does not address the cause — measured on the same page,
   `flex: 0 1 50%` without min-width:0 gave 196.3 / 868.8, far worse than the bug.

   STATIC, not generated_css, on purpose: it carries no setting, and a rule compiled into
   that column reaches a store only when an admin next saves the product design. Here it
   reaches every store on deploy. Harmless in the mobile column layout, where the columns
   stack and there is no horizontal contention to resolve. */
.single .cl_gallery,
.single .cl-checkout-sections {
    min-width: 0;
}
/* The second selector reaches THROUGH a .cl-design-wrap anchor. In `in_product`
   cart/checkout mode each block is wrapped in one, so the wrapper — not the real
   last block — became `> div:last-child`. It is `display: contents`, so it has no
   box to zero and the block below it kept its margin, leaving a stray gap at the
   foot of the funnel. */
.cl-checkout-sections > div:last-child,
.cl-checkout-sections > .cl-design-wrap:last-child > :last-child {
    margin-bottom: 0px;
}
/*-----------*/

/*----- prices -----*/
.cl-regular-price {
    text-decoration: line-through;
}
/*---------- toggle block -------------*/
.cl_toggle_block[is_open="no"] .cl_toggle_body {
    display: none;
}
.cl_toggle_block[is_open="no"] *[show_in_open], .cl_toggle_block[is_open="yes"] *[show_in_close] {
    display: none;
}
.cl_toggle_header {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    cursor: pointer !important;
    justify-content: space-between;
    gap: 5px;
}
/*----the title container-----*/
.cl_toggle_header div.toggle-title {
    display: flex;
    align-items: center;
    column-gap: 3px;
}
.cl_toggle_header div.toggle-close {
    display: flex;
    column-gap: 3px;
    align-items: center;
}
.cl_toggle_preview {
    cursor: pointer;
    width: 100%; flex-grow: 1;display: flex; justify-content: center;
}

.cl_toggle_block .toggle-close .cl-icon {
    cursor: pointer;
    display: none;
}
.cl_toggle_block[is_open="no"] .cl-icon-open {
    display: inline-flex;
}
/* No animation: the icon change already shows the block opened. It used to shake every 4 s for as long as the block
   stayed open, a loop WCAG 2.2.2 asks a way to stop (whole_plugin WP-4, owner 02-11-2026). */
.cl_toggle_block[is_open="yes"] .cl-icon-close {
    display: inline-flex;
}
/*---------- End toggle block -------------*/

/* A box that carries ANOTHER element's card class (cl-preset-N) only to take its side padding: everything else a card
   can set is taken off — background, border, corners, shadow, top / bottom padding, margin, hover included. The header's
   Bottom Row and the topbar's menu use it so their links start where the header bar's content starts, whatever card the
   bar has (G137). 0,3,0 / 0,4,0 with !important beat a card with "Force styles" (0,2,0 / 0,3,0 !important). */
.cl-card-pad-only.cl-card-pad-only[class*="cl-preset-"],
.cl-card-pad-only.cl-card-pad-only[class*="cl-preset-"]:hover {
    background: none !important;
    border: 0 none !important;
    border-radius: 0 !important;
    box-shadow: none !important;
    padding-top: 0 !important;
    padding-bottom: 0 !important;
    margin: 0 !important;
}
/* A card split over two boxes (G142, the header bar's background across the screen): its paint — background, border,
   radius, shadow, margin — on the outer box with no padding, its padding on the inner box with no paint. Same weights
   as above. */
.cl-card-paint-only.cl-card-paint-only[class*="cl-preset-"],
.cl-card-paint-only.cl-card-paint-only[class*="cl-preset-"]:hover {
    padding: 0 !important;
}
.cl-card-padding-only.cl-card-padding-only[class*="cl-preset-"],
.cl-card-padding-only.cl-card-padding-only[class*="cl-preset-"]:hover {
    background: none !important;
    border: 0 none !important;
    border-radius: 0 !important;
    box-shadow: none !important;
    margin: 0 !important;
}

/* --- Sticky Header Styles (IntersectionObserver Method) --- */
.cl-header-placeholder {
    display: none;
}

.cl_can_be_sticky.is-sticky {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    width: 100%;
    z-index: 1000000;
    animation: slideDown 0.3s ease-in-out;
}
/* Logged in, the stuck header sat at top:0 and covered the admin bar (it out-ranks the bar's z-index).
   The same offset core gives its own sticky blocks: the bar's height — a variable core sets only while
   the bar shows, 32px, or 46px at 782px and below — and 0 at 600px and below, where core stops fixing
   the bar and it scrolls away with the page. */
body.admin-bar .cl_can_be_sticky.is-sticky {
    top: var(--wp-admin--admin-bar--height, 0px);
}
@media screen and (max-width: 600px) {
    body.admin-bar .cl_can_be_sticky.is-sticky {
        top: 0;
    }
}

.hide_in_sticky {
    /* You can add transition here for smoother hiding if needed */
}

.is-sticky + .cl-header-placeholder {
    display: block;
}

.is-sticky .hide_in_sticky {
    display: none;
}

@keyframes slideDown {
    from {
        transform: translateY(-100%);
    }
    to {
        transform: translateY(0);
    }
}
 
/*--------- End Sticky system handler---------*/

@keyframes shakeMe {
    2%, 18% {
        transform: translate3d(-5px, 0, 0);
    }

    4%, 16% {
        transform: translate3d(5px, 0, 0);
    }

    6%, 10%, 14% {
        transform: translate3d(-5px, 0, 0);
    }

    8%, 12% {
        transform: translate3d(5px, 0, 0);
    }
    
    18.1% {
        transform: translate3d(0px, 0, 0);
    }
}
/* Reduced motion stops every shake: under it this later definition wins over the one above, so every element that
   runs shakeMe (ADD TO CART, the options error message, any rule written later) runs it without moving and without
   losing its own transform (whole_plugin WP-4, 02-11-2026). It animates only an unused custom property, which moves
   nothing — an empty definition would do the same but a minifier may drop it. */
@media (prefers-reduced-motion: reduce) {
    @keyframes shakeMe {
        0%, 100% { --cl-shake-stopped: 1; }
    }
}
@keyframes spin {
    0% { transform: rotate(0deg); }
    100% { transform: rotate(360deg); }
}

/* ============================================================
   .cl-btn-loading — frontend AJAX-button loading utility
   ============================================================
   Apply this class to any button (or interactive element) for the
   duration of an AJAX request. CSS-only — no markup needed inside
   the button. Disables clicks via pointer-events:none, fades the
   element slightly, and renders a small spinner via ::after next
   to the button text.

   Usage pattern (frontend JS):
     $btn.addClass('cl-btn-loading');
     FrontendFn_cl.sendAjaxRequest(formData, onSuccess, function (response) {
         $btn.removeClass('cl-btn-loading');
         onError(response);
     });
   public.js auto-removes the class on every AJAX success, so most
   call sites only need to clear it explicitly in their error path.

   Reuses @keyframes spin defined just above (canonical home —
   public.css is enqueued unconditionally on every public page).
   ============================================================ */
.cl-btn-loading {
    pointer-events: none;
    opacity: 0.7;
}
.cl-btn-loading::after {
    content: '';
    display: inline-block;
    width: 14px;
    height: 14px;
    margin-left: 8px;
    border: 2px solid currentColor;
    border-top-color: transparent;
    border-radius: 50%;
    animation: spin 0.6s linear infinite;
    vertical-align: middle;
}
.cl_shake_animation {
    animation-name: shakeMe;
    animation-duration: 8s;
    animation-iteration-count: infinite;
    animation-timing-function: linear;
}

/*-------Modal system----------*/

.cl_modal {
    z-index: 100000001;
    position: fixed;
    overflow: auto;
    background-color: #00000087;
    width: 100%;
    height: 100%;
    top: 0;
    left: 0;
    max-height: 100%;
}
.cl_modal_header {
    display: flex;
    gap: 10px;
    z-index: 10;
    justify-content: space-between;
    align-items: center;
    padding: 10px 10px;
    position: sticky;
    top: 0;
    background: #fff;
    color: #000;
}
.cl_modal_title {
    color: inherit;
}
.cl_modal_logo {
    display: flex;
    align-items: center;
}
.cl_modal_close {
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 5px;
    /* Native-button reset — .cl_modal_close is a <button> for keyboard/SR accessibility; strip the browser's default
       chrome. Its look is the design preset it carries (0,2,0, wins over this): the store's close design
       (publicUtils_cl::renderModalHeaderCloseButton(), Store → Site info), or its popup's own (the checkout popup's,
       the filter drawer's). */
    appearance: none;
    -webkit-appearance: none;
    background: none;
    border: 0;
    padding: 0;
    margin: 0;
    color: inherit;
    font: inherit;
}
/* The store's close button pinned in the top-trailing corner (publicUtils_cl::renderModalCloseButton(): the cart
   drawer, the quick view, the upsell confirmation, the thank-you upsell, the account invitation), RTL-aware via
   inset-inline-end; a consumer needing a different spot (the quick view's half-outside look) overrides the position
   with a more-specific rule. Only the position and a native-button reset live here: its look — size, colours, shape —
   is the store's close design preset (0,2,0), 44 x 44 by default (whole_plugin WP-1, 02-11-2026; until then a fixed
   32px black disc, the cart drawer's square). */
.cl-modal-close-x {
    position: absolute;
    top: 0px;
    inset-inline-end: 0px;
    z-index: 10;
    display: inline-flex !important;
    align-items: center;
    justify-content: center;
    appearance: none;
    -webkit-appearance: none;
    background: none;
    border: 0;
    padding: 0;
    margin: 0;
    color: inherit;
    font: inherit;
    cursor: pointer !important;
}
.cl_modal_container {
    background: #fff;
}
/* The box takes focus when a popup opens (FrontendFn_cl.onModalOpened) so the keyboard starts inside it; a
   ring around the whole popup would mark nothing the shopper can act on. Its fields keep their own ring. */
.cl_modal_container[tabindex="-1"]:focus {
    outline: none;
}
.cl_modal_left .cl_modal_container {
    right: auto;
    left: 0;
    margin-inline-end: auto;
    margin-inline-start: 0;
}
.cl_modal_right .cl_modal_container {
    left: auto;
    right: 0;
    margin-inline-end: 0;
    margin-inline-start: auto;
}
.cl_modal_left .cl_modal_container, .cl_modal_right .cl_modal_container {
    inset-block: .001px 0;
    width: min(340px, 100vw);
    min-height: 100%;
    bottom : 0;
    flex-direction: column;
}
.cl_modal_center .cl_modal_container {
    position: fixed;
    top: 50%;
    left: 50% !important;
    transform: translate(-50%, -50%);
    /*width: auto;*/
    width: max-content;
    max-width: 1000px;
    margin: auto;
    height: auto;
    max-height: 96%;
    overflow: auto;
    border-radius: 10px;
}
/* A centred popup with a header scrolls its body only, as the checkout modal's sticky-submit layout does; the header
   and a footer stay in place. When the container scrolled, its content passed under the sticky header into the
   container's top padding (its design preset) and showed above the title (options pop-up, 23-10-2026). */
.cl_modal_center .cl_modal_container:has(> .cl_modal_header) {
    display: flex;
    flex-direction: column;
    overflow: hidden;
}
.cl_modal_center .cl_modal_container:has(> .cl_modal_header) > * {
    flex-shrink: 0;
}
.cl_modal_center .cl_modal_container:has(> .cl_modal_header) > .cl_modal_body {
    flex: 1 1 auto;
    min-height: 0;
    overflow: auto;
}
/*-custom-*/
.cl_modal_body .cl_toggle_body {
    padding-top: 10px;
}
@media (max-width: 767.98px) {
    .cl_modal_center .cl_modal_container {
        max-width: 96% !important;
        width: 94%;
    }
    
    .cl-checkout-container {
        flex-wrap: wrap;
    }
}

@media (max-width: 480px) {
    .cl_modal_left .cl_modal_container, .cl_modal_right .cl_modal_container {
        max-width: 96% !important;
        width: 94%;
    }
}

/* The pop-up a missing required option opens (variations_all_pages.js, Variations → Errors). Its look is the
   design's presets (card, title, button); this is layout only. Here because a card's variations can open it on
   any page. */
.cl-vr-error-popup .cl_modal_container {
    width: min(440px, 94vw);
}
.cl-vr-error-popup-body {
    padding: 10px;
}
.cl-vr-error-popup-msg {
    margin: 0 0 8px;
}
/* The shell that carries the card's or list's classes around the copied options: no box of its own. Under the
   pop-up (0,2,0): the thank-you card's own `.upsell-products-card` (display:flex, max-width:fit-content) came later
   and turned it into a 280px box (pov, 23-10-2026). */
.cl-vr-error-popup .cl-vr-picker-scope {
    display: contents;
}
/* The copied block's header is shown, not used: it does not fold the copy. */
.cl-vr-picker .cl_toggle_header {
    pointer-events: none;
}
.cl-vr-picker ul.cl-vr-elements {
    flex-wrap: wrap;
    overflow: visible;
}
/* A dropdown's copy as wide as the pop-up: with no width of its own (a thank-you card's select) it shrank to its
   empty first option, about 40px (pov, 23-10-2026). */
.cl-vr-picker .cl-vr-picker-group select {
    width: 100%;
}
.cl-vr-error-popup-footer {
    display: flex;
    padding: 10px;
}
.cl-vr-error-popup-btn {
    flex: 1;
}

/*------Modal system end----------*/


/*------Tooltip utility start------
 * Reusable persistent tooltip for all frontend components.
 * Shows a small label when data-selected attribute is set on the element.
 * Default position: top. Override with data-pos="bottom|left|right".
 *
 * Usage:
 *   <span class="cl-tooltip" data-selected="value"></span>           (top)
 *   <span class="cl-tooltip" data-selected="value" data-pos="bottom"></span>
 *   <span class="cl-tooltip" data-selected="value" data-pos="left"></span>
 *   <span class="cl-tooltip" data-selected="value" data-pos="right"></span>
 *
 * The parent element MUST have position:relative for correct positioning.
 * The tooltip only appears when data-selected is present — remove the attribute to hide it.
 *------*/
.cl-tooltip[data-selected]::after {
    content: attr(data-selected);
    position: absolute;
    bottom: calc(100% + 0px);
    inset-inline-start: 0;
    white-space: nowrap;
    max-width: 150px;
    overflow: hidden;
    text-overflow: ellipsis;
    font-size: 11px;
    line-height: 1.2;
    padding: 2px 4px;
    border-radius: 2px;
    background-color: rgba(0, 0, 0, 0.75);
    color: #fff;
    pointer-events: none;
    z-index: 1;
}

/* Bottom */
.cl-tooltip[data-selected][data-pos="bottom"]::after {
    bottom: auto;
    top: calc(100% + 4px);
}

/* Left */
.cl-tooltip[data-selected][data-pos="left"]::after {
    bottom: auto;
    top: 50%;
    left: auto;
    right: calc(100% + 6px);
    transform: translateY(-50%);
}

/* Right */
.cl-tooltip[data-selected][data-pos="right"]::after {
    bottom: auto;
    top: 50%;
    left: calc(100% + 6px);
    transform: translateY(-50%);
}

/*------Hover tooltip mode------
 * The SAME contract as the admin tooltip (admin.css .cl-tooltip): anchor carries
 * `cl_title="…"`, the bubble is :before and the arrow :after, hidden until hover or
 * focus. One mental model across admin and frontend — a dev moving between the two
 * writes the same markup.
 *
 * Distinct from the [data-selected] mode above, which is a PERSISTENT single-line
 * label (nowrap + ellipsis). The two are attribute-scoped so they never collide;
 * an element uses one or the other.
 *
 * Usage:
 *   <span class="cl-tooltip" cl_title="Text" tabindex="0">…</span>
 *   <span class="cl-tooltip" cl_title="Text" position="top-start">…</span>   (top-end too)
 *
 * The anchor MUST be position:relative (the base .cl-tooltip rule below sets it).
 * `tabindex="0"` is not optional on touch: :hover is unreliable there, and a tap on a
 * focusable element does fire :focus — which is why the admin rule pairs the two.
 * A tooltip is still a poor PRIMARY channel on a phone; keep essential copy visible.
 *------*/
.cl-tooltip[cl_title] {
    cursor: help;
    position: relative;
}
.cl-tooltip[cl_title]::before {
    content: attr(cl_title);
    position: absolute;
    /* Default: centred above. position="top-start|top-end" override below. */
    bottom: 100%;
    /* `left`, NOT `inset-inline-start` — deliberately physical, matching the admin original this
       block was ported from. The centring idiom only stays symmetric while BOTH halves share a
       convention: `transform` never flips with `direction`, so a logical inset paired with a
       physical translate breaks in RTL — the inset resolves to `right:50%`, then the box shifts a
       further half-width the SAME way, landing a full bubble-width off its anchor (measured, and
       the arrow detaches from the bubble because each shifts by its own width). Physical+physical
       is direction-agnostic here and needs no [dir="rtl"] override. */
    left: 50%;
    transform: translateX(-50%);
    margin-bottom: 8px;
    padding: 8px 12px;
    background: #202223;
    color: #fff;
    font-size: 13px;
    /* The bubble is CHROME — never let it inherit the anchor's casing (a storefront
       theme may uppercase the element the tooltip is attached to). */
    text-transform: none;
    /* Wrap long text instead of forcing one line that overflows a narrow viewport;
       max-content sizes to the text, capped by max-width so wrapping kicks in. */
    white-space: normal;
    width: max-content;
    max-width: 280px;
    line-height: 1.4;
    border-radius: 6px;
    pointer-events: none;
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.2s, visibility 0.2s;
    z-index: 1;
}
.cl-tooltip[cl_title]::after {
    content: '';
    position: absolute;
    bottom: 100%;
    /* `left`, NOT `inset-inline-start` — deliberately physical, matching the admin original this
       block was ported from. The centring idiom only stays symmetric while BOTH halves share a
       convention: `transform` never flips with `direction`, so a logical inset paired with a
       physical translate breaks in RTL — the inset resolves to `right:50%`, then the box shifts a
       further half-width the SAME way, landing a full bubble-width off its anchor (measured, and
       the arrow detaches from the bubble because each shifts by its own width). Physical+physical
       is direction-agnostic here and needs no [dir="rtl"] override. */
    left: 50%;
    transform: translateX(-50%);
    margin-bottom: -4px;
    border: 6px solid transparent;
    border-top-color: #202223;
    pointer-events: none;
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.2s, visibility 0.2s;
    z-index: 1;
}
/* Reveal on hover OR keyboard/tap focus. */
.cl-tooltip[cl_title]:hover::before,
.cl-tooltip[cl_title]:hover::after,
.cl-tooltip[cl_title]:focus::before,
.cl-tooltip[cl_title]:focus::after {
    opacity: 1;
    visibility: visible;
}
/* Edge-anchored variants keep the bubble inside a narrow / overflow:hidden parent by
   aligning it to the anchor's start or end edge instead of centring it. */
.cl-tooltip[cl_title][position="top-start"]::before {
    inset-inline-start: 0;
    transform: none;
}
.cl-tooltip[cl_title][position="top-end"]::before {
    inset-inline-start: auto;
    inset-inline-end: 0;
    transform: none;
}
/*------Tooltip utility end--------*/

/*------Celebration confetti — shared utility--------
   Used by both thankyou page-level overlay (.celebration-wrapper alone) AND
   any compo Confirmation Modal that opts in (e.g. p_upsell, thankyou upsell)
   via .celebration-wrapper.modal-celebration. Promoted from inline <style>
   blocks per the DRY decision in p-upsell-subtabs-confirmation-26-04-2026
   task. Per-compo z-index overrides for the modal variant live in each
   compo's generated_css.php. */
.celebration-wrapper {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    pointer-events: none;
    z-index: 1;
    overflow: hidden;
}
.confetti-piece {
    position: absolute;
    width: 8px;
    height: 16px;
    background: #ffd700;
    top: -20px;
    opacity: 0;
}
.confetti-piece:nth-child(1) { background: #ffbe0b; left: 10%; animation: confettiFall 3s ease-in infinite; animation-delay: 0s; }
.confetti-piece:nth-child(2) { background: #fb5607; left: 20%; animation: confettiFall 2.5s ease-in infinite; animation-delay: 0.2s; }
.confetti-piece:nth-child(3) { background: #ff006e; left: 30%; animation: confettiFall 2.8s ease-in infinite; animation-delay: 0.4s; }
.confetti-piece:nth-child(4) { background: #8338ec; left: 40%; animation: confettiFall 2.6s ease-in infinite; animation-delay: 0.6s; }
.confetti-piece:nth-child(5) { background: #3a86ff; left: 50%; animation: confettiFall 3.2s ease-in infinite; animation-delay: 0.8s; }
.confetti-piece:nth-child(6) { background: #ff006e; left: 60%; animation: confettiFall 2.9s ease-in infinite; animation-delay: 1s; }
.confetti-piece:nth-child(7) { background: #fb5607; left: 70%; animation: confettiFall 2.7s ease-in infinite; animation-delay: 1.2s; }
.confetti-piece:nth-child(8) { background: #ffbe0b; left: 80%; animation: confettiFall 3.1s ease-in infinite; animation-delay: 1.4s; }

@keyframes confettiFall {
    0%   { transform: translateY(0)     rotate(0deg);   opacity: 1; }
    25%  { transform: translateY(100px) rotate(45deg);  opacity: 1; }
    50%  { transform: translateY(200px) rotate(90deg);  opacity: 0.7; }
    75%  { transform: translateY(300px) rotate(135deg); opacity: 0.4; }
    100% { transform: translateY(400px) rotate(180deg); opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
    .confetti-piece { animation: none !important; }
}
/*------Celebration confetti end--------*/

/* ─── Custom-code design anchor ──────────────────────────────────────────────
   Every Section Manager design that renders is wrapped in an element carrying
   `cl-design="{type}-{id}"`. That attribute is the scoping root for the
   design's own custom CSS:

       @scope ([cl-design="cart-15"]) to ([cl-design]) { …merchant css… }

   The ATTRIBUTE does the scoping. This class is a separate, opt-in layout
   escape used ONLY on wrappers the plugin adds, so the wrapper contributes no
   box of its own and the children keep their original relationship to the
   parent (a plain <div> would otherwise become the single flex/grid item).

   Deliberately NOT `[cl-design] { display: contents }`: that would also hit
   anchors placed on EXISTING containers, and measurement showed the two prime
   candidates (.cl-topbar-container, .cl-header-container) compute display:block
   — stripping their boxes would break the header and topbar on every page.

   NOTE: display:contents removes the BOX, not the NODE — `>` and :nth-child
   still see the wrapper. Each added wrapper is checked for that at its site. */
.cl-design-wrap { display: contents; }

/* ── Keyboard focus ring ──────────────────────────────────────────────────────
   WCAG 2.4.7 requires a visible focus indicator, and 1.4.11 requires it to reach
   3:1 against its background. Before this rule the storefront had exactly ONE
   focus style anywhere — .cl-header a:focus-visible in header.css, using
   currentColor — so every other plugin control fell back to whatever the browser
   or the active theme happened to draw, which on several themes is nothing at all.

   Carried by --cl-border-color3, whose palette slot exists for exactly this and
   had no consumer. It clears 3:1 on all four shipped grounds with margin, and
   because it is a palette slot the merchant re-themes it with everything else
   rather than hunting for a hardcoded colour.

   :focus-visible, NOT :focus — a mouse click must not draw a ring. Scoped to the
   plugin's own controls so it can never restyle theme or admin chrome. */
.cl_container :focus-visible,
.cl_modal :focus-visible,
.cl-checkout-form :focus-visible,
.cl-topbar-container :focus-visible,
.cl-header-container :focus-visible,
.cl-footer-container :focus-visible {
    outline: 2px solid var(--cl-border-color3);
    outline-offset: 2px;
    border-radius: inherit;
}

/* ── Rating stars (G28, 08-10-2026) ───────────────────────────────────────────
   public/partials/rating_stars.php: five stars filled to the exact average. The filled row is
   clipped to N tenths of a star — cl-rating-fill-N, one width per value, N = 0–50 — from the
   reading side (inset-inline-start), so on an RTL store it fills right to left. Size and colours
   come from each design's own style keys; this is structure only. The filled row's rule has two
   classes so the admin preview's `[attached-setting] { position: relative }` (preview_fr.css, one
   attribute, loaded later) cannot pull it out of the overlay. */
.cl-rating-stars {
    position: relative;
    display: inline-block;
    line-height: 1;
    white-space: nowrap;
    vertical-align: middle;
}
.cl-rating-stars .cl-rating-stars-filled {
    position: absolute;
    top: 0;
    inset-inline-start: 0;
    overflow: hidden;
    width: 0;
}
.cl-rating-fill-1 .cl-rating-stars-filled { width: 2%; }
.cl-rating-fill-2 .cl-rating-stars-filled { width: 4%; }
.cl-rating-fill-3 .cl-rating-stars-filled { width: 6%; }
.cl-rating-fill-4 .cl-rating-stars-filled { width: 8%; }
.cl-rating-fill-5 .cl-rating-stars-filled { width: 10%; }
.cl-rating-fill-6 .cl-rating-stars-filled { width: 12%; }
.cl-rating-fill-7 .cl-rating-stars-filled { width: 14%; }
.cl-rating-fill-8 .cl-rating-stars-filled { width: 16%; }
.cl-rating-fill-9 .cl-rating-stars-filled { width: 18%; }
.cl-rating-fill-10 .cl-rating-stars-filled { width: 20%; }
.cl-rating-fill-11 .cl-rating-stars-filled { width: 22%; }
.cl-rating-fill-12 .cl-rating-stars-filled { width: 24%; }
.cl-rating-fill-13 .cl-rating-stars-filled { width: 26%; }
.cl-rating-fill-14 .cl-rating-stars-filled { width: 28%; }
.cl-rating-fill-15 .cl-rating-stars-filled { width: 30%; }
.cl-rating-fill-16 .cl-rating-stars-filled { width: 32%; }
.cl-rating-fill-17 .cl-rating-stars-filled { width: 34%; }
.cl-rating-fill-18 .cl-rating-stars-filled { width: 36%; }
.cl-rating-fill-19 .cl-rating-stars-filled { width: 38%; }
.cl-rating-fill-20 .cl-rating-stars-filled { width: 40%; }
.cl-rating-fill-21 .cl-rating-stars-filled { width: 42%; }
.cl-rating-fill-22 .cl-rating-stars-filled { width: 44%; }
.cl-rating-fill-23 .cl-rating-stars-filled { width: 46%; }
.cl-rating-fill-24 .cl-rating-stars-filled { width: 48%; }
.cl-rating-fill-25 .cl-rating-stars-filled { width: 50%; }
.cl-rating-fill-26 .cl-rating-stars-filled { width: 52%; }
.cl-rating-fill-27 .cl-rating-stars-filled { width: 54%; }
.cl-rating-fill-28 .cl-rating-stars-filled { width: 56%; }
.cl-rating-fill-29 .cl-rating-stars-filled { width: 58%; }
.cl-rating-fill-30 .cl-rating-stars-filled { width: 60%; }
.cl-rating-fill-31 .cl-rating-stars-filled { width: 62%; }
.cl-rating-fill-32 .cl-rating-stars-filled { width: 64%; }
.cl-rating-fill-33 .cl-rating-stars-filled { width: 66%; }
.cl-rating-fill-34 .cl-rating-stars-filled { width: 68%; }
.cl-rating-fill-35 .cl-rating-stars-filled { width: 70%; }
.cl-rating-fill-36 .cl-rating-stars-filled { width: 72%; }
.cl-rating-fill-37 .cl-rating-stars-filled { width: 74%; }
.cl-rating-fill-38 .cl-rating-stars-filled { width: 76%; }
.cl-rating-fill-39 .cl-rating-stars-filled { width: 78%; }
.cl-rating-fill-40 .cl-rating-stars-filled { width: 80%; }
.cl-rating-fill-41 .cl-rating-stars-filled { width: 82%; }
.cl-rating-fill-42 .cl-rating-stars-filled { width: 84%; }
.cl-rating-fill-43 .cl-rating-stars-filled { width: 86%; }
.cl-rating-fill-44 .cl-rating-stars-filled { width: 88%; }
.cl-rating-fill-45 .cl-rating-stars-filled { width: 90%; }
.cl-rating-fill-46 .cl-rating-stars-filled { width: 92%; }
.cl-rating-fill-47 .cl-rating-stars-filled { width: 94%; }
.cl-rating-fill-48 .cl-rating-stars-filled { width: 96%; }
.cl-rating-fill-49 .cl-rating-stars-filled { width: 98%; }
.cl-rating-fill-50 .cl-rating-stars-filled { width: 100%; }

/* ── Product tags as badges + badges on a product photo (G29, 09-10-2026) ──────────────────────────
   Shared by listing cards, upsell cards, the product gallery and search results. The look of each
   badge is its design preset (.cl-preset-{id}); these rules only place them.
   The photo layer covers the photo; .cl-photo-badges-box is its content box, so the layer's padding is
   the distance from the photo's edges (a design may compile its own). Each place is a row: badges that
   chose the same place line up in it. Start / end follow the text direction, like the stock badge did. */
.cl-tag-badges {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
}
/* A cart line's row is printed for every line and filled by cart.js; a product with no shown tag leaves it
   empty, and its margin left a gap under the name (until 27-10-2026). */
.cl-tag-badges:empty {
    display: none;
}
.cl-tag-badge {
    align-items: center;
    gap: 4px;
    text-decoration: none;
}
.cl-tag-badge .cl-icon,
.cl-tag-badge svg {
    width: 1em;
    height: 1em;
    flex: none;
}
.cl-photo-badges {
    position: absolute;
    inset: 0;
    z-index: 3;
    padding: 8px;
    box-sizing: border-box;
    pointer-events: none;
}
.cl-photo-badges-box {
    position: relative;
    width: 100%;
    height: 100%;
}
.cl-photo-badges-slot {
    position: absolute;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    max-width: 100%;
}
.cl-photo-badges-slot a.cl-tag-badge {
    pointer-events: auto;
}
/* A sold-out card's label in the stock badge's place (listing cards): shown only by a design whose
   compiled CSS says its label sits "Inside The Box"; the badge preset sets display at (0,2,0). */
.cl-photo-badges-slot .cl-soldout-slot-label {
    display: none !important;
}
.cl-pos-top-start, .cl-pos-top-center, .cl-pos-top-end { top: 0; }
.cl-pos-bottom-start, .cl-pos-bottom-center, .cl-pos-bottom-end { bottom: 0; }
.cl-pos-top-start, .cl-pos-center-start, .cl-pos-bottom-start { inset-inline-start: 0; }
.cl-pos-top-end, .cl-pos-center-end, .cl-pos-bottom-end { inset-inline-end: 0; justify-content: flex-end; }
.cl-pos-top-center, .cl-pos-bottom-center, .cl-pos-center {
    left: 50%;
    transform: translateX(-50%);
    justify-content: center;
    width: max-content;
}
.cl-pos-center-start, .cl-pos-center-end, .cl-pos-center { top: 50%; }
.cl-pos-center-start, .cl-pos-center-end { transform: translateY(-50%); }
.cl-pos-center { transform: translate(-50%, -50%); }
/* Start and end on the same row share it: each keeps to its half and wraps there, so on a narrow card
   (two columns on a phone) one corner's badges never run under the other's. */
.cl-photo-badges-box:has(> .cl-pos-top-start):has(> .cl-pos-top-end) > :is(.cl-pos-top-start, .cl-pos-top-end),
.cl-photo-badges-box:has(> .cl-pos-center-start):has(> .cl-pos-center-end) > :is(.cl-pos-center-start, .cl-pos-center-end),
.cl-photo-badges-box:has(> .cl-pos-bottom-start):has(> .cl-pos-bottom-end) > :is(.cl-pos-bottom-start, .cl-pos-bottom-end) {
    max-width: calc(50% - 4px);
}
