/* Product cards and colour swatches, defined once for the home page, catalog pages and
   "recently viewed". Loaded after storefront_shell.css on every storefront page; page
   stylesheets must not restyle these components (see storefront_typography_test.rb). */

.products {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px;
}

.product {
  position: relative;
  display: flex;
  min-width: 0;
  flex-direction: column;
  overflow: hidden;
  border-radius: 20px;
  background: var(--paper);
  /* Resting and hover shadows are the same two outer layers, so the browser eases
     between them instead of jumping. The shadow is the only thing hover animates.
     No content-visibility: a skipped card takes a guessed height and snaps to its real
     one as it scrolls in, shifting the rows and holding back its lazy photo. */
  box-shadow: 0 0 0 1px rgb(20 28 24 / 0%), 0 20px 40px -26px rgb(20 28 24 / 0%);
  transition: box-shadow 260ms var(--ease);
}

/* The product name is the card's only link in the tab order; its ::after covers the
   whole card so the image and empty space are clickable too. Cart, favourites and search
   rows in the panel reuse .product-name, so the overlay stays scoped to .product: there
   the nearest positioned ancestor is the dialog and it would swallow every click. */
.product-name {
  display: block;
  color: var(--ink);
  font-family: var(--display);
  font-size: 16px;
  font-weight: 600;
  font-feature-settings: "ss02";
  letter-spacing: -0.012em;
  line-height: 1.3;
  outline: 0;
}

.product .product-name::after {
  position: absolute;
  z-index: 1;
  inset: 0;
  content: "";
}

.product:has(.product-name:focus-visible) {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.product-image {
  position: relative;
  aspect-ratio: 5 / 4;
  overflow: hidden;
}

.product-image-link {
  display: flex;
  width: 100%;
  height: 100%;
  align-items: center;
  justify-content: center;
  padding: 11% 12% 6%;
}

/* Multiply melts the white backgrounds of non-transparent packshots into the card tone.
   The photo never moves on hover: a moving blended photo sits on fractional pixels, is
   lifted onto its own layer for the transition and re-rasterized when it ends, which
   shows as a twitch at both ends of the hover. */
.product-image img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  mix-blend-mode: multiply;
}

.product-image-placeholder {
  display: flex;
  width: 100%;
  height: 100%;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  gap: 8px;
  color: var(--muted);
  font-size: 12px;
  text-align: center;
}

.product-image-placeholder svg {
  width: 24px;
  height: 24px;
  color: var(--faint);
}

.product-tag {
  position: absolute;
  z-index: 2;
  top: 12px;
  left: 12px;
  padding: 5px 10px;
  border-radius: 999px;
  background: var(--ink);
  color: #fff;
  font-size: 11px;
  font-weight: 650;
  line-height: 1.2;
}

.product-tag--promo {
  background: var(--promo);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.01em;
}

/* A hairline in the promo colour sets the card apart without a second badge. */
.product--promo {
  box-shadow: 0 0 0 1px rgb(212 42 53 / 22%), 0 20px 40px -26px rgb(20 28 24 / 0%);
}

.product-image .favorite {
  position: absolute;
  z-index: 2;
  top: 10px;
  right: 10px;
  display: grid;
  width: 36px;
  min-width: 36px;
  height: 36px;
  min-height: 36px;
  place-items: center;
  border-radius: 50%;
  background: rgb(255 255 255 / 88%);
  color: var(--ink);
  box-shadow: 0 1px 3px rgb(20 28 24 / 10%);
  /* Keeps .icon-btn's transform so the :active press eases instead of snapping. */
  transition: color 180ms var(--ease), background-color 180ms var(--ease), box-shadow 180ms var(--ease), transform 180ms var(--ease);
}

.product-image .favorite svg {
  width: 18px;
  height: 18px;
}

/* Hover colours for the heart, cart button and swatches live in the hover media query
   at the end: on a phone a tap leaves :hover stuck until the next tap elsewhere. */
.product-image .favorite:focus-visible {
  background: #fff;
  color: var(--accent);
  box-shadow: 0 2px 8px rgb(20 28 24 / 16%);
}

.product-image .favorite.selected {
  color: var(--accent);
}

.product-image .favorite.selected:focus-visible {
  color: var(--accent-dark);
}

.product-image .favorite.selected svg {
  fill: currentColor;
}

.product-info {
  display: flex;
  flex: 1 1 auto;
  min-width: 0;
  flex-direction: column;
  padding: 6px 18px 18px;
}

/* Two lines, not one with an ellipsis: on a phone card a single line cut the memory and
   SIM off «Star White · 256 ГБ · eSIM», the part that tells two cards apart. */
.product-meta {
  display: -webkit-box;
  overflow: hidden;
  margin: 4px 0 0;
  color: var(--muted);
  font-size: 13px;
  line-height: 1.4;
  overflow-wrap: break-word;
  text-wrap: pretty;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
}

/* Variant cards name the colour in text; the dot is a quiet echo of it. */
.product-meta .color-swatch {
  display: inline-block;
  width: 10px;
  height: 10px;
  margin-right: 6px;
  vertical-align: -1px;
}

/* Tall enough for the quick-add button, so prices line up across a row with or without it.
   On the narrowest phones a price and the button do not fit one line; the button then
   takes a line of its own instead of covering the last digits. */
.purchase {
  display: flex;
  min-height: 54px;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 6px 8px;
  margin-top: auto;
  padding-top: 14px;
}

.price {
  min-width: 0;
  color: var(--ink);
  font-family: var(--display);
  font-size: 19px;
  font-weight: 700;
  letter-spacing: -0.01em;
  white-space: nowrap;
}

.price-from {
  color: var(--muted);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0;
}

/* The old price sits under the promo price: two prices and the cart button do not fit
   one line on a phone card. */
.price--promo {
  display: inline-flex;
  flex-direction: column;
  gap: 2px;
  color: var(--promo-ink);
  line-height: 1.05;
}

.price-old {
  color: var(--muted);
  font-family: var(--body);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0;
  text-decoration-thickness: 1px;
}

.product-add {
  position: relative;
  z-index: 2;
  display: grid;
  width: 40px;
  height: 40px;
  flex: 0 0 auto;
  place-items: center;
  margin-left: auto;
  border-radius: 50%;
  background: var(--accent);
  color: #fff;
  transition: background-color 180ms var(--ease);
}

.product-add svg {
  width: 18px;
  height: 18px;
}

.product-add:focus-visible,
.product-add:active {
  background: var(--accent-dark);
}

.product-add:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* Swatches: the real variant colour with a soft highlight, a hairline edge so white and
   silver finishes read on light backgrounds, and a ring for the current choice. */
.swatches {
  position: relative;
  z-index: 2;
  display: flex;
  min-height: 24px;
  align-items: center;
  gap: 2px;
  margin: 10px 0 0 -4px;
}

.color-swatch-button {
  display: grid;
  width: 24px;
  height: 24px;
  flex: 0 0 auto;
  place-items: center;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: transparent;
  cursor: pointer;
}

/* Shared look for card swatches and the product page colour choice; each sets its own size. */
.color-swatch,
.product-color {
  border-radius: 50%;
  background-image:
    radial-gradient(circle at 32% 28%, rgb(255 255 255 / 50%), rgb(255 255 255 / 0%) 48%),
    radial-gradient(circle at 70% 78%, rgb(0 0 0 / 18%), rgb(0 0 0 / 0%) 60%);
  box-shadow: inset 0 0 0 1px rgb(20 28 24 / 16%);
}

.color-swatch {
  display: block;
  width: 16px;
  height: 16px;
  flex: 0 0 auto;
}

.color-swatch-button .color-swatch {
  outline: 1.5px solid transparent;
  outline-offset: 2px;
  transition: outline-color 160ms var(--ease);
}

.color-swatch-button.is-selected .color-swatch,
.color-swatch-button[aria-pressed="true"] .color-swatch {
  outline-color: var(--ink);
}

.color-swatch-button:focus-visible {
  outline: 0;
}

.color-swatch-button:focus-visible .color-swatch {
  outline: 2px solid var(--accent);
}

.swatches-more {
  margin-left: 4px;
  color: var(--muted);
  font-size: 12px;
  font-weight: 600;
}

/* Packshots whose source files carry extra transparent margins (see
   STOREFRONT_PRODUCT_MEDIA_CLASSES) are scaled so every device fills its card alike. */
.product--iphone-18-pro .product-image img,
.product--iphone-18-pro-max .product-image img {
  scale: 1.35;
}

/* Keyboard focus raises the card like hover does; a clicked heart or cart button keeps
   focus without :focus-visible, so the card settles once the pointer leaves. Only the
   shadow changes: the card keeps its paper tone (on white, multiplied white packshots
   lose their edges and the white heart button disappears) and nothing in it moves, so
   the text and the photo stay on the same pixels. */
@media (hover: hover) and (pointer: fine) {
  .product:hover,
  .product:has(:focus-visible) {
    box-shadow: 0 0 0 1px rgb(20 28 24 / 9%), 0 20px 40px -24px rgb(20 28 24 / 42%);
  }

  .product--promo:hover,
  .product--promo:has(:focus-visible) {
    box-shadow: 0 0 0 1px rgb(212 42 53 / 32%), 0 20px 40px -24px rgb(20 28 24 / 42%);
  }

  .product-image .favorite:hover {
    background: #fff;
    color: var(--accent);
    box-shadow: 0 2px 8px rgb(20 28 24 / 16%);
  }

  .product-image .favorite.selected:hover {
    color: var(--accent-dark);
  }

  .product-add:hover {
    background: var(--accent-dark);
  }

  .color-swatch-button:not(.is-selected, [aria-pressed="true"]):hover .color-swatch {
    outline-color: #b8bdb9;
  }
}

@media (prefers-reduced-motion: reduce) {
  .product {
    transition: none;
  }
}

@media (max-width: 1100px) {
  .products {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  /* The home page always shows four picks; 2 × 2 avoids a lone card on tablets. */
  main.home:not(.catalog-page) .products {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 760px) {
  .products {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 10px;
  }

  .product {
    border-radius: 16px;
  }

  .product-image {
    aspect-ratio: 1 / 1;
  }

  .product-image-link {
    padding: 12% 10% 4%;
  }

  .product-image .favorite {
    top: 6px;
    right: 6px;
    width: 32px;
    min-width: 32px;
    height: 32px;
    min-height: 32px;
  }

  .product-image .favorite svg {
    width: 16px;
    height: 16px;
  }

  .product-tag {
    top: 8px;
    left: 8px;
    padding: 4px 8px;
  }

  /* Phone cards are ~165px wide: the text is a step larger than its column would suggest
     and sits on a slightly taller rhythm, so name, configuration and price read at arm's
     length without zooming. */
  .product-info {
    padding: 6px 12px 14px;
  }

  .product-name {
    font-size: 15px;
    line-height: 1.25;
  }

  .product-meta {
    margin-top: 4px;
    font-size: 13px;
    line-height: 1.35;
  }

  .swatches {
    margin-top: 8px;
  }

  .color-swatch {
    width: 14px;
    height: 14px;
  }

  .purchase {
    min-height: 46px;
    padding-top: 10px;
  }

  .price {
    font-size: 17px;
  }

  .price-from {
    font-size: 12px;
  }

  .price-old {
    font-size: 12px;
  }

  .product-add {
    width: 36px;
    height: 36px;
  }

  .product-add svg {
    width: 16px;
    height: 16px;
  }

  /* Square mobile frames are height-bound, so the portrait iPhone 18 shots need less boost. */
  .product--iphone-18-pro .product-image img,
  .product--iphone-18-pro-max .product-image img {
    scale: 1.12;
  }
}

/* Touch screens: the favourite and swatches keep their drawn size, but a finger gets
   a ~44px target. Swatches grow only vertically so a tap never lands on a neighbour. */
@media (pointer: coarse) {
  .color-swatch-button {
    position: relative;
  }

  .color-swatch-button::before,
  .product-image .favorite::before {
    position: absolute;
    content: "";
  }

  .color-swatch-button::before {
    inset: -10px -1px;
  }

  .product-image .favorite::before {
    inset: -6px;
  }
}
