/* Precision Labs — homepage bands.
   Bands 3–8 of the design; the promo bar, header and footer are shared and
   styled elsewhere. Everything here builds on the component kit in base.css —
   .pl-wrap, .pl-section, .pl-btn, .pl-card, .pl-h*, .pl-eyebrow, .pl-grid--*,
   .pl-badge — which is why almost nothing below sets a font or a button style
   of its own. Where a component needs to sit on a dark band it is re-coloured
   in context rather than redefined, so the component keeps one definition.

   Colours come from tokens.css only. Corners are square throughout; there is
   not a single border-radius in this file, by decision.

   Two layout rules the design calls out explicitly and this file obeys:
   every grid track holding an image is minmax(0, 1fr), and the two-column
   bands use minmax(0, …) on both tracks. An image's intrinsic width otherwise
   pushes the track past its share and the whole band overflows. */

/* ── 3. Hero ─────────────────────────────────────────────── */

/* Full viewport height, minus the chrome above it.
 *
 * The promo bar and the header sit in normal flow above this band, so a plain
 * 100svh would make the first screen taller than the window and push the fold
 * down by exactly their height. --pl-chrome is that height, MEASURED on the
 * live page rather than guessed:
 *
 *     desktop  38 promo + 74 header = 112
 *     tablet   38 promo + 79 header = 117   (the nav wraps taller here)
 *     phone    38 promo + 65 header = 103
 *
 * If the bar's height changes these must be re-measured — _dev/probe-chrome.js
 * prints all three, and mobile-top-verify.js asserts the next section starts
 * within one screen, so drift is caught rather than eyeballed.
 *
 * svh, with a vh line first as the fallback: on iOS a collapsing address bar
 * makes vh taller than the visible window, which would leave the band running
 * past the bottom of the screen. */
.pl-hero {
  --pl-inset: max(var(--pl-gutter), calc((100% - var(--pl-content)) / 2 + var(--pl-gutter)));
  --pl-chrome: 112px;
  position: relative;
  display: flex;
  align-items: center;
  min-height: calc(100vh - var(--pl-chrome));
  min-height: calc(100svh - var(--pl-chrome));
  overflow: hidden;
  background: var(--pl-ink);
  color: var(--pl-on-dark);
}

/* The dark treatment — a navy wash out of the bottom-right corner over a 40px
   grid, matching the shop banner.
 *
 * Applied to EVERY hero, not only the photograph-less one: the photo now
 * occupies the right portion of the band rather than the full bleed, so the
 * left side needs a designed ground rather than flat black behind the copy. */
.pl-hero,
.pl-hero--flat {
  background:
    repeating-linear-gradient(
      to right,
      rgba(255, 255, 255, .035) 0 1px,
      transparent 1px 40px
    ),
    repeating-linear-gradient(
      to bottom,
      rgba(255, 255, 255, .035) 0 1px,
      transparent 1px 40px
    ),
    radial-gradient(
      120% 150% at 88% 108%,
      rgba(34, 55, 126, .55) 0%,
      rgba(34, 55, 126, .18) 42%,
      transparent 72%
    ),
    var(--pl-ink);
}

/* The chromatogram, as background rather than content.
 *
 * Sized to the band and anchored right, so the peak sits in the half the copy
 * does not use. invert() turns the lab's black-on-white plot into a lit line;
 * opacity and the left-edge mask keep it behind the headline instead of
 * competing with it — at .16 it registers as texture, not as a chart to read.
 *
 * pointer-events:none so it can never intercept a click on the CTAs. */
.pl-hero__trace {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  z-index: 0;
}
.pl-hero__trace img {
  position: absolute;
  right: -4%;
  top: 50%;
  transform: translateY(-50%);
  width: 78%;
  height: auto;
  min-height: 46%;
  object-fit: cover;
  filter: invert(1) brightness(2.1) contrast(.85);
  opacity: .16;
  /* Fade the left edge into the band so the plot has no visible frame and
     never runs under the headline at full strength. */
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 34%, #000 88%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 34%, #000 88%, transparent);
}
/* The copy sits above it. */
.pl-hero__inner { position: relative; z-index: 1; }

@media (max-width: 999px) {
  /* On a phone the hero is one headline and two buttons; a trace behind them
     is one more thing on the first screen. Kept, but quieter and pushed to the
     lower half where nothing else sits. */
  .pl-hero__trace img {
    width: 130%;
    right: -18%;
    top: auto;
    bottom: 4%;
    transform: none;
    opacity: .1;
  }
}

/* The photograph occupies the RIGHT of the band, not the full bleed.
 *
 * Why not object-position: the source is a 1600x2400 portrait with the subject
 * dead centre. At 1500x788 `cover` scales it to 1500x2250 — there is no
 * horizontal overflow at all, so object-position's X value has nothing to move
 * and he lands centred, behind the headline, whatever it is set to. Giving the
 * media its own narrower box is what actually puts him on the right.
 *
 * The left edge is masked into the ground so the photo has no visible seam and
 * the copy sits on the designed dark rather than on a photograph. */
.pl-hero__media {
  position: absolute;
  top: 0;
  bottom: 0;
  right: 0;
  width: 58%;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent 0%, #000 34%);
          mask-image: linear-gradient(90deg, transparent 0%, #000 34%);
}
/* 50% 42%, and the number is derived rather than nudged.
 *
 * The media box is ~870x788 and the 1600x2400 source covers it at scale .544,
 * so it renders 870x1305 and there are 1305 - 788 = 517px of vertical play.
 * object-position Y is the fraction of THAT play, not of the image:
 *
 *     window top = 517 * Y
 *     subject's crown sits 326px into the scaled image
 *     crown on screen = 326 - (517 * Y)
 *
 * At the previous 20% the crown landed 223px down — 28% of the band — which
 * cropped him at the chest and read as a headshot. 42% puts it at ~106px, about
 * 13% down, so the frame carries head, shoulders and torso.
 *
 * RAISING the subject means RAISING Y: a larger Y moves the crop window further
 * down the source, which brings more of the lower image into view and pushes
 * him up the band. It reads backwards until you write it out.
 *
 * These are numbers about THIS photograph at THIS box. Replace either and they
 * need re-deriving, not adjusting. */
.pl-hero__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 42%;
}

@media (max-width: 1199px) {
  /* Less width to share, so the photo takes a smaller slice and fades sooner —
     otherwise it starts creeping under the lead paragraph. */
  .pl-hero__media { width: 52%; }
}
@media (max-width: 767px) {
  /* Full bleed again on a phone: there is no second column to protect, and a
     58% strip on a 390px screen is a sliver. The scrim below carries
     legibility, as it did before. */
  .pl-hero__media {
    width: 100%;
    -webkit-mask-image: none;
            mask-image: none;
  }
  .pl-hero__img { object-position: 50% 16%; }
}

/* Diagonal scrim, per the design's stops. All four are the same scrim colour,
   only the opacity moves.
 *
 * Lighter on the right than it was: the photo no longer runs under the copy,
 * so the scrim's job is to keep the subject sitting in the band rather than to
 * make text legible over him. Holding the old .80 at 38% would have dimmed him
 * to the point the client could not see what was happening in the image. */
.pl-hero__scrim {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(100deg,
    var(--pl-scrim-94) 0%,
    rgba(9, 13, 24, .82) 34%,
    rgba(9, 13, 24, .34) 58%,
    rgba(9, 13, 24, .12) 100%);
}

.pl-hero__bracket {
  position: absolute;
  left: var(--pl-inset);
  top: 44px;
  width: 24px;
  height: 24px;
  border-left: 1px solid rgba(243, 245, 244, .5);
  border-top: 1px solid rgba(243, 245, 244, .5);
  pointer-events: none;
}

.pl-hero__inner {
  position: relative;
  z-index: 1;
  padding-top: 64px;
  padding-bottom: 120px;   /* clears the claims bar pinned to the bottom edge */
}

.pl-hero__copy {
  display: flex;
  flex-direction: column;
  gap: 22px;
  max-width: 700px;
}


.pl-hero .pl-eyebrow { color: var(--pl-accent-lt); letter-spacing: .26em; font-weight: 600; }
.pl-hero__h    { max-width: 600px; color: var(--pl-on-dark); }
.pl-hero__lead { max-width: 520px; font-size: 18px; color: var(--pl-on-dark-nv); }
/* Two leads live in the markup; the <768px block swaps which one shows. The
   short one is phone copy and must never appear beside the long one. */
.pl-hero__lead--short { display: none; }

.pl-hero__cta {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: center;
  margin-top: 6px;
}

.pl-hero__claims {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 1;
  padding: 16px 0;
  background: rgba(9, 13, 24, .5);
  border-top: 1px solid rgba(243, 245, 244, .18);
}

.pl-hero__claimlist {
  display: flex;
  gap: 32px;
  list-style: none;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--pl-on-dark);
}

.pl-hero__claimlist li:last-child { margin-left: auto; }

/* ── 4. What are you researching? ────────────────────────── */

.pl-cats__head {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  gap: 20px;
  margin-bottom: 22px;
}

.pl-cats__all {
  flex: none;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
}

.pl-cat {
  display: flex;
  flex-direction: column;
  gap: 9px;
  min-height: 180px;
  padding: 22px 20px;
  color: var(--pl-ink);
  transition: border-color .18s;
}

.pl-cat:hover { border-color: var(--pl-bd-strong); color: var(--pl-ink); }

.pl-cat__top  { display: flex; align-items: center; justify-content: space-between; }
.pl-cat__icon { display: flex; color: var(--pl-navy); }

.pl-cat__n {
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: .16em;
  color: var(--pl-faint);
}

.pl-cat__name { font-size: 21px; font-weight: 700; line-height: 1.1; letter-spacing: -.02em; }
.pl-cat__desc { font-size: 13.5px; line-height: 1.5; color: var(--pl-muted); text-wrap: pretty; }

.pl-cat__meta {
  margin-top: auto;
  padding-top: 6px;
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--pl-ink);
}

/* ── 5. Testing band ─────────────────────────────────────── */

.pl-testing {
  position: relative;
  display: flex;
  align-items: center;
  min-height: 420px;
  overflow: hidden;
  background: var(--pl-ink);
  color: var(--pl-on-dark);
}

.pl-testing__media {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.pl-testing__scrim {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(90deg,
    rgba(9, 13, 24, .90) 0%,
    rgba(9, 13, 24, .55) 55%,
    rgba(9, 13, 24, .20) 100%);
}

/* padding-block: this element also carries .pl-wrap, and a `padding: 56px 0`
   shorthand deletes that class's horizontal gutter — which is why the "How we
   source" band used to start 44px left of every other section on the page. */
.pl-testing__inner { position: relative; z-index: 1; padding-block: 56px; }

.pl-testing__copy {
  display: flex;
  flex-direction: column;
  gap: 16px;
  max-width: 640px;
}

.pl-testing .pl-eyebrow { color: var(--pl-accent-lt); letter-spacing: .26em; font-weight: 600; }
.pl-testing__h { max-width: 520px; line-height: 1.04; color: var(--pl-on-dark); }

.pl-testing__p {
  max-width: 480px;
  font-size: 16.5px;
  line-height: 1.6;
  color: var(--pl-on-dark-nv);
  text-wrap: pretty;
}

.pl-testing__claims {
  display: flex;
  flex-wrap: wrap;
  gap: 26px;
  margin-top: 6px;
  list-style: none;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--pl-on-dark);
}

/* ── 6. Three-step row ───────────────────────────────────── */

.pl-how__list { gap: 36px; list-style: none; }

.pl-how__i {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding-top: 16px;
  border-top: 2px solid var(--pl-navy);
}

.pl-how__icon  { display: flex; margin-bottom: 2px; color: var(--pl-navy); }

.pl-how__label {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--pl-navy);
}

.pl-how__copy { font-size: 14.5px; line-height: 1.6; color: var(--pl-muted); text-wrap: pretty; }

/* ── 7. Protocol bundles ─────────────────────────────────── */

.pl-bundles { padding-top: 0; }

.pl-bundles__head {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  gap: 20px;
  margin-bottom: 20px;
}

.pl-bundles__all {
  flex: none;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
}

.pl-bundle { display: flex; flex-direction: column; transition: border-color .18s; }
.pl-bundle:hover { border-color: var(--pl-bd-strong); }

/* One track per bundle, up to three, each at least 320px.
   The section was a fixed 3-up grid; with two bundles published that left a
   whole empty column and shrank both cards to fit two thirds of the row. */
.pl-bundles__grid {
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
}

/* Squarer, and the vials are no longer cropped.
 *
 * The media box was a fixed 210px strip with `object-fit: cover`, so on a wide
 * card the product shot was scaled up until the caps of the vials were sliced
 * off the top. `contain` shows the whole group, the 4:3 box gives it room to be
 * shown at a sensible size, and the padding keeps it off the card's edges. */
.pl-bundle__media {
  position: relative;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  background: var(--pl-bd-light);
}

.pl-bundle__media > a { display: block; height: 100%; }
.pl-bundle__pic {
  width: 100%;
  height: 100%;
  object-fit: contain;
  padding: 18px;
}

.pl-bundle__badges {
  position: absolute;
  top: 12px;
  left: 12px;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  pointer-events: none;
}

.pl-bundle__body {
  display: flex;
  flex: 1;
  flex-direction: column;
  gap: 9px;
  padding: 20px;
}

.pl-bundle__name { font-size: 22px; font-weight: 700; line-height: 1.15; letter-spacing: -.02em; }
.pl-bundle__desc { font-size: 14px; line-height: 1.55; color: var(--pl-muted); text-wrap: pretty; }

.pl-bundle__foot {
  display: flex;
  gap: 12px;
  align-items: center;
  justify-content: space-between;
  margin-top: auto;
  padding-top: 12px;
}

.pl-bundle__price { font-size: 19px; font-weight: 600; }

/* ── 8. FAQ ──────────────────────────────────────────────── */

.pl-faq {
  background: var(--pl-bd);
  border-top: 1px solid var(--pl-bd-strong);
  color: var(--pl-ink);
}

.pl-faq__inner {
  display: grid;
  grid-template-columns: minmax(0, .85fr) minmax(0, 1.15fr);
  gap: 52px;
  align-items: start;
}

.pl-faq__h   { margin-top: 12px; }
.pl-faq__sub { max-width: 340px; margin-top: 14px; font-size: 15.5px; line-height: 1.6; color: var(--pl-muted); }
.pl-faq__cta { margin-top: 22px; }

.pl-faq__list { display: flex; flex-direction: column; }
.pl-faq__row  { border-bottom: 1px solid var(--pl-bd-strong); }
.pl-faq__row:last-child { border-bottom: 0; }

.pl-faq__q {
  display: flex;
  gap: 20px;
  align-items: baseline;
  justify-content: space-between;
  padding: 17px 0;
  font-size: 16.5px;
  line-height: 1.4;
  cursor: pointer;
  list-style: none;           /* Firefox */
}

.pl-faq__q::-webkit-details-marker { display: none; }   /* Safari */

.pl-faq__q::after {
  content: "+";
  flex: none;
  font-size: 19px;
  font-weight: 600;
  line-height: 1;
  color: var(--pl-navy);
}

.pl-faq__row[open] .pl-faq__q::after { content: "\2013"; }

.pl-faq__a {
  padding: 0 0 20px;
  max-width: 62ch;
  font-size: 14.5px;
  line-height: 1.65;
  color: var(--pl-muted);
  text-wrap: pretty;
}

/* ── Responsive ──────────────────────────────────────────── */

@media (max-width: 1199px) {
  /* Still a full screen; only the chrome above it is taller here, because the
     nav wraps to a second line between 768 and 1199px. Measured: 38 + 79. */
  .pl-hero          { --pl-chrome: 117px; }
  .pl-hero__copy    { max-width: none; }
  .pl-hero__h,
  .pl-hero__lead    { max-width: none; }
  .pl-hero__inner   { padding-top: 56px; padding-bottom: 108px; }
  .pl-hero__bracket { top: 28px; }

  .pl-testing__copy { max-width: none; }
  .pl-testing__h,
  .pl-testing__p    { max-width: 560px; }

  .pl-how__list     { gap: 28px; }

  .pl-faq__inner    { grid-template-columns: minmax(0, 1fr); gap: 30px; }
  .pl-faq__sub      { max-width: 52ch; }
}

@media (max-width: 767px) {
  /* `.pl-hero { display: block; min-height: 0 }` used to sit here, from when
     the phone hero was a short band. A LATER <768px block now sets
     display:flex and --pl-chrome, but it does not set min-height — so this
     `min-height: 0` survived and silently collapsed the phone hero to 359px
     while desktop and tablet filled their viewports correctly. Removed rather
     than overridden: two mobile blocks fighting over one element is how it got
     missed the first time. */

  .pl-hero__scrim {
    background: linear-gradient(180deg,
      rgba(9, 13, 24, .55) 0%,
      var(--pl-scrim-86) 45%,
      var(--pl-scrim-94) 100%);
  }

  /* ── one screen, one idea ──
   *
   * The hero fills the viewport that is left under the chrome and stops. The
   * subtraction is the sticky header (65px) plus the promo bar (38px); svh
   * rather than vh so an iOS address bar collapsing does not leave the section
   * taller than the window, with a vh line first for anything that lacks svh.
   *
   * Content is centred in that space instead of stacking from the top, so the
   * headline sits where the eye lands rather than under a paragraph.
   *
   * Measured before this pass at 390px: 585px hero + a 127px claims block, the
   * lead running six lines, and the first section starting 748px down. The
   * point is not that it was tall — it is that a shopper met four claims, a
   * five-line paragraph and two buttons before being given one thing to do. */
  .pl-hero {
    display: flex;
    /* COLUMN, not the base rule's row.
     *
     * On mobile .pl-hero__claims is position:static, so it becomes a second
     * in-flow child. As a flex ROW it sat BESIDE .pl-hero__inner and the two
     * split the width — measured at 390px: the copy column came out 178px wide,
     * about 22 characters a line, which pushed the headline to five lines and
     * the lead to four. The symptom read as "too much copy"; the cause was the
     * direction of one flex container. */
    flex-direction: column;
    justify-content: center;
    /* The base rule already sets min-height from --pl-chrome; only the value
       changes here. Measured on a phone: 38 promo + 65 header. */
    --pl-chrome: 103px;
  }
  .pl-hero__inner   { padding-top: 28px; padding-bottom: 28px; width: 100%; }
  .pl-hero__copy    { gap: 16px; }

  /* Headline carries the screen. */
  .pl-hero__h { font-size: 40px; line-height: 1.04; letter-spacing: -.03em; }

  /* The long lead is desktop copy; the phone gets the two-line version. */
  .pl-hero__lead--long  { display: none; }
  .pl-hero__lead--short { display: block; }
  .pl-hero__lead    { font-size: 16px; line-height: 1.5; }

  .pl-hero__cta { gap: 10px; }
  .pl-hero__cta .pl-btn { flex: 1 1 100%; padding-block: 15px; }   /* ≥44px hit targets, full width */
  .pl-hero__bracket { display: none; }

  /* One wrapped row with dot separators instead of three stacked lines: the
     same three claims in roughly two lines rather than 127px of column. */
  /* Claims strip: not on a phone.
   *
   * Four claims under the buttons was a half-read line that scrolled sideways
   * and cut a word at the edge — the last thing on the first screen, competing
   * with the two calls to action directly above it. Every one of them is made
   * again below the fold and in the footer, and two of the four ("free tracked
   * shipping", "ships from Canada") are already scrolling past in the promo bar
   * at the top of the same screen.
   *
   * Removed from the layout entirely rather than hidden with visibility, so it
   * costs no height and is not announced. It returns at 768px, where there is
   * room for it to be one full line beside the copy. */
  .pl-hero__claims { display: none; }
  .pl-hero__claimlist li:last-child { margin-left: 0; }

  .pl-cats__head,
  .pl-bundles__head { flex-direction: column; align-items: flex-start; gap: 10px; }

  .pl-testing__inner { padding-block: 44px; }
  .pl-testing__claims { gap: 8px 18px; }

  .pl-bundle__media { height: 190px; }

  .pl-faq__q { padding: 15px 0; min-height: 44px; }
}

/* The band's video never starts under reduced motion — the script declines to
   attach a source at all — but if a browser autoplays a cached source anyway,
   this keeps the poster frame still. */
@media (prefers-reduced-motion: reduce) {
  .pl-testing__media { animation-play-state: paused; }
}
