/* ==========================================================================
   The product page.

   Loaded only by templates/product.html. The chrome, the modal shell, the buttons and the
   touch-device rules all come from storefront.css, so this file holds the gallery, the
   picker and the availability table and nothing else.
   ========================================================================== */

.wrap{ max-width:1160px; }

.product-page{ padding-bottom:80px; }

.crumbs{
  display:flex; align-items:center; gap:8px; flex-wrap:wrap;
  padding:28px 0 18px; font-size:var(--type-sm); color:var(--text-muted);
}
.crumbs a{ color:var(--text-muted); }
.crumbs a:hover{ color:var(--text-heading); text-decoration:underline; }
.crumbs [aria-current]{ color:var(--text-heading); font-weight:600; }

.product-layout{
  display:grid; grid-template-columns:minmax(0, 480px) minmax(0, 1fr); gap:48px; align-items:start;
}
@media(max-width:860px){ .product-layout{ grid-template-columns:1fr; gap:28px; } }

/* ============ Gallery ============ */

/*
   No JavaScript anywhere in here. Each photograph is preceded by its own radio button, so the
   one rule below decides which is on show, and the radio group gives keyboard users arrow-key
   navigation between shots for free.

   The stage is bound by the shorter side of the window, not only by the column. The column caps the
   width at 480px and the shape is 4:5, which makes the stage 600px tall — taller than a laptop
   window, so the page used to open on a photograph with the name, the price and Add to Bag all
   below the fold. Two limits now, and the smaller wins.

   Expressed as a max-width rather than a max-height, because a height cap against an aspect-ratio
   leaves the box its full width and lets the crop take the difference. Derived this way round the
   shape holds and both sides come in together.

   svh with vh behind it, the pair the promotion banner and the drawer already use: vh is the
   viewport with a phone's toolbars retracted, so a box measured in it is taller than the screen.

   --gallery-chrome is the room above and below that is not the stage — header, breadcrumb, thumbnail
   strip, and a margin so the strip is not flush against the window. A deliberately generous guess,
   wrong only towards a smaller picture; the floor stops a very short window reducing it to a stamp.

   Only where the page is two columns. Below 861px the layout stacks and nothing competes for the
   height, and a phone held sideways has so little that this rule would shrink the photograph to a
   thumbnail. That layout is already right, so it is left exactly as it was.
*/
.gallery-stage{
  position:relative; border-radius:var(--radius-lg); overflow:hidden;
  background:var(--surface-sunken); border:1px solid var(--border); aspect-ratio:4/5;
  width:100%; margin-inline:auto;
}
@media(min-width:861px){
  .gallery{ --gallery-chrome:280px; }
  .gallery-stage{
    max-width:max(300px, calc((100vh - var(--gallery-chrome)) * 4 / 5));
    max-width:max(300px, calc((100svh - var(--gallery-chrome)) * 4 / 5));
  }
}
.gallery-pick{
  position:absolute; width:1px; height:1px; opacity:0; margin:0; pointer-events:none;
}
.gallery-shot{ display:none; width:100%; height:100%; object-fit:cover; }
.gallery-pick:checked + .gallery-shot{ display:block; }
.gallery-empty{
  display:flex; align-items:center; justify-content:center; height:100%; margin:0;
  color:var(--text-muted); font-size:var(--type-sm);
}

/* A focused radio is invisible, so the ring has to appear on the picture it controls. */
.gallery-pick:focus-visible + .gallery-shot{ outline:2px solid var(--focus-ring); outline-offset:-3px; }

/* Which photograph this is, out of how many. Chosen by the same checked radio as the image, through
   the sibling chain the markup lays out in that order — input, image, counter. No script, and no way
   for the number and the picture to disagree, because one selector shows both. */
.gallery-index{
  display:none; position:absolute; right:12px; bottom:12px; margin:0;
  padding:5px 11px; border-radius:999px;
  background:var(--scrim-photo); color:var(--text-on-inverse-strong);
  font-size:var(--type-xs); font-weight:700; letter-spacing:.06em;
}
.gallery-pick:checked + .gallery-shot + .gallery-index{ display:block; }

.gallery-thumbs{ display:flex; gap:10px; margin-top:12px; flex-wrap:wrap; }
.gallery-thumb{
  position:relative;
  width:64px; height:80px; border-radius:var(--radius-sm); overflow:hidden; cursor:pointer;
  border:2px solid transparent; transition:border-color .2s ease; background:var(--surface-sunken);
}
.gallery-thumb:hover{ border-color:var(--border-accent); }
.gallery-thumb img{ width:100%; height:100%; object-fit:cover; }
/* The thumbnails are a numbered list, so "2 / 4" on the stage names one of them rather than a
   position the reader has to count out for themselves. */
.gallery-thumb-index{
  position:absolute; top:3px; left:3px; min-width:17px; height:17px;
  display:flex; align-items:center; justify-content:center;
  border-radius:var(--radius-sm); padding:0 4px;
  background:var(--scrim-photo); color:var(--text-on-inverse-strong);
  font-size:var(--type-xs); font-weight:700; line-height:1;
}

/* ============ Detail column ============ */

.product-detail{ padding-top:4px; }
.product-detail .badge{
  display:inline-block; background:var(--surface-accent); color:var(--text-on-accent); font-size:var(--type-xs);
  font-weight:700; padding:5px 12px; border-radius:999px; letter-spacing:0.03em;
  text-transform:uppercase; margin-bottom:12px;
}
.product-detail .brand{
  margin:0 0 6px; font-size:var(--type-xs); letter-spacing:0.18em; text-transform:uppercase;
  font-weight:600; color:var(--text-accent);
}
.product-detail h1{ font-size:var(--type-2xl); line-height:1.15; }
@media(max-width:768px){ .product-detail h1{ font-size:var(--type-xl); } }
.product-detail .price{ font-size:var(--type-lg); font-weight:700; color:var(--text-heading); margin:12px 0 0; }
/* ---- A reduced headline -----------------------------------------------------------------------
   Same three parts as a card, at the size the product page prints a price. The old figure is
   smaller as well as quieter: at the headline size, two prices set alike read as two products.

   The script rewrites the inside of this paragraph when a size is chosen, so these rules have to
   hold for markup that was not in the first response. They are all class-based for that reason;
   nothing here depends on the order the server happened to render. */
.product-detail .price.is-on-sale{ display:flex; align-items:baseline; flex-wrap:wrap; gap:6px 12px; }
.product-detail .price .price-now{ color:var(--sale-ink); }
.product-detail .price:not(.is-on-sale) .price-now{ color:var(--text-heading); }
.product-detail .price-was{ font-size:var(--type-md); font-weight:600; color:var(--text-muted); }
.product-detail .price-off{
  font-size:var(--type-xs); font-weight:700; letter-spacing:0.02em;
  color:var(--sale-ink); background:var(--sale-surface);
  border:1px solid var(--sale-border); border-radius:999px; padding:3px 10px;
}
/* The availability table's own column, where the two figures share one cell. */
.availability td.is-on-sale .price-was{ font-size:var(--type-xs); margin-right:6px; }
.availability td.is-on-sale{ color:var(--sale-ink); font-weight:600; }
.product-detail .stock-headline{ color:var(--danger); font-weight:700; margin:10px 0 0; font-size:var(--type-sm); }

/* .description was the single paragraph in the right-hand column. The prose is a list of headed
   sections now and has moved below the fold to .detail-sections, where it has room to be read. */

/* What the shop knows about how this item sizes. Rendered only when somebody has typed it in,
   and rendered inside the size fieldset, next to the decision it exists to inform. */
.sizing-note{
  margin:0 0 12px; padding:11px 13px; border-radius:10px; background:var(--accent-wash);
  border-left:3px solid var(--surface-accent); font-size:var(--type-sm); line-height:1.55;
  display:flex; flex-direction:column; gap:3px;
}
.sizing-note span{ color:var(--text-secondary); }

/* ============ What we know about your size ============
   The fit panel and the three-question form inside it stood here, between the sizing note above
   and the size pills below. Both are withdrawn with the Fit Finder. The sizing note stays: it is
   the product's own copy, served in the HTML, and reads the same for everybody. */

.picker{ border:none; margin:22px 0 0; padding:0; }
.picker legend{
  font-size:var(--type-sm); text-transform:uppercase; letter-spacing:0.08em; color:var(--text-heading);
  font-weight:700; padding:0; margin-bottom:10px;
}
/* The third of the shop's three colour controls, and the only one that decides what goes in the
   bag. Named for the picker it sits in, because the other two — the card's dots in storefront.css
   and the catalogue filter's chips below them — were also called .swatch, and this page loads that
   sheet. `.swatch-row .swatch` was specific enough to win back the width and the radius, but not
   the filter chip's `min-height:38px` and `padding:7px 14px`, so a 22px circle rendered as a 38px
   tall pill with the colour squeezed out of the middle of it. */
.picker-swatch-row{ display:flex; gap:8px; align-items:center; flex-wrap:wrap; }
.picker-swatch{
  width:22px; height:22px; border-radius:50%; border:2px solid var(--border); position:relative;
  background:var(--surface-sunken); transition:border-color .2s ease, transform .15s ease;
}
.picker-swatch.active{ border-color:var(--surface-selected); transform:scale(1.12); }
.picker-swatch[disabled]{ opacity:.35; cursor:not-allowed; }
.picker-swatch-label{ font-size:var(--type-sm); color:var(--text-muted); margin-left:6px; }

/* The way in to the size guide, between the sizing note and the pills. A button that reads as a
   link: it is a quiet offer beside the decision, not a third thing competing with Add to Bag. */
.size-guide-row{ margin:0 0 12px; }
.size-guide-open{
  font-size:var(--type-sm); color:var(--text-accent); font-weight:600;
  border-bottom:1px solid var(--border-accent); padding:0; background:none; border-radius:0;
  border-left:none; border-right:none; border-top:none; font-family:inherit;
}
.size-guide-open:hover{ border-bottom-color:var(--text-accent); }

.size-row{ display:flex; gap:8px; flex-wrap:wrap; }
.size-row .size-pill{
  border:1.5px solid var(--border); border-radius:999px; padding:10px 17px; font-size:var(--type-sm);
  font-weight:600; color:var(--text-heading); background:var(--surface-raised); transition:all .2s ease;
}
.size-row .size-pill:hover:not([disabled]){ border-color:var(--border-accent); }
.size-row .size-pill.active{ background:var(--surface-selected); color:var(--text-on-selected); border-color:var(--surface-selected); }
.size-row .size-pill[disabled]{ opacity:.4; cursor:not-allowed; }

.selection-state{ margin:16px 0 0; font-size:var(--type-sm); color:var(--text-muted); min-height:20px; }
.selection-state.warn{ color:var(--danger); }

/* ============ The two ways to buy ============
   Add to Bag and Buy Now, side by side and deliberately not equals in width. Add to Bag keeps the
   filled button and the larger share of the row; Buy Now is the outline role from the design
   system, which is the same primary/secondary pair the home page hero uses.

   Not equals in width. Equal in height — that part was never a decision, it was arithmetic. Buy
   Now used to stand a pixel taller because its 1.5px border was counted inside its box and Add to
   Bag had no border to count. Nothing here fixes that: the two roles do, in storefront.css, where
   both now carry the same frame and the filled one's is transparent. A height override in this
   file would have papered over a pair that is wrong everywhere else it is used.

   Both roles read their colours from --surface-action and --text-heading, so the row follows the
   theme without either button naming a colour of its own. */
.buy-row{ display:flex; gap:10px; margin-top:14px; }
/* Add to Bag was width:100% when it was alone in the row. Flex basis rather than a width, so the
   two share the line instead of one of them forcing it open. */
.buy-row .add-to-bag{ flex:3 1 0; margin-top:0; }
.buy-row .buy-now{ flex:2 1 0; }
/* The two roles set 30px of horizontal padding each, which is generous for a button that is now
   sharing a row. At these widths the label is what has to fit. Only the padding is narrowed here;
   the border is left alone, so the two boxes stay the same size as each other.

   text-align:center stood here and did nothing. Both roles are flex containers, and a flex item is
   placed by justify-content — text-align only reaches lines of text inside a block. It read like
   the thing keeping the two labels centred for as long as only one of them was centred, which is
   how the fault under it went unnoticed. Centring belongs to the roles and is theirs now. */
.buy-row .btn-primary,
.buy-row .btn-outline{ padding-left:12px; padding-right:12px; white-space:nowrap; }

/* Under about 420px, "Add to Bag" and "Buy Now" side by side leaves each of them around 150px
   before padding, and the labels start to crowd the edges. Stacking is better than shrinking type
   or wrapping a two-word label onto two lines. The order is kept: the primary action stays first
   under the thumb, and Buy Now stays the second thing read. */
@media(max-width:420px){
  .buy-row{ flex-direction:column; }
  .buy-row .add-to-bag,
  .buy-row .buy-now{ flex:none; width:100%; }
}

/* .quiz-link was the line under the buy row offering the full Fit Finder. Withdrawn with it. */

.features{ margin:26px 0 0; padding-left:18px; color:var(--text-secondary); font-size:var(--type-sm); line-height:1.9; }

/* ============ Detail sections ============
   The description, in the headed parts a shopper asks about separately.

   Built on <details>, so the open and closed states, the keyboard and the "expanded" the screen
   reader announces are all the browser's rather than ours. What is left to style is the marker,
   which every browser draws differently and none of them draw in this shop's type.

   Full width under the two columns rather than squeezed into the right-hand one: prose wants a
   measure, and 60ch of warranty beside a photograph is a column two words wide on a laptop. */

.detail-sections{ margin-top:56px; max-width:72ch; }
.detail-section{ border-bottom:1px solid var(--border); }
.detail-section:first-child{ border-top:1px solid var(--border); }

.detail-section summary{
  /* list-style on the summary is what Firefox and Chrome read; ::-webkit-details-marker is
     Safari's, and it ignores the first. Both are needed to be rid of the default triangle. */
  list-style:none; cursor:pointer; padding:18px 40px 18px 2px; position:relative;
  font-size:var(--type-md); font-weight:600; color:var(--text-heading);
}
.detail-section summary::-webkit-details-marker{ display:none; }

/* Two rules of a cross, rotated. A single glyph would be the reader's font rather than the shop's
   and would sit differently in every one of them; two boxes are the same everywhere. */
.detail-section summary::before,
.detail-section summary::after{
  content:""; position:absolute; right:6px; top:50%; background:var(--text-accent);
  transition:transform .2s ease, opacity .2s ease;
}
.detail-section summary::before{ width:13px; height:1.5px; margin-top:-0.75px; }
.detail-section summary::after{ width:1.5px; height:13px; margin-top:-6.5px; right:11.75px; }
.detail-section[open] summary::after{ transform:rotate(90deg); opacity:0; }

.detail-section summary:hover{ color:var(--text-accent); }

.detail-body{ padding:0 2px 20px; }
.detail-body p{ margin:0; color:var(--text-secondary); font-size:var(--type-sm); line-height:1.75;
  white-space:pre-line; }

/* A phone has less room for the indicator and the heading to share, and 40px of right padding on a
   320px screen is an eighth of the line. */
@media(max-width:480px){
  .detail-section summary{ padding-right:32px; font-size:var(--type-sm); }
}

/* ============ More from this category ============
   The cards are the catalogue's own — one fragment, one set of rules in home.css — so there is
   nothing here but the room around them. */

.also-in{ margin-top:56px; }
.also-in h2{ font-size:var(--type-lg); margin-bottom:14px; }

/* ============ The size guide overlay ============
   Only the overlay is here now. The chart inside it — .size-guide-table, .size-guide-how and
   .table-scroll — moved to storefront.css when /size-guide started rendering the same fragment,
   because a rule two pages depend on cannot live in one page's sheet. */

.size-guide-panel{ width:640px; }

/* The way out of the overlay and onto the page that holds every chart. */
.size-guide-more{ margin:18px 0 0; font-size:var(--type-sm); }
.size-guide-more a{ color:var(--text-accent); font-weight:600; }

/* ============ Availability ============ */

.availability{ margin-top:56px; }
.availability h2{ font-size:var(--type-lg); margin-bottom:14px; }

.availability table{
  width:100%; border-collapse:collapse; background:var(--surface-raised); border:1px solid var(--border);
  border-radius:var(--radius-md); overflow:hidden; font-size:var(--type-sm); min-width:520px;
}
.availability th, .availability td{ text-align:left; padding:12px 16px; border-bottom:1px solid var(--border); }
.availability thead th{
  background:var(--surface-sunken); font-size:var(--type-xs); text-transform:uppercase;
  letter-spacing:0.08em; color:var(--text-heading); font-weight:700;
}
.availability tbody tr:last-child td{ border-bottom:none; }
.availability .sku{ font-family:ui-monospace, SFMono-Regular, Menlo, monospace; font-size:var(--type-sm); color:var(--text-muted); }
.availability tr.sold-out td{ color:var(--text-muted); }

/* ============ Reviews ============
   The stars themselves are in storefront.css, because a card in the row at the foot of this page
   draws the same ones.

   Everything here renders only for a product that has been reviewed. There is no empty state to
   style: a product nobody has reviewed shows no section, no heading and no star row beside the
   price, which on a shop with no sales is every product in the catalogue. */

/* Beside the name, above the price. Quiet: it is a fact about the product, not a claim. */
.pdp-rating{ display:flex; align-items:center; gap:8px; margin:10px 0 0; font-size:var(--type-sm); }
.pdp-rating a{ color:var(--text-muted); border-bottom:1px solid var(--border); }
.pdp-rating a:hover{ color:var(--text-accent); border-bottom-color:var(--border-accent); }

.reviews{ margin-top:56px; max-width:72ch; }
.reviews h2{ font-size:var(--type-lg); margin-bottom:16px; }

.review-summary{
  display:flex; gap:32px; align-items:center; flex-wrap:wrap; padding:18px 20px;
  background:var(--surface-sunken); border:1px solid var(--border); border-radius:var(--radius-md);
}
.review-average{ display:flex; align-items:center; gap:10px; margin:0; flex-wrap:wrap; }
.review-figure{ font-size:var(--type-xl); font-weight:700; color:var(--text-heading); }
.review-total{ font-size:var(--type-sm); color:var(--text-muted); }

/* Five rows, always, including the stars nobody gave. A chart that drops its empty rows makes the
   worst rating a product has look like the bottom of the scale. */
.review-bars{ list-style:none; margin:0; padding:0; flex:1 1 220px; min-width:0; }
.review-bars li{
  display:grid; grid-template-columns:52px 1fr 24px; align-items:center; gap:8px;
  font-size:var(--type-xs); color:var(--text-muted);
}
.review-bars .bar{
  height:6px; border-radius:999px; background:var(--surface-hover); overflow:hidden;
}
.review-bars .bar-fill{ display:block; height:100%; background:var(--surface-accent); }
.review-bars .bar-count{ text-align:right; }

.review-list{ list-style:none; margin:24px 0 0; padding:0; }
.review{ padding:20px 0; border-bottom:1px solid var(--border); }
.review:first-child{ border-top:1px solid var(--border); }
.review-head{ display:flex; align-items:center; gap:10px; flex-wrap:wrap; }
.review-head h3{ font-size:var(--type-md); margin:0; color:var(--text-heading); }
.review-body{
  margin:10px 0 0; color:var(--text-secondary); font-size:var(--type-sm); line-height:1.75;
  white-space:pre-line;
}
.review-by{
  display:flex; gap:10px; flex-wrap:wrap; margin:10px 0 0; font-size:var(--type-xs);
  color:var(--text-muted);
}
.review-author{ font-weight:600; color:var(--text-secondary); }
/* The size is the most useful thing on the row in a shop where fit is the question, so it is the
   one part of the byline that is not grey. */
.review-size{ color:var(--text-accent); font-weight:600; }

.review-pager{
  display:flex; align-items:center; justify-content:space-between; gap:12px; margin-top:20px;
  font-size:var(--type-sm); flex-wrap:wrap;
}
.review-page-link{ color:var(--text-accent); font-weight:600; border-bottom:1px solid var(--border-accent); }
.review-page-count{ color:var(--text-muted); }

/* The invitation, which a script puts here for somebody who bought this and nobody else. Empty and
   hidden in the HTML, so a visitor who is not signed in sees no trace of it. */
.review-invite{
  margin-top:40px; padding:18px 20px; border-radius:var(--radius-md);
  background:var(--accent-wash); border-left:3px solid var(--surface-accent);
}
.review-invite p{ margin:0 0 12px; font-size:var(--type-sm); color:var(--text-secondary); }
.review-invite .review-mine{ margin-bottom:10px; }

/* The review form itself is not here any more. It is a modal, it is opened from the account page
   as well as this one, and a rule two pages depend on cannot live in one page's sheet — the same
   argument that moved the measurement chart. See "Writing a review" in storefront.css. */

/* One column on a phone: the summary's two halves each want the full width, and a six-pixel bar
   squeezed beside a large number is unreadable at either size. */
@media(max-width:600px){
  .review-summary{ flex-direction:column; align-items:stretch; gap:16px; }
  .review-bars{ flex:none; }
  .review-pager{ justify-content:center; }
}

/* ============ Touch ============ */

@media (pointer: coarse){
  .gallery-thumb{ width:72px; height:90px; }
  .size-row .size-pill{ min-height:44px; }
  /* A summary is the whole row, so it is already wide; what it needs is height. The size guide
     link is a line of text and needs both, which is why it gets a block of its own. */
  .detail-section summary{ min-height:52px; display:flex; align-items:center; }
  .size-guide-open{ display:inline-flex; align-items:center; min-height:44px; }
  /* Both buy buttons, so the secondary one is as tappable as the primary. */
  .buy-row .btn-primary,
  .buy-row .btn-outline{ min-height:48px; }
  /* The two links that page through the reviews. The star buttons grew with the form, into
     storefront.css. */
  .review-page-link{ display:inline-flex; align-items:center; min-height:44px; }
  /* The dot stays small; the tappable area around it does not. */
  .picker-swatch-row{ gap:16px; }
  .picker-swatch{ width:28px; height:28px; }
  .picker-swatch::after{
    content:''; position:absolute; top:50%; left:50%; transform:translate(-50%,-50%);
    width:44px; height:44px; border-radius:50%;
  }
  .picker-swatch-label{ margin-left:0; }
}
