/* ═══════════════════════════════════════════════════════════════════
   Product Page Styles
   ═══════════════════════════════════════════════════════════════════ */

/* ─── Two-column layout ──────────────────────────────────────────── */
.product-layout {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-2xl);
  align-items: start;
}

/* A grid item's min-width is auto, which means it refuses to shrink below the
   min-content width of what is inside it. The thumbnail strip is a flex row of
   `flex-shrink: 0` thumbs, so its min-content width is every thumb side by
   side, and the `overflow-x: auto` on it could never take effect.

   Under ten colourways nothing showed. At 24 the strip measured 1713px, which
   pushed the gallery track past the viewport and squeezed .product-info from
   704px to 125px: the Color chips went one per line, the accent swatches went
   to five lines and the page scrolled sideways. Measured at 1440 on
   best-dog-mom-ever-jersey-tee, 2026-10-07.

   `min-width: 0` is what lets the declared overflow do its job, and it keeps
   the 1fr 1fr split exact at every colourway count. Nothing that already fits
   moves. */
.product-layout > .product-gallery,
.product-layout > .product-info {
  min-width: 0;
}

@media (max-width: 768px) {
  .product-layout {
    grid-template-columns: 1fr;
    gap: var(--space-lg);
  }
}

/* ─── Image Gallery ──────────────────────────────────────────────── */
.product-gallery__main {
  border-radius: var(--radius);
  overflow: hidden;
  margin-bottom: var(--space-sm);
}

.product-gallery__main img {
  width: 100%;
  aspect-ratio: 1;
  object-fit: cover;
  border-radius: 0;
}

.product-gallery__thumbs {
  display: flex;
  gap: var(--space-xs);
  overflow-x: auto;
}

/* Labelled gallery thumbnails. The color name sits UNDER the photo; laid over
   it, it covered the bottom of the shirt it was naming (Andy, 2026-09-19).
   Kept here, not in global.css: this file loads after it, so rules split
   across the two fought and the label was clipped. */

.product-gallery__thumb {
  position: relative;
  flex-shrink: 0;
  cursor: pointer;
  background: none;
  padding: 0;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 4px;
  height: auto;
  border: 0;
  border-radius: 0;
  overflow: visible;
}

.product-gallery__thumb img {
  width: 80px;
  height: 80px;
  border: 2px solid transparent;
  border-radius: var(--radius-sm);
  transition: border-color 0.2s ease;
}

.product-gallery__thumb.is-active img,
.product-gallery__thumb:hover img {
  border-color: var(--color-brand);
}

.product-gallery__thumb-label {
  display: block;
  max-width: 80px;
  font-size: 0.68rem;
  line-height: 1.3;
  text-align: center;
  color: var(--color-meta);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  pointer-events: none;
}

.product-gallery__thumb.is-active .product-gallery__thumb-label {
  color: var(--color-brand);
  font-weight: var(--font-bold);
}

/* Phone: the square mockup used to own the first screen, so the accent
   picker sat below the fold. Changing ink meant scrolling off the shirt.
   Cap the photo and stick the gallery so the mockup stays in view. */
@media (max-width: 768px) {
  .product-gallery {
    position: sticky;
    top: var(--site-header-height);
    z-index: 6;
    background: var(--color-bg);
    padding-bottom: 0.4rem;
  }

  .product-gallery__main {
    margin-bottom: 0.4rem;
  }

  .product-gallery__main img {
    aspect-ratio: auto;
    max-height: 26vh;
    width: 100%;
    object-fit: contain;
  }

  /* After the base .product-gallery__thumbs { display: flex } rule. */
  .product-gallery__thumbs {
    display: none;
  }

  .product-info__rating--empty {
    display: none;
  }

  .accent {
    margin-bottom: var(--space-sm);
  }

  .accent__note {
    margin-bottom: 0.35rem;
  }
}

/* ─── Product Info ───────────────────────────────────────────────── */
.product-info__title {
  font-size: var(--text-3xl);
  margin-bottom: var(--space-xs);
}

.product-info__price {
  font-size: var(--text-2xl);
  font-weight: var(--font-extrabold);
  color: var(--color-brand);
  margin-bottom: var(--space-md);
}

.product-info__price--unavailable {
  color: var(--color-meta);
  font-size: var(--text-xl);
}

.product-info__trust {
  display: flex;
  gap: var(--space-md);
  flex-wrap: wrap;
  font-size: var(--text-sm);
  color: var(--color-meta);
  font-weight: var(--font-semibold);
  margin-bottom: var(--space-md);
  padding-bottom: var(--space-md);
  border-bottom: 1px solid var(--color-border);
}

.product-info__hook {
  margin-bottom: var(--space-md);
  font-size: var(--text-lg);
  line-height: 1.6;
}

/* ─── Variant Selectors ──────────────────────────────────────────── */
.product-info__variant {
  margin-bottom: var(--space-md);
}

.product-info__variant label {
  display: block;
  font-weight: var(--font-bold);
  font-size: var(--text-sm);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin-bottom: var(--space-xs);
  color: var(--color-brand);
}

.product-info__variant select {
  width: 100%;
  padding: 0.75rem 1rem;
  font-family: var(--font-family);
  font-size: var(--text-base);
  border: 2px solid var(--color-border);
  border-radius: var(--radius-btn);
  background: var(--color-bg);
  color: var(--color-brand);
  cursor: pointer;
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='%23212121' viewBox='0 0 16 16'%3E%3Cpath d='M8 11L3 6h10z'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 1rem center;
}

.product-info__variant select:focus {
  outline: none;
  border-color: var(--color-brand);
}

/* ─── Full-width button ──────────────────────────────────────────── */
.btn--full {
  width: 100%;
  margin-bottom: var(--space-lg);
}

/* ─── Product Tabs ───────────────────────────────────────────────── */
.product-tabs {
  border-top: 1px solid var(--color-border);
  padding-top: var(--space-md);
}

.product-tabs__nav {
  display: flex;
  gap: 0;
  border-bottom: 2px solid var(--color-border);
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

.product-tabs__btn {
  background: none;
  border: none;
  padding: var(--space-sm) var(--space-md);
  font-family: var(--font-family);
  font-size: var(--text-sm);
  font-weight: var(--font-semibold);
  color: var(--color-meta);
  cursor: pointer;
  white-space: nowrap;
  border-bottom: 2px solid transparent;
  margin-bottom: -2px;
  transition: color 0.2s ease, border-color 0.2s ease;
}

.product-tabs__btn:hover {
  color: var(--color-brand);
}

.product-tabs__btn.is-active {
  color: var(--color-brand);
  border-bottom-color: var(--color-brand);
}

.product-tab {
  display: none;
  padding: var(--space-md) 0;
  line-height: 1.7;
}

.product-tab.is-active {
  display: block;
}

/* ─── Reviews ────────────────────────────────────────────────────── */
.review-card {
  background: var(--color-bg);
  border-radius: var(--radius-sm);
  padding: var(--space-md);
  margin-bottom: var(--space-sm);
}

.review-card__stars {
  color: #f5a623;
  font-size: var(--text-lg);
  margin-bottom: var(--space-xs);
}

.review-card__body {
  margin-bottom: var(--space-xs);
}

.review-card__author {
  font-size: var(--text-sm);
  color: var(--color-meta);
  font-weight: var(--font-semibold);
}

/* ─── Collection Intro ───────────────────────────────────────────── */
.collection-intro {
  max-width: 65ch;
  margin-bottom: var(--space-lg);
  font-size: var(--text-lg);
  line-height: 1.7;
}

/* ═══════════════════════════════════════════════════════════════════
   REVIEWS ENGINE CSS — Append to apps/api/public/css/product.css
   ═══════════════════════════════════════════════════════════════════ */

/* ─── Reviews Header ─────────────────────────────────────────────── */
.reviews-header {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-md);
  margin-bottom: var(--space-lg);
}

.reviews-header h2 {
  margin: 0;
}

.reviews-summary {
  display: flex;
  align-items: center;
  gap: var(--space-xs);
}

.reviews-summary__stars {
  display: flex;
  gap: 2px;
}

.reviews-summary__count {
  font-size: var(--text-sm);
  color: var(--color-meta);
}

.star {
  font-size: 1.25rem;
  line-height: 1;
}

.star--full {
  color: #f5a623;
}

.star--empty {
  color: #ddd;
}

/* ─── Review Form ────────────────────────────────────────────────── */
.review-form-wrap {
  background: var(--color-bg);
  border: 1px solid #e0e0e0;
  border-radius: var(--radius);
  padding: var(--space-lg);
  margin-bottom: var(--space-xl);
}

.review-form__row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-md);
}

@media (max-width: 600px) {
  .review-form__row {
    grid-template-columns: 1fr;
  }
}

.review-form__field {
  margin-bottom: var(--space-md);
}

.review-form__field label {
  display: block;
  font-weight: var(--font-semibold);
  margin-bottom: var(--space-xs);
  font-size: var(--text-sm);
}

.review-form__field .required {
  color: var(--color-accent, #f44336);
}

.review-form__field small {
  display: block;
  margin-top: 4px;
  font-size: 0.75rem;
  color: var(--color-meta);
}

.review-form__field input,
.review-form__field textarea {
  width: 100%;
  padding: 0.625rem 0.75rem;
  border: 1px solid #ccc;
  border-radius: var(--radius-sm, 8px);
  font-family: inherit;
  font-size: var(--text-base, 1rem);
  transition: border-color 0.2s ease;
  background: #fff;
}

.review-form__field input:focus,
.review-form__field textarea:focus {
  outline: none;
  border-color: var(--color-brand);
  box-shadow: 0 0 0 3px rgba(33, 33, 33, 0.1);
}

.review-form__field textarea {
  resize: vertical;
  min-height: 100px;
}

/* ─── Star Picker ────────────────────────────────────────────────── */
.star-picker {
  display: flex;
  gap: 4px;
}

.star-picker__star {
  background: none;
  border: none;
  cursor: pointer;
  font-size: 2rem;
  color: #ddd;
  padding: 0;
  line-height: 1;
  transition: color 0.15s ease, transform 0.15s ease;
}

.star-picker__star:hover,
.star-picker__star.is-hovered {
  color: #f5a623;
  transform: scale(1.15);
}

.star-picker__star.is-selected {
  color: #f5a623;
}

/* ─── Review Form Actions ────────────────────────────────────────── */
.review-form__actions {
  display: flex;
  gap: var(--space-sm);
  margin-top: var(--space-md);
}

.btn--sm {
  padding: 0.5rem 1rem;
  font-size: var(--text-sm);
}

.btn--ghost {
  background: transparent;
  color: var(--color-meta);
  border: none;
  cursor: pointer;
  padding: 0.5rem 1rem;
  font-size: var(--text-sm);
  font-weight: var(--font-semibold);
}

.btn--ghost:hover {
  color: var(--color-brand);
}

/* ─── Review Form Message ────────────────────────────────────────── */
.review-form__message {
  margin-top: var(--space-md);
  padding: var(--space-sm) var(--space-md);
  border-radius: var(--radius-sm, 8px);
  font-size: var(--text-sm);
}

.review-form__message--success {
  background: #e8f5e9;
  color: #2e7d32;
  border: 1px solid #a5d6a7;
}

.review-form__message--error {
  background: #fbe9e7;
  color: #c62828;
  border: 1px solid #ef9a9a;
}

/* ─── Review Cards ───────────────────────────────────────────────── */
.review-card {
  background: var(--color-bg);
  border-radius: var(--radius-sm, 8px);
  padding: var(--space-md) var(--space-lg);
  margin-bottom: var(--space-md);
  border: 1px solid #eee;
}

.review-card__header {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  margin-bottom: var(--space-xs);
}

.review-card__stars {
  display: flex;
  gap: 2px;
}

.review-card__badge {
  font-size: 0.75rem;
  color: #2e7d32;
  font-weight: var(--font-semibold);
  background: #e8f5e9;
  padding: 2px 8px;
  border-radius: 12px;
}

.review-card__headline {
  font-size: var(--text-base, 1rem);
  font-weight: var(--font-bold, 700);
  margin: var(--space-xs) 0;
}

.review-card__body {
  margin-bottom: var(--space-sm);
  line-height: 1.6;
  color: var(--color-text);
}

.review-card__meta {
  display: flex;
  align-items: center;
  gap: var(--space-md);
  font-size: var(--text-sm);
  color: var(--color-meta);
}

.review-card__author {
  font-weight: var(--font-semibold);
}

.review-card__dog {
  font-style: italic;
}

.reviews-empty {
  text-align: center;
  color: var(--color-meta);
  padding: var(--space-xl) 0;
  font-size: var(--text-lg);
}

/* Care moved under About this design (2026-09-19): space it from the story. */
.product-detail__care { margin-top: var(--space-lg); }

/* ─── Accent Color picker ──────────────────────────────────────────────
   Scoped to .accent* and .cart-item__accent on purpose: global.css is shared
   with the home page, which Cursor is editing in the same deploy window, so
   nothing here goes in that file. */

.accent {
  margin: 0 0 var(--space-md);
  padding: var(--space-sm);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-bg-alt);
}

.accent__head {
  display: flex;
  align-items: center;
  gap: var(--space-xs);
  margin-bottom: 0.15rem;
}

/* Scoped through .accent to outrank global.css's `.section h2`, which adds a
   3rem top margin and knocked the Free badge off the heading's line. */
.accent .accent__title {
  font-size: var(--text-base);
  font-weight: var(--font-bold);
  color: var(--color-brand);
  margin: 0;
}

/* The price promise rides on the control itself, not in the small print. */
.accent__free {
  font-size: var(--text-xs);
  font-weight: var(--font-bold);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--color-white);
  background: var(--color-accent);
  border-radius: 999px;
  padding: 0.1rem 0.45rem;
}

.accent__note {
  font-size: var(--text-sm);
  color: var(--color-body);
  margin: 0 0 var(--space-sm);
}

.accent__slot + .accent__slot { margin-top: var(--space-sm); }

.accent__slot-head {
  display: flex;
  align-items: baseline;
  gap: 0.35rem;
  margin-bottom: 0.35rem;
}

.accent__slot-label {
  font-size: var(--text-sm);
  font-weight: var(--font-semibold);
  color: var(--color-brand);
}

.accent__slot-value {
  font-size: var(--text-sm);
  color: var(--color-meta);
}

/* One radiogroup, stacked: the inks that print boldly on this shirt, then the
   ones that print quietly. Both rows are usable. The row a shopper reads first
   is the one with the strongest answers in it (2026-10-05). */
/* The box holds the height of the WORST colourway this product sells, so
   re-sorting the tiers on a shirt change cannot move the Add to cart button
   below it. The counts come from the server as inline custom properties, one
   pair per breakpoint, measured across every colourway (2026-10-05).

   Only ever a min-height: over-reserving by a pixel costs dead space, while
   under-reserving costs a jump, so the server's per-line figures are
   deliberately the floor. The fallbacks are what a page with no precomputed
   verdicts gets, and they reserve a plausible two rows rather than nothing. */
.accent__swatches {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  min-height: calc(
    var(--rows-narrow, 2) * 28px + (var(--rows-narrow, 2) - 1) * 0.4rem
    + var(--low-narrow, 0) * (18px + 0.4rem)
    + var(--lowbox-narrow, 0) * (0.5rem + 1.15rem + 0.3rem - 0.4rem)
  );
}

@media (min-width: 768px) {
  .accent__swatches {
    min-height: calc(
      var(--rows-wide, 2) * 28px + (var(--rows-wide, 2) - 1) * 0.4rem
      + var(--low-wide, 0) * (18px + 0.4rem)
      + var(--lowbox-wide, 0) * (0.5rem + 1.15rem + 0.3rem - 0.4rem)
    );
  }
}

.accent__row { display: flex; flex-wrap: wrap; gap: 0.4rem; }

.accent__low { display: flex; flex-direction: column; gap: 0.3rem; }

.accent__low-label {
  font-size: var(--text-xs);
  color: var(--color-meta);
}

/* The ink is the whole control, so it carries its own ring: True White on a
   near-white card is otherwise an invisible button. */
.accent__swatch {
  width: 28px;
  height: 28px;
  padding: 0;
  border: 1px solid rgba(0, 0, 0, 0.3);
  border-radius: 50%;
  background: var(--swatch);
  cursor: pointer;
  position: relative;
  transition: transform 0.12s ease, box-shadow 0.12s ease;
}

.accent__swatch:hover:not(:disabled) { transform: scale(1.12); }

.accent__swatch:focus-visible {
  outline: 2px solid var(--color-brand);
  outline-offset: 2px;
}

.accent__swatch[aria-checked="true"] {
  box-shadow: 0 0 0 2px var(--color-bg), 0 0 0 4px var(--color-brand);
}

/* The design's own color, marked so "put it back" is a choice and not a hunt
   through thirteen circles for the one that was there first. */
.accent__swatch.is-original::after {
  content: "";
  position: absolute;
  inset: -7px;
  border: 1px dashed var(--color-meta);
  border-radius: 50%;
}

.accent__swatch:disabled { opacity: 0.35; cursor: not-allowed; }

/* An ink that prints quietly on the garment colour now selected.

   Size is the ONLY thing that separates it from the first row. Full hue, full
   ring, no fade, no not-allowed cursor, no aria-disabled: these are real
   choices, and anything that reads as a disabled control would be a lie about
   what happens when she clicks (Andy, 2026-10-05).

   Fading was tried on 2026-10-03, for inks that genuinely could not print, and
   it is what made Cream and True White vanish against the panel. The ring is
   what tells a shopper a swatch is a control, so the ring survives. These are
   secondary by POSITION and by SIZE, never by paleness. */
.accent__row--low .accent__swatch {
  width: 18px;
  height: 18px;
}

/* The shopper's own selection stays full size wherever it sits, so the thing
   she is looking at is never a small dot in the second row. */
.accent__row--low .accent__swatch[aria-checked="true"] {
  width: 28px;
  height: 28px;
}

/* Calm, and never red. A refused ink and an empty row are both the shopper
   finding something out, not doing something wrong (Andy, 2026-10-05). */
.accent__slot-note {
  margin: 0.4rem 0 0;
  font-size: var(--text-sm);
  color: var(--color-body);
}

.accent__slot.is-dead .accent__row:not(.accent__row--low) { opacity: 1; }

.accent__foot {
  margin-top: var(--space-sm);
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}

.accent__reset {
  align-self: flex-start;
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  font-size: var(--text-sm);
  color: var(--color-body);
  text-decoration: underline;
  cursor: pointer;
}

.accent__reset:hover { color: var(--color-brand); }

.accent__status { font-size: var(--text-sm); color: var(--color-body); margin: 0; }

/* The engine refusing a combination is information, not an error state: it
   tells the shopper which way to move. It used to be set in the brand red,
   which read as an alarm for something the shopper had not done wrong, so it
   is the body colour now and carries its weight instead (Andy, 2026-10-05).
   The red is kept for the one case that IS a fault: a colourway we cannot
   recolor at all. */
.accent__status[data-kind="warn"] { color: var(--color-brand); font-weight: var(--font-semibold); }
.accent__status[data-kind="blocked"] { color: var(--color-accent); font-weight: var(--font-semibold); }

.accent.is-loading { opacity: 0.75; }
.accent.is-unavailable .accent__slots { opacity: 0.45; }

@media (prefers-reduced-motion: reduce) {
  .accent__swatch { transition: none; }
  .accent__swatch:hover:not(:disabled) { transform: none; }
}

/* The chosen inks, on the cart line. */
.cart-item__accent {
  font-size: var(--text-sm);
  color: var(--color-body);
  margin: 0.15rem 0 0;
}

.cart-item__accent-free {
  font-size: var(--text-xs);
  font-weight: var(--font-bold);
  text-transform: uppercase;
  color: var(--color-accent);
}

/* ─── The one line that can arrive after first paint ──────────────────
   "That size and color combination is not available." It appears when a
   colour change lands on a size that colourway does not sell, which is why
   the template renders this slot only where the size run differs by
   colourway. One line is held open from first paint, so the sentence arriving
   cannot push Add to cart down the page.

   Metrics match .product-info__price-note deliberately: this sits in the same
   place and reads as the same kind of line. The line-height is stated rather
   than inherited, so 1.5em is exactly one line. */
p.product-info__variant-note {
  margin: -0.35rem 0 var(--space-sm);
  font-size: 0.85rem;
  /* Both of these are stated on `p.` rather than the class alone. `.section p`
     in global.css sets line-height 1.7 and outranks a lone class, so a reserve
     written against an unapplied 1.5 was 2.72px short and the button still
     moved (measured 2026-10-05). The reserve is the SAME number as the line
     height for that reason: one line, exactly. */
  line-height: 1.7;
  min-height: 1.7em;
  color: var(--color-meta);
}
