/* ------------------------------------------------------------------ */
/* Product tabs (sections/product-tabs.liquid)                         */
/* ------------------------------------------------------------------ */
/* One structure, three presentations, and the CSS is what selects which
   controls exist:
     - no JS            -> plain headings, every panel open
     - html.js, <750px  -> accordion buttons, the default tab expanded
     - html.js, >=750px -> tab row, one panel at a time
   Whichever control set is not in play is `display: none`, which also takes
   it out of the accessibility tree - that is what keeps a [role=tab] from
   ever being present while the thing behaves like an accordion. The panel's
   own role is applied by product-tabs.js, not here.

   A tab's panel holds whatever theme blocks the merchant dragged into it, so
   nothing below assumes one kind of content: the panel sets the rhythm
   between blocks and each block styles only itself.

   Theme blocks arrive inside a wrapper element Shopify prints around each
   one, which is why the sibling selectors below reach through `> *` rather
   than joining two blocks directly. */
.product-tabs {
  display: block;
  margin-top: var(--space-9);
  border-top: 1px solid var(--color-line);
  padding-top: var(--space-6);
}

/* No live tab, no region. A tab prints nothing when its content turns out to
   be empty, and prints itself `hidden` when it is a recommendations tab still
   waiting on its fetch - so "is there anything here" is a question only the
   rendered DOM can answer, and :has() is what asks it. Doing it here rather
   than in JS means it holds with JS off too, and that the region appears by
   itself the moment product-tabs.js un-hides a tab whose grid has landed. */
.product-tabs:not(:has(.product-tabs__item:not([hidden]))) {
  display: none;
}

.product-tabs[hidden] {
  display: none;
}

/* A theme block that rendered nothing still leaves its wrapper behind. Left
   alone it would take a turn in the panel's gap rhythm and an empty tab would
   still look occupied, so an element with no element children is removed from
   layout outright. */
.product-tabs__items > *:not(:has(*)),
.product-tabs__panel > *:not(:has(*)) {
  display: none;
}

/* The scroller owns the overflow, the tablist owns the layout - see the same
   split in section-tabbed-products.css. Hidden until html.js: a tab row that
   cannot switch is worse than no tab row. */
.product-tabs__tabs {
  display: none;
  overflow-x: auto;
  scrollbar-width: none;
  scroll-padding-inline: var(--space-4);
  padding-bottom: var(--space-4);
  margin-bottom: var(--space-6);
  border-bottom: 1px solid var(--color-line);
}

.product-tabs__tabs::-webkit-scrollbar {
  display: none;
}

/* TABS AT EVERY WIDTH, NOT ACCORDIONS ON A PHONE.

   This used to switch to accordions below 750px. It works, but it is a second
   navigation pattern for the same content, and the rest of the site does not
   do it: tabbed-products keeps its pill row on a phone and lets it scroll
   sideways. The scroller above already handles the overflow, so the row simply
   moves horizontally when it does not fit - one pattern everywhere, and the
   other tabs stay visible instead of collapsing into rows a visitor has to
   guess at. */
html.js .product-tabs__tabs {
  display: block;
}

.product-tabs__tablist {
  display: inline-flex;
  gap: var(--space-2);
}

/* Pills with conviction, the same control grammar tabbed-products settled
   on: outlined at rest, solid ink when selected - a state legible from
   across the room, where the old 2px underline whispered. */
.product-tabs__tab {
  position: relative;
  flex: 0 0 auto;
  padding: var(--space-2) var(--space-4);
  min-height: 40px;
  background: none;
  border: 1px solid var(--color-line);
  border-radius: var(--radius-pill);
  font-family: var(--font-heading);
  font-size: 13px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--color-muted);
  cursor: pointer;
  white-space: nowrap;
}

@media (prefers-reduced-motion: no-preference) {
  .product-tabs__tab {
    transition: color 0.2s ease, border-color 0.2s ease, background-color 0.2s ease;
  }
}

.product-tabs__tab:hover {
  color: var(--color-ink);
  border-color: var(--color-ink);
}

/* Cursor-origin hover fill, the same sweep the buttons and the homepage's
   product tabs use. assets/motion.js sets --fill-x/--fill-y from where the
   pointer entered and toggles .is-hover-fill; the four things that file's
   contract requires are all here.

   z-index MUST be -1. At 0 or auto the fill paints above inline content and
   sweeps over the tab's own label, which is the bug that contract calls out. */
.product-tabs__tab::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  background-color: var(--color-ink);
  clip-path: circle(0% at var(--fill-x, 50%) var(--fill-y, 50%));
  pointer-events: none;
}

.product-tabs__tab {
  isolation: isolate;
}

/* The transition is declared on BOTH states, not only on .is-hover-fill.
   A transition runs according to whichever rule matches the DESTINATION, so
   declaring it once gives a control that sweeps in and then vanishes on the
   way out - the exact failure the contract in motion.js warns about. */
@media screen and (prefers-reduced-motion: no-preference) {
  .product-tabs__tab::before {
    transition: clip-path var(--btn-fill-out) var(--btn-fill-out-ease);
  }

  html.has-cursor-fill .product-tabs__tab.is-hover-fill::before {
    transition: clip-path var(--btn-fill-in) var(--btn-fill-in-ease);
  }
}

html.has-cursor-fill .product-tabs__tab.is-hover-fill::before {
  clip-path: circle(150% at var(--fill-x, 50%) var(--fill-y, 50%));
}

/* The label has to invert as the dark fill arrives under it. */
html.has-cursor-fill .product-tabs__tab.is-hover-fill {
  color: var(--color-bg);
  border-color: var(--color-ink);
}

/* The selected tab is already filled, so it takes no sweep - a fill animating
   into a box that is that colour already reads as a flicker. */
html.has-cursor-fill .product-tabs__tab[aria-selected='true']::before {
  display: none;
}

.product-tabs__tab[aria-selected='true'] {
  background-color: var(--color-ink);
  border-color: var(--color-ink);
  color: var(--color-bg);
}

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

/* Accordion header - the mobile control. Hidden above the breakpoint and
   before JS, so it is never a dead button. */
.product-tabs__accordion-heading {
  display: none;
  margin: 0;
}

/* The accordion headers stay in the markup for the no-JS case - without a
   script there are no tabs to switch, so plain headings over plain content is
   the only honest fallback - but html.js now always gets the tab row. */

.product-tabs__accordion {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  width: 100%;
  padding-block: var(--space-4);
  background: none;
  border: 0;
  text-align: start;
  font-family: var(--font-heading);
  font-size: 14px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.01em;
  color: var(--color-ink);
  cursor: pointer;
}

.product-tabs__accordion svg {
  flex-shrink: 0;
  color: var(--color-muted);
}

@media (prefers-reduced-motion: no-preference) {
  .product-tabs__accordion svg {
    transition: transform 0.15s ease;
  }
}

.product-tabs__accordion[aria-expanded='true'] svg {
  transform: rotate(180deg);
  color: var(--color-brand);
}

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

/* The no-JS label. Nothing else names the panels there. */
html.js .product-tabs__static-heading {
  display: none;
}

.product-tabs__static-heading {
  margin: 0 0 var(--space-3);
}

/* Each item is a rule-separated block on mobile/no-JS, where several panels
   can be open at once; on the desktop tab view only one panel shows and the
   tablist already draws the line above it.

   `~` rather than `+`: the wrappers of tabs that rendered nothing are still
   in the DOM between two live ones, and an adjacent-sibling match would be
   broken by them. "Any item that has a live item somewhere before it" is the
   same set as "every item but the first" and survives the gaps. */
.product-tabs__items > *:has(.product-tabs__item) ~ *:has(.product-tabs__item) .product-tabs__item {
  border-top: 1px solid var(--color-line);
}

@media screen and (min-width: 750px) {
  html.js
    .product-tabs__items
    > *:has(.product-tabs__item)
    ~ *:has(.product-tabs__item)
    .product-tabs__item {
    border-top: 0;
  }
}

.product-tabs__panel {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  padding-bottom: var(--space-5);
}

@media screen and (min-width: 750px) {
  html.js .product-tabs__panel {
    padding-bottom: 0;
  }
}

.product-tabs__panel[hidden] {
  display: none;
}

/* Pre-marked server-side so the non-default panels never flash open between
   first paint and the element upgrading. Without JS the attribute is simply
   never honoured, which is the whole no-JS contract. */
html.js .product-tabs__panel[data-inactive] {
  display: none;
}

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

/* Measure, not full width: these descriptions are long, and on this store
   they are a run of short spec lines that would otherwise stretch across the
   whole page. Anything with its own layout (an app widget, a wide table)
   scrolls inside itself instead of widening the page. */
.product-tabs__prose {
  max-width: 68ch;
  color: var(--color-muted);
  line-height: 1.75;
}

/* This store's descriptions are spec sheets typed as plain lines with bold
   group headers ("Compatibility", "What is inside the box") between <br>s.
   Read raw they are a wall; the bold runs become section marks - heading
   face, uppercase, air above - which typesets the whole sheet without
   touching merchant HTML. inline-block, not block, so a bold word inside a
   real sentence lifts slightly instead of tearing the line apart. */
.product-tabs__prose strong,
.product-tabs__prose b {
  display: inline-block;
  margin-top: var(--space-5);
  font-family: var(--font-heading);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--color-ink);
}

.product-tabs__prose p {
  margin-block: 0 var(--space-4);
}

.product-tabs__prose > :first-child {
  margin-top: 0;
}

.product-tabs__prose > :last-child {
  margin-bottom: 0;
}

.product-tabs__prose table {
  display: block;
  max-width: 100%;
  overflow-x: auto;
  /* Beats the rich-text editor's inline height, and it has to be !important
     because that height is an inline style.

     A real <table> treats `height` as a MINIMUM and grows past it, so the
     pixel height the editor writes when someone drag-resizes a table is
     harmless there. `display: block` above - the usual way to make a wide
     table scrollable on a phone - changes that: as a block box the height
     becomes authoritative and clips, and because `overflow-x: auto` forces
     `overflow-y` to `auto` as well, the clipped remainder turns into an
     internal scroll area with no visible scrollbar. A four-row spec table
     shipped showing two rows, with the rest reachable only by scrolling
     inside it, which also swallowed the wheel on the way past. */
  height: auto !important;
}

/* Inside a tab the panel is already named - by the tab, the accordion button
   or (no JS) the static heading - so the snippet's own heading and top rule
   would just repeat it. The snippet keeps them for any other caller. */
/* No measure cap, unlike the prose beside it. 68ch was right while this was a
   run of short single-column lines that would otherwise stretch across the
   page; it is now a two-column grid sitting directly under the dimension
   cards, and capping it there left the sheet ending half way across while the
   cards above ran the full width - which reads as the sheet having failed to
   load rather than as a measure. Neither column holds prose, so there is no
   line length to protect. */
.product-tabs__panel .spec-table {
  border-top: 0;
  padding-top: 0;
}

.product-tabs__panel .spec-table__heading {
  display: none;
}

/* ------------------------------------------------------------------ */
/* Relocated recommendations                                           */
/* ------------------------------------------------------------------ */
/* The "You may also like" grid is rendered by sections/related-products.liquid
   and moved into a tab panel by product-tabs.js. Only its inner content node
   moves, so the section's own page-width padding stays behind with the empty
   element; the grid keeps every rule
   section-related-products.css gives it, including its 2/4 column tracks. */
.product-tabs__panel .section-related-products__heading {
  display: none;
}

/* The standalone section once its content has been relocated. Emptied rather
   than removed - the element still owns the fetch - so it is hidden here
   rather than deleted, which would also drop its 64px of block padding on an
   empty box. */
product-recommendations[data-relocated] {
  display: none;
}

/* ------------------------------------------------------------------ */
/* Content blocks inside a panel                                       */
/* ------------------------------------------------------------------ */
/* A tab can hold any theme block, in any order and any mix, so the rhythm
   between them belongs to the panel rather than to any one block. The panel
   is a flex column so that the wrappers hidden above contribute no gap - a
   margin between siblings would have counted them. */

/* The video block is shared with sections/video.liquid, which gives it the
   full width of a section. In a panel it is one element among several, so it
   is capped at the width the panel's prose already uses. */
.product-tabs__panel .video-section__frame {
  max-width: 68ch;
}

/* Slot for the relocated recommendations grid (see below). Empty until the
   fetch lands, and it must take up no room while it is. */
.product-tabs__recs:empty {
  display: none;
}

/* Two columns for the spec sheet in a tab, with a rule between them.

   Explicit `repeat(2, ...)` rather than `auto-fit`: the column count has to
   be knowable here, because the divider below is drawn with :nth-child(2n)
   and an auto-fit grid that silently became three columns would draw it down
   the middle of a row. Below 750px it stays the single column the snippet
   defaults to. */
@media screen and (min-width: 750px) {
  .product-tabs__panel .spec-table__list {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: var(--space-6);
  }

  .product-tabs__panel .spec-table__row:nth-child(2n) {
    padding-left: var(--space-6);
    border-left: 1px solid var(--color-line);
  }
}


/* ------------------------------------------------------------------ */
/* Stacked layout                                                      */
/* ------------------------------------------------------------------ */
/* The no-JS state, chosen on purpose: every panel visible under its own
   heading, no tab row, no accordion. */
.product-tabs--stacked .product-tabs__tabs,
.product-tabs--stacked .product-tabs__accordion-heading {
  display: none;
}

html.js .product-tabs--stacked .product-tabs__static-heading {
  display: block;
}

html.js .product-tabs--stacked .product-tabs__panel[data-inactive] {
  display: block;
}

.product-tabs--stacked .product-tabs__item {
  padding-block: var(--space-8);
  border-top: 1px solid var(--color-line);
}

.product-tabs--stacked .product-tabs__item:first-child {
  border-top: 0;
  padding-top: 0;
}

.product-tabs--stacked .product-tabs__static-heading {
  margin: 0 0 var(--space-6);
}

/* ------------------------------------------------------------------ */
/* Product document: specs table, write-up, in the box                 */
/* ------------------------------------------------------------------ */
/* Typeset like a well-set page rather than a rich-text dump: a reading
   measure, one heading face, rows as a quiet two-column table with no
   vertical rules, generous rhythm between sections. */
.product-doc {
  display: grid;
  gap: var(--space-8);
  max-width: 76ch;
}

.product-doc__section {
  display: grid;
  gap: var(--space-4);
}

.product-doc__heading,
.product-doc__prose h2,
.product-doc__prose h3 {
  margin: 0;
  font-family: var(--font-heading);
  font-size: 22px;
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: -0.01em;
  color: var(--color-ink);
}

.product-doc__prose {
  display: grid;
  gap: var(--space-4);
  color: var(--color-ink);
  font-size: 16px;
  line-height: 1.7;
}

.product-doc__prose h2,
.product-doc__prose h3 {
  margin-top: var(--space-3);
}

.product-doc__prose h2:first-child,
.product-doc__prose h3:first-child {
  margin-top: 0;
}

.product-doc__prose p {
  margin: 0;
  max-width: 68ch;
}

.product-doc__prose ul,
.product-doc__list {
  margin: 0;
  padding-left: 1.2em;
  display: grid;
  gap: var(--space-2);
}

.product-doc__prose img {
  max-width: 100%;
  height: auto;
  border-radius: var(--radius-m);
}

/* Label-value rows. A table because that is what they are, styled so the
   labels read as a column of quiet captions beside the values. */
.product-doc__rows {
  width: 100%;
  border-collapse: collapse;
  font-size: 15px;
}

.product-doc__rows tr {
  border-top: 1px solid var(--color-line);
}

.product-doc__rows tr:last-child {
  border-bottom: 1px solid var(--color-line);
}

.product-doc__rows th,
.product-doc__rows td {
  padding: var(--space-3) var(--space-2);
  text-align: left;
  vertical-align: top;
}

.product-doc__rows th {
  width: 34%;
  font-weight: 600;
  color: var(--color-muted);
  white-space: nowrap;
}

.product-doc__rows td {
  color: var(--color-ink);
  font-variant-numeric: tabular-nums;
}

.product-doc__rows--specs tr:nth-child(odd) {
  background-color: color-mix(in srgb, var(--color-ink) 3%, transparent);
}

@media screen and (max-width: 749px) {
  .product-doc__rows th {
    width: 40%;
    white-space: normal;
  }
}


/* ------------------------------------------------------------------ */
/* Product document, second pass: tiles, numbered parts, figures       */
/* ------------------------------------------------------------------ */
.product-doc {
  max-width: none;
}

.product-doc__tiles {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-3);
}

@media screen and (min-width: 750px) {
  .product-doc__tiles {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

.product-doc__tile {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: var(--space-4) var(--space-5);
  border: 1px solid var(--color-line);
  border-radius: var(--radius-m);
  background-color: color-mix(in srgb, var(--color-ink) 3%, transparent);
  min-width: 0;
}

.product-doc__tile-value {
  font-family: var(--font-heading);
  font-size: clamp(18px, 1.5vw, 24px);
  font-weight: 700;
  line-height: 1.1;
  letter-spacing: -0.02em;
  color: var(--color-ink);
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.product-doc__tile-note {
  font-size: 12px;
  color: var(--color-muted);
}

.product-doc__tile-label {
  margin-top: 4px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--color-brand);
}

/* Numbered parts: the number is a quiet gutter mark, the body is a
   reading measure, and a figure the overview names floats beside it. */
.product-doc__prose {
  gap: var(--space-7);
  max-width: none;
}

.product-doc__part {
  display: grid;
  grid-template-columns: 48px minmax(0, 1fr);
  gap: var(--space-3);
  align-items: start;
  padding-top: var(--space-6);
  border-top: 1px solid var(--color-line);
}

.product-doc__part:first-child {
  padding-top: 0;
  border-top: 0;
}

.product-doc__num {
  font-family: var(--font-heading);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.1em;
  color: var(--color-brand);
  padding-top: 6px;
}

.product-doc__part-body {
  display: grid;
  gap: var(--space-4);
  max-width: 78ch;
}

.product-doc__part-body h3 {
  margin: 0;
  font-size: clamp(22px, 2vw, 28px);
  letter-spacing: -0.02em;
}

.product-doc__part-body p {
  max-width: 64ch;
}

.product-doc__figure {
  margin: 0;
  border-radius: var(--radius-m);
  overflow: hidden;
  background-color: var(--color-card-media, #f1f0f3);
}

.product-doc__figure img {
  display: block;
  width: 100%;
  height: auto;
  mix-blend-mode: var(--card-media-blend, normal);
}

@media screen and (min-width: 990px) {
  .product-doc__part-body {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 280px;
    grid-auto-flow: dense;
    column-gap: var(--space-7);
  }

  .product-doc__part-body > *:not(.product-doc__figure) {
    grid-column: 1;
  }

  .product-doc__figure {
    grid-column: 2;
    grid-row: 1 / span 4;
    align-self: start;
  }
}

/* Rows inside a part: label in the accent, value in ink, no outer box. */
.product-doc__part-body .product-doc__rows th {
  color: var(--color-brand);
  font-size: 13px;
  letter-spacing: 0.02em;
}

.product-doc__part-body .product-doc__rows tr:first-child {
  border-top: 0;
}

/* Judge.me's review widget ships its own 1200px cap with 80px side margins,
   which leaves it narrower than the tab it sits in. The tab already sets the
   measure. */
.product-tabs__panel .jdgm-rev-widg,
.product-tabs__panel .jdgm-widget {
  max-width: none !important;
  margin-inline: 0 !important;
}
