/* ============================================================
   PRODUCT / SOLUTION PAGES
   Used by layouts/product.njk for every product and solution page.

   Namespaced `zx-pr-`. The drawn visuals inside each row carry
   their own `zxa-` styles and ship with components/product-art.njk,
   not from here — this sheet only positions the frame around them.

   Reused rather than re-declared: .zx-container, .zx-section,
   .zx-eyebrow, .zx-btn*, and the whole .zx-faq block from site.css.
   ============================================================ */

.zx-pr { padding-bottom: 0; }

/* ── 1 · HERO ──────────────────────────────────────────────────
   Full-bleed dark plate with an ember bloom off the top right, so
   the headline lands on the dark end of the ramp where bone type
   keeps its contrast. Same construction as the blog and case-study
   heroes, deliberately — these are siblings in the nav. */
.zx-pr-hero {
  position: relative;
  overflow: hidden;
  padding-block: calc(var(--nav-height) + var(--s8)) var(--s9);
  border-radius: 0 0 var(--r-2xl) var(--r-2xl);
}
.zx-pr-hero__bg {
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    radial-gradient(78% 105% at 86% 4%, rgba(239, 90, 25, .52) 0%, rgba(239, 90, 25, 0) 60%),
    radial-gradient(64% 84% at 6% 100%, rgba(185, 63, 23, .34) 0%, rgba(185, 63, 23, 0) 70%),
    linear-gradient(158deg, #1A1210 0%, var(--ink) 56%, #14100E 100%);
}
.zx-pr-hero__in {
  display: grid;
  grid-template-columns: 1.02fr .98fr;
  gap: var(--s8);
  align-items: center;
}
.zx-pr-hero__copy { min-width: 0; }

.zx-pr-hero__eyebrow {
  display: inline-flex;
  align-items: center;
  margin-bottom: var(--s4);
  padding: var(--s1) var(--s3);
  border-radius: var(--r-chip);
  background: rgba(239, 90, 25, .22);
  border: 1px solid rgba(255, 158, 113, .34);
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--ember-100);
}
.zx-pr-hero__title {
  margin-bottom: var(--s5);
  font-size: clamp(2.5rem, 5.4vw, 4rem);
  font-weight: var(--fw-heavy);
  line-height: var(--lh-display);
  letter-spacing: var(--ls-display);
  color: var(--bone);
  text-wrap: balance;
}
.zx-pr-hero__sub {
  margin-bottom: var(--s6);
  max-width: 52ch;
  font-size: var(--fs-lead);
  line-height: var(--lh-lead);
  color: rgba(var(--bone-rgb), .78);
}
.zx-pr-hero__cta { display: flex; flex-wrap: wrap; gap: var(--s3); }
.zx-pr-hero__media { min-width: 0; }

/* ── 2 · ALTERNATING ROWS ──────────────────────────────────────
   Media left / copy right by default; every EVEN row swaps sides.

   The swap is done with grid-column, not flex order or
   flex-direction: row-reverse. Both of those leave the DOM order
   intact but reverse the *painting* order, which is fine visually
   and wrong for keyboard users — tabbing would jump backwards on
   alternate rows. Assigning explicit columns keeps source order and
   focus order identical on every row while still flipping the
   picture. */
.zx-pr-rows { padding-block: var(--section-y); }

.zx-pr-row {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(var(--s6), 5vw, var(--s9));
  align-items: center;
}
.zx-pr-row + .zx-pr-row { margin-top: clamp(var(--s8), 9vw, 140px); }

/* grid-row: 1 on BOTH is load-bearing, not belt-and-braces.
   Without it, even rows break in half. Auto-placement walks a cursor
   forward and never backward: on an even row the media is placed at
   column 2 first, which leaves the cursor past column 1, so the copy
   asking for column 1 cannot fit on that line and is pushed down into
   a brand new row. The result is the visual floating above the text
   instead of beside it — and only on even rows, because odd rows take
   column 1 first and never trip the cursor.
   Pinning both to row 1 removes auto-placement from the decision. */
.zx-pr-row__media { grid-column: 1; grid-row: 1; min-width: 0; }
.zx-pr-row__copy  { grid-column: 2; grid-row: 1; min-width: 0; }

.zx-pr-row:nth-child(even) .zx-pr-row__media { grid-column: 2; grid-row: 1; }
.zx-pr-row:nth-child(even) .zx-pr-row__copy  { grid-column: 1; grid-row: 1; }

.zx-pr-row__img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: var(--r-card);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-lg);
}

.zx-pr-row__copy .zx-eyebrow { margin-bottom: var(--s4); }
.zx-pr-row__copy h2 {
  margin-bottom: var(--s4);
  font-size: var(--fs-h2);
  line-height: var(--lh-heading);
  letter-spacing: var(--ls-heading);
  text-wrap: balance;
}
.zx-pr-row__copy > p {
  margin-bottom: var(--s5);
  max-width: 48ch;
  font-size: var(--fs-lead);
  line-height: var(--lh-lead);
  color: var(--muted);
}

.zx-pr-points {
  list-style: none;
  margin: 0 0 var(--s5);
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--s3);
  max-width: 48ch;
}
.zx-pr-points li {
  display: flex;
  align-items: flex-start;
  gap: var(--s3);
  line-height: var(--lh-body);
  color: var(--text);
}
.zx-pr-points__tick {
  display: grid;
  place-items: center;
  width: 22px; height: 22px;
  flex: none;
  margin-top: 2px;
  border-radius: var(--r-full);
  background: var(--primary-soft);
  color: var(--primary);
}

.zx-pr-row__link {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  min-height: 24px;              /* WCAG 2.5.8 target size */
  font-weight: var(--fw-medium);
  color: var(--primary);
  text-decoration: none;
  transition: color var(--dur-fast) var(--ease-out);
}
.zx-pr-row__link:hover { color: var(--primary-hover); }

/* ── 4 · CLOSING CTA ─────────────────────────────────────────
   The section itself stays on the page canvas. Only the rounded panel
   inside it is dark — see the note in layouts/product.njk for why this
   is not a [data-band="invert"] section. */
.zx-pr-cta { padding-block: 0 var(--section-y); }
.zx-pr-cta__panel {
  position: relative;
  overflow: hidden;
  padding: clamp(var(--s7), 7vw, var(--s9)) var(--gutter);
  border-radius: var(--r-2xl);
  text-align: center;
  color: var(--bone);
}
/* ---- the panel's ember ramp ----
   One vertical gradient: orange at the top falling to black at the
   bottom. No radial layers — a single 180deg ramp is the whole effect.

   WHERE THE STOPS SIT IS A CONTRAST CONSTRAINT, NOT A TASTE ONE.
   Bone text measured against the Ember scale:

       ember-400  2.48:1   fails everything
       ember-500  3.27:1   large headings only
       ember-600  5.31:1   passes body text
       ember-700  7.47:1

   The heading starts around a third of the way down and the body copy
   below it, so the ramp has to be at ember-600 or darker by ~20%. That
   is why the vivid end is compressed into the top fifth: it is the
   only band with no text over it. Lifting the mid stops to get "more
   orange" behind the copy is what would break this — check the ratio
   before moving any stop below 20%. */
.zx-pr-cta__bg {
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  overflow: hidden;
  background: linear-gradient(180deg,
    #FF8A4E 0%,
    var(--ember-500) 9%,
    var(--ember-600) 20%,
    var(--ember-700) 33%,
    var(--ember-800) 47%,
    #55160B 62%,
    #331006 76%,
    #1B0B05 88%,
    var(--ink) 100%);
}

/* Film grain. A gradient this large bands visibly on 8-bit displays —
   the noise breaks the steps up and is what makes the panel read as a
   surface rather than a CSS fill. Same treatment as the home hero. */
.zx-pr-cta__bg::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.5'/%3E%3C/svg%3E");
  opacity: .10;
  mix-blend-mode: overlay;
  pointer-events: none;
}

/* Lit top edge and a warm hairline border, so the panel has an edge
   instead of dissolving into the page. Inset shadows only — nothing
   here changes the box's size or position. */
.zx-pr-cta__panel::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  box-shadow:
    inset 0 1px 0 rgba(255, 225, 210, .16),
    inset 0 0 0 1px rgba(255, 158, 113, .12);
}
.zx-pr-cta__panel h2 {
  margin-bottom: var(--s4);
  font-size: clamp(1.9rem, 4vw, 3rem);
  line-height: var(--lh-heading);
  letter-spacing: var(--ls-heading);
  color: var(--bone);
  text-wrap: balance;
}
.zx-pr-cta__panel p {
  margin-inline: auto;
  margin-bottom: var(--s6);
  max-width: 52ch;
  font-size: var(--fs-lead);
  line-height: var(--lh-lead);
  color: rgba(var(--bone-rgb), .76);
}
.zx-pr-cta__row { display: flex; flex-wrap: wrap; gap: var(--s3); justify-content: center; }

/* ── RESPONSIVE ────────────────────────────────────────────────
   Below 900px the rows stack. When they do, the visual leads on
   EVERY row — an alternating stack reads as arbitrary once the two
   halves are no longer side by side, because there is no longer a
   left and a right for them to alternate between. */
@media (max-width: 899px) {
  .zx-pr-hero__in { grid-template-columns: 1fr; gap: var(--s7); }
  .zx-pr-hero__media { order: -1; }

  .zx-pr-row { grid-template-columns: 1fr; gap: var(--s6); }
  .zx-pr-row__media,
  .zx-pr-row:nth-child(even) .zx-pr-row__media { grid-column: 1; grid-row: 1; }
  .zx-pr-row__copy,
  .zx-pr-row:nth-child(even) .zx-pr-row__copy { grid-column: 1; grid-row: 2; }
}
@media (max-width: 767px) {
  .zx-pr-hero { padding-block: calc(var(--nav-height) + var(--s6)) var(--s7); }
  .zx-pr-hero__cta .zx-btn,
  .zx-pr-cta__row .zx-btn { width: 100%; justify-content: center; }
}
