/**
 * MCB Productions — Product Page
 *
 * Identity, plate, and the request action sit in one block at the top, and
 * the three authored sections arrive beneath as a tab strip: one panel
 * visible at a time, the other two a click away.
 *
 * Below 640px the strip becomes a stack of disclosures, because three
 * labelled tabs do not fit a phone without truncating the labels. That is
 * a different ARIA pattern rather than the same one restyled, so
 * product-detail.js rebuilds the region at the breakpoint. Both states are
 * styled here.
 *
 * The page is deliberately short: a buyer who only wants the plain-English
 * answer should not have to scroll past a specification to reach the
 * request button. The cost, accepted knowingly, is that two thirds of an
 * item's content sits behind a click. Two alternatives were built and
 * rejected; see docs/briefs/2026-07-21-inventory-product.md.
 *
 * Layout only. Requires tokens.css and base.css (the rendered-markdown
 * component in base.css section 13 styles the three authored sections).
 */

.product-page {
  padding-block: var(--space-2xl) var(--space-5xl);
}

/* =====================================================================
   1. RETURN PATH AND STATES
   ===================================================================== */

.product-back-wrap {
  margin: 0 0 var(--space-2xl);
}

.product-back {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  font-family: var(--font-sans);
  font-size: var(--type-label-size);
  font-weight: var(--type-label-weight);
  letter-spacing: var(--type-label-tracking);
  text-transform: uppercase;
}

.product-back::before {
  content: '\2190';
  margin-right: var(--space-sm);
}

.product-state {
  margin: 0;
  padding-block: var(--space-4xl);
  color: var(--ink-muted);
  font-family: var(--font-sans);
}

.product-error {
  margin: 0 0 var(--space-2xl);
  padding: var(--space-lg);
  border: 1px solid var(--alert);
  border-radius: var(--radius-control);
  color: var(--alert);
  font-family: var(--font-sans);
  font-size: 1rem;
  line-height: 1.5;
}

.product-missing {
  padding-block: var(--space-3xl) var(--space-4xl);
}

/* The measure belongs to the prose, not to the panel. It sat on
   .product-missing until the mode-mismatch state grew a third control, at
   which point a reading width was deciding how many buttons fit on a row
   and dropping the last one onto a line of its own. 34rem is the 56ch it
   replaced, in a unit that does not re-resolve against the heading's own
   font size. */
.product-missing-heading {
  max-width: 34rem;
  margin-bottom: var(--space-lg);
}

.product-missing-message {
  max-width: 34rem;
  margin: 0 0 var(--space-xl);
  color: var(--ink-muted);
  text-wrap: pretty;
}

/* Holds the "browse the catalog" fallback, plus the two corrections that
   product-detail.js prepends when the item exists on the other side of the
   toggle: the mode switch and the contact route. Wraps rather than
   scrolls at narrow widths. */
.product-missing-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-md);
  margin: 0;
}


/* =====================================================================
   2. HEAD
   ===================================================================== */

.product-head {
  display: grid;
  gap: var(--space-2xl);
  padding-bottom: var(--space-2xl);
  border-bottom: 1px solid var(--paper-300);
}

@media (min-width: 900px) {
  .product-head {
    grid-template-columns: minmax(0, 1fr) 320px;
    gap: var(--space-3xl) var(--space-4xl);
    align-items: start;
  }

  /* With no photograph the identity block spans the text column alone and
     the action stays beside it. Today every item is in this state. */
  .product-plate,
  .product-plate-thumbs {
    grid-column: 1;
  }

  .product-action {
    grid-column: 2;
    grid-row: 1 / span 2;
  }
}

.product-category {
  margin: 0 0 var(--space-md);
  color: var(--ink-muted);
}

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

.product-sku {
  margin: 0 0 var(--space-lg);
  color: var(--ink-muted);
}

.product-lede {
  color: var(--ink);
}

/* The plate is capped to a 360px height, chosen 2026-07-21: at the full
   width of this column a 3:2 photograph stands 507px tall and pushes the
   tab strip to y=1091, below the fold on a laptop — so a page whose whole
   point is that you do not scroll to reach things would hide its own
   sections. The cap puts the strip at y=946.

   The cap is expressed as a WIDTH, not a height. 540 / 1.5 = 360, so the
   height decision is satisfied by the geometry of the box. It was
   previously a max-height plus object-fit: cover on the image, which
   reached the same 360px by throwing away 80px off the top and 80px off
   the bottom of every photograph — 31% of the frame, invisible in dev
   because no item carries a photograph here. Height caps crop; width caps
   do not. */
.product-plate {
  margin: 0;
  max-width: 540px;
  overflow: hidden;
  border: 1px solid var(--paper-200);
  border-radius: var(--radius-panel);
  background: var(--paper-100);
}

/* No aspect-ratio and no object-fit: catalog photographs are baked to
   1200x800 by the admin frame dialog and the <img> declares those
   intrinsic dimensions, so the ratio is already reserved and the box needs
   no second opinion. A legacy file that is not 3:2 then renders whole
   rather than cropped, which is the failure mode to want. */
.product-plate img {
  display: block;
  width: 100%;
  height: auto;
}

/* Thumbnail rail — present only when the item carries more than one
   photograph. Shares the plate's width cap so it reads as part of the same
   object. Thumbs are controls; the pressed one carries the signal hairline.
   At 96px wide a 3:2 thumbnail stands 64px tall, over the 44px touch
   floor. */
.product-plate-thumbs {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-sm);
  max-width: 540px;
  margin-top: var(--space-sm);
}

.product-thumb {
  width: 96px;
  padding: 0;
  border: 1px solid var(--paper-200);
  border-radius: var(--radius-control);
  background: var(--paper-000);
  overflow: hidden;
  cursor: pointer;
}

.product-thumb img {
  display: block;
  width: 100%;
  height: auto;
}

.product-thumb[aria-pressed="true"] {
  border-color: var(--signal);
}

/* =====================================================================
   3. ACTION
   The one region on this page that is equipment rather than document.
   ===================================================================== */

.product-action {
  display: grid;
  gap: var(--space-xl);
  padding: var(--space-xl);
  background: var(--paper-100);
  border: 1px solid var(--paper-200);
  border-radius: var(--radius-panel);
}

.product-action-head {
  margin: 0 0 var(--space-sm);
  padding: 0;
  color: var(--ink-muted);
}

.product-mode {
  margin: 0;
  padding: 0;
  border: 0;
}

.product-mode-switch {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1px;
  padding: 3px;
  background: var(--graphite-900);
  border-radius: var(--radius-control);
  box-shadow: var(--shadow-seated);
}

.product-mode-btn {
  min-height: 44px;
  padding-inline: var(--space-sm);
  background: transparent;
  border: 0;
  border-radius: 3px;
  color: var(--graphite-300);
  font-family: var(--font-sans);
  font-size: var(--type-label-size);
  font-weight: var(--type-label-weight);
  letter-spacing: var(--type-label-tracking);
  text-transform: uppercase;
  cursor: pointer;
  transition:
    background-color var(--duration-hover) var(--ease-out-quart),
    color var(--duration-hover) var(--ease-out-quart),
    transform var(--duration-press) var(--ease-out-quart);
}

.product-mode-btn:hover {
  color: var(--paper-000);
}

.product-mode-btn:active {
  transform: translateY(1px);
}

.product-mode-btn.is-active {
  background: var(--signal-ink);
  color: var(--paper-000);
  box-shadow: var(--bevel);
}

/* Pricing. On the rental side this is the explanation of why there is no
   number; on the sales side it is the number. */
.product-pricing {
  padding-top: var(--space-lg);
  border-top: 1px solid var(--paper-200);
}

.product-price-label {
  margin: 0 0 var(--space-sm);
  color: var(--ink-muted);
}

.product-price {
  margin: 0 0 var(--space-sm);
  font-size: 2rem;
  font-weight: 700;
  line-height: 1.1;
  color: var(--ink);
}

.product-price-note {
  margin: 0;
  font-size: 0.9375rem;
  line-height: 1.55;
  color: var(--ink-muted);
  text-wrap: pretty;
}

.product-quantity {
  display: grid;
  gap: var(--space-sm);
}

/* A 44px square control either side of the field, seated in graphite so
   the pair reads as hardware rather than as two more text buttons. */
.product-stepper {
  display: grid;
  grid-template-columns: 44px minmax(0, 1fr) 44px;
  gap: var(--space-sm);
  align-items: center;
}

.product-stepper-btn {
  width: 44px;
  height: 44px;
  padding: 0;
  background: var(--graphite-900);
  border: 0;
  border-radius: var(--radius-control);
  box-shadow: var(--shadow-seated);
  color: var(--paper-000);
  font-family: var(--font-sans);
  font-size: 1.25rem;
  line-height: 1;
  cursor: pointer;
  transition:
    background-color var(--duration-hover) var(--ease-out-quart),
    transform var(--duration-press) var(--ease-out-quart);
}

.product-stepper-btn:hover:not(:disabled) {
  background: var(--graphite-700);
}

.product-stepper-btn:active:not(:disabled) {
  transform: translateY(1px);
  box-shadow: var(--shadow-pressed);
}

/* Disabled at one rather than silently clamping: the reason the control
   will not move is visible before it is pressed. */
.product-stepper-btn:disabled {
  background: var(--paper-300);
  color: var(--ink-muted);
  box-shadow: none;
  cursor: not-allowed;
}

.product-stepper-input {
  text-align: center;
  font-variant-numeric: tabular-nums slashed-zero;
  font-weight: 700;
}

.product-add {
  width: 100%;
}

.product-confirmation {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-xs);
  margin: 0;
  padding: var(--space-md) var(--space-lg);
  border-radius: var(--radius-control);
  font-family: var(--font-sans);
  font-size: 0.9375rem;
  line-height: 1.5;
}

.product-confirmation.is-success {
  background: var(--paper-000);
  border: 1px solid var(--available);
  color: var(--available);
}

.product-confirmation.is-error {
  background: var(--paper-000);
  border: 1px solid var(--alert);
  color: var(--alert);
}

/* =====================================================================
   4. TAB STRIP
   ===================================================================== */

/* Capped to the width its own content can actually fill. A tab strip
   spanning the full 1240px shell above a panel of 68ch prose leaves the
   right half of every panel empty and makes the strip read as chrome
   belonging to nothing. */
.product-sections {
  max-width: 820px;
  padding-block: var(--space-3xl);
}

/* Above the head's two-column threshold the cap is derived from the grid
   rather than guessed, so the strip and the plate above it share a right
   edge. The subtraction is the action column plus its gutter — the same
   two values the head grid is built from. Hard-coding 820px here left the
   two objects 60px out of alignment once photographs arrived. */
@media (min-width: 900px) {
  .product-sections {
    max-width: calc(100% - 320px - var(--space-4xl));
  }
}

.product-tablist {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xs);
  padding: 4px;
  background: var(--graphite-900);
  border-radius: var(--radius-control);
  box-shadow: var(--shadow-seated);
}

.product-tab {
  flex: 1 1 auto;
  min-height: 48px;
  padding-inline: var(--space-xl);
  background: transparent;
  border: 0;
  border-radius: 3px;
  color: var(--graphite-300);
  font-family: var(--font-sans);
  font-size: var(--type-label-size);
  font-weight: var(--type-label-weight);
  letter-spacing: var(--type-label-tracking);
  text-transform: uppercase;
  cursor: pointer;
  transition:
    background-color var(--duration-hover) var(--ease-out-quart),
    color var(--duration-hover) var(--ease-out-quart),
    transform var(--duration-press) var(--ease-out-quart);
}

.product-tab:hover {
  color: var(--paper-000);
}

.product-tab:active {
  transform: translateY(1px);
}

.product-tab[aria-selected='true'] {
  background: var(--graphite-700);
  color: var(--paper-000);
  box-shadow: var(--bevel);
}

/* The tablist is graphite, so a focus ring in signal-ink would disappear
   against it. */
.product-tablist :focus-visible {
  outline-color: var(--signal-bright);
}

.product-panel {
  padding-top: var(--space-2xl);
}

/* =====================================================================
   5. DISCLOSURES (below 640px)
   ===================================================================== */

.product-disclosure {
  border-bottom: 1px solid var(--paper-200);
}

.product-disclosure:first-of-type {
  border-top: 1px solid var(--paper-200);
}

.product-disclosure-summary {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-height: 56px;
  padding-block: var(--space-lg);
  /* Room for the drawn chevron at the right edge. */
  padding-right: var(--space-2xl);
  cursor: pointer;
  list-style: none;
}

.product-disclosure-summary::-webkit-details-marker {
  display: none;
}

/* A drawn chevron rather than the platform marker, so the control looks
   the same in every browser and carries no text semantics. */
.product-disclosure-summary::after {
  content: '';
  position: absolute;
  right: 4px;
  width: 9px;
  height: 9px;
  border-right: 2px solid var(--graphite-700);
  border-bottom: 2px solid var(--graphite-700);
  transform: translateY(0.6em) rotate(45deg);
  transition: transform var(--duration-hover) var(--ease-out-quart);
}

.product-disclosure[open] .product-disclosure-summary::after {
  transform: translateY(1em) rotate(-135deg);
}

.product-disclosure-gloss {
  color: var(--ink-muted);
}

.product-disclosure-body {
  padding-bottom: var(--space-xl);
}

/* =====================================================================
   6. RELATED
   ===================================================================== */

.product-related {
  padding-block: var(--space-2xl) var(--space-3xl);
  border-top: 1px solid var(--paper-300);
}

.product-related-heading {
  margin-bottom: var(--space-lg);
}

.product-related-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: var(--space-md);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* A photograph and a name. No description: four plain-English sentences
   side by side compete with the item the visitor is actually reading, and
   each sentence is one click away on its own page. */
.product-related-link {
  display: flex;
  flex-direction: column;
  height: 100%;
  background: var(--paper-100);
  border: 1px solid var(--paper-200);
  border-radius: var(--radius-control);
  overflow: hidden;
  text-decoration: none;
  color: inherit;
  transition:
    background-color var(--duration-hover) var(--ease-out-quart),
    border-color var(--duration-hover) var(--ease-out-quart);
}

.product-related-link:hover {
  background: var(--paper-000);
  border-color: var(--graphite-500);
}

/* Full-bleed to the card's top edge, like the catalog card in DESIGN.md
   section 5: the image is the evidence and is not politely framed. */
.product-related-plate {
  display: block;
  background: var(--paper-200);
  border-bottom: 1px solid var(--paper-200);
}

/* 3:2 matches the ratio the admin frame dialog bakes, so neither value
   re-crops a conforming source. `contain` rather than `cover` so the one
   that does not conform renders whole. */
.product-related-plate img {
  width: 100%;
  height: auto;
  aspect-ratio: 3 / 2;
  object-fit: contain;
}

.product-related-body {
  display: flex;
  flex: 1;
  align-items: center;
  padding: var(--space-md) var(--space-lg) var(--space-lg);
}

.product-related-name {
  display: block;
  font-size: 1.0625rem;
  transition: color var(--duration-hover) var(--ease-out-quart);
}

.product-related-link:hover .product-related-name {
  color: var(--signal-ink);
}

/* With no photograph the card is a name alone, so it needs its full
   padding back rather than the tighter spacing that sits under a plate. */
.product-related-link:not(.has-plate) .product-related-body {
  padding-top: var(--space-lg);
}

/* =====================================================================
   7. CLOSE
   ===================================================================== */

.product-close {
  padding-top: var(--space-2xl);
}

.product-close-band {
  padding-block: var(--space-3xl);
}

.product-close-inner {
  display: grid;
  gap: var(--space-2xl);
}

@media (min-width: 860px) {
  .product-close-inner {
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    gap: var(--space-4xl);
  }
}

.product-close-heading {
  margin-bottom: var(--space-md);
  color: var(--paper-000);
}

.product-close-body {
  max-width: 52ch;
  margin: 0;
  color: var(--graphite-300);
  text-wrap: pretty;
}

.product-close-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-md);
}

/* The follow-on action is a block-level target rather than a link trailing
   the sentence, so it clears the 44px touch floor instead of inheriting the
   line height of the text it sat in. */
.product-confirmation-action {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  font-family: var(--font-sans);
  font-size: var(--type-label-size);
  font-weight: var(--type-label-weight);
  letter-spacing: var(--type-label-tracking);
  text-transform: uppercase;
}

/* =====================================================================
   STATE FEEDBACK
   The acknowledgement register from base.css §17. Every panel here
   arrives by having [hidden] removed, so none of them needs script:
   the article once its item has been fetched, the confirmation after an
   item is added, and the two states that stand in for it when the SKU
   cannot be shown.

   Pricing is the exception. It is rewritten in place when the visitor
   switches between rentals and for-sale, and product-detail.js announces
   it from setMode().
   ===================================================================== */

.product-article:not([hidden]),
.product-confirmation:not([hidden]),
.product-missing:not([hidden]),
.product-error:not([hidden]) {
  animation: state-in var(--duration-state) var(--ease-out-quart);
}
