/*
 * Tesla Product Card — the single canonical general product card.
 * ---------------------------------------------------------------------------
 * Hand-authored plain CSS at a fixed, theme-version-independent path, following the
 * assets/qsm/qsm.css precedent. Deliberately NOT part of the style.less monolith: the card is
 * the general product presentation and must render identically regardless of which asset
 * generation ThemeCssVersionUrl selects.
 *
 * ONE card. Context differences are outer-layout modifiers on the SAME markup tree, never a
 * second card implementation:
 *
 *     .tc-grid            desktop / mobile product grid   (hairline separators)
 *     .tc-row             horizontal product row/slider   (dark section)
 *     --tc-media-ratio    media aspect, per context
 *
 * GEOMETRY IS MEASURED, NOT GUESSED. Values below come from the native-resolution references
 * in G:\Projects\Design\plp (all @2x):
 *
 *   PLP-FullPage @1920      card pitch 341.25 · 4 columns · 1px hairline between cards
 *                           grid 1365 wide · sidebar ~318 on the inline-start side
 *   plp-mobile-1 @414       card 195 · 2 columns · gap 8.5 · outer 8 · media 195x259 = 3:4
 *   products-row-slider     card 252 · gap 24 · media 252x301 = 5:6 · section background #000
 *   @1440
 *
 * Colour tokens follow the Ryan palette (assets/v6/css/variables.less):
 *   @color-error-200  #ED2E7E  discount %, special-sale label, selected swatch ring
 *   @color-success-200 #00BA88 free shipping
 *   @color-info-200   #18A0FF  expedited shipping
 *   @color-secondary  #2F2F2F  primary text
 *   @color-secondary-500 #979797 muted / old price
 *   @color-secondary-300 #E6E6E6 hairlines, swatch borders
 *   @color-warning-200 #F4B740 rating star
 *
 * RTL is the storefront default. Every directional rule uses logical properties so the LTR
 * sheet needs no card-specific counterpart.
 *
 * Typography: the card sets size/weight/line-height only. It never sets font-family — the
 * Ryan face is inherited.
 */

/* ==========================================================================
   1. CARD
   ========================================================================== */

.tc-card {
    --tc-accent: #ED2E7E;
    --tc-success: #00BA88;
    --tc-info: #18A0FF;
    --tc-danger: #ED303D;
    --tc-ink: #2F2F2F;
    --tc-ink-soft: #5E5E5E;
    --tc-muted: #979797;
    --tc-hairline: #E6E6E6;
    --tc-star: #F4B740;
    --tc-media-bg: #F5F5F5;

    /* Media aspect. 3:4 for grids; the row context overrides it. */
    --tc-media-ratio: 3 / 4;
    --tc-media-radius: 8px;

    /* Reserved region heights. These are what make every card in a row the same height and
       put the QSM host, title, swatches and price on shared baselines. Overridden per
       breakpoint below. */
    --tc-badge-h: 18px;
    /* Title metrics measured on plp-mobile-1 (card 195): glyph band 15.5 tall -> ~15px, and the
       first line sits 19.0 below the media edge. */
    --tc-title-lh: 22px;
    --tc-title-h: 44px;      /* exactly two lines */
    --tc-swatch-h: 24px;
    --tc-meta-h: 17px;
    --tc-price-h: 26px;
    --tc-oldprice-h: 15px;
    /* --tc-pad-x is the card's own horizontal inset; --tc-text-pad-x insets the text columns
       relative to the media. On mobile the reference shows the media running the full card
       width (card 195 -> media 195 -> 260 tall at 3:4) with only the text inset, so the card
       inset is 0 there and the text carries its own. Desktop insets the media instead. */
    /* CARD CONTENT SAFE-AREA.
       --tc-pad-x insets the media; --tc-text-pad-x insets the text column inside it. The media
       may run the full card width, but the badge, title, swatches and price must never touch the
       card edge. Where the media is full-bleed (mobile, row) the text carries the whole inset. */
    --tc-pad-x: 0px;
    --tc-text-pad-x: 10px;
    /* Deep enough to hold the hanging old-price row (15) plus a little air. Uniform on
       every card, so it reads as card padding rather than a reserved discount slot. */
    --tc-pad-b: 20px;
    --tc-gap: 4px;

    /* Per-seam gaps. Each falls back to --tc-gap, so a context only has to name the seams it
       actually re-times. Measured seam-by-seam from the references rather than assumed to be
       one uniform rhythm - they are not. */
    /* Mobile seams, measured off plp-mobile-1 (card 195, media 195x259):
           media bottom 330 -> title glyph 352      seam ~4 on the box
           title bottom  385 -> swatch chips 403    seam 18
           swatch bottom 427 -> meta glyph  445     seam 20
           meta bottom   460 -> price glyph 470     seam 16
       These are structural gaps in the design system, so they are reserved even where this
       catalogue has no rating or discount to put in them - but nothing fake is rendered. */
    /* Box seam, not optical seam: the title's half-leading (line-height 22 over a 15px glyph)
       eats ~3.5px, so a 14px box seam rendered as 17.5px of visible air under the media and the
       title read as glued to it. 18 lands the glyph at ~21.5, which is the reference's 22. */
    --tc-gap-media-title: 18px;
    --tc-gap-title-swatch: 13px;
    --tc-gap-swatch-meta: 16px;
    --tc-gap-meta-price: 6px;

    /* Seams for the COLLAPSED neighbourings (MP5). When a section is absent the price must not
       inherit the seam of a section that is no longer there: 6px is the meta->price seam, and
       reading it as a swatch->price seam glues the price to the swatch rail. These are the
       section-level seams the price falls back to as its predecessor changes. They are seams,
       not placeholders - nothing is reserved and nothing is rendered. */
    --tc-gap-swatch-price: 18px;   /* swatches present, meta collapsed */
    --tc-gap-title-price: 14px;    /* swatches AND meta collapsed */

    /* Price-row direction.
       row          -> price on the inline-start (right in RTL), discount % on the inline-end.
                       This is plp-mobile-1.
       row-reverse  -> price on the inline-end, discount % on the inline-start.
                       This is products-row-slider.
       The two reference sets genuinely disagree here, so the arrangement is a context token on
       ONE markup tree rather than a second card. --tc-oldprice-align follows it so the old
       price always sits directly under the price it replaces. */
    --tc-price-dir: row;
    --tc-oldprice-align: flex-start;

    position: relative;
    display: flex;
    flex-direction: column;
    width: 100%;
    height: 100%;
    padding: 0 var(--tc-pad-x) var(--tc-pad-b);
    /* No card surface: both reference sets show the card sitting directly on the page/section
       background, separated by rules rather than by a tile. */
    background: transparent;
    color: var(--tc-ink);
    box-sizing: border-box;
}

.tc-card *,
.tc-card *::before,
.tc-card *::after { box-sizing: inherit; }

.tc-card a { text-decoration: none; color: inherit; }

/* ==========================================================================
   2. BADGE STRIP
   ========================================================================== */

/*
 * Always occupies its reserved height, badge or not, so the media top edge is identical on
 * every card in the row. This is the first of the shared baselines.
 */
.tc-card__badges {
    display: flex;
    align-items: center;
    justify-content: flex-start;   /* inline-start = right in RTL, as in both references */
    padding-inline: var(--tc-text-pad-x);
    height: var(--tc-badge-h);
    min-height: var(--tc-badge-h);
    flex: 0 0 auto;
}

/*
 * Sampled off products-row-slider (card 2 badge band, CSS y 91.0-103.5, media top 114):
 *     colour  #E7113D      glyph height 12.5  ->  ~13px
 *     flush against the card's inline-start edge, 10.5 above the media
 *
 * Note the reference uses a RED for this badge and the pink #ED2E7E only for the discount
 * percentage - two different colours. Using --tc-danger here keeps that separation, which also
 * reads correctly: Special Sale is not a discount.
 */
.tc-card__badge--special {
    font-size: 13px;
    font-weight: 700;
    line-height: 1;
    color: var(--tc-danger);
    white-space: nowrap;
}

/* ==========================================================================
   3. MEDIA
   ========================================================================== */

.tc-card__media {
    position: relative;
    width: 100%;
    aspect-ratio: var(--tc-media-ratio);
    overflow: hidden;
    border-radius: var(--tc-media-radius);
    background: var(--tc-media-bg);
    flex: 0 0 auto;
}

@supports not (aspect-ratio: 1 / 1) {
    .tc-card__media::before { content: ""; display: block; padding-top: 133.33%; }
    .tc-card__media > .tc-card__viewport,
    .tc-card__media > .tc-card__media-link { position: absolute; inset: 0; }
}

.tc-card__viewport,
.tc-card__media > .tc-card__media-link { width: 100%; height: 100%; }

.tc-card__slide,
.tc-card__media-link {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;
}

.tc-card__img {
    display: block;
    width: 100%;
    height: 100%;
    max-width: 100%;
    /* The references show product photography filling the media frame edge to edge. */
    object-fit: cover;
}

/*
 * Minimal Swiper structural CSS, scoped to the card.
 *
 * assets/v6/css/style.css pulls the Swiper bundle in only through a plain CSS @import on
 * line 5, AFTER other rules have already been emitted. A CSS @import is honoured only when it
 * precedes every rule except @charset, so browsers drop it and Swiper's layout rules never
 * arrive: .swiper-wrapper is not a flex row and the slides stack vertically, showing the next
 * image underneath the current one.
 *
 * Rather than reorder the shared sheet (which would touch every slider on the site), the card
 * carries the few structural rules it needs, scoped to .tc-card__viewport. Harmless if the
 * bundle ever does load.
 */
.tc-card__viewport.swiper {
    position: relative;
    display: block;
    height: 100%;
    margin: 0;
    padding: 0;
    overflow: hidden;
    list-style: none;
    z-index: 1;
}

.tc-card__viewport .swiper-wrapper {
    position: relative;
    display: flex;
    width: 100%;
    height: 100%;
    margin: 0;
    padding: 0;
    box-sizing: content-box;
    transition-property: transform;
    transform: translate3d(0, 0, 0);
    z-index: 1;
}

.tc-card__viewport .swiper-slide {
    position: relative;
    flex-shrink: 0;
    width: 100%;
    height: 100%;
    transition-property: transform;
}

/* ==========================================================================
   4. GALLERY DOTS
   ==========================================================================
   Refined to the reference language: small, circular, tightly and evenly spaced, subtle.
   Inactive reads as a soft ring, active as a solid ink dot. Deliberately not Swiper's
   default heavy blue bullets.
   ========================================================================== */

/*
 * MEASURED off products-row-slider (card 1 media 252x302 @1440, sampled at native @2x):
 *
 *     bullet diameter   4.0      bullet gap    3.0     bullet pitch  7.0
 *     bottom offset    12.5      side offset  12.5
 *
 * The rail sits on the media's inline-END (left in RTL), opposite the QSM host, in both
 * reference sets.
 */
.tc-card__dots {
    position: absolute;
    inset-block-end: 12px;
    inset-inline-end: 12px;        /* opposite the QSM host, as both references show */
    z-index: 2;
    display: flex;
    align-items: center;
    gap: 3px;
    width: auto !important;
    line-height: 0;
    pointer-events: none;          /* the rail must never block the media link */
}

/*
 * Dots sit directly on product photography, which may be light or dark. A single-colour
 * treatment disappears on one of the two, so inactive is a light fill and active is ink,
 * each carrying a faint counter-coloured ring for separation. Reads on both.
 */
/* Inactive: light centre inside a thin visible ring. The ring is drawn as a real border so it
   reads at 4px; a box-shadow hairline optically vanished against product photography. */
.tc-card__dots .swiper-pagination-bullet {
    pointer-events: auto;
    width: 5px;
    height: 5px;
    margin: 0 !important;
    border-radius: 50%;
    background: rgba(255, 255, 255, .9);
    border: 1px solid rgba(47, 47, 47, .55);
    box-sizing: border-box;
    box-shadow: none;                       /* no glow */
    opacity: 1;
    transition: background-color .18s ease, border-color .18s ease;
}

/* Active: solid dark, same diameter, so the rail never shifts as slides change. The two states
   differ by fill, which is what makes them separable at this size. */
.tc-card__dots .swiper-pagination-bullet-active {
    background: #2F2F2F;
    border-color: #2F2F2F;
}


/* ==========================================================================
   5. QSM HOST  —  SLOT ONLY (see firewall note)
   ==========================================================================
   QSM FIREWALL.

   QSM (assets/qsm/qsm.js + qsm.css) owns everything inside this host: markup, classes,
   dimensions, colours, icon, radius, shadow, states and behaviour. The card owns ONLY the
   slot — where the host sits and how much room is reserved — so the control lands at the
   identical position on every card in a row.

   No rule here targets a QSM-owned selector (.vp-product-item-theme-v2,
   .vp-quantity-supermarket-v3, .vp-quantity-theme-v1, .vp-input, …). An earlier revision set
   background/border-radius/box-shadow on .vp-product-item-theme-v2; that was a firewall
   violation and has been removed.

   THE CARD ADAPTS AROUND QSM. QSM DOES NOT ADAPT TO THE CARD.
   ========================================================================== */

/*
 * POSITION ONLY. Nothing here touches how QSM looks or behaves.
 *
 * Target measured off products-row-slider (card 1, media 252x302 @1440):
 *     control 32x32, bottom offset 12.0, inline-start (right in RTL) offset 12.0
 *
 * The control itself is 35x35 and is drawn entirely by qsm.css - unchanged, and out of scope.
 * The host box measures 0x0 because the control inside it is `position: relative` and overflows
 * it, and it renders 16px ABOVE the host's own bottom edge. With the host pinned at 10px the
 * control therefore landed 26px above the media bottom instead of 12. The -4px cancels that
 * 16px overhang: -4 + 16 = 12. It is an anchor correction on the card-owned slot, not a QSM
 * change - verified by re-measuring the control's own box, which is still 35x35.
 */
.tc-card__quickadd {
    position: absolute;
    inset-block-end: -2px;
    inset-inline-start: 12px;
    z-index: 3;
    /* Anchored to the media box, so its position is identical on every card regardless of
       title length, swatches, rating or discount. */
}

/* ==========================================================================
   6. BODY  —  reserved regions
   ========================================================================== */

.tc-card__body {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    padding-block-start: var(--tc-gap-media-title);
    padding-inline: var(--tc-text-pad-x);
}

/*
 * Region order is explicit so a context can re-sequence the SAME markup instead of forking it.
 * Default (plp-mobile-1 / grid):  title, swatches, meta, pricing.
 * Horizontal row (products-row-slider): title, meta, pricing, swatches - see section 8.
 */
.tc-card__title-link { display: block; order: 1; }
.tc-card__swatches   { order: 2; }
.tc-card__meta       { order: 3; }
.tc-card__pricing    { order: 4; }

.tc-card__title {
    margin: 0;
    font-size: 15px;
    /* The reference title is the anchor of the text block - heavier than the price label and
       clearly ahead of the meta line. 500 read as a caption; 600 reads as a title. */
    font-weight: 600;
    line-height: var(--tc-title-lh);
    color: var(--tc-ink);
    text-align: start;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    overflow-wrap: anywhere;
    /* Two-line CEILING, not a two-line box. The clamp above already stops a long title at two
       lines; reserving the second line as height meant a one-line title carried an empty line of
       air into the seam below it. As a max-height the box is exactly as tall as the lines it
       has, and the grid still equalises neighbouring cards. */
    max-height: var(--tc-title-h);
}

/* Swatches ---------------------------------------------------------------- */

.tc-card__swatches {
    display: flex;
    align-items: center;
    justify-content: flex-start;   /* inline-start, as in the references */
    gap: 6px;
    margin: 0;
    padding: 0;
    list-style: none;
    height: var(--tc-swatch-h);
    min-height: var(--tc-swatch-h);
    flex: 0 0 auto;
    margin-block-start: var(--tc-gap-title-swatch);
}

/* COLLAPSED, not reserved. A product with no variations must not carry a swatch-sized hole:
   `display: none` takes the rail's height AND its seam margin with it, so the body closes up.
   Equal card height is still guaranteed - the grid stretches every card to the tallest cell
   (min-height: 100%) - but the slack now lands at the card's bottom instead of in the middle
   of the text block. */
.tc-card__swatches--empty { display: none; }

.tc-card__swatch {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
}

.tc-card__swatch-chip {
    display: block;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    border: 1px solid var(--tc-hairline);
    background: #FFFFFF;
    object-fit: cover;
}

.tc-card__swatches--image .tc-card__swatch-chip { border-color: rgba(0, 0, 0, .10); }

/* Outer accent ring with a white gap, drawn with box-shadow so selection costs no layout. */
.tc-card__swatch.is-selected .tc-card__swatch-chip {
    box-shadow: 0 0 0 2px #FFFFFF, 0 0 0 3px var(--tc-accent);
}

.tc-card__swatch-chip--blank {
    background: repeating-linear-gradient(45deg, #F7F7F7 0 4px, #EDEDED 4px 8px);
}

.tc-card__swatch-more {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 22px;
    height: 22px;
    padding-inline: 5px;
    border-radius: 11px;
    background: #F5F5F5;
    color: var(--tc-muted);
    font-size: 10px;
    font-weight: 600;
    line-height: 1;
}

/* Meta: rating on the inline-end, shipping/stock on the inline-start ------- */

.tc-card__meta {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-direction: row-reverse;   /* rating (first in DOM) lands on the inline-end */
    gap: 8px;
    height: var(--tc-meta-h);
    min-height: var(--tc-meta-h);
    flex: 0 0 auto;
    margin-block-start: var(--tc-gap-swatch-meta);
}

.tc-card__rating { display: inline-flex; align-items: center; gap: 4px; }
.tc-card__rating-star { width: 13px; height: 13px; fill: var(--tc-star); flex: 0 0 auto; }
.tc-card__rating-value { font-size: 12px; font-weight: 600; color: var(--tc-ink); }

.tc-card__shipping {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: 11px;
    font-weight: 600;
    color: var(--tc-success);
}
.tc-card__shipping-icon { width: 15px; height: 15px; fill: var(--tc-success); flex: 0 0 auto; }

/* Pricing ----------------------------------------------------------------- */

.tc-card__pricing {
    display: flex;
    flex-direction: column;
    /* The price is the card's bottom anchor: neighbouring cards must share a price baseline even
       when one has swatches and the other does not. The auto margin absorbs whatever equal-height
       slack the grid hands the card, so the flexible space lands BETWEEN the optional content and
       the price - never below the price, and never as a reserved placeholder row. The collapsed
       seams above still apply as the minimum gap. */
    margin-top: auto;
    padding-block-start: var(--tc-gap-meta-price);
}

/* Row 1: price and discount % on opposite edges; which edge is which is the context token. */
.tc-card__price-row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    flex-direction: var(--tc-price-dir);
    gap: 8px;
    height: var(--tc-price-h);
    min-height: var(--tc-price-h);
}

/* flex: 0 0 auto keeps the amount and its currency mark welded together. Without it the price
   group is a flex item that can be stretched by the row, which pushes the currency mark to the
   far edge and leaves a gap in the middle of the price. */
.tc-card__price {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    flex: 0 0 auto;
    white-space: nowrap;
}

/* The row-reverse arrangement (price on the inline-end, % on the inline-start) is the reference's
   only when BOTH elements are there to balance each other. On an undiscounted card the price is
   the row's only child and lands alone against the far card edge, reading as floating away from
   the title above it. A lone price returns to the inline-start, under the title. The row shows
   the same defect - a 252 card left ~142px between the title edge and its own price - so this
   is card-level, not context-level. */
.tc-card__price-row > .tc-card__price:only-child { margin-inline-end: auto; }

/* products-row-slider price glyph band is 21.5 CSS tall (digits plus the comma descender), which
   puts the numeral around 19-20px - the price is one of the card's two visual anchors, alongside
   the title. 15px read as body copy. */
.tc-card__price-value {
    font-size: 18px;
    font-weight: 700;
    line-height: 1.2;
    color: var(--tc-ink);
    direction: ltr;
    unicode-bidi: embed;
}

/* Official Toman asset (pro-toman.svg), scaled off the numeral so the two read as one unit:
   ~0.95x the price font-size, sitting on the digits' optical baseline. Held slightly back in
   weight so the amount stays dominant, exactly as the reference does. */
/* Specificity is deliberate: a theme-level `img { width: 100% }` was winning over `width: auto`
   here, so the mark's CSS box stretched to the whole price line (97.6px for a 24px-tall mark).
   preserveAspectRatio then centred the artwork inside that box, which is what pushed the mark
   ~37px away from the numeral and made it read as small and detached. */
.tc-card__price .tc-card__price-currency {
    width: auto;
    max-width: none;
    min-width: 0;
    /* The asset carries internal padding inside its 25x26 viewBox, so the VISIBLE wordmark is
       smaller than the CSS box. Sized off the rendered glyph, not the box, to sit next to the
       numeral at the reference's optical weight. */
    height: 22px;
    flex: 0 0 auto;
    align-self: center;
    position: relative;
    top: 1px;
    opacity: 1;
}

.tc-card__discount-badge {
    display: inline-flex;
    align-items: center;
    font-size: 13px;
    font-weight: 700;
    color: var(--tc-accent);
    direction: rtl;
}

/* Row 2: old price, always reserved so discounted and undiscounted cards match in height.
   Aligned to the same edge the price sits on, so it reads as the value being replaced. */
.tc-card__oldprice-row {
    display: flex;
    align-items: center;
    justify-content: var(--tc-oldprice-align);
    height: var(--tc-oldprice-h);
    min-height: var(--tc-oldprice-h);
    /* The old price HANGS below the current price instead of lifting it. In ProductRowSample the
       current-price line of a discounted card is level with its neighbours' and the struck price
       sits underneath; if the old-price row consumed layout height it would push the bottom-
       anchored price block up by its own height and break that line. The negative end margin
       takes it out of the height calculation while leaving it in normal flow - no absolute
       positioning, and no reserved slot on cards that have no old price. */
    margin-block-end: calc(-1 * var(--tc-oldprice-h));
}

.tc-card__old-price {
    font-size: 12px;
    font-weight: 500;
    color: var(--tc-muted);
    text-decoration: line-through;
    direction: ltr;
    unicode-bidi: embed;
}

/* Optional rows collapse when the product genuinely has no data for them. Same rule as the
   swatch rail: no fake content, no reserved hole. */
.tc-card__meta--empty,
.tc-card__oldprice-row--empty { display: none; }

/* ...and the price re-times itself against whatever section actually precedes it. DOM order is
   title, swatches, meta, pricing, so the adjacent-sibling chain reads the collapsed state
   directly off the markup - no extra class on the pricing block, no JS, no reserved row. */
.tc-card__meta--empty + .tc-card__pricing {
    padding-block-start: var(--tc-gap-swatch-price);
}

.tc-card__swatches--empty + .tc-card__meta--empty + .tc-card__pricing {
    padding-block-start: var(--tc-gap-title-price);
}

/* Non-price states -------------------------------------------------------- */

.tc-card__state {
    display: inline-flex;
    align-items: center;
    /* `.tc-card__pricing` is a column flex container, so a bare inline-flex child still STRETCHES
       to the full card width - which rendered "ناموجود" as a full-width grey bar rather than as a
       pill. align-self makes it hug its own text.

       Which EDGE it hugs has to follow the price, and that differs by context: the mobile grid
       puts the price on the inline-start, the desktop grid and the row on the inline-end. That is
       already encoded in --tc-oldprice-align (the struck price tracks the same edge), so this
       reuses it rather than introducing a second token that could drift out of step. */
    align-self: var(--tc-oldprice-align);
    min-height: 24px;
    padding-inline: 8px;
    border-radius: 6px;
    font-size: 11px;
    font-weight: 600;
    line-height: 1;
}
.tc-card__state--out { background: #F5F5F5; color: var(--tc-muted); }
.tc-card__state--soon,
.tc-card__state--call { border: 1px solid var(--tc-success); color: var(--tc-success); }

/* ==========================================================================
   7. GRID CONTEXT
   ==========================================================================
   Desktop: 4 columns of 341.25 with 1px hairlines between them and no gutter — cards butt
   together and are separated by rules, exactly as PLP-FullPage shows.
   Mobile: 2 columns of 195 with an 8.5px gutter and no rules.
   ========================================================================== */

/*
 * The grid container is an existing theme element (.km-category-grid-product-list), so these
 * rules must neutralise the widths/floats the theme sets on .product-5 cells. Everything is
 * scoped under .tc-grid, so any list that does not opt in is untouched.
 */
.tc-grid {
    display: grid !important;
    grid-template-columns: repeat(var(--tc-cols, 2), minmax(0, 1fr));
    column-gap: var(--tc-col-gap, 8.5px);
    row-gap: var(--tc-row-gap, 20px);
    align-items: stretch;          /* equal card heights across the row */
    padding-inline: var(--tc-grid-pad, 8px);
    float: none;
}

.tc-grid > .tc-grid__cell,
.tc-grid > * {
    min-width: 0;
    width: auto !important;
    max-width: none !important;
    margin: 0 !important;
    padding: 0;
    float: none !important;
    display: flex;
}

/* min-height, not height: with `height: 100%` the card's height resolves against a grid row that
   was itself sized before the card's reserved regions were counted, so growing a region made the
   card overflow its cell instead of growing the row. min-height keeps the equal-height contract
   (every card still fills the tallest cell) while letting the row track the content. */
.tc-grid > * > .tc-card { min-height: 100%; }

/* Hairline separators are drawn by the cell, not the card, so the card stays context-free. */
.tc-grid__cell { border: 0 solid var(--tc-hairline, #E6E6E6); }

@media (min-width: 992px) {
    .tc-grid {
        --tc-cols: 4;
        --tc-col-gap: 0px;
        --tc-row-gap: 0px;
        --tc-grid-pad: 0px;
    }

    /* 1px hairline between columns, and between stacked rows. */
    .tc-grid > * {
        border-inline-start: 1px solid var(--tc-hairline);
        border-block-end: 1px solid var(--tc-hairline);
    }
    .tc-grid > *:nth-child(4n) { border-inline-start: 0; }

    .tc-card {
        --tc-pad-x: 16px;
        --tc-text-pad-x: 0px;
        --tc-pad-b: 24px;   /* holds the hanging old-price row (18) */
        --tc-gap: 6px;
        /* Seams measured on the POPULATED PLP-FullPage cards (column 1, CSS @1920):
               title line 2 bottom 1076   -> meta band  1092.5   16.5
               meta bottom          1105  -> price      1118.5   13.5
               price bottom         1138.5-> old price  1150.5   12.0 */
        --tc-gap-title-swatch: 16px;
        --tc-gap-swatch-meta: 14px;
        --tc-gap-meta-price: 12px;
        --tc-gap-swatch-price: 18px;
        --tc-gap-title-price: 16px;
        --tc-title-lh: 23px;
        --tc-title-h: 46px;
        /* Same correction as mobile, one step wider: the desktop card is ~325 across, so the
           media edge needs a little more air under it than the 195 mobile card does. */
        --tc-gap-media-title: 20px;
        --tc-badge-h: 20px;
        --tc-swatch-h: 28px;
        --tc-meta-h: 20px;
        --tc-price-h: 28px;
        --tc-oldprice-h: 18px;
        --tc-media-radius: 6px;
    }

    .tc-card__title { font-size: 16px; }
    .tc-card__price-value { font-size: 19px; }
    .tc-card__price-currency { height: 24px; }
    .tc-card__swatch-chip { width: 24px; height: 24px; }

    /* The POPULATED desktop cards in PLP-FullPage put the price on the inline-end and the pink
       percentage on the inline-start - the same arrangement as products-row-slider, and the
       opposite of plp-mobile-1. Two of the three reference sets agree, so the desktop grid
       follows them and mobile keeps its own. Same markup, one token. */
    .tc-card {
        --tc-price-dir: row-reverse;
        --tc-oldprice-align: flex-end;
    }
}

/* --------------------------------------------------------------------------
   7b. PLP LISTING WIDTH
   --------------------------------------------------------------------------
   PLP-FullPage @1920 puts the grid at x 122 - 1487: 1365 wide, pitch 341.25, sitting flush
   against the page container's margin edge rather than inside its 20px padding. The theme's
   own split (`.size` padding 20 + `grid-template-columns: 300px minmax(0,1fr)` + `gap: 16`)
   left the grid 1320 wide - a 3.2% shortfall that showed up as a visibly narrower card.

           reference   122 .. 1487   =  1365   pitch 341.25
           before      141 .. 1462   =  1321   pitch 330.30
           after       122 .. 1487   =  1365   pitch 341.25

   Deliberately scoped to the listing page shell (`.container-plp-page`) and to desktop only:
   `.size` is a site-wide container and this must not re-proportion any other page. The sidebar
   column keeps its 300px; the 45px comes from the container padding (40) and the column gap
   (16 -> 11), so no filter control is squeezed.
   -------------------------------------------------------------------------- */

@media (min-width: 992px) {
    .container-plp-page > .size { padding-inline: 0; }
    .container-plp-page .km-page-category-content { gap: 11px; }
}

/* ==========================================================================
   8. HORIZONTAL ROW CONTEXT
   ==========================================================================
   Applied by the eight shared row components (HomepageNewProducts, HomepageProducts,
   HomepageBestSellers, RelatedProducts, SimilarProducts, ProductsAlsoPurchased,
   CrossSellProducts, RecentlyViewedProductsBlock, SmartProductBasedUserViewedProducts). They
   all emit the same section/track markup, so opting in is one class per view and the row
   behaves identically everywhere.

   Everything here is an OUTER-CONTEXT override on the same card markup: no row-specific
   partial, no row-specific class on any card element.

   GEOMETRY — measured from products-row-slider.png (2880x1208 @2x, i.e. a 1440 viewport).
   Vertical anchors are relative to the media top; each was read off the reference's own
   band map, not interpolated from a single uniform gap:

       badge strip      22      glyph band 91.0 - 103.5
       media            302     114.0 - 414.5   (252 x 302.4 = 5:6)
       -> title         14      title line 1 glyph top 435.0
       title            42      two lines at 21
       -> meta          11      meta glyph band 485.5 - 501.0
       meta             20
       -> price          7      price glyph band 512.5 - 534.0
       price            26
       -> old price      4      old price glyph band 542.5 - 555.0
       old price        18
       -> swatches      14      swatch chips 575.0 - 594.0
       swatches         24      chips 20 diameter, 6 apart
                        ---
       card height     ~508     reference ~505 - 516

   Card width 252, card-to-card gutter 32. Because the card carries its own width, the row runs
   Swiper in `slidesPerView: 'auto'` - see TcProductRow in assets/product-card/product-card.js.

   ENGINE: SWIPER. The row is not an OwlCarousel and no `.owl-*` rule takes part in its layout
   or behaviour; sliders-rtl.js / sliders-ltr.js hand every .tc-card slider straight over.
   ========================================================================== */

/* Row-level tokens. Declared on the section so the card, the slide that measures it and the
   navigation all read the same numbers - and so none of them is a page-width decision. */
.tc-row {
    --tc-row-card-w: 252px;
}

.tc-row .tc-card {
    /* SQUARE media. Re-measured off ProductRowSample.png at native @2x: the hairline between
       two ProductBoxes runs y 230..1069, and its top edge IS the media top. The gallery dot rail
       sits at 12px above the media bottom (raw y 652..661 -> media bottom 685), so the media box
       is raw 230..685 = 455 tall against a 456-wide content box. That is 1:1, not the 5:6 this
       was carrying.

       The design set names the two ProductBox families directly and confirms it independently:
           productBox-moraba-*.png    ("moraba"  = square)    195 card, media 195x195  -> ROW
           productBox-mostatil-*.png  ("mostatil"= rectangle) 390 card, media 390x506  -> GRID (3:4)
       The grid already runs 3:4; the row is the square one. */
    --tc-media-ratio: 1 / 1;
    --tc-media-radius: 10px;

    --tc-pad-x: 0px;                 /* media runs the full card width, as the reference shows */
    --tc-text-pad-x: 10px;           /* ...but the text column keeps the card safe-area */
    --tc-pad-b: 24px;   /* holds the hanging old-price row (18) */

    --tc-badge-h: 22px;
    --tc-title-lh: 21px;
    --tc-title-h: 42px;
    --tc-meta-h: 20px;
    --tc-price-h: 26px;
    --tc-oldprice-h: 18px;
    --tc-swatch-h: 24px;

    /* Same half-leading correction the grid got: 14 rendered as ~17 of visible air and the title
       read as glued to the media. */
    --tc-gap-media-title: 18px;
    --tc-gap-title-swatch: 14px;     /* swatches sit last here, so this is the price seam */
    --tc-gap-swatch-meta: 11px;
    --tc-gap-meta-price: 7px;

    /* ProductRowSample reads as four separate groups - title, swatches, meta, price - so the
       seam under the swatch rail is a GROUP seam, not the 7px meta->price tick it was inheriting.
       That inheritance is what glued the price to the chips. */
    --tc-gap-swatch-price: 20px;
    --tc-gap-title-price: 16px;

    /* ProductRowSample.png is the row's authority. RE-MEASURED at native @2x rather than
       inherited from the previous reading, which had it backwards:

           card 3 (no discount)  content box x 831..1287   price ink x  831..1027   -> inline-END
           card 4 (discount)     content box x 1351..1807  price ink x 1351..1543
                                                           percentage x 1735..1805  -> inline-START
                                                           old price under the price, same edge

       So the CURRENT price sits on the inline-END (left in RTL) and the pink percentage on the
       inline-START (right), with the struck old price directly beneath the current price. In an
       RTL flex row that is `row-reverse`, and the old-price row follows it to `flex-end`. */
    --tc-price-dir: row-reverse;
    --tc-oldprice-align: flex-end;

    /* ONE source of truth for row card width. The Swiper slide reads the same token (see the
       Track section), so the card and the slide that measures it can never disagree. This is
       CARD geometry - it is not, and must not become, a page-width decision. */
    width: var(--tc-row-card-w);
}

/* An undiscounted card must keep the price on the SAME edge as a discounted one, or a row mixes
   two price alignments. ProductRowSample's card 3 has no discount and still puts its price on the
   inline-end, so the card-level "lone price returns to the inline-start" nudge is switched off
   here: in row-reverse, space-between already parks a single child on the correct edge. */
.tc-row .tc-card__price-row > .tc-card__price:only-child { margin-inline-end: 0; }

/* The row uses the CANONICAL sequence - media, name, swatches, meta, price - exactly like the
   grid (ProductRowSample.png). It no longer re-orders the swatch rail below the price: the rail
   belongs with the product name, and the price is the bottom anchor in every context. Only
   sizing and seam values stay context-specific. */

.tc-row .tc-card__title { font-size: 15px; }
.tc-row .tc-card__price-value { font-size: 19px; }
/* Same theme `img { width: 100% }` fight as the grid, one specificity step higher because the
   slider's own image rules also apply here. */
.tc-row .tc-card__price .tc-card__price-currency { width: auto; height: 24px; }
.tc-row .tc-card__old-price { font-size: 13px; }
/* productBox-moraba-color.png (native 1x, card 195) measures the chips at 22 across with an 8
   gap. 20 read as a row of dots rather than as selectable variations. */
.tc-row .tc-card__swatch-chip { width: 22px; height: 22px; }
.tc-row .tc-card__swatches { gap: 6px; }

/* Track --------------------------------------------------------------------
   The row runs on SWIPER (TcProductRow in assets/product-card/product-card.js). Swiper's own
   bundle supplies the flex wrapper, the transform track and the touch behaviour; everything
   below is only what the CARD needs from the track.

   `slidesPerView: 'auto'` means the slide takes its width from the card inside it, so the
   canonical 252 card is the single source of card width at every container width.

   WIDTH OWNERSHIP. Nothing in this file gives the row a width. The chain is

       div.size2              max-width: 1336px + auto margins   <- OWNS THE PAGE WIDTH
         section.tc-row       100% of parent
           .tc-row__content   100% of parent
             .swiper          100% of parent, overflow hidden
               .tc-card       252px  <- card geometry, not page geometry

   Change the parent to .size (or anything else) and the row follows it with no edit here. */
/*
 * STRUCTURAL SWIPER CSS FOR THE ROW TRACK — and it is not optional.
 *
 * assets/v6/css/style.css pulls the Swiper bundle in through a plain CSS `@import` on line 5,
 * AFTER other rules have already been emitted. A CSS @import is honoured only when it precedes
 * every rule except @charset, so every browser drops it and Swiper's layout rules never arrive.
 * Without them .swiper-wrapper is not a flex row: the slides stack VERTICALLY, the track grows
 * to ~6200px tall, and every horizontal translate Swiper computes lands on nothing.
 *
 * The card gallery already carries its own copy of these rules for exactly this reason (see
 * section 3, scoped to .tc-card__viewport). The row carries the ones it needs, scoped to
 * .tc-row__track, rather than reordering the shared sheet - which would touch every slider on
 * the site. All of it is harmless if the bundle ever does load properly.
 */
.tc-row__track.swiper {
    position: relative;
    display: block;
    width: 100%;
    margin: 0;
    padding: 0;
    list-style: none;
    z-index: 1;
    /* The ONLY clip in the row, and it clips the track alone. The navigation is a sibling of
       this element precisely so it escapes it. */
    overflow: hidden;
}

.tc-row__track > .swiper-wrapper {
    position: relative;
    display: flex;
    flex-direction: row;
    width: 100%;
    /* height: auto, NOT 100% - the wrapper is sized by its tallest slide, which is what gives
       every card in the row a shared bottom and therefore a shared price baseline. */
    height: auto;
    margin: 0;
    padding: 0;
    box-sizing: content-box;
    transition-property: transform;
    transform: translate3d(0, 0, 0);
    z-index: 1;
}

.tc-row__track > .swiper-wrapper > .swiper-slide {
    flex-shrink: 0;
    transition-property: transform;
}

/* PARTIALLY VISIBLE EDGE CARD — never show a half-rendered price.
   ------------------------------------------------------------------------------------------
   The track is 1304 wide at a 284 pitch, so 4.59 cards fit and the last one is a 66%-visible
   "peek". The price sits on the card's inline-END, which is the edge the clip cuts, so on that
   card the track sliced the numeral mid-way and left just its last two zeros showing. At card
   scale that reads as an infinity symbol - and worse, it reads as a PRICE OF ZERO. `750,000`
   rendering as `۰۰` is misinformation, not a cosmetic blemish.

   ProductRowSample does the same thing structurally: its peek card's price is off-canvas
   entirely, so the peek shows imagery and a clipped title and no price at all. That is what is
   reproduced here - the media, title and swatch rail still peek and still signal "more to the
   left", but the price block is withheld until the card it belongs to is actually whole.

   TcProductRow marks the fully-visible slides (see markFullyVisible), re-evaluated on init,
   resize and every transition, so this tracks the real geometry rather than assuming which
   index is the edge. */
.tc-row__track > .swiper-wrapper > .swiper-slide:not(.tc-row__slide--whole) .tc-card__pricing {
    visibility: hidden;
}

/* SCOPING IS LOAD-BEARING. Every row rule below matches the row's OWN wrapper via the direct
   child chain `.tc-row__track > .swiper-wrapper > .swiper-slide`. A descendant selector such as
   `.tc-row__content .swiper-slide` also matches the CARD GALLERY's slides, because each card
   carries its own nested Swiper (.tc-card__viewport) inside the row - which handed every gallery
   slide the row's width, the row's stretch and the row's gutter separator. */
.tc-row__track > .swiper-wrapper { align-items: stretch; }

/* With `slidesPerView: 'auto'` Swiper measures the slide, so the slide must carry the width.
   It is the SAME token the card uses, so card width is stated once for the whole row. */
.tc-row__track > .swiper-wrapper > .swiper-slide {
    width: var(--tc-row-card-w);
    height: auto;
    display: flex;
}

.tc-row__track > .swiper-wrapper > .swiper-slide > .tc-card { min-height: 100%; }

/* Track width — CONTAINER-BASED, NOT FULL-BLEED ----------------------------
   The row track stays inside the normal centred Ryan container and lines up with every other
   homepage section. There is deliberately NO viewport break-out here.

   A previous revision pulled the track out to the viewport edges with
   `margin-inline: calc(50% - 50vw)` plus `overflow-x: clip`, on the reading that
   ProductRowSample shows partial cards bleeding off both edges. That is a property of the
   reference ARTBOARD, not of this storefront's layout: it made the product rows the only
   full-width sections on the page and broke their alignment with the banners, the category
   tiles and the section headings above them.

   Two things this section must NOT do, because they break navigation placement:
     * clip .tc-row or .tc-row__content on the x axis - the arrows live outside the track
     * pull the track full-bleed - the arrows would then have no side margin to sit in */
/* Header -------------------------------------------------------------------
   Reference composition: title on the inline-start, a view-all action on the opposite edge
   with a chevron, and the cards beginning below. The heading keeps the container inset while
   the track bleeds, which is what the reference shows. */
.tc-row__head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 16px;
}

.tc-row__more {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 13px;
    font-weight: 600;
    line-height: 1;
    white-space: nowrap;
    color: inherit;
}

.tc-row__more-chevron { width: 7px; height: 12px; fill: currentColor; flex: 0 0 auto; }

/* Row surface --------------------------------------------------------------
   ProductRowSample.png is the authority: the ProductBox row sits on the page's own LIGHT
   surface, not on a black band. The former dark treatment (full-bleed black pseudo-element,
   inverted ink tokens, held-back title, inverted Toman mark, light-on-dark swatch rings and
   carousel arrows) was deleted rather than recoloured, and the surface now belongs to EVERY row
   rather than to a `--dark` modifier. `.tc-row--dark` is still emitted by the HomepageNewProducts
   view; it carries nothing of its own now, so the class is inert and the two homepage rows are
   byte-identical in styling. */
.tc-row {
    position: relative;
    padding-block: 24px 28px;
}

/* Row surface: the RYAN PANEL, owned by the theme -----------------------------
   `.vp-product-slider { background: #fff; border-radius: 16px }` (assets/css/style.css:20399)
   is the theme's own product-row panel. The nine row views used to opt out of it with `no-bg`
   and this file re-asserted it; the views now simply do not opt out, so the surface comes from
   the theme unaided and nothing is duplicated here.

   This replaced a full-bleed `::before` that used `inset-inline: calc(50% - 50vw)`. That band
   spanned the viewport, which is what made the rows read as the only full-width sections on the
   homepage. The panel now ends exactly where the `.size2` container ends. */

/* The track runs edge to edge of that panel, so the panel needs an inset or the first card's
   media sits flush against the rounded corner - and Ryan's -22px navigation has nothing to be
   mounted on. Row layout only; it carries no page-width decision. */
.vp-product-slider.tc-row { padding-inline: 16px; }

/* Separation between neighbouring ProductBoxes ------------------------------
   The separator belongs to the GUTTER, not to the card. Drawn on the card it read as a border
   welded to the product image. Swiper puts the `spaceBetween` gutter in each slide's own margin,
   so the rule is drawn by the SLIDE, centred in that margin and inset vertically so it spans the
   card body rather than running the full media height.

   `inset-inline-start: -16px` is half the gutter on the slide's leading edge, which is the side
   Swiper actually margins in both directions - so one logical rule serves RTL and LTR.

   GUTTER WIDTH. ProductRowSample @2x: hairline pitch 520, card content box 456 -> gutter 64, i.e.
   32 CSS with the rule 16 from each neighbour. `spaceBetween: 32` in TcProductRow
   (assets/product-card/product-card.js) is the other half of this pair - the two must move
   together, and a change to either alone puts the rule off-centre. */
.tc-row__track > .swiper-wrapper > .swiper-slide { position: relative; }

.tc-row__track > .swiper-wrapper > .swiper-slide::before {
    content: "";
    position: absolute;
    inset-inline-start: -16px;
    top: var(--tc-badge-h, 22px);
    bottom: 0;
    width: 1px;
    background: var(--tc-hairline, #E6E6E6);
    pointer-events: none;
}

/* The leading edge of the first slide is the row's own edge, not a gutter between two cards. */
.tc-row__track > .swiper-wrapper > .swiper-slide:first-child::before { content: none; }

/* Carousel navigation ------------------------------------------------------
   RYAN'S PRODUCT-SLIDER CONTROL, driven by Swiper.

   THE AUTHORITY IS NOT THE GENERIC RYAN SLIDER NAV. Our rows carry `nav-slider product`, and
   the theme has a dedicated control for exactly that pair - a TALL ROUNDED PILL, not a square:

       assets/css/style.css:16308  .nav-slider .owl-nav [class*='owl-'] i
           width 40 · border-radius 16 · colour #5E5E5E · font-size 34
           background rgba(255,255,255,.3) · backdrop-filter blur(15px)
           box-shadow 0 0 8px rgba(0,0,0,.08)
       assets/css/style.css:16404  .nav-slider.product .owl-nav [class*='owl-'] i
           height 81                       <-- the product-slider override
       :16330/:16346  owl-prev { right: -22px }   owl-next { left: -22px }
       :16337/:16353  960-1199 -> -18px          :16341/:16357  <960 -> 0
       :16322  disabled { opacity: 0; visibility: hidden }
       :16326  :hover i { background: #fff }
       :16333/:16349  prev i { padding-left: 3px }  next i { padding-right: 3px }

   Measured on a live Owl `nav-slider product` host still on this page, the glyph plate computes
   40 x 81 - which is why an earlier revision that forced `height: auto` on it, and the 40x40
   square that replaced it, both read as foreign controls. The pill IS the Ryan product-slider
   navigation.

   Swiper cannot match those `.owl-*` selectors, so the declarations are restated against the
   row's own elements. Nothing here is invented; the only deliberate deviation from the Owl rule
   is the vertical anchor, which centres on the MEDIA band rather than on 50% of the whole card
   (the card is much taller than a legacy Ryan slide, so 50% put the control down by the title).

   The buttons are siblings of .swiper (see TcProductRow.buildNav) because .swiper is
   overflow:hidden; inside it, a control mounted outside the track edge would be clipped away. */
.tc-row {
    /* Ryan's product-slider plate: 40 wide, 81 tall, radius 16. */
    --tc-nav-w: 40px;
    --tc-nav-h: 81px;
    /* Ryan hangs it off the track edge. The row's white panel is inset 16px from the track, so
       -22px lands the pill mounted on the panel's edge, which is how Ryan's own product sliders
       read. Ryan's own breakpoint steps are kept. */
    --tc-nav-offset: -22px;
    /* The card's own tokens live on .tc-card, which is a DESCENDANT of the nav's ancestor chain,
       not an ancestor of it - so they are out of scope here and are restated. Keeping them as
       row-level tokens is what makes the calc below resolve at all; referencing --tc-badge-h
       here would silently invalidate the whole declaration. */
    --tc-nav-badge-h: 22px;   /* badge strip above the media, mirrors --tc-badge-h */
    /* Vertical centre of the MEDIA band, measured from the track's top edge. The media is 1:1
       and runs the full card width, so its height IS the card width token. */
    --tc-nav-top: calc(var(--tc-nav-badge-h) + var(--tc-row-card-w) / 2 - var(--tc-nav-h) / 2);
}

@media only screen and (min-width: 960px) and (max-width: 1199px) {
    .tc-row { --tc-nav-offset: -18px; }
}

@media only screen and (max-width: 959px) {
    .tc-row { --tc-nav-offset: 0px; }
}

/* The nav is positioned against the TRACK's box, so the anchor is stated rather than inherited
   from whatever the theme happens to set on .vp-content. */
.tc-row__content { position: relative; }

.tc-row__nav {
    position: absolute;
    top: var(--tc-nav-top);
    z-index: 4;
    display: flex;
    align-items: center;
    justify-content: center;
    width: var(--tc-nav-w);
    height: var(--tc-nav-h);
    padding: 0;
    border: 0;
    border-radius: 16px;
    background: rgba(255, 255, 255, .3);
    -webkit-backdrop-filter: blur(15px);
    backdrop-filter: blur(15px);
    box-shadow: 0 0 8px rgba(0, 0, 0, .08);
    color: #5E5E5E;
    cursor: pointer;
    transition: all .3s ease-in-out;
}

.tc-row__nav i {
    font-size: 34px;
    line-height: 1;
    color: inherit;
}

/* Ryan nudges the chevron 3px against its own side so it reads optically centred in the pill. */
.tc-row__nav--prev { inset-inline-start: var(--tc-nav-offset); }
.tc-row__nav--next { inset-inline-end: var(--tc-nav-offset); }
.tc-row__nav--prev i { padding-inline-start: 3px; }
.tc-row__nav--next i { padding-inline-end: 3px; }

/* Ryan's own hover: the frosted plate goes solid. */
.tc-row__nav:hover { background: #FFFFFF; color: #5E5E5E; }

/* Swiper writes these classes (see the navigation config in TcProductRow). `--disabled` is an
   edge; `--locked` is a row short enough not to need navigation at all. Ryan hides rather than
   greys out, so both go away completely. */
.tc-row__nav--disabled,
.tc-row__nav--locked {
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
}

/* ==========================================================================
   8b. DEALS CONTEXT  (پیشنهاد شگفت‌انگیز / تخفیف‌های ویژه)
   ==========================================================================
   The Deals section was the last general product presentation still running the
   pre-Haxamanesh `.product_box.offer` card. Themes/Ryan/Views/Shared/_HomepageDealsProductBox
   now renders the canonical _ProductCard, so everything below is OUTER CONTEXT on the same
   card - no deals card partial, no deals-only class on any card element. The only markup
   this context adds is the countdown, which the canonical card has no concept of.

   Membership: the desktop track is a `.vp-slider` holding `.tc-card`, so TcProductRow claims
   it and it becomes a Swiper row like every other; the mobile branch is a native scroller and
   carries `tc-row` in the markup for the same tokens.

   WHY A PLATE HERE AND NOWHERE ELSE. Every other row sits on the theme's white
   `.vp-product-slider` panel, so the canonical card is deliberately transparent. This section
   paints its OWN decorative background (an admin-chosen image or colour on
   `.vp-special-discount`), and card text on top of that artwork is unreadable. The plate is
   therefore container presentation for this surface - the card inside it is untouched.
   ========================================================================== */

/* Neither host owns page width; both sit inside the section's own padding. */
.tc-deals.tc-row { padding-block: 0; }

/* The row must be able to SHRINK to its container.
 *
 * The mobile Deals section (`.amazing-offer`) is a flex container in the theme's own CSS, so this
 * row host is a flex item - and a flex item defaults to `min-width: auto`, meaning it refuses to
 * shrink below its content's min-content width. This item's content is a Swiper track whose
 * natural width is the sum of every slide (2 x 252 + 32 = 568 on this catalogue), so the row blew
 * the section out to 568px inside a 390px viewport and the whole page scrolled sideways.
 *
 * `min-width: 0` is the flexbox opt-out of that floor, not a magic number: it lets `width: 100%`
 * on `.tc-row__track.swiper` finally resolve against the space the container actually has. The row
 * still owns no page width - it takes whatever `.amazing-offer` / `.size2` give it. */
.tc-deals {
    min-width: 0;
    width: 100%;
}

/* EQUAL HEIGHT is inherited, never declared.
 *
 * `min-height`, deliberately not `height: 100%`. A flex item with a definite cross size is not
 * stretched, so `height: 100%` made the plate opt OUT of any equalising parent and size to its own
 * content - which is exactly how the mobile row ended up with an 18px plate-height spread and two
 * different timer baselines. With min-height the plate takes the row's line height when there is
 * one and still fills its slide, so no fixed height and no per-product rule is needed anywhere. */
.tc-deal {
    display: flex;
    flex-direction: column;
    width: 100%;
    min-height: 100%;
    padding: 10px 10px 14px;
    border-radius: 16px;
    background: #FFFFFF;
    box-sizing: border-box;
}

/* The card fills the plate; the plate, not the card, carries the width. Without this the
   252px on `.tc-row .tc-card` would fight the plate's own padding and overflow it. */
.tc-deal .tc-card {
    width: 100%;
    flex: 1 1 auto;
    /* the plate supplies the safe-area, so the card's own text inset would double it */
    --tc-text-pad-x: 0px;
    /* the countdown sits below, so the card no longer needs to reserve the hanging row's air */
    --tc-pad-b: 10px;
}

/* The slide carries the row's line height - `.tc-row__track > .swiper-wrapper` already stretches
   every slide to the tallest one, in section 8 - so the plate only has to fill the slide it is
   given. That single rule is the whole equalisation: no fixed height, no per-product rule, and
   nothing that has to know which products have a rating or a discount.
   Both breakpoints run this same path now - the mobile branch emits the same .vp-slider markup -
   which is why there is no mobile-only equalisation rule here. */
.tc-deals .tc-row__track > .swiper-wrapper > .swiper-slide > .tc-deal { height: 100%; }

/* No gutter hairline in this context: the plates already separate one deal from the next, and
   a rule drawn between two white tiles on a photographic background reads as damage. */
.tc-deals .tc-row__track > .swiper-wrapper > .swiper-slide::before { content: none; }

/* Countdown ---------------------------------------------------------------
   Same rail the legacy deals card showed - digits, clock glyph, sale progress bar - re-seated
   under the canonical card. Colours are the card's own danger token, not a new palette. */
.tc-deal__timer {
    flex: 0 0 auto;
    margin-top: 10px;
    padding-top: 10px;
    border-top: 1px solid var(--tc-hairline, #E6E6E6);
}

.tc-deal__timer .vp-row {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    color: var(--tc-danger, #ED303D);
}

.tc-deal__timer .vp-discount-timer-time-v2 {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    font-size: 15px;
    font-weight: 700;
    line-height: 1;
    direction: ltr;
}

.tc-deal__timer .vp-row i { font-size: 15px; line-height: 1; }

.tc-deal__timer .vp-progress {
    height: 6px;
    margin-top: 8px;
    border-radius: 999px;
    background: #FADBDD;
    overflow: hidden;
}

.tc-deal__timer .vp-progress-bar {
    height: 100%;
    border-radius: inherit;
    background: var(--tc-danger, #ED303D);
}

/* ==========================================================================
   9. RESPONSIVE / ACCESSIBILITY
   ========================================================================== */

@media (max-width: 991.98px) {
    /* Larger touch target for the dots without changing how they look. */
    .tc-card__dots .swiper-pagination-bullet { position: relative; }
    .tc-card__dots .swiper-pagination-bullet::after { content: ""; position: absolute; inset: -8px; }
}

@media (prefers-reduced-motion: reduce) {
    .tc-card__viewport.swiper .swiper-wrapper { transition-duration: 0ms !important; }
    .tc-card__dots .swiper-pagination-bullet { transition: none; }
}

/* ==========================================================================
   10. MOBILE FLAT PRESENTATION
   ==========================================================================
   MOBILE ONLY. Listing items are presented FLAT - no frame, no plate, no shadow, no outer
   radius - so the content owns the width instead of a chrome box owning it.

   BREAKPOINT. 959.98px is the theme's own mobile/tablet boundary, not a new number: it is the
   edge `.justMobileTablet` / `.justDesktop` switch on, and the same edge the row navigation
   already changes offset at (assets/css/style.css:16341/16357). Everything in this section is
   inside the query, so DESKTOP IS UNTOUCHED - there is no rule here that can reach it.

   WHAT COUNTS AS A FRAME. Measured on an iPhone 12, these were the containers painting a
   surface around listing items:

       section.vp-product-slider.tc-row    #fff, radius 16, padding-inline 16   (homepage rows)
       div.tc-deal                         #fff, radius 16, padding 10/10/14    (deal item)
       .vp-selected-brands .vp-item        #fff, radius 16, 1px border, shadow  (brand item)
       .vp-post-item-theme                 #fff, radius 16, shadow              (post item)

   SECTION vs ITEM. Where a section carries a background ON PURPOSE - the Deals section paints an
   admin-chosen image or colour, and the brand section is the page's own panel - the section is
   left alone and only the ITEM boxes inside it are flattened. Where the panel IS the frame and
   nothing else needs it, as on the product rows, the panel goes.

   WHAT IS NOT TOUCHED. Gutters, seams and alignment are untouched everywhere: spacing is what
   keeps flat items readable, so removing it would trade one defect for another. Banner sliders
   keep their radius - a rounded photograph is artwork, not a card frame.
   ========================================================================== */

@media only screen and (max-width: 959.98px) {

    /* --- homepage product rows -------------------------------------------
       The white panel IS the frame here: the cards inside are already transparent, and nothing
       else in the section depends on the surface. Dropping it and its 16px inline padding hands
       32px of width back to the cards. `.tc-row` raises specificity over the theme's own
       `.vp-product-slider` rule (assets/css/style.css:20399) so this does not depend on which
       stylesheet loads last. Vertical rhythm is kept - only the box goes. */
    .vp-product-slider.tc-row {
        background: transparent;
        border-radius: 0;
        box-shadow: none;
        padding-inline: 0;
    }

    /* --- deals -----------------------------------------------------------
       The SECTION keeps its background: it is an administrator's artwork, chosen per campaign,
       and is the one section background on the page that is deliberate. Only the per-deal plate
       is flattened. Its 10px inset went with it, so the card takes its inset back from the row
       token and its media runs the full card width - exactly like a homepage row card. */
    .tc-deals .tc-deal {
        background: transparent;
        border-radius: 0;
        box-shadow: none;
        padding: 0;
    }

    /* ONE ground for the list, instead of one tile per deal.
     *
     * This is the one section whose background is artwork rather than a flat colour - and that
     * artwork was composed to sit BEHIND opaque cards. With the per-deal plates removed, the
     * title, the struck old price and the swatch chips landed straight on a giant printed "%"
     * and on the campaign's own lettering, and the old price in particular stopped being
     * readable. Its fallback colour is no help either: the section computes to
     * rgb(235,58,58), so removing the image alone would put dark text on red.
     *
     * So the surface moves DOWN one layer rather than disappearing: off each item, onto the list
     * they share. That is still a flat presentation - no per-item frame, no radius, no shadow, no
     * tile edges, and the deals read as one continuous list exactly like the homepage rows do -
     * and it honours "flatten the item boxes inside that section, not the whole section", because
     * the section keeps its artwork above and below the list. Legibility is not something a flat
     * treatment can trade away. */
    .tc-deals {
        background: #FFFFFF;
        border-radius: 0;
        padding-block: 14px;
    }

    .tc-deals .tc-deal .tc-card {
        /* undo the plate-era override: the card owns its own text safe-area again */
        --tc-text-pad-x: 10px;
    }

    /* --- brand / manufacturer items --------------------------------------
       A white bordered tile inside a white panel - the frame was the only thing separating it
       from its own background. Margins stay, so the items keep their spacing and never touch.

       The selector list and the two !important flags are NOT padding: the theme paints this item
       from three places, and the strongest of them wins on both counts.
           style.css  .vp-selected-brands .vp-item                       box-shadow / radius !important
           style.css  .vp-selected-brands.vp-all .vp-content .vp-item    (0,4,0) bg / shadow / radius
           style.css  same selector inside max-width:959px               1px border
       Matching (0,4,0) and re-declaring only the two properties the theme itself marked important
       is what it takes to actually turn the frame off; a weaker rule silently loses. */
    .vp-selected-brands .vp-item,
    .vp-content-brands .vp-item,
    .vp-selected-brands.vp-all .vp-content .vp-item,
    .vp-selected-brands.vp-all .vp-content-brands .vp-item {
        background: transparent;
        border: 0;
        border-radius: 0 !important;
        box-shadow: none !important;
    }

    /* --- post / article listing items ------------------------------------
       Same boxed treatment, same listing-slider role, so it follows the same rule. Background and
       radius are won on load order alone; only the shadow needs !important, because the theme's
       own mobile rule declares it that way (style.css, max-width:959px). */
    .vp-post-item-theme {
        background: transparent;
        border-radius: 0;
        box-shadow: none !important;
    }
}
