/* ==========================================================================
   NHV-13 — Product page
   ==========================================================================
   Sampled from the live product page. Two of its values turned out to be tokens
   we already had: the Add to Cart ground is rgb(2,19,27) = --nhv-footer-ground,
   and the quantity field is rgb(246,240,232) = --nhv-sand. The price is 30px/700
   and the title Sora 22px/600. */

.nhv-product-top { margin-bottom: 28px; }

/* --- Gallery -------------------------------------------------------------- */

.nhv-gallery {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 10px;
  list-style: none;
  margin: 0;
  padding: 0;
}
/* The main image takes the full width above the additional shots. */
.nhv-gallery > li:first-child { grid-column: 1 / -1; }

.nhv-gallery .thumbnail {
  display: block;
  margin: 0;
  padding: 0;
  background: var(--nhv-cream-bright);
  border: 1px solid var(--nhv-rule-warm);
  border-radius: var(--nhv-radius-sm);
  overflow: hidden;
  transition: border-color 0.15s ease;
}
.nhv-gallery .thumbnail:hover,
.nhv-gallery .thumbnail:focus { border-color: var(--nhv-copper); }
.nhv-gallery .thumbnail:focus-visible { outline: 2px solid var(--nhv-copper); outline-offset: 2px; }

/* Reserve the box so a missing or slow image cannot shift the buy box beside it.
   Product photography here is square. */
.nhv-gallery .thumbnail img {
  width: 100%;
  height: auto;
  aspect-ratio: 1 / 1;
  object-fit: contain;
  display: block;
}

/* --- Buy box -------------------------------------------------------------- */

.nhv-product-actions { display: flex; gap: 6px; float: right; }
.nhv-product-actions .btn,
.nhv-product-actions .btn:focus {
  width: 34px;
  height: 34px;
  padding: 0;
  color: var(--nhv-navy);
  background: var(--nhv-sand);
  border: 1px solid var(--nhv-rule-warm);
  border-radius: var(--nhv-radius-sm);
  box-shadow: none;
}
.nhv-product-actions .btn:hover {
  color: var(--nhv-cream-bright);
  background: var(--nhv-copper);
  border-color: var(--nhv-copper);
}
.nhv-product-actions .btn:focus-visible { outline: 2px solid var(--nhv-copper); outline-offset: 2px; }

.nhv-product-title {
  margin: 0 0 12px;
  font-family: var(--nhv-font-display);
  font-size: 22px;
  font-weight: var(--nhv-fw-semi);
  line-height: 1.25;
  color: var(--nhv-navy);
}

.nhv-product-meta {
  margin: 0 0 16px;
  padding: 0 0 16px;
  border-bottom: 1px solid var(--nhv-rule-warm);
  font-family: var(--nhv-font-body);

  /* Up from --nhv-fs-small. This block carries the three facts a shopper checks
     before buying — who makes it, which one it is, can I have it — and it was
     set smaller than the description below it. */
  font-size: var(--nhv-fs-base);
  line-height: 1.75;
  color: var(--nhv-navy);
}

.nhv-product-meta li { display: flex; align-items: center; gap: 7px; }

/* --- Code + availability, one strip -----------------------------------------
   The two facts checked together, on a sand ground so they read as a stated
   panel rather than two more lines of the list. The divider is a real border on
   the second item, not a pseudo-element, so it disappears by itself when the
   pair wraps onto two lines. */
.nhv-meta-strip {
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  gap: 0;
  margin: 2px 0 4px;
  padding: 0;
  background: var(--nhv-sand);
  border: 1px solid var(--nhv-rule-warm);
  border-radius: var(--nhv-radius-sm);
  overflow: hidden;
}

.nhv-meta-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 9px 14px;
}

.nhv-meta-item + .nhv-meta-item { border-left: 1px solid var(--nhv-rule-warm); }

.nhv-meta-strip strong {
  font-family: var(--nhv-font-display);
  font-size: var(--nhv-fs-small);
  font-weight: var(--nhv-fw-semi);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--nhv-copper-muted);      /* the label recedes; the value leads */
}

.nhv-meta-value {
  font-family: var(--nhv-font-body);
  font-size: var(--nhv-fs-base);
  font-weight: var(--nhv-fw-semi);
  color: var(--nhv-navy);
}

/* --- Availability pill -------------------------------------------------------
   A pill, not coloured text. The shape carries the state alongside the colour,
   which is what makes it legible to anyone who cannot separate the green from
   the red — colour alone would be the only signal otherwise. */
.nhv-stock-pill {
  display: inline-block;
  padding: 3px 11px;
  font-family: var(--nhv-font-display);
  font-size: var(--nhv-fs-small);
  font-weight: var(--nhv-fw-semi);
  letter-spacing: 0.02em;
  line-height: 1.5;
  color: var(--nhv-cream-bright);
  border-radius: 999px;
  white-space: nowrap;
}

.nhv-stock-pill.is-in  { background: var(--nhv-stock-green); }   /* 6.36:1 */
.nhv-stock-pill.is-out { background: var(--nhv-sale-red); }      /* 7.06:1 */

@media (max-width: 480px) {
  /* Stacked, and the divider becomes a rule between rows rather than columns. */
  .nhv-meta-item { flex: 1 1 100%; }
  .nhv-meta-item + .nhv-meta-item {
    border-left: 0;
    border-top: 1px solid var(--nhv-rule-warm);
  }
}

/* The label, not the value. Reading down the left edge should find the field
   you want without reading the answers. */
.nhv-product-meta strong {
  font-weight: var(--nhv-fw-semi);
  color: var(--nhv-navy);
}

.nhv-product-meta a { color: var(--nhv-copper); }
.nhv-product-meta a:hover { color: var(--nhv-navy); }

/* --- Brand card ---
   NAMESPACED nhv-product-brand-*, and it has to be. NHV-18's manufacturer.css
   already owns `.nhv-brand-card` for the brand index, every block stylesheet is
   linked on every page, and manufacturer.css loads AFTER product.css — so its
   rule won on the product page and brought a 12px gap, 8px 12px of padding and
   a cream ground with it. Same specificity, later file, no warning.

   The old name is left entirely to NHV-18. --- ----------------------------------------------------------
   A 100px logo and the brand name in one bordered block. The name's panel uses
   --nhv-brand-mat, the grey the artwork is printed on, so the join between the
   two is invisible and the card reads as a single object.

   align-items: stretch is what makes that work: the name panel takes the
   logo's full 100px height, so the mat runs edge to edge with no lighter strip
   above or below it. */
.nhv-product-brand-row { margin-bottom: 10px; }

.nhv-product-brand {
  display: inline-flex;
  align-items: stretch;
  border: 1px solid var(--nhv-rule-warm);
  border-radius: var(--nhv-radius-sm);
  overflow: hidden;                     /* keeps the mat inside the radius */
  text-decoration: none;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.nhv-product-brand:hover,
.nhv-product-brand:focus {
  border-color: var(--nhv-copper);
  box-shadow: 0 1px 4px rgba(16, 47, 66, 0.12);
  text-decoration: none;
}

.nhv-product-brand:focus-visible { outline: 2px solid var(--nhv-copper); outline-offset: 2px; }

/* 100px square, matching the 100x100 the modification asks resize() for, so the
   JPEG is displayed at its native size and stays crisp. object-fit is insurance
   against a future brand supplying non-square artwork. */
.nhv-product-brand-logo {
  display: block;
  width: 100px;
  height: 100px;
  object-fit: contain;
}

/* A deliberate hairline between the logo and the name, and it is there for a
   reason rather than decoration.

   --nhv-brand-mat matches 91% of the artwork exactly, but the rest sit a few
   points off — OXVA's mat is #444341 against the token's #3F3F3F — and a
   near-match across a hard edge reads as a mistake, a faint seam that looks like
   a rendering fault. A stated rule turns the same join into a design: it reads
   as two panels intentionally divided, and whether the greys agree to the point
   stops mattering. */
.nhv-product-brand-name {
  display: flex;
  align-items: center;
  padding: 0 20px;
  border-left: 1px solid var(--nhv-rule);
  background: var(--nhv-brand-mat);
  color: var(--nhv-cream);              /* 9.45:1 */
  font-family: var(--nhv-font-display);
  font-size: var(--nhv-fs-base);
  font-weight: var(--nhv-fw-semi);
  letter-spacing: 0.02em;
  white-space: nowrap;
}

/* With no logo the name is the whole card, and a bare strip of mat would look
   like a mistake — it gets a height that echoes the logo it stands in for. */
.nhv-product-brand-logo + .nhv-product-brand-name { min-height: 100px; }
.nhv-product-brand > .nhv-product-brand-name:only-child { min-height: 52px; }

.nhv-product-brand:hover .nhv-product-brand-name { color: var(--nhv-cream-bright); }

.nhv-price-block {
  margin: 0 0 18px;
  font-family: var(--nhv-font-body);
  font-size: var(--nhv-fs-small);
  color: var(--nhv-grey-link);
}
.nhv-price-now {
  margin: 0;
  font-family: var(--nhv-font-body);
  font-size: 30px;
  font-weight: var(--nhv-fw-bold);
  line-height: 1.1;
  color: var(--nhv-navy);
}
/* On a reduced item the live price carries the emphasis and the old one is
   struck through beside it. --nhv-sale-red is the badge colour from NHV-10, so
   a reduction reads the same on the card and on the product page. */
.nhv-price-now--special { color: var(--nhv-sale-red); }
.nhv-price-was {
  font-size: var(--nhv-fs-base);
  color: var(--nhv-grey-link);
  text-decoration: line-through;
}

.nhv-buybox-heading {
  margin: 18px 0 10px;
  font-family: var(--nhv-font-display);
  font-size: var(--nhv-fs-base);
  font-weight: var(--nhv-fw-bold);
  color: var(--nhv-navy);
}

/* Core's option fields are Bootstrap .form-control; bring them onto the palette
   rather than restyling each of the seven option types. */
.nhv-buybox .form-control,
.nhv-buybox .form-control:focus {
  height: 38px;
  padding: 0 10px;
  font-family: var(--nhv-font-body);
  font-size: var(--nhv-fs-base);
  color: var(--nhv-navy);
  background-color: var(--nhv-cream-bright);
  border: 1px solid var(--nhv-rule-warm);
  border-radius: var(--nhv-radius-sm);
  box-shadow: none;
}
.nhv-buybox textarea.form-control { height: auto; padding: 8px 10px; }
.nhv-buybox .form-control:focus-visible { outline: 2px solid var(--nhv-copper); outline-offset: 1px; }
.nhv-buybox .control-label {
  font-family: var(--nhv-font-display);
  font-size: var(--nhv-fs-small);
  font-weight: var(--nhv-fw-semi);
  color: var(--nhv-navy);
}

/* Quantity and Add to Basket share a row: the button is the page's primary
   action and a full-width block button under a 60px number field looked
   unbalanced.

   One row now, not two — the "Qty" label is gone. A number box beside an Add to
   Basket button needs no naming, and the row it occupied was pure vertical
   spend. The explicit grid-row on both children went with it; two items in a
   two-column grid place themselves. */
.nhv-buy {
  display: grid;
  grid-template-columns: 84px 1fr;
  align-items: center;
  gap: 10px;
  margin: 18px 0 0;
}
.nhv-qty { grid-column: 1; text-align: center; }
.nhv-buybox .nhv-qty { background-color: var(--nhv-sand); }
.nhv-buy-button {
  grid-column: 2;
  height: 38px;
  padding: 0 20px;
  font-family: var(--nhv-font-display);
  font-size: var(--nhv-fs-small);
  font-weight: var(--nhv-fw-bold);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--nhv-cream-bright);
  background: var(--nhv-footer-ground);
  border: 1px solid var(--nhv-footer-ground);
  border-radius: var(--nhv-radius-sm);
  cursor: pointer;
  transition: background-color 0.15s ease, border-color 0.15s ease;
}
/* `color` is declared here on purpose. Bootstrap sets `.btn:focus, .btn:hover
   { color: #333 }` at the same specificity as this rule, so a hover that only
   changes the background inherits Bootstrap's dark grey — #333 on navy is
   1.10:1, which is why the button became unreadable the moment you pointed at
   it. Stating the colour puts it back to 13.68:1.

   Copper was the obvious brand hover and is not used: cream on copper is 3.79:1
   and this label is 12px bold, which counts as normal text and needs 4.5:1. */
.nhv-buy-button:hover,
.nhv-buy-button:focus {
  color: var(--nhv-cream-bright);
  background: var(--nhv-navy);

  /* Copper on the BORDER, not the ground. It is the brand's hover accent and
     makes the state obvious — footer-ground to navy is a real change but a
     quiet one between two near-blacks. As a background it would fail: cream on
     copper is 3.79:1 and this 12px bold label needs 4.5:1. A border carries no
     text, so it costs nothing. */
  border-color: var(--nhv-copper);
}
.nhv-buy-button:focus-visible { outline: 2px solid var(--nhv-copper); outline-offset: 2px; }

.nhv-product-rating { margin-top: 18px; color: var(--nhv-copper-text); }
.nhv-product-rating a { color: var(--nhv-copper); }
.nhv-product-rating a:hover { color: var(--nhv-navy); }

/* --- Tabs ----------------------------------------------------------------- */

.nhv-product-detail { margin-bottom: 32px; }

/* The tab strip IS a block head. Same navy gradient, same --nhv-navy-border
   hairline, same corner radius as .nhv-block-head in nhv.css — so "Description /
   Specification / Reviews" reads as the heading of the panel beneath it rather
   than as a row of light chips sitting on top of one.

   The strip carries the ground; the tabs sit on it and are transparent until
   chosen. That is the inversion from before, where each tab painted its own
   sand background and the strip was just a 2px rule. */
.nhv-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 0;
  margin: 0;
  padding: 5px 5px 0;
  background-color: var(--nhv-navy-panel);
  background-image: linear-gradient(130deg, var(--nhv-navy-panel) 0%, var(--nhv-navy) 50%);
  border: 1px solid var(--nhv-navy-border);
  border-bottom: 0;
  border-radius: var(--nhv-radius-sm) var(--nhv-radius-sm) 0 0;
}

.nhv-tabs > li { margin: 0; float: none; }

/* Sora at the block-title's weight but small-caps sized: these are labels on a
   heading, not headings themselves, so they borrow the family and colour rather
   than the 22px. */
.nhv-tabs > li > a,
.nhv-tabs > li > a:focus {
  margin: 0;
  padding: 10px 22px;

  /* 22px bold Sora — the exact type of .nhv-block-title, so the tab strip and
     the "Related Products" heading further down the page are the same voice.
     They were 12px semibold, which read as controls beneath the buy box rather
     than as the heading of the panel they open. */
  font-family: var(--nhv-font-display);
  font-size: 22px;
  font-weight: var(--nhv-fw-bold);
  line-height: 1.3;
  letter-spacing: 0;
  color: var(--nhv-cream);
  background: transparent;
  border: 0;
  border-radius: var(--nhv-radius-sm) var(--nhv-radius-sm) 0 0;
  transition: background-color 0.15s ease, color 0.15s ease;
}

/* Not cream-on-copper: --nhv-cream on --nhv-copper is 3.5:1 and these are 12px.
   A lift in the navy family keeps the hover legible. */
.nhv-tabs > li > a:hover {
  color: var(--nhv-cream-bright);
  background: rgba(251, 243, 209, 0.10);
}

/* The chosen tab is the panel below, pulled up: same cream ground, same side
   hairlines, and no bottom edge so the two are one surface. */
.nhv-tabs > li.active > a,
.nhv-tabs > li.active > a:hover,
.nhv-tabs > li.active > a:focus {
  color: var(--nhv-navy);
  background: var(--nhv-cream-bright);
  border: 0;
}

.nhv-tabs > li > a:focus-visible { outline: 2px solid var(--nhv-copper); outline-offset: -2px; }

/* Three 22px tabs need about 520px. Below that they wrap, which is fine, but
   they also start to dominate a small screen — so the type steps back down
   while keeping the family and weight. */
@media (max-width: 767px) {
  .nhv-tabs > li > a,
  .nhv-tabs > li > a:focus { font-size: var(--nhv-fs-base); padding: 9px 14px; }
}

/* Square top corners: the strip above already rounds them, and rounding both
   leaves a notch where they meet. */
.nhv-tab-content {
  border-radius: 0 0 var(--nhv-radius-sm) var(--nhv-radius-sm);
  padding: 20px;
  font-family: var(--nhv-font-body);
  font-size: var(--nhv-fs-base);
  line-height: 1.7;
  color: var(--nhv-navy);
  background: var(--nhv-cream-bright);
  border: 1px solid var(--nhv-rule-warm);
  border-top: 0;
}
.nhv-tab-content img { max-width: 100%; height: auto; }
.nhv-tab-content .table { margin-bottom: 0; }
.nhv-tab-content .table > thead > tr > td,
.nhv-tab-content .table-bordered > thead > tr > td {
  font-family: var(--nhv-font-display);
  font-weight: var(--nhv-fw-bold);
  color: var(--nhv-cream);
  background: var(--nhv-navy-panel);
  border-color: var(--nhv-navy-border);
}

/* --- Related -------------------------------------------------------------- */
/* Reuses .nhv-products from blocks/category.css so a related card and a category
   card cannot drift apart. Only the column count differs. */
.nhv-related { grid-template-columns: repeat(4, 1fr); }

.nhv-product-tags {
  margin: 0 0 24px;
  font-family: var(--nhv-font-body);
  font-size: var(--nhv-fs-small);
  color: var(--nhv-grey-link);
}
.nhv-product-tags a { color: var(--nhv-copper); }

@media (max-width: 991px) {
  .nhv-related { grid-template-columns: repeat(3, 1fr); }
}
@media (max-width: 767px) {
  .nhv-gallery { grid-template-columns: repeat(3, 1fr); }
  .nhv-related { grid-template-columns: repeat(2, 1fr); }
  .nhv-buy { grid-template-columns: 72px 1fr; }
}

/* --- Nothing left to buy (NHV-28) -----------------------------------------
   Replaces the quantity field and Add to Cart when every variant has sold out.
   Stated rather than implied: the old behaviour was an empty required dropdown
   above a button that could not work. Deliberately not red — the shopper has
   done nothing wrong and the product is expected back. */

.nhv-unbuyable {
  margin: 18px 0 0;
  padding: 14px 16px;
  color: var(--nhv-cream-bright);
  background: var(--nhv-sale-red);
  border: 1px solid var(--nhv-sale-red);
  border-radius: var(--nhv-radius-sm);
}

.nhv-unbuyable strong {
  display: block;
  margin-bottom: 3px;
  font-family: var(--nhv-font-display);
  font-size: var(--nhv-fs-base);
  font-weight: var(--nhv-fw-semi);
  color: var(--nhv-cream-bright);
}

/* Cream rather than pure white, matching every other light-on-dark surface in
   the theme. 7.06:1 on --nhv-sale-red, so it clears AA for body text and AAA
   for the heading above it. */
.nhv-unbuyable span {
  font-family: var(--nhv-font-body);
  font-size: var(--nhv-fs-small);
  line-height: 1.6;
  color: var(--nhv-cream-bright);
}

/* --- Variation chips (NHV-29) ----------------------------------------------
   A 'select' option drawn as a row of buttons. The markup underneath is a
   radiogroup of visually-hidden inputs with styled labels, so selection, keyboard
   navigation and form submission are all the browser's own — no JavaScript.

   Everything below hangs off :checked. There is no .is-selected class to keep in
   sync, and nothing to go stale if a shopper uses the arrow keys. */

.nhv-option-choices {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 2px;
}

.nhv-option-chip {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  margin: 0;                       /* Bootstrap puts 5px on every label */
  padding: 9px 15px;
  font-family: var(--nhv-font-body);
  font-size: var(--nhv-fs-base);
  font-weight: var(--nhv-fw-normal, 400);
  line-height: 1.2;
  color: var(--nhv-navy);
  background: var(--nhv-cream-bright);
  border: 1px solid var(--nhv-rule-warm);
  border-radius: var(--nhv-radius-sm);
  cursor: pointer;
  user-select: none;
  transition: border-color 0.12s ease, background-color 0.12s ease, color 0.12s ease;
}

.nhv-option-chip:hover { border-color: var(--nhv-copper); }

/* The price adjustment, when a variant costs more than the base. */
.nhv-option-adjust {
  font-size: var(--nhv-fs-small);
  color: var(--nhv-copper);
}

/* --- Selected --------------------------------------------------------------
   Solid navy rather than a tint. The chosen variant has to be obvious at a
   glance from anywhere on the page, including on a phone where the buy box has
   scrolled away from the price. */
.nhv-option-input:checked + .nhv-option-chip {
  color: var(--nhv-cream-bright);
  background: var(--nhv-footer-ground);
  border-color: var(--nhv-footer-ground);
  font-weight: var(--nhv-fw-semi);
}

.nhv-option-input:checked + .nhv-option-chip .nhv-option-adjust {
  color: var(--nhv-sand);
}

/* --- Keyboard --------------------------------------------------------------
   The input is visually hidden, so its own focus ring is invisible and the ring
   has to be drawn on the label instead. :focus-visible keeps it off mouse
   clicks. */
.nhv-option-input:focus-visible + .nhv-option-chip {
  outline: 2px solid var(--nhv-copper);
  outline-offset: 2px;
}

/* Older browsers with no :focus-visible support still get a ring on :focus.
   Kept in its own rule: a selector an engine cannot parse invalidates the whole
   list, and merging these would lose the modern rule everywhere. */
.nhv-option-input:focus + .nhv-option-chip {
  outline: 2px solid var(--nhv-copper);
  outline-offset: 2px;
}
.nhv-option-input:focus:not(:focus-visible) + .nhv-option-chip {
  outline: none;
}

/* A validation error is inserted after .nhv-option-choices and Bootstrap marks
   the form-group; the chips need to answer to it themselves. */
.has-error .nhv-option-chip { border-color: var(--nhv-sale-red); }

@media (max-width: 480px) {
  .nhv-option-chip { padding: 10px 14px; }   /* a comfortable tap target */
}

/* --- Validation messages in the buy box ------------------------------------
   Core's add-to-cart handler injects `<div class="text-danger">Variation
   required!</div>` and Bootstrap styles it as red text on the page ground —
   easy to miss beside a row of chips and a large dark button.

   Scoped to #product deliberately. `.text-danger` is core's, used across
   checkout, account and review forms that have their own designs; restyling it
   globally would repaint pages this change was never about. */

#product .text-danger {
  display: block;
  margin: 8px 0 0;
  padding: 8px 12px;
  font-family: var(--nhv-font-body);
  font-size: var(--nhv-fs-small);
  font-weight: var(--nhv-fw-semi);
  line-height: 1.4;
  color: var(--nhv-cream-bright);          /* 7.06:1 on --nhv-sale-red */
  background: var(--nhv-sale-red);
  border-radius: var(--nhv-radius-sm);
  animation: nhv-error-pulse 2.4s ease-in-out infinite;
}

/* The pulse is a halo, not a change of background or opacity. Fading the panel
   would drag the text's contrast down with it on every cycle; a shadow sits
   outside the box and leaves the 7.06:1 untouched throughout. */
@keyframes nhv-error-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(163, 43, 31, 0.55); }
  50%      { box-shadow: 0 0 0 6px rgba(163, 43, 31, 0); }
}

/* Anyone who has asked their system for less movement gets the panel without
   the animation. The colour alone already carries the message — the pulse only
   draws the eye to it. */
@media (prefers-reduced-motion: reduce) {
  #product .text-danger { animation: none; }
}
