/* ============================================================
   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);
}

/* ------------------------------------------------------------
   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;
  }
}
