/* ==========================================================================
   PddFalcon storefront — product page premium layer

   Loaded after snap-inner.css and home-premium.css and before site-premium.css,
   so it refines the product page and the quick view without !important and
   without touching the footer or the home bands that site-premium owns.

   Scope: the product page (.s-pdp and everything inside it), the reviews and
   related rails beneath it, the sticky buy bar, and the quick-view sheet
   (.sp-quick) that the same picker markup is rendered into.

   Every colour here is a token from tokens.css or an rgb()/color-mix() built
   from one of the brand values:
     navy #0d2454  deep navy #061031  red #c4260c  gold #ffb800
     canvas #f4f6fa  tile #f3f5f8  hairline #e6eaf2  ink #111827  muted #666f7d

   Motion is transform and opacity only, and the last block of this file hands
   every one of those back under prefers-reduced-motion.
   ========================================================================== */

/* ==========================================================================
   1. The gallery
   ========================================================================== */

/*
 * The stage.
 *
 * It was a white square inside a flat hairline — correct, but it sat on the
 * page rather than being presented on it. A layered shadow lifts it off the
 * band, a warmer hairline ties it to the navy, and an inner ring keeps the
 * edge crisp where the photograph's own white meets the frame.
 */
.s-gallery__stage {
  background: var(--s-surface);
  border-color: rgb(13 36 84 / .09);
  box-shadow:
    0 1px 2px rgb(13 36 84 / .04),
    0 24px 48px -32px rgb(13 36 84 / .38);
  transition: box-shadow .35s var(--sp-ease), border-color .35s var(--sp-ease);
}

.s-gallery__stage:hover {
  border-color: rgb(13 36 84 / .16);
  box-shadow:
    0 1px 2px rgb(13 36 84 / .05),
    0 30px 60px -34px rgb(13 36 84 / .45);
}

/* The ring rides above the picture and below the badges, and never eats a
   click meant for the magnifier. */
.s-gallery__stage::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  border-radius: inherit;
  box-shadow: inset 0 0 0 1px rgb(13 36 84 / .05);
  pointer-events: none;
}

/* A little more air around the product, so the photograph reads as a piece
   that has been placed rather than one that has been fitted. */
.s-gallery__photo { padding: var(--s-5); }
@media (min-width: 62rem) { .s-gallery__photo { padding: var(--s-6); } }

/* The offer tags arrive with the picture instead of being there from the
   first paint, which is what makes them read as a label on the photograph. */
.s-gallery__badges { gap: .35rem; }
.s-gallery__badges .s-tag {
  box-shadow: 0 6px 14px -8px rgb(196 38 12 / .8);
  animation: pdp-tag .5s var(--sp-ease) .25s both;
}

/*
 * The thumbs.
 *
 * A thumb becoming the stage is the one moment of cause and effect in this
 * column, and it used to be told only by a border colour. Now the chosen
 * thumb lifts, keeps the red frame, and draws a red rule along its foot —
 * a shape change, so the state does not depend on seeing the red.
 */
.s-gallery__thumb {
  position: relative;
  background: var(--s-surface);
  border-color: var(--sp-line);
  transition:
    border-color .25s var(--sp-ease),
    box-shadow .25s var(--sp-ease),
    translate .25s var(--sp-ease);
}

.s-gallery__thumb::after {
  content: "";
  position: absolute;
  inset-block-end: 3px;
  inset-inline: 22%;
  block-size: 3px;
  border-radius: 3px;
  background: var(--s-accent-500);
  scale: 0 1;
  transition: scale .3s var(--sp-ease);
}

.s-gallery__thumb:hover {
  border-color: rgb(13 36 84 / .3);
  box-shadow: 0 10px 20px -14px rgb(13 36 84 / .6);
  translate: 0 -2px;
}

.s-gallery__thumb.is-active {
  border-color: var(--s-accent-500);
  box-shadow: 0 10px 22px -16px rgb(196 38 12 / .9);
}

.s-gallery__thumb.is-active::after { scale: 1 1; }

.s-gallery__thumb img { transition: scale .35s var(--sp-ease); }
.s-gallery__thumb:hover img { scale: 1.06; }

/* The strip is allowed to scroll inside its own box; it snaps so a half thumb
   never comes to rest at the edge. */
.s-gallery__thumbs {
  scroll-snap-type: x proximity;
  scroll-padding-inline: .25rem;
  padding: 2px;
  margin: -2px;
}
.s-gallery__thumbs .s-gallery__thumb { scroll-snap-align: start; }
@media (min-width: 62rem) {
  .s-gallery__thumbs { scroll-snap-type: y proximity; }
}

/*
 * The tablet band.
 *
 * Between 640 and 992 the gallery had the full column, so at 768 the stage was
 * a 686px square and the whole first screen was one photograph — the title,
 * the price and the buy button all began below the fold. Capped and centred it
 * reads as a presented photograph and brings the price back into view.
 */
@media (min-width: 40rem) and (max-width: 61.99rem) {
  /* The stage is capped and centred; the strip below it keeps the whole
     column, so all six thumbs stand in one uncut row under the picture. */
  .s-pdp .s-gallery__stage { max-inline-size: 26rem; margin-inline: auto; }
  .s-pdp .s-gallery__thumbs { justify-content: safe center; }
}

/* The lightbox settles into place rather than appearing at full size. */
.s-lightbox img { scale: .965; transition: scale .32s var(--sp-ease); }
.s-lightbox.is-open img { scale: 1; }
.s-lightbox.is-zoomed img { scale: 1; }

/* ==========================================================================
   2. Identity — category, title, brand, rating
   ========================================================================== */

.s-pdp__cat {
  font-size: var(--s-text-2xs);
  letter-spacing: .14em;
  margin-block-end: .5rem;
}
.s-pdp__cat a { transition: color .2s var(--sp-ease); }
.s-pdp__cat a:hover { color: var(--s-brand-800); }

.s-pdp__title {
  line-height: 1.14;
  letter-spacing: -.02em;
  margin-block-end: .45rem;
  text-wrap: balance;
}

.s-pdp__brand { font-size: var(--s-text-sm); }
.s-pdp__brand a {
  color: var(--s-brand-800);
  font-weight: 700;
  text-decoration-color: rgb(13 36 84 / .25);
  text-underline-offset: 3px;
  transition: color .2s var(--sp-ease), text-decoration-color .2s var(--sp-ease);
}
.s-pdp__brand a:hover { color: var(--s-accent-500); text-decoration-color: currentColor; }

/* The rating line is a link to the reviews; make it read like one. */
.s-pdp__panel .s-rating {
  gap: .5rem;
  padding: .2rem 0;
  border-radius: var(--s-radius-sm);
  transition: opacity .2s var(--sp-ease);
}
.s-pdp__panel .s-rating:hover { opacity: .78; }
.s-pdp__panel .s-rating__stars { color: var(--s-cool-500); font-size: var(--s-text-md); }

/* ==========================================================================
   3. The price
   ========================================================================== */

.s-pdp__price-row {
  gap: .55rem;
  margin-block: var(--s-4) var(--s-2);
}

/* "From" is a caption on the number, not a word beside it. */
.s-pdp__from {
  align-self: center;
  font-size: var(--s-text-2xs);
  font-weight: 800;
  letter-spacing: var(--s-tracking-caps);
  text-transform: uppercase;
  color: var(--s-muted);
}

.s-pdp__price {
  font-family: var(--s-font-display);
  font-size: clamp(1.8rem, 1.25rem + 1.9vw, 2.4rem);
  font-weight: 800;
  line-height: 1;
  letter-spacing: -.03em;
  color: var(--s-brand-950);
  font-variant-numeric: tabular-nums;
}

.s-pdp__mrp { font-size: var(--s-text-sm); text-decoration-thickness: 1px; }

/* The saving is a mark, not a sentence — and it keeps its own shape so the
   green is never the only thing carrying it. */
.s-pdp__off {
  padding: .18rem .5rem;
  border-radius: var(--s-radius-pill);
  background: color-mix(in srgb, var(--s-success) 12%, var(--s-surface));
  color: var(--s-success);
  font-size: var(--s-text-xs);
  font-weight: 800;
  letter-spacing: .01em;
}

/*
 * The top of the range, on a line of its own.
 *
 * Full width so it can never land between the price and the M.R.P. struck
 * against it, which is the one arrangement that misreads: the eye pairs a
 * struck figure with whatever number is nearest, and "From ₹305.00 – ₹315.00
 * ₹381.25" hands it the wrong one. Set as a caption, not a second price, so it
 * stays subordinate to the figure above it.
 */
.s-pdp__upto {
  inline-size: 100%;
  margin-block-start: .15rem;
  font-size: var(--s-text-xs);
  color: var(--s-muted);
  font-variant-numeric: tabular-nums;
}

.s-pdp__tax {
  margin-block-start: .1rem;
  font-size: var(--s-text-2xs);
  letter-spacing: .02em;
}

/*
 * The stock line signals with a shape as well as a colour: in stock is a
 * filled dot, low stock a ring, out of stock a diamond.
 */
.s-stockline { margin-block-end: .2rem; }
.s-stockline::before { transition: none; }
.s-stockline--low::before {
  background: transparent;
  box-shadow: inset 0 0 0 2px currentColor;
}
.s-stockline--out::before {
  border-radius: 2px;
  rotate: 45deg;
}

.s-pdp__summary { margin-block-start: var(--s-3); line-height: 1.6; }

/* ==========================================================================
   4. The panel's blocks
   ========================================================================== */

/*
 * The rules between the blocks used to run the full width at full strength,
 * which cut the panel into slabs. A hairline that fades out along its length
 * separates without dividing.
 */
.s-pdp__block {
  position: relative;
  border-block-start: 0;
  padding-block: var(--s-5) var(--s-4);
}
.s-pdp__block::before {
  content: "";
  position: absolute;
  inset-block-start: 0;
  inset-inline: 0;
  block-size: 1px;
  background: linear-gradient(90deg, var(--s-line), rgb(230 234 242 / .25));
}

.s-pdp__block-title {
  font-size: var(--s-text-md);
  letter-spacing: -.005em;
  margin-block-end: var(--s-3);
}
.s-pdp__hint { font-size: var(--s-text-sm); }

/* ==========================================================================
   5. The multi-version picker
   ========================================================================== */

.s-picker { gap: .55rem; }

.s-picker__row {
  position: relative;
  padding: .7rem .85rem;
  background: var(--s-surface);
  transition:
    border-color .25s var(--sp-ease),
    box-shadow .25s var(--sp-ease),
    background-color .25s var(--sp-ease);
}

/*
 * The chosen version carries a red rule on its edge. The row already turns
 * navy when it is ticked; the rule is the part a red–green deficiency can
 * still read, and it grows rather than appearing.
 */
.s-picker__row::before {
  content: "";
  position: absolute;
  inset-block: 20%;
  inset-inline-start: -1.5px;
  inline-size: 3px;
  border-radius: 3px;
  background: var(--s-accent-500);
  scale: 1 0;
  transition: scale .28s var(--sp-ease);
}
.s-picker__row:has(input:checked)::before { scale: 1 1; }

.s-picker__row:hover:not(.is-out) {
  border-color: rgb(13 36 84 / .28);
  box-shadow: 0 10px 24px -20px rgb(13 36 84 / .8);
}

.s-picker__row:has(input:checked) {
  box-shadow: 0 0 0 3px rgb(13 36 84 / .06), 0 12px 26px -22px rgb(13 36 84 / .9);
}

.s-picker__row:has(input:focus-visible) {
  outline: 2px solid var(--s-brand-500);
  outline-offset: 2px;
}

.s-picker__check {
  inline-size: 1.25rem;
  block-size: 1.25rem;
  accent-color: var(--s-accent-500);
  cursor: pointer;
}

.s-picker__thumb {
  background: var(--s-surface);
  border-color: var(--sp-line);
  padding: 2px;
  transition: scale .3s var(--sp-ease), border-color .25s var(--sp-ease);
}
.s-picker__row:hover .s-picker__thumb { scale: 1.05; }
.s-picker__row:has(input:checked) .s-picker__thumb { border-color: rgb(13 36 84 / .35); }

.s-picker__name {
  font-size: var(--s-text-md);
  font-weight: 700;
  color: var(--s-brand-800);
  letter-spacing: -.005em;
}
.s-picker__meta { line-height: 1.45; }

.s-picker__price {
  font-family: var(--s-font-display);
  font-size: var(--s-text-md);
  font-weight: 800;
  color: var(--s-brand-950);
  font-variant-numeric: tabular-nums;
}
.s-picker__sub { font-weight: 600; letter-spacing: .01em; }

/* The stepper is the thing a thumb has to hit, so it gets a real 44px target
   on every width — it was 32px, and it still fits inside the row because the
   version's picture is taller than it is. */
.s-picker .s-qty { border-color: var(--sp-line); background: var(--s-surface); }
.s-picker .s-qty--sm .s-qty__btn { inline-size: 2.75rem; block-size: 2.75rem; font-size: 1rem; }
.s-picker .s-qty--sm .s-qty__value { inline-size: 2.75rem; block-size: 2.75rem; font-weight: 700; }

/*
 * The running total.
 *
 * It is the answer to everything ticked above it, so it stops being a grey
 * tray and becomes a card: lit from the top, lifted off the panel, with the
 * sum set in the display face and figures that do not jump width as they
 * change.
 */
.s-picker__total {
  align-items: center;
  flex-wrap: wrap;
  padding: var(--s-4) var(--s-5);
  border: 1px solid var(--sp-line);
  background: linear-gradient(180deg, var(--s-surface), var(--sp-tile));
  box-shadow:
    0 1px 2px rgb(13 36 84 / .04),
    0 20px 40px -32px rgb(13 36 84 / .55);
}
.s-picker__total > div { min-inline-size: 0; }
.s-picker__total small {
  font-size: var(--s-text-2xs);
  font-weight: 700;
  letter-spacing: var(--s-tracking-caps);
  text-transform: uppercase;
}
.s-picker__total strong {
  display: block;
  font-family: var(--s-font-display);
  font-size: var(--s-text-2xl);
  font-weight: 800;
  line-height: 1.1;
  letter-spacing: -.02em;
  color: var(--s-brand-950);
  font-variant-numeric: tabular-nums;
}
.s-picker__total .s-btn--primary {
  flex: 1 1 13rem;
  max-inline-size: 19rem;
  min-block-size: 3.25rem;
  font-variant-numeric: tabular-nums;
}
.s-picker__total .s-btn--primary:disabled { box-shadow: none; }

/* ==========================================================================
   6. The single buy row and the secondary actions
   ========================================================================== */

.s-pdp__buy .s-btn--primary { min-block-size: 3.25rem; }
.s-pdp__buy .s-qty__btn { inline-size: 2.9rem; block-size: 3.25rem; }
.s-pdp__buy .s-qty__value { block-size: 3.25rem; inline-size: 3.25rem; font-weight: 700; }

/* 36px was under the thumb-sized minimum; these are the buttons a shopper
   reaches for after the main one. */
.s-pdp__secondary { gap: .5rem; margin-block-start: var(--s-4); }
.s-pdp__secondary .s-btn--sm {
  min-block-size: 2.75rem;
  padding-inline: 1rem;
  font-size: var(--s-text-sm);
}
.s-pdp__secondary .s-btn--ghost { border-color: var(--sp-line); }
.s-pdp__secondary .s-btn--ghost:hover { border-color: var(--s-brand-800); }

/* ==========================================================================
   7. Delivery — the pincode check and the policy trio
   ========================================================================== */

.s-pincode__row { gap: .6rem; }
.s-pincode__row .s-input { max-inline-size: 13rem; font-variant-numeric: tabular-nums; letter-spacing: .08em; }
.s-pincode__row .s-btn { min-block-size: 3rem; padding-inline: 1.4rem; }

/*
 * The answer is a chip and a word, not a coloured sentence: a tick for a
 * pincode we deliver to, an exclamation for one we do not.
 */
.s-pincode__result {
  display: flex;
  align-items: flex-start;
  gap: .5rem;
  margin-block-start: .2rem;
}
.s-pincode__result.is-ok::before,
.s-pincode__result.is-bad::before {
  flex: none;
  display: grid;
  place-items: center;
  inline-size: 1.25rem;
  block-size: 1.25rem;
  border-radius: 50%;
  font-size: .7rem;
  font-weight: 800;
  line-height: 1;
  color: var(--s-surface);
}
.s-pincode__result.is-ok::before { content: "✓"; background: var(--s-success); }
.s-pincode__result.is-bad::before { content: "!"; background: var(--s-danger); }

/*
 * The policy trio was three grey tiles. Now each is a white card with its icon
 * in a chip, and the chip turns navy as the card lifts — the same lift the
 * cards everywhere else on the shop use.
 */
.s-policy { gap: .5rem; margin-block-start: var(--s-4); }
.s-policy__item {
  gap: .5rem;
  padding: .9rem .5rem;
  background: var(--s-surface);
  border: 1px solid var(--sp-line);
  box-shadow: 0 1px 2px rgb(13 36 84 / .04);
  font-size: var(--s-text-2xs);
  font-weight: 600;
  line-height: 1.3;
  transition:
    translate .3s var(--sp-ease),
    box-shadow .3s var(--sp-ease),
    border-color .3s var(--sp-ease);
}
.s-policy__item:hover {
  translate: 0 -2px;
  border-color: rgb(13 36 84 / .16);
  box-shadow: 0 14px 28px -22px rgb(13 36 84 / .8);
}
.s-policy__item svg {
  inline-size: 2.15rem;
  block-size: 2.15rem;
  padding: .45rem;
  border-radius: 11px;
  background: var(--sp-tile);
  color: var(--s-brand-800);
  transition: background-color .3s var(--sp-ease), color .3s var(--sp-ease);
}
.s-policy__item:hover svg { background: var(--s-brand-800); color: var(--s-surface); }

.s-pdp__policy-note { margin-block-start: var(--s-4); line-height: 1.6; }

/* ==========================================================================
   8. The specification table
   ========================================================================== */

/*
 * snap-inner.css stripes the rows — `tr:nth-child(odd)` filled with the tile
 * grey — and an earlier pass here drew a rounded frame around the result.
 * Together they read as an admin data grid dropped into a shop: grey label
 * cell, white value cell, ruled box, and a hover highlight on rows that
 * nobody can click.
 *
 * A specification is a list of facts, so it is set as one. The fills go, the
 * frame goes, and what is left is a small uppercase label in the muted grey
 * with its answer at reading size beside it, separated by a single hairline.
 * Nothing in here is interactive, so nothing in here lights up.
 */
.s-specs {
  inline-size: 100%;
  border-collapse: separate;
  border-spacing: 0;
  overflow-wrap: anywhere;
}

/* Both halves of the stripe, so the sheet is transparent whichever row it is,
   and whichever of the two stylesheets set it. */
.s-specs tr:nth-child(odd),
.s-specs tr:nth-child(even),
.s-specs tr:hover th,
.s-specs tr:hover td {
  background: none;
}

.s-specs th,
.s-specs td {
  border-inline: 0;
  border-block-start: 0;
  border-block-end: 1px solid var(--s-line-soft);
  border-radius: 0;
  vertical-align: top;
}

.s-specs th {
  inline-size: 34%;
  /* No cell padding on the outside edge: the sheet lines up with the prose
     above and below it rather than sitting in an invisible box of its own. */
  /* The extra 2px is optical: a 12px label and a 15px value given the same
     padding do not start on the same line, because the smaller type sits
     higher in its own line box. */
  padding: calc(.95rem + 2px) 1.25rem .95rem 0;
  font-size: var(--s-text-xs);
  font-weight: 700;
  line-height: 1.6;
  letter-spacing: var(--s-tracking-wide);
  text-transform: uppercase;
  color: var(--s-muted);
  white-space: normal;
}

.s-specs td {
  padding: .95rem 0;
  font-size: var(--s-text-md);
  font-weight: 500;
  color: var(--s-ink);
  line-height: 1.6;
}

/* The block below already opens with a rule of its own; the sheet does not
   need to close itself with a second one directly above it. */
.s-specs tr:last-child th,
.s-specs tr:last-child td { border-block-end: 0; padding-block-end: 0; }

.s-pdp__panel .s-prose { font-size: var(--s-text-sm); line-height: 1.7; color: var(--s-ink-soft); }
.s-pdp__panel .s-prose li { margin-block: .25rem; }

/* ==========================================================================
   9. The reviews rail
   ========================================================================== */

.s-review {
  background: var(--s-surface);
  border-color: var(--sp-line);
  box-shadow: 0 1px 2px rgb(13 36 84 / .04);
  transition:
    translate .3s var(--sp-ease),
    box-shadow .3s var(--sp-ease),
    border-color .3s var(--sp-ease);
}
.s-review:hover {
  translate: 0 -3px;
  border-color: rgb(13 36 84 / .14);
  box-shadow: 0 18px 36px -26px rgb(13 36 84 / .8);
}
.s-review__stars {
  color: var(--s-cool-500);
  font-size: var(--s-text-lg);
  letter-spacing: .02em;
  line-height: 1;
}
.s-review__title { font-weight: 700; color: var(--s-brand-800); }
.s-review__body { line-height: 1.6; }

/* Verified is carried by a mark as well as by the green. */
.s-review__verified::before {
  content: "✓";
  margin-inline-end: .2rem;
  font-weight: 800;
}
.s-review__reply {
  border-radius: 0 var(--s-radius-sm) var(--s-radius-sm) 0;
  border-inline-start-color: var(--s-accent-500);
  background: var(--sp-tile);
}

.s-reviewrail .s-rail-arrow,
.s-reviewrail .s-carousel__arrow {
  transition: background-color .2s var(--sp-ease), color .2s var(--sp-ease), scale .2s var(--sp-ease);
}
.s-reviewrail .s-rail-arrow:hover {
  background: var(--s-brand-800);
  color: var(--s-surface);
  border-color: var(--s-brand-800);
  scale: 1.06;
}

/* The related rail's arrows answer the pointer the same way — scoped to a page
   that actually has a product on it, so this sheet never reaches a carousel on
   the home page or the listing, which belong to other sheets. */
body:has(.s-pdp) .s-carousel__arrow {
  transition: opacity var(--s-fast) var(--s-ease), background-color .2s var(--sp-ease), color .2s var(--sp-ease);
}
body:has(.s-pdp) .s-carousel__arrow:hover { background: var(--s-brand-800); color: var(--s-surface); border-color: var(--s-brand-800); }

/* ==========================================================================
   10. The sticky buy bar
   ========================================================================== */

/*
 * It used to slide up as a plain white slab. Now it arrives with the brand's
 * hairline lit along its top edge, fades as it rises, and its figures are
 * tabular so the total does not shuffle as versions are ticked.
 */
.s-stickybuy {
  gap: .75rem;
  padding: .65rem var(--sp-gutter);
  padding-block-end: max(.65rem, var(--s-safe-bottom));
  border-block-start: 0;
  background: var(--s-surface);
  box-shadow: 0 -12px 34px -16px rgb(13 36 84 / .4);
  opacity: 0;
  translate: 0 130%;
  transition: translate .42s var(--sp-ease), opacity .28s linear;
}
.s-stickybuy::before {
  content: "";
  position: absolute;
  inset-inline: 0;
  inset-block-start: 0;
  block-size: 2px;
  background: linear-gradient(90deg, transparent, var(--s-accent-500) 28%, var(--s-cool-500) 50%, var(--s-accent-500) 72%, transparent);
  opacity: .6;
}
.s-stickybuy.is-shown, .s-stickybuy.is-on { opacity: 1; translate: 0; }

/* The price and its two marks travel together; the bar's own gap is then the
   space between that group and the button, not between every figure in it. */
.s-stickybuy__figs {
  /* Allowed to give way. With `flex: none` the struck price and the pill kept
     their full 204px on a 320px phone and the Add-to-cart button beside them
     absorbed the whole squeeze, down to 72px. The figures wrap instead. */
  flex: 0 1 auto;
  min-inline-size: 0;
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: .38rem;
  min-inline-size: 0;
}
.s-stickybuy__mrp {
  font-size: var(--s-text-xs);
  color: var(--s-muted);
  text-decoration-thickness: 1px;
  font-variant-numeric: tabular-nums;
}
/* Same pill as the price row's saving, one step down — it is a reminder of
   something already said above, not the announcement. */
.s-stickybuy__off {
  padding: .1rem .38rem;
  border-radius: var(--s-radius-pill);
  background: color-mix(in srgb, var(--s-success) 12%, var(--s-surface));
  color: var(--s-success);
  font-size: var(--s-text-2xs);
  font-style: normal;
  font-weight: 800;
}

.s-stickybuy__price {
  flex: none;
  font-family: var(--s-font-display);
  font-size: var(--s-text-xl);
  font-weight: 800;
  letter-spacing: -.02em;
  color: var(--s-brand-950);
  font-variant-numeric: tabular-nums;
}
.s-stickybuy .s-btn {
  flex: 1 1 auto;
  min-inline-size: 0;
  min-block-size: 3rem;
}

/* ==========================================================================
   11. The quick view
   ========================================================================== */

/* The sheet settles rather than snapping into place. */
.s-modal:has(.sp-quick) .s-modal__panel {
  scale: .99;
  transition:
    translate var(--s-base) var(--s-ease-out),
    scale var(--s-base) var(--s-ease-out);
}
.s-modal:has(.sp-quick).is-open .s-modal__panel { scale: 1; }

/* A grip you can actually see, and a close button a thumb can actually hit.
   The button that is really on screen is the one motion.js moves into the
   panel (`.sp-quick__close`); the layout's own `.s-modal__close` is set to
   display:none by snap.css, so it is not the one to size. */
.s-modal__grip {
  inline-size: 2.75rem;
  block-size: 5px;
  background: rgb(13 36 84 / .16);
}
.sp-quick__close {
  inline-size: 2.75rem;
  block-size: 2.75rem;
  box-shadow: 0 1px 2px rgb(13 36 84 / .06), 0 12px 24px -18px rgb(13 36 84 / .8);
}
.sp-quick__close svg { inline-size: 1.05rem; block-size: 1.05rem; }

.sp-quick__figure {
  border: 1px solid var(--sp-line);
  background: var(--s-surface);
  box-shadow: inset 0 0 0 1px rgb(13 36 84 / .04);
}
.sp-quick__figure img { transition: scale .4s var(--sp-ease); }

/*
 * The picture strip.
 *
 * Two faults, one cause. The strip was `overflow: hidden`, so a product with
 * six pictures showed four and cut the fifth; and because the sheet's grid
 * track sizes itself to its widest content, those six thumbs (386px of them)
 * stretched the whole right-hand column past the panel — measured at 390, the
 * title, the price and every option row ended 12px outside the sheet and the
 * panel scrolled sideways. Capping the track at the space available and
 * letting the strip scroll inside its own box fixes both at once.
 */
.sp-quick { grid-template-columns: minmax(0, 1fr); }
.sp-quick__gallery,
.sp-quick__info,
.sp-quick__thumbs { min-inline-size: 0; }
@media (min-width: 62rem) { .sp-quick { grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr); } }

.sp-quick__thumbs {
  max-inline-size: 100%;
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: none;
  scroll-snap-type: x proximity;
  padding-block: 2px;
}
.sp-quick__thumbs::-webkit-scrollbar { display: none; }
.sp-quick__thumbs li { flex: none; scroll-snap-align: start; }
.sp-quick__thumb {
  position: relative;
  border-color: var(--sp-line);
  transition: border-color .25s var(--sp-ease), translate .25s var(--sp-ease), box-shadow .25s var(--sp-ease);
}
.sp-quick__thumb:hover { border-color: rgb(13 36 84 / .3); translate: 0 -2px; }
.sp-quick__thumb.is-on { box-shadow: 0 8px 18px -14px rgb(196 38 12 / .9); }
.sp-quick__thumb::after {
  content: "";
  position: absolute;
  inset-block-end: 2px;
  inset-inline: 24%;
  block-size: 3px;
  border-radius: 3px;
  background: var(--s-accent-500);
  scale: 0 1;
  transition: scale .3s var(--sp-ease);
}
.sp-quick__thumb.is-on::after { scale: 1 1; }

.sp-quick__price strong {
  font-family: var(--s-font-display);
  letter-spacing: -.03em;
  color: var(--s-brand-950);
  font-variant-numeric: tabular-nums;
}
/* "From" is a caption on the number, not a word beside it — the same mark the
   product page puts in front of a range, so the sheet and the page it opens
   onto phrase a range the same way. */
.sp-quick__from {
  align-self: center;
  font-size: var(--s-text-2xs);
  font-weight: 800;
  letter-spacing: var(--s-tracking-caps);
  text-transform: uppercase;
  color: var(--s-muted);
}
/* Its own line, for the reason .s-pdp__upto carries: a range printed between
   the price and the M.R.P. struck against it pairs the strike with the wrong
   figure. `flex-basis` because .sp-quick__price is a wrapping flex row and
   this is the break in it. */
.sp-quick__upto {
  flex-basis: 100%;
  margin-block-start: .1rem;
  font-size: var(--s-text-xs);
  color: var(--s-muted);
  font-variant-numeric: tabular-nums;
}
.sp-quick__price em {
  padding: .16rem .45rem;
  border-radius: var(--s-radius-pill);
  background: color-mix(in srgb, var(--s-success) 12%, var(--s-surface));
  font-size: var(--s-text-xs);
}
.sp-quick__text { line-height: 1.6; }

.sp-quick__buy .sp-btn--lg { min-block-size: 3.25rem; }
.sp-quick__foot { gap: .6rem; }
.sp-quick__foot .sp-btn { min-block-size: 2.75rem; }

/*
 * On a phone the sheet opened on a full-width square photograph, which put the
 * price, the options and the buy button below the fold of a 92dvh sheet. The
 * picture keeps its frame but gives back the height a shopper needs.
 */
@media (max-width: 47.99rem) {
  .sp-quick { gap: 1rem; }
  /* The frame stays square — capping its height caps its width with it — so it
     is centred in the column rather than left against one edge. */
  .sp-quick__figure { max-block-size: 34vh; margin-inline: auto; }
  /* `safe` so a strip that overflows still starts at its first thumb; a browser
     that does not understand it drops the line and keeps the default. */
  .sp-quick__thumbs { margin-block-start: .55rem; justify-content: safe center; }
  .sp-quick__info { gap: .5rem; }
  .s-modal:has(.sp-quick) .s-modal__panel { border-radius: 24px 24px 0 0; }
}

/* ==========================================================================
   12. Arrival
   ========================================================================== */

/*
 * The page that sells should look composed the moment it lands. A short rise
 * on the gallery and on the buy panel's opening lines, and the versions
 * arriving one after another — transform and opacity only, no delay long
 * enough for a shopper to notice waiting, and every one of them cancelled
 * under prefers-reduced-motion below.
 */
@keyframes pdp-rise {
  from { opacity: 0; translate: 0 16px; }
  to { opacity: 1; translate: 0 0; }
}
@keyframes pdp-tag {
  from { opacity: 0; scale: .9; }
  to { opacity: 1; scale: 1; }
}

.s-pdp .s-gallery { animation: pdp-rise .5s var(--sp-ease) both; }
.s-pdp__cat { animation: pdp-rise .45s var(--sp-ease) .06s both; }
.s-pdp__title { animation: pdp-rise .5s var(--sp-ease) .1s both; }
.s-pdp__brand { animation: pdp-rise .5s var(--sp-ease) .14s both; }
.s-pdp__panel .s-rating { animation: pdp-rise .5s var(--sp-ease) .17s both; }
.s-pdp__price-row { animation: pdp-rise .5s var(--sp-ease) .2s both; }
.s-pdp__panel > .s-stockline { animation: pdp-rise .5s var(--sp-ease) .23s both; }
.s-pdp__summary { animation: pdp-rise .5s var(--sp-ease) .26s both; }
.s-pdp__panel > .s-pdp__block:first-of-type { animation: pdp-rise .5s var(--sp-ease) .3s both; }

.s-picker__row { animation: pdp-rise .45s var(--sp-ease) both; }
.s-picker__row:nth-child(1) { animation-delay: .34s; }
.s-picker__row:nth-child(2) { animation-delay: .39s; }
.s-picker__row:nth-child(3) { animation-delay: .44s; }
.s-picker__row:nth-child(4) { animation-delay: .49s; }
.s-picker__row:nth-child(5) { animation-delay: .54s; }
.s-picker__row:nth-child(6) { animation-delay: .59s; }
.s-picker__row:nth-child(n + 7) { animation-delay: .62s; }
.s-picker__total { animation: pdp-rise .45s var(--sp-ease) .5s both; }

/* Inside the quick view the sheet is already animating in, so the contents
   arrive with it rather than staggering a second time. */
.sp-quick .s-picker__row,
.sp-quick .s-picker__total { animation: none; }

/* ==========================================================================
   13. Reach — focus rings on everything the keyboard can land on
   ========================================================================== */

.s-gallery__thumb:focus-visible,
.s-gallery__stage:focus-visible,
.sp-quick__thumb:focus-visible,
.sp-quick__close:focus-visible,
.s-picker__check:focus-visible,
.s-stickybuy .s-btn:focus-visible,
.s-policy__item:focus-visible,
.s-reviewrail .s-rail-arrow:focus-visible {
  outline: 2px solid var(--s-brand-500);
  outline-offset: 3px;
}

/* ==========================================================================
   14. Narrow widths
   ========================================================================== */

@media (max-width: 39.99rem) {
  /*
   * The stacked version row put the stepper across the full width and dropped
   * the price underneath it, left aligned, where it read as a stray number.
   * Stepper and price share the second line now, the price on the end where a
   * total belongs.
   */
  .s-picker__row {
    grid-template-columns: auto 2.75rem minmax(0, 1fr);
    column-gap: .7rem;
    row-gap: .55rem;
  }
  /*
   * Both share the second line: the stepper pulled to the start, the price to
   * the end. They are given the same cell rather than a column each, because a
   * column narrow enough for the picture is far too narrow for a 132px
   * stepper — placed that way the stepper spilled under the price's box and
   * the price, painting later, swallowed every tap meant for "+".
   */
  .s-picker__row .s-qty { grid-row: 2; grid-column: 2 / -1; justify-self: start; }
  .s-picker__price {
    grid-row: 2;
    grid-column: 2 / -1;
    justify-self: end;
    align-self: center;
    text-align: end;
  }
  .s-picker .s-qty--sm .s-qty__btn { inline-size: 2.75rem; block-size: 2.75rem; }
  .s-picker .s-qty--sm .s-qty__value { inline-size: 2.75rem; block-size: 2.75rem; }

  .s-picker__total { padding: var(--s-4); row-gap: .75rem; }
  .s-picker__total .s-btn--primary { flex: 1 1 100%; max-inline-size: none; }

  .s-policy__item { padding: .8rem .35rem; }
  .s-policy__item svg { inline-size: 1.9rem; block-size: 1.9rem; }

  /* A 104px label column cannot hold "Country of origin" upright, so on a
     phone the label takes the room the removed cell padding just gave back. */
  .s-specs th { inline-size: 42%; padding: calc(.8rem + 1px) .9rem .8rem 0; }
  .s-specs td { padding: .8rem 0; font-size: var(--s-text-sm); }
  .s-specs tr:last-child th,
  .s-specs tr:last-child td { padding-block-end: 0; }
}

/* Nothing on this page may push the page sideways; a long specification value
   or an unbroken product code wraps instead. */
.s-pdp, .s-pdp__panel, .s-picker, .s-picker__row, .s-picker__total { min-inline-size: 0; }
/* `anywhere` gives the browser leave to break a word even where a narrower
   break would do. `break-word` keeps the permission where it is needed — a word
   that genuinely cannot fit a line of its own — and leaves the rest whole.
   Nothing here can push the page sideways either way. */
.s-picker__name, .s-picker__meta { overflow-wrap: break-word; }

/*
 * The option rows inside the quick view stack, whatever the window is doing.
 *
 * `.s-picker__row` is a five-column grid — tick, picture, name, stepper, price
 * — and it fits the product page, where the column has the width for it. The
 * quick view is a panel, and there the name column solved to 76px: not enough
 * for "Minicandy", which came out as "Minicand / y". The existing phone rule
 * already stacks this row properly, but it is a viewport media query and the
 * quick view is narrow at a *wide* viewport, so it never applied.
 *
 * Same three columns, same reason — the container is narrow, not the screen.
 */
.sp-quick .s-picker__row { grid-template-columns: auto 2.75rem minmax(0, 1fr); }
/* Second row: the stepper at its own width beside the price, not one control
   stretched across the card. They line up under the name, which is where the
   eye already is. */
.sp-quick .s-picker__row .s-qty { grid-column: 2; justify-self: start; }
.sp-quick .s-picker__price { grid-column: 3; justify-self: end; align-self: center; }

/* ==========================================================================
   15. The bottom of a phone — one decision bar, not two
   ========================================================================== */

/*
 * Measured on /p/leak-proof-barni at 390x844, scrolled to 1400:
 *
 *   sticky header   118px
 *   sticky buy bar   69px   fixed, top 715 → bottom 784
 *   bottom nav       60px   fixed, top 784 → bottom 844
 *   ------------------------------------------------------
 *   permanent chrome 247px of an 844px screen
 *
 * and because nothing gives the buy bar's 69px back, the trust trio sat at
 * 658→753 with 38px of it under the bar — the labels reading "Secure onl…"
 * and "N COD" with their feet cut off. At 360x800 the same three tiles lost
 * 70px. Worse than the slicing: the page was showing "Add 1 item · ₹479.00"
 * in the panel and "Add selected" in the bar at the same moment, so two bars
 * were asking for one decision.
 *
 * The answer is not more padding — padding would open a hole in the middle of
 * the page to protect the bottom of it. The answer is to stop stacking. While
 * the buy bar is up the bottom nav steps aside and the bar takes the edge it
 * leaves: 60px of screen handed straight back to the product, and one bar
 * carrying one decision. The nav is never gone for long — shop.js takes
 * `.is-shown` off again the moment the price row is back on screen — and
 * search, the menu and Cart are in the sticky header the whole time, so
 * nothing on the page becomes unreachable.
 *
 * The whole behaviour hangs off `.is-shown`, which shop.js puts on the bar
 * from an IntersectionObserver. With scripts off the class never arrives, the
 * bar never rises, and the nav stays exactly where it has always been.
 */

/* One above the nav rather than five below it, so the two never trade places
   during the third of a second they are both travelling. */
.s-stickybuy { z-index: calc(var(--s-z-bottomnav) + 1); }

@media (max-width: 61.99rem) {
  /*
   * The nav leaves on the buy bar's own easing and in its own time, so the
   * exchange reads as one movement rather than two. `visibility` is switched
   * only once the travel is over — a nav that has left the screen must not
   * still be a place the keyboard can land — and switched back at the first
   * frame of the return so it is focusable again all the way in.
   */
  body:has(.s-stickybuy) .s-bottomnav {
    transition:
      translate .34s var(--sp-ease),
      visibility 0s linear;
  }

  body:has(.s-stickybuy.is-shown) .s-bottomnav,
  body:has(.s-stickybuy.is-on) .s-bottomnav {
    translate: 0 100%;
    visibility: hidden;
    transition:
      translate .34s var(--sp-ease),
      visibility 0s linear .34s;
  }

  /*
   * The bar drops onto the edge the nav has vacated. This is the same
   * `translate` the bar already animates in on, so it slides into its new
   * rest instead of jumping to it, and slides back the same way — no `bottom`
   * is animated and nothing is laid out twice. Its own padding still carries
   * `--s-safe-bottom`, so on a notched phone the strip below the button stays
   * the bar's own white.
   */
  .s-stickybuy.is-shown,
  .s-stickybuy.is-on {
    translate: 0 calc(var(--s-bottomnav-height) + var(--s-safe-bottom));
  }
}

/* ==========================================================================
   16. Where a jump lands
   ========================================================================== */

/*
 * The rating line under the title is a link to #reviews. With a 118px sticky
 * header and a 69px buy bar, a jump used to put its target under one or the
 * other. Scoped to the product page by `:has(.s-pdp)` so the rest of the shop
 * keeps whatever behaviour it has; scroll padding costs nothing until
 * something is actually scrolled into view.
 */
html:has(.s-pdp) {
  scroll-padding-block-start: 7.5rem;
  scroll-padding-block-end: calc(var(--s-bottomnav-height) + var(--s-safe-bottom) + 1.25rem);
}

@media (min-width: 62rem) {
  html:has(.s-pdp) {
    /* The gallery's own sticky offset, so a jump and the pinned gallery agree
       about where the top of the page is. */
    scroll-padding-block-start: 8.5rem;
    scroll-padding-block-end: 2rem;
  }
}

/* ==========================================================================
   17. A product with no reviews yet
   ========================================================================== */

/*
 * The empty state was two lines of grey text lying loose on a white panel the
 * full width of the page — the shape of something missing rather than the
 * shape of something honest. It keeps every word; it is simply given a box of
 * its own, centred on the band, so it reads as a note the shop has written
 * rather than as a gap where the reviews should have been.
 */
.s-reviews__empty {
  /* Start-aligned, not centred: the band's own heading sits on the left edge,
     and a note centred against it gives the section two competing axes. */
  margin-inline: 0;
  padding: var(--s-6) var(--s-5);
  border: 1px dashed color-mix(in srgb, var(--s-brand-800) 20%, var(--s-surface));
  border-radius: var(--sp-radius-lg);
  /* Both stops are mixed from the theme's own surface, so the box is a shade
     of whatever the page is rather than a light tile stranded on a dark one. */
  background: linear-gradient(
    180deg,
    color-mix(in srgb, var(--s-brand-800) 5%, var(--s-surface)),
    var(--s-surface) 78%);
  line-height: 1.65;
}

/* ==========================================================================
   18. prefers-reduced-motion — every animation above is handed back
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  .s-gallery__stage,
  .s-gallery__thumb,
  .s-gallery__thumb img,
  .s-gallery__thumb::after,
  .s-lightbox img,
  .s-pdp__cat a,
  .s-pdp__brand a,
  .s-pdp__panel .s-rating,
  .s-picker__row,
  .s-picker__row::before,
  .s-picker__thumb,
  .s-policy__item,
  .s-policy__item svg,
  .s-review,
  .s-reviewrail .s-rail-arrow,
  body:has(.s-pdp) .s-carousel__arrow,
  .s-stickybuy,
  body:has(.s-stickybuy) .s-bottomnav,
  body:has(.s-stickybuy.is-shown) .s-bottomnav,
  body:has(.s-stickybuy.is-on) .s-bottomnav,
  .s-modal:has(.sp-quick) .s-modal__panel,
  .sp-quick__close,
  .sp-quick__figure img,
  .sp-quick__thumb,
  .sp-quick__thumb::after {
    transition: none;
  }

  .s-pdp .s-gallery,
  .s-pdp__cat,
  .s-pdp__title,
  .s-pdp__brand,
  .s-pdp__panel .s-rating,
  .s-pdp__price-row,
  .s-pdp__panel > .s-stockline,
  .s-pdp__summary,
  .s-pdp__panel > .s-pdp__block:first-of-type,
  .s-picker__row,
  .s-picker__total,
  .s-gallery__badges .s-tag {
    animation: none;
    opacity: 1;
    translate: none;
    scale: none;
  }

  /*
   * The states themselves stay — they simply arrive without travelling. The
   * rules under a thumb grow sideways and the picker's edge grows downwards,
   * so each is put back to its own axis before the selected one is restored.
   */
  .s-gallery__thumb::after,
  .sp-quick__thumb::after { scale: 0 1; }
  .s-picker__row::before { scale: 1 0; }
  .s-gallery__thumb.is-active::after,
  .sp-quick__thumb.is-on::after,
  .s-picker__row:has(input:checked)::before { scale: 1 1; }
  .s-stickybuy { translate: 0 130%; }
  .s-stickybuy.is-shown, .s-stickybuy.is-on { translate: 0; opacity: 1; }

  /*
   * Section 15's exchange is a change of state, not an animation, so it still
   * happens — it simply happens at once. The bar must keep the offset that
   * puts it on the screen's edge, or the nav would step aside and leave a
   * 60px hole under the bar; it is restated here because the rule above
   * resets the same property.
   */
  @media (max-width: 61.99rem) {
    .s-stickybuy.is-shown,
    .s-stickybuy.is-on {
      translate: 0 calc(var(--s-bottomnav-height) + var(--s-safe-bottom));
    }
  }

  /* snap.css spins the quick view's close button on hover; with motion turned
     down it changes colour and stays where it is. */
  .sp-quick__close:hover { transform: none; }
}
