/* =========================================================
   ControlIO — Commerce Primitives
   Handle: wb-commerce · depends on wb-tokens, wb-controls
   Step 3 Pass F

   Card, product card, grid, image ratio, price, quantity,
   price+CTA action block.

   These will carry hundreds of lighting products, so the
   structure matters more than the styling: a card must hold a
   long product name, a variable price range, a stock state and
   an action without changing height relative to its neighbours.

   Boundary: the price primitive PRESENTS a price. It never
   computes one. Pricing logic belongs to wb-pricing-engine and
   that boundary is enforced by ops/ci/validate-architecture.sh.
   ========================================================= */

/* ---------------------------------------------------------
   GENERIC CARD

   Deliberately free of product assumptions so non-product
   content (guides, categories, support) can use it too.
   --------------------------------------------------------- */

.wbc-card{
  display: flex;
  flex-direction: column;
  min-width: 0;
  /* Fills its grid cell, so every card in a row is the same height regardless
     of how long its title ran. Carried over from the theme definitions this
     primitive replaced — without it the grid loses its baseline. */
  height: 100%;
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--card-shadow, var(--elevation-raised));
  overflow: hidden;
  color: inherit;
  text-decoration: none;
  transition:
    box-shadow var(--duration-fast) var(--ease-standard),
    transform  var(--duration-fast) var(--ease-standard);
}

/* Hover lift is an enhancement, never a way to discover function, and it is
   pointless on touch — where :hover sticks after a tap. Applied to every card
   rather than only .wbc-card--interactive, which is what the theme definitions
   did; the modifier is kept as an alias so existing markup still reads clearly. */
@media (hover: hover) and (pointer: fine){
  .wbc-card:hover,
  .wbc-card--interactive:hover{
    box-shadow: var(--elevation-overlay);
    transform: translateY(-2px);
  }
}

/* When the whole card is a link target, the focus ring belongs to the card, not
   to the invisible anchor inside it. */
.wbc-card:focus-within{
  outline: var(--focus-width) solid var(--focus-color);
  outline-offset: var(--focus-offset);
}

.wbc-card__media{
  position: relative;
  display: block;
  background: var(--card-media-bg);
  /* Reserving the box before the image loads is what stops the grid jumping. */
  aspect-ratio: var(--wbc-media-ratio, 1 / 1);
  overflow: hidden;
}
.wbc-card__media img{
  width: 100%;
  height: 100%;
  /* contain, not cover: a downlight photographed on white must not be cropped
     into an abstract. Lighting product imagery varies too much for cover. */
  object-fit: contain;
  display: block;
}

.wbc-card__badges{
  position: absolute;
  inset: var(--space-2) auto auto var(--space-2);
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1);
  max-width: calc(100% - var(--space-4));
}

.wbc-card__body{
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-4);
  flex: 1 1 auto;
  min-width: 0;
}
.wbc-card__header{ min-width: 0; }
.wbc-card__meta{
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  min-width: 0;
}
.wbc-card__actions{
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  /* Pin actions to the bottom so every card in a row lines up regardless of how
     long its title ran. */
  margin-block-start: auto;
  padding-block-start: var(--space-2);
}

/* ---------------------------------------------------------
   PRODUCT CARD
   --------------------------------------------------------- */

.wbc-prodcard__title{
  margin: 0;
  font-size: var(--text-base);
  font-weight: 700;
  line-height: var(--leading-snug);
  /* Two lines then ellipsis: uniform card heights without hiding so much of the
     name that two similar fittings become indistinguishable. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.wbc-prodcard__brand{
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: .03em;
  text-transform: uppercase;
  color: var(--muted);
}
.wbc-prodcard__spec{
  font-size: var(--text-sm);
  color: var(--muted);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.wbc-prodcard__sku{
  font-size: var(--text-xs);
  color: var(--muted);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}

/* ----- Horizontal compact -----
   For search suggestions, cart lines, recently viewed — anywhere a tall
   vertical card would waste the viewport. */
.wbc-prodcard--compact{
  flex-direction: row;
  align-items: stretch;
}
.wbc-prodcard--compact .wbc-card__media{
  flex: none;
  width: 5.5rem;
  aspect-ratio: 1 / 1;
}
.wbc-prodcard--compact .wbc-card__body{
  padding: var(--space-3);
  gap: var(--space-1);
}
.wbc-prodcard--compact .wbc-card__actions{
  flex-direction: row;
  align-items: center;
  padding-block-start: var(--space-1);
}
.wbc-prodcard--compact .wbc-prodcard__title{ -webkit-line-clamp: 2; }
.wbc-prodcard--compact .wbc-prodcard__spec{ display: none; }

/* ---------------------------------------------------------
   PRODUCT GRID

   Ultrawide strategy: cap the CARD, not the column count.
   Letting columns grow indefinitely produces four 800px cards
   with a postage-stamp photo adrift in each.
   --------------------------------------------------------- */

.wbc-grid{
  display: grid;
  gap: var(--space-4);
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 15rem), 1fr));
}

/* Two columns on a phone: for a catalogue of visually similar fittings,
   comparison matters more than image size. */
@media (max-width: 767px){
  .wbc-grid{
    gap: var(--space-3);
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .wbc-grid--single{ grid-template-columns: 1fr; }
}

@media (min-width: 2560px){
  .wbc-grid{
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 16rem), 22rem));
    justify-content: center;
  }
}

/* ---------------------------------------------------------
   PRICE

   Presentation only. Every value is rendered by the pricing
   system; nothing here computes, rounds or converts.
   --------------------------------------------------------- */

.wbc-price{
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-2);
  min-width: 0;
}
.wbc-price__current{
  font-size: var(--text-lg);
  font-weight: 800;
  line-height: 1.1;
  color: var(--text);
  font-variant-numeric: tabular-nums;   /* prices align down a column */
}
.wbc-price__original{
  font-size: var(--text-sm);
  color: var(--muted);
  text-decoration: line-through;
  font-variant-numeric: tabular-nums;
}
.wbc-price__save{
  font-size: var(--text-xs);
  font-weight: 700;
  color: var(--status-success);
}
.wbc-price--range .wbc-price__current{ font-size: var(--text-base); }

/* Tax messaging hook. The wording is owned by the tax/compliance layer, not by
   this stylesheet — Step 2 recorded GST presentation as an open decision, so
   this deliberately only reserves a slot. */
.wbc-price__tax{
  flex-basis: 100%;
  font-size: var(--text-xs);
  color: var(--muted);
}
.wbc-price__unit{
  flex-basis: 100%;
  font-size: var(--text-xs);
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.wbc-price--lg .wbc-price__current{ font-size: var(--text-2xl); }

/* ---------------------------------------------------------
   QUANTITY

   One control, reused on the product page, in the cart and in
   the cart drawer. Previously three separate implementations.
   --------------------------------------------------------- */

.wbc-qty{
  display: inline-flex;
  align-items: center;
  gap: 0;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-pill);
  background: var(--surface);
  overflow: hidden;
  min-width: 0;
}
.wbc-qty__btn{
  appearance: none;
  display: grid;
  place-items: center;
  width: var(--control-height-md);
  height: var(--control-height-md);
  flex: none;
  border: 0;
  background: transparent;
  color: var(--text);
  font-size: var(--text-lg);
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
  transition: background-color var(--duration-fast) var(--ease-standard);
}
.wbc-qty__btn:hover{ background: color-mix(in srgb, var(--text) 6%, transparent); }
.wbc-qty__btn:focus-visible{
  outline: var(--focus-width) solid var(--focus-color);
  outline-offset: calc(var(--focus-offset) * -1);
}
.wbc-qty__btn:disabled{ opacity: .4; cursor: not-allowed; }

.wbc-qty__input{
  width: 3.25rem;
  height: var(--control-height-md);
  border: 0;
  border-inline: 1px solid var(--border);
  background: transparent;
  color: var(--text);
  font: inherit;
  font-weight: 700;
  text-align: center;
  font-variant-numeric: tabular-nums;
  /* The stepper buttons are the control; the native spinners duplicate them and
     are far too small to hit. */
  -moz-appearance: textfield;
  appearance: textfield;
}
.wbc-qty__input::-webkit-outer-spin-button,
.wbc-qty__input::-webkit-inner-spin-button{ -webkit-appearance: none; margin: 0; }
.wbc-qty__input:focus-visible{
  outline: var(--focus-width) solid var(--focus-color);
  outline-offset: calc(var(--focus-offset) * -1);
}
@media (pointer: coarse){
  /* iOS Safari zooms the viewport for any input under 16px. */
  .wbc-qty__input{ font-size: max(16px, var(--text-base)); }
}

/* The compact variant exists for dense desktop surfaces — a cart line, a drawer
   row. It is NOT applied on touch: a quantity stepper is one of the most-tapped
   controls in the whole purchase flow, and 36px is below the minimum. */
@media (hover: hover) and (pointer: fine){
  .wbc-qty--sm .wbc-qty__btn,
  .wbc-qty--sm .wbc-qty__input{ height: var(--control-height-sm); }
  .wbc-qty--sm .wbc-qty__btn{ width: var(--control-height-sm); }
  .wbc-qty--sm .wbc-qty__input{ width: 2.75rem; }
}

/* ---------------------------------------------------------
   PRICE + CTA ACTION BLOCK

   The reusable purchase pattern: price, availability, quantity,
   primary action, then supporting detail. Used by the product
   page and by quick-buy surfaces.
   --------------------------------------------------------- */

.wbc-buybox{
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  padding: var(--space-5);
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  background: var(--surface);
  box-shadow: var(--elevation-raised);
}
.wbc-buybox__row{
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
}
.wbc-buybox__cta{ flex: 1 1 12rem; }
.wbc-buybox__support{
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding-block-start: var(--space-3);
  border-block-start: 1px solid var(--border-soft);
  font-size: var(--text-sm);
  color: var(--muted);
}

/* On a phone the buy box is the page's purpose — give it the full width and
   stack it, rather than squeezing a row that then wraps unpredictably. */
@media (max-width: 767px){
  .wbc-buybox{ padding: var(--space-4); border-radius: var(--radius-lg); }
  .wbc-buybox__cta{ flex-basis: 100%; }
}
