/* ============================================================
   DropshipSA v2 — Commerce components (P0.3)
   Source of truth: design.md section 7.9 (commerce-specific).

   Store components built as classes:
     - Product card (image, title, price, compare-at, rating, quick-add)
     - Quantity stepper
     - Price (with compare-at)
     - Variant swatch (color / size)
     - Rating stars
     - Order status timeline (pending -> processing -> shipped -> delivered)
     - Cart line item
     - Price summary (subtotal / shipping / VAT / discount / total)

   Rules for this file:
     - Consume tokens only. No raw hex, no raw spacing values.
       All colors/sizes come from design-system.css (#2).
     - Read --accent so each store color works (per-store theming, 4.2 / 13).
     - RTL + LTR from one sheet: use CSS logical properties
       (padding-inline, margin-inline, inset-inline, border-inline).
       Never left/right physical props for flow-relative layout.
     - Correct on mobile: adapt at the app's existing breakpoints (8.1).
     - Motion uses the --dur / --ease tokens so the reduced-motion
       guard in design-system.css can damp it.
     - Presentation only. No page is changed by loading this file.

   Load AFTER design-system.css (tokens) and components.css (base).
   ============================================================ */

/* ------------------------------------------------------------
   1. Price — design.md 7.9
   Current price + optional compare-at (struck through).
   ------------------------------------------------------------ */
.price {
  display: inline-flex;
  align-items: baseline;
  gap: var(--sp-2);
  font-variant-numeric: tabular-nums;
}
/* Price text reads the price token. color.php defaults --price-color to the
   store accent, so the price follows the store color on every theme (issue 155).
   A theme can still override --price-color on purpose. */
.price-now {
  color: var(--price-color, var(--accent));
  font-size: var(--fs-body-lg);
  font-weight: 700;
}
/* Compare-at ("was") price — muted and struck through */
.price-was {
  color: var(--text-muted);
  font-size: var(--fs-small);
  font-weight: 400;
  text-decoration: line-through;
}
/* On sale the price keeps the accent too. Red is reserved for the sale badge
   and the old struck-through price stays muted, so the discount is still
   readable without a hardcoded red price (issue 155). */
.price.is-sale .price-now {
  color: var(--price-color, var(--accent));
}

/* ------------------------------------------------------------
   2. Rating stars — design.md 7.9
   Base row of empty stars with a filled overlay clipped to the
   rating value. Filled stars read --accent so the store color
   drives them.
   ------------------------------------------------------------ */
.stars {
  position: relative;
  display: inline-flex;
  font-size: var(--fs-body);
  line-height: 1;
  color: var(--border-strong); /* empty star color */
  white-space: nowrap;
}
.stars::before {
  content: "★★★★★";
  letter-spacing: var(--sp-1);
}
/* Filled overlay — width set inline via --stars-value (0-100%) */
.stars-fill {
  position: absolute;
  inset-block-start: 0;
  inset-inline-start: 0;
  inline-size: var(--stars-value, 0%);
  overflow: hidden;
  color: var(--accent);
}
.stars-fill::before {
  content: "★★★★★";
  letter-spacing: var(--sp-1);
}
.stars-count {
  margin-inline-start: var(--sp-2);
  color: var(--text-muted);
  font-size: var(--fs-small);
}
/* Card size — issue 2054 (no hash: see the note above the sale flag below).
   The star row sits under the card title in every
   theme, so it must never be the loudest thing in the cell and must never
   change the height of one grid cell. 12px, and `.stars` above already carries
   `white-space: nowrap`, so the row cannot wrap onto a second line. */
.stars--card {
  font-size: 12px;
  margin-block-end: var(--sp-1);
}
.stars--card .stars-count { font-size: 11px; }
/* Very narrow cards (a 2-up grid at 360px): the stars stay, the count goes.
   The stars are the signal; the number is the detail. */
@media (max-width: 400px) {
  .stars--card .stars-count { display: none; }
}

/* ------------------------------------------------------------
   3. Variant swatch — design.md 7.9
   Color + size swatches. Selected state reads from shape + the
   --accent ring (not color alone), per a11y (14).
   ------------------------------------------------------------ */
.swatch {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-inline-size: 40px;
  min-block-size: 40px;
  padding: 0;
  border: 1px solid var(--border-strong);
  background-color: var(--surface);
  color: var(--text);
  cursor: pointer;
  user-select: none;
  transition: border-color var(--dur) var(--ease),
              box-shadow var(--dur) var(--ease),
              transform var(--dur-fast) var(--ease);
}
.swatch:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px var(--focus-ring);
}
.swatch:disabled,
.swatch[disabled],
.swatch.is-disabled {
  opacity: 0.4;
  cursor: not-allowed;
  /* struck to show "unavailable" without relying on color */
  text-decoration: line-through;
}
/* Color swatch — round chip; background set inline per variant */
.swatch-color {
  inline-size: 32px;
  block-size: 32px;
  min-inline-size: 0;
  min-block-size: 0;
  border-radius: var(--r-pill);
}
/* Size swatch — pill with the size label */
.swatch-size {
  padding-inline: var(--sp-4);
  border-radius: var(--r-md);
  font-size: var(--fs-small);
  font-weight: 600;
}
/* Selected — accent ring + accent border (shape cue + color) */
.swatch.is-selected,
.swatch[aria-checked="true"] {
  border-color: var(--accent);
  box-shadow: 0 0 0 2px var(--accent);
}

/* ------------------------------------------------------------
   4. Quantity stepper — design.md 7.9
   Minus / value / plus. 40px controls (44px on mobile, 7.2).
   ------------------------------------------------------------ */
.qty-stepper {
  display: inline-flex;
  align-items: stretch;
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  overflow: hidden;
  background-color: var(--surface);
}
.qty-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  inline-size: 40px;
  block-size: 40px;
  border: none;
  background-color: var(--surface);
  color: var(--text);
  font-size: var(--fs-body-lg);
  line-height: 1;
  cursor: pointer;
  transition: background-color var(--dur) var(--ease),
              color var(--dur) var(--ease);
}
.qty-btn:hover {
  background-color: var(--surface-2);
  color: var(--accent);
}
.qty-btn:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 2px var(--focus-ring);
}
.qty-btn:disabled,
.qty-btn[disabled] {
  opacity: 0.45;
  cursor: not-allowed;
}
.qty-input {
  inline-size: 48px;
  border: none;
  border-inline: 1px solid var(--border);
  background-color: var(--surface);
  color: var(--text);
  text-align: center;
  font-family: inherit;
  font-size: var(--fs-body);
  font-variant-numeric: tabular-nums;
  -moz-appearance: textfield;
  appearance: textfield;
}
.qty-input:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 2px var(--focus-ring);
}
.qty-input::-webkit-outer-spin-button,
.qty-input::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

/* ------------------------------------------------------------
   5. Product card — design.md 7.9
   Image, title, price, compare-at, rating, quick-add.
   Whole card is a link (hover lift, per 7.3).
   ------------------------------------------------------------ */
.product-card {
  display: flex;
  flex-direction: column;
  background-color: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
  transition: box-shadow var(--dur) var(--ease),
              transform var(--dur) var(--ease),
              border-color var(--dur) var(--ease);
}
.product-card:hover {
  box-shadow: var(--shadow-md);
  border-color: var(--border-strong);
  transform: translateY(-2px);
}
.product-card:focus-within {
  outline: none;
  box-shadow: 0 0 0 3px var(--focus-ring);
}
/* Media — fixed square ratio so the grid stays even */
.product-card-media {
  position: relative;
  display: block;
  aspect-ratio: 1 / 1;
  background-color: var(--surface-2);
  overflow: hidden;
}
.product-card-media img {
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
  display: block;
}
/* Sale flag over the image — logical inset so it flips in RTL.
   Issue 1526: the badge holds a signed percent ("-35%") and nothing else.
   (The issue number is written without a hash here on purpose — this file
   forbids raw hex colors and the guard test would read a hashed number as one.)
   In an Arabic page the leading hyphen is a neutral character, so the bidi
   algorithm hands it to the RTL paragraph and draws it AFTER the digits —
   the shopper read "35%-". Forcing the badge left to right glues the minus
   back to its number. `isolate` keeps that decision inside the badge so the
   price next to it is not dragged along. */
.product-card-flag {
  position: absolute;
  inset-block-start: var(--sp-2);
  inset-inline-start: var(--sp-2);
  direction: ltr;
  unicode-bidi: isolate;
  padding-block: var(--sp-1);
  padding-inline: var(--sp-2);
  border-radius: var(--r-pill);
  background-color: var(--accent);
  color: var(--n-0);
  font-size: var(--fs-label);
  font-weight: 600;
}
.product-card-body {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  padding: var(--sp-4);
}
.product-card-title {
  color: var(--text);
  font-size: var(--fs-body);
  font-weight: 600;
  line-height: var(--lh-body);
  /* clamp to 2 lines so cards stay even */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.product-card-price {
  margin-block-start: auto;
}
/* Quick-add — accent CTA pinned at the end of the card */
.product-card-add {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  margin-block-start: var(--sp-2);
  block-size: 40px;
  border: 1px solid var(--accent);
  border-radius: var(--r-md);
  background-color: var(--accent);
  color: var(--n-0);
  font-family: inherit;
  font-size: var(--fs-body);
  font-weight: 600;
  cursor: pointer;
  transition: background-color var(--dur) var(--ease),
              border-color var(--dur) var(--ease);
}
.product-card-add:hover {
  /* --accent-deep, not --accent-hover: only --accent-deep is set per store by
     storefront/css/color.php, so the hover follows the shop's own colour.
     --accent-hover is the platform brand red and is never set per store. */
  background-color: var(--accent-deep);
  border-color: var(--accent-deep);
  /* Keep the label white on hover. Do NOT delete as "redundant": omnimart.css
     has a bare `a:hover{color:var(--c-primary)}` (0,1,1) that beats the resting
     `.product-card-add` (0,1,0). This rule is 0,2,0, so it wins without
     !important. The button is an <a>, so that bare rule applies to it. */
  color: var(--n-0);
}
.product-card-add:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px var(--focus-ring);
}

/* ------------------------------------------------------------
   6. Order status timeline — design.md 7.9
   pending -> processing -> shipped -> delivered.
   State reads from shape (dot fill + check) + color, not color
   alone (14). Horizontal on desktop, vertical stack on mobile.
   ------------------------------------------------------------ */
.timeline {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-2);
  list-style: none;
  margin: 0;
  padding: 0;
}
.timeline-step {
  position: relative;
  flex: 1 1 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-2);
  text-align: center;
  color: var(--text-muted);
  font-size: var(--fs-small);
}
/* The node dot */
.timeline-step::before {
  content: "";
  inline-size: 16px;
  block-size: 16px;
  border-radius: var(--r-pill);
  border: 2px solid var(--border-strong);
  background-color: var(--surface);
  z-index: 1;
  transition: background-color var(--dur) var(--ease),
              border-color var(--dur) var(--ease);
}
/* The connector line to the next step — logical so it flips in RTL */
.timeline-step::after {
  content: "";
  position: absolute;
  inset-block-start: 7px;
  inset-inline-start: 50%;
  inline-size: 100%;
  block-size: 2px;
  background-color: var(--border);
  z-index: 0;
}
.timeline-step:last-child::after {
  display: none;
}
/* Done — accent fill + check glyph as the non-color cue */
.timeline-step.is-done {
  color: var(--text);
}
.timeline-step.is-done::before {
  content: "✓";
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--n-0);
  font-size: var(--fs-label);
  line-height: 1;
  background-color: var(--accent);
  border-color: var(--accent);
}
.timeline-step.is-done::after {
  background-color: var(--accent);
}
/* Current — accent ring so the active step stands out by shape */
.timeline-step.is-current {
  color: var(--text);
  font-weight: 600;
}
.timeline-step.is-current::before {
  border-color: var(--accent);
  background-color: var(--accent-weak);
  box-shadow: 0 0 0 3px var(--focus-ring);
}

/* ------------------------------------------------------------
   7. Cart line item — design.md 7.9
   Thumb, title + variant, qty stepper, line price, remove.
   ------------------------------------------------------------ */
.cart-line {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-4);
  padding-block: var(--sp-4);
  border-block-end: 1px solid var(--border);
}
.cart-line-media {
  inline-size: 64px;
  block-size: 64px;
  flex: none;
  border-radius: var(--r-md);
  background-color: var(--surface-2);
  overflow: hidden;
}
.cart-line-media img {
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
  display: block;
}
.cart-line-body {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
  min-inline-size: 0;
}
.cart-line-title {
  color: var(--text);
  font-size: var(--fs-body);
  font-weight: 600;
  line-height: var(--lh-body);
}
.cart-line-variant {
  color: var(--text-muted);
  font-size: var(--fs-small);
}
.cart-line-price {
  flex: none;
  margin-inline-start: auto;
  color: var(--text);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
/* Remove — quiet control that turns danger on hover */
.cart-line-remove {
  /* The row may shrink its other children, never this button. */
  flex: none;
  border: none;
  background: none;
  padding: var(--sp-1);
  color: var(--text-muted);
  cursor: pointer;
  transition: color var(--dur) var(--ease);
}
/* An SVG with a viewBox has no minimum width, so it must not shrink either. */
.cart-line-remove svg {
  flex: none;
}
.cart-line-remove:hover {
  color: var(--danger);
}
.cart-line-remove:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px var(--focus-ring);
  border-radius: var(--r-sm);
}

/* ------------------------------------------------------------
   8. Price summary — design.md 7.9
   subtotal / shipping / VAT / discount / total.
   Numbers align to the inline-end edge (tabular-nums).
   ------------------------------------------------------------ */
.summary {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  padding: var(--sp-4);
  background-color: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
}
.summary-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-4);
  color: var(--text-muted);
  font-size: var(--fs-body);
}
.summary-row > .summary-value {
  color: var(--text);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.summary-subtotal,
.summary-shipping,
.summary-vat {
  /* default row look inherited from .summary-row */
  color: var(--text-muted);
}
/* Discount reads as a saving */
.summary-discount {
  color: var(--success);
}
.summary-discount > .summary-value {
  color: var(--success);
}
/* Free shipping cue without relying on color alone */
.summary-shipping.is-free > .summary-value {
  color: var(--success);
  font-weight: 600;
}
/* Total — the unmistakable number (checkout, 7.9) */
.summary-total {
  margin-block-start: var(--sp-2);
  padding-block-start: var(--sp-3);
  border-block-start: 1px solid var(--border-strong);
  color: var(--text);
  font-size: var(--fs-body-lg);
  font-weight: 700;
}
.summary-total > .summary-value {
  color: var(--text);
  font-size: var(--fs-h3);
  font-weight: 700;
}

/* ------------------------------------------------------------
   Mobile — design.md 8.1 (breakpoint 767)
   ------------------------------------------------------------ */
@media (max-width: 767px) {
  /* Touch targets grow to 44px on mobile (7.2) */
  .qty-btn {
    inline-size: 44px;
    block-size: 44px;
  }
  .swatch {
    min-inline-size: 44px;
    min-block-size: 44px;
  }
  /* Timeline stacks vertically so labels stay readable */
  .timeline {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--sp-4);
  }
  .timeline-step {
    flex: none;
    flex-direction: row;
    align-items: center;
    inline-size: 100%;
    text-align: start;
  }
  .timeline-step::after {
    inset-block-start: 100%;
    inset-inline-start: 7px;
    inline-size: 2px;
    block-size: var(--sp-4);
  }
  /* Cart line: price drops under the body on narrow screens */
  .cart-line-price {
    margin-inline-start: 0;
  }
}
