/* ============================================================
   BLOG — listing index + post detail
   Loaded on /blog/ and on every /blog/<slug>/ page.

   Namespaced `zx-bp-` (blog post) and `zx-bi-` (blog index) so
   nothing here can collide with the case-study sheet, which uses
   `zx-cs-`. The two pages are deliberately similar but they are
   NOT sharing selectors — a change to one must not silently move
   the other.

   The listing cards are the Playbook cards from the home page,
   reused unmodified from components/playbook-card.njk. Their
   styles ship with that component (`zxp-`), not from here.
   ============================================================ */

/* ══════════════════════════════════════════════════════════════
   BLOG INDEX
   ══════════════════════════════════════════════════════════════ */
.zx-bi-hero {
  /* Matches the case-studies index deliberately — these two listing
     pages sit side by side in the nav and any difference in where the
     grid starts reads as a mistake. var(--nav-height) is the floor (the
     nav is fixed); the token after it is the discretionary part. */
  padding-block: calc(var(--nav-height) + var(--s5)) var(--s7);
  text-align: center;
}
.zx-bi-hero__inner { max-width: 680px; margin-inline: auto; }
.zx-bi-hero__inner .zx-eyebrow { justify-content: center; margin-bottom: var(--s4); }

.zx-bi-title {
  margin-bottom: var(--s4);
  font-size: var(--fs-h1);
  line-height: var(--lh-heading);
  letter-spacing: var(--ls-heading);
}
.zx-bi-sub {
  font-size: var(--fs-lead);
  line-height: var(--lh-lead);
  color: var(--muted);
}

.zx-bi-grid { padding-top: 0; }

/* ══════════════════════════════════════════════════════════════
   BLOG POST DETAIL
   ══════════════════════════════════════════════════════════════ */
.zx-bp { padding-bottom: var(--s10); }

/* ── 1 · HERO ──────────────────────────────────────────────────
   Full-bleed dark plate with an ember bloom off the top right, so
   the headline sits on the dark end of the ramp where bone type
   keeps its contrast. Same construction as the case-study hero. */
.zx-bp-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-bp-hero__bg {
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    radial-gradient(90% 120% at 88% 8%, rgba(239, 90, 25, .55) 0%, rgba(239, 90, 25, 0) 62%),
    radial-gradient(70% 90% at 8% 100%, rgba(185, 63, 23, .38) 0%, rgba(185, 63, 23, 0) 70%),
    linear-gradient(158deg, #1A1210 0%, var(--ink) 55%, #14100E 100%);
}
.zx-bp-hero__in {
  display: grid;
  grid-template-columns: 1.05fr .95fr;
  gap: var(--s8);
  align-items: center;
}
.zx-bp-hero__copy { min-width: 0; }

.zx-bp-crumb { margin-bottom: var(--s5); }
.zx-bp-crumb a {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  min-height: 24px;              /* WCAG 2.5.8 target size */
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  color: rgba(var(--bone-rgb), .68);
  text-decoration: none;
  transition: color var(--dur-fast) var(--ease-out);
}
.zx-bp-crumb a:hover { color: var(--bone); }

.zx-bp-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-bp-hero__title {
  margin-bottom: var(--s4);
  font-size: var(--fs-h1);
  line-height: var(--lh-heading);
  letter-spacing: var(--ls-heading);
  color: var(--bone);
}
.zx-bp-hero__sub {
  margin-bottom: var(--s6);
  max-width: 54ch;
  font-size: var(--fs-lead);
  line-height: var(--lh-lead);
  color: rgba(var(--bone-rgb), .78);
}
.zx-bp-hero__meta { display: flex; flex-wrap: wrap; gap: var(--s5); }
.zx-bp-hero__metaitem {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  color: rgba(var(--bone-rgb), .60);
}

.zx-bp-hero__media { min-width: 0; }
.zx-bp-hero__img {
  width: 100%;
  height: auto;                 /* fit the whole image, no crop */
  border-radius: var(--r-card);
  border: 1px solid rgba(var(--bone-rgb), .12);
}
.zx-bp-hero__img--empty {
  display: grid;
  place-items: center;
  background: rgba(251, 250, 246, .05);
  color: rgba(255, 158, 113, .35);
}

/* ── 2 · TWO RAILS + BODY ──────────────────────────────────────
   Left rail carries the contents and share; the right carries the
   related and other lists. The article sits between them.

   NO align-items: start on this grid. It reads like the right call
   for a sticky child and is exactly backwards — `start` shrinks each
   grid item to its own content height, so a rail collapses to
   precisely its sticky child's height and is left with 0px of travel.
   A sticky element can only move inside its parent's box, so it never
   sticks at all. Stretch (the default) gives each rail the full row
   height and the child somewhere to travel. */
.zx-bp-wrap {
  max-width: 880px;
  margin-inline: auto;
  padding-top: var(--s8);
}
.zx-bp-rail { min-width: 0; }

/* ---------- blog listing: big image cards, one-line title + arrow on hover ---------- */
/* centered, capped at 2 cards per row (max-width holds the ceiling);
   a lone card centers instead of stretching across the row */
.zx-bgrid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(360px, 540px));
  justify-content: center;
  align-items: start;     /* each card hugs its own image — no stretch, no gap */
  gap: var(--s6);
  max-width: 1120px;      /* holds 2 bigger cards per row */
  margin-inline: auto;
}
.zx-bcard {
  position: relative;
  display: block;
  border-radius: var(--r-xl);
  overflow: hidden;
  isolation: isolate;
  text-decoration: none;
  background: var(--ink);
  box-shadow: var(--shadow-md);
  transition: box-shadow var(--dur-base) var(--ease-out);
}
.zx-bcard:hover, .zx-bcard:focus-visible { box-shadow: var(--shadow-lg); }
/* both cards share ONE fixed 16:9 frame → identical height & width. Wide +
   short, so the trim comes off the TOP/BOTTOM (anchored to top → off the
   bottom) and the full width stays, keeping the titles intact. No cream,
   no hover zoom. */
.zx-bcard__img { display: block; width: 100%; aspect-ratio: 16 / 9; object-fit: cover; object-position: top center; }
/* dark strip pinned to the bottom, slides up + fades in on hover */
.zx-bcard__overlay {
  position: absolute;
  inset-inline: 0;
  bottom: 0;
  z-index: 1;
  padding: var(--s5) var(--s5) var(--s5);
  color: var(--bone);
  background: linear-gradient(to top, rgba(15, 10, 8, .96) 0%, rgba(15, 10, 8, .74) 60%, rgba(15, 10, 8, 0) 100%);
  opacity: 0;
  transform: translateY(12px);
  transition: opacity var(--dur-base) var(--ease-out), transform var(--dur-base) var(--ease-out);
}
.zx-bcard:hover .zx-bcard__overlay,
.zx-bcard:focus-visible .zx-bcard__overlay { opacity: 1; transform: translateY(0); }
/* the single line: title left, arrow right, same baseline */
.zx-bcard__bar { display: flex; align-items: center; gap: var(--s4); }
.zx-bcard__title {
  flex: 1 1 auto;
  min-width: 0;
  font-family: var(--font-display);
  font-weight: var(--fw-bold);
  font-size: var(--fs-h4);
  line-height: 1.25;
  color: var(--white);
  /* one line, clip cleanly with an ellipsis if it runs long */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.zx-bcard__go {
  display: inline-grid;
  place-items: center;
  width: 40px; height: 40px;
  flex: none;
  border-radius: var(--r-full);
  background: var(--primary);
  color: var(--on-primary);
}
.zx-bcard__go svg { width: 16px; height: 16px; }
/* touch / small screens have no hover: show ONLY the arrow — no dark
   gradient, no title text, no hover reveal. */
@media (hover: none), (max-width: 640px) {
  .zx-bcard__overlay {
    opacity: 1;
    transform: none;
    background: none;            /* drop the black gradient */
    padding: var(--s3);
    transition: none;
  }
  .zx-bcard__bar { justify-content: flex-end; }   /* arrow to bottom-right */
  .zx-bcard__title { display: none; }             /* no title text on mobile */
  .zx-bcard__go { box-shadow: 0 4px 14px rgba(15, 10, 8, .35); }  /* reads on any image */
}
@media (prefers-reduced-motion: reduce) {
  .zx-bcard__img, .zx-bcard__overlay { transition: none; transform: none; }
}
.zx-bp-rail__stick {
  position: sticky;
  top: calc(var(--nav-height) + var(--s5));
  display: flex;
  flex-direction: column;
  gap: var(--s5);
  /* A rail taller than the viewport would pin with its top section
     unreachable above the fold. Cap it and let it scroll internally. */
  max-height: calc(100dvh - var(--nav-height) - var(--s7));
  overflow-y: auto;
  overscroll-behavior: contain;
  /* thin, unobtrusive scrollbar — this is a secondary surface */
  scrollbar-width: thin;
}

/* shared card chrome for every panel in either rail */
.zx-bp-toc,
.zx-bp-share,
.zx-bp-more {
  padding: var(--s5);
  border-radius: var(--r-card);
  background: var(--surface);
  border: 1px solid var(--border);
}
.zx-bp-rail__head {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--muted);
}

/* ---- contents ----
   The rolling readout. overflow:hidden is what makes it read as one
   label replacing another rather than two labels crossfading. */
.zx-bp-toc__now {
  display: block;
  overflow: hidden;
  margin: var(--s3) 0 var(--s4);
  padding-bottom: var(--s4);
  border-bottom: 1px solid var(--border);
}
.zx-bp-toc__nowtxt {
  display: block;
  font-family: var(--font-display);
  font-weight: var(--fw-bold);
  font-size: var(--fs-small);
  line-height: 1.35;
  color: var(--primary);
  transition: transform var(--dur-slow) var(--ease-out),
              opacity var(--dur-slow) var(--ease-out);
}
/* start state: sat below the mask. JS removes this and the label rises. */
.zx-bp-toc__now.is-enter .zx-bp-toc__nowtxt {
  transform: translateY(110%);
  opacity: 0;
  transition: none;                 /* jump to the start, then animate out of it */
}

.zx-bp-toc__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.zx-bp-toc__list a {
  display: block;
  padding: var(--s2) var(--s3);
  border-left: 2px solid transparent;
  border-radius: 0 var(--r-2xs) var(--r-2xs) 0;
  font-size: var(--fs-small);
  line-height: var(--lh-small);
  color: var(--muted);
  text-decoration: none;
  transition: color var(--dur-fast) var(--ease-out),
              background-color var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out);
}
.zx-bp-toc__list a:hover { color: var(--text); background: var(--surface-2); }
.zx-bp-toc__list a.is-active {
  color: var(--text);
  font-weight: var(--fw-medium);
  border-left-color: var(--ember-500);
  background: var(--surface-2);
}

/* ---- share ---- */
.zx-bp-share__row { display: flex; gap: var(--s2); margin-top: var(--s3); }
.zx-bp-share__btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px; height: 38px;
  flex: none;
  border-radius: var(--r-icon);
  border: 1px solid var(--border);
  background: var(--bg);
  color: var(--muted);
  cursor: pointer;
  transition: color var(--dur-fast) var(--ease-out),
              background-color var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out);
}
.zx-bp-share__btn:hover {
  color: var(--on-primary);
  background: var(--primary);
  border-color: var(--primary);
}
.zx-bp-share__note {
  display: block;
  margin-top: var(--s3);
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  color: var(--success);
}

/* ---- related / other lists ----
   Text only, no card art: these sit in a 240px rail where a Playbook
   card's visual would be illegible. The listing page is where the
   cards get room to work. */
.zx-bp-more__list {
  list-style: none;
  margin: var(--s3) 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
}
.zx-bp-more__list li + li {
  margin-top: var(--s3);
  padding-top: var(--s3);
  border-top: 1px solid var(--border);
}
.zx-bp-more__list a {
  display: flex;
  flex-direction: column;
  gap: 3px;
  text-decoration: none;
}
.zx-bp-more__title {
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  line-height: var(--lh-small);
  color: var(--text);
  transition: color var(--dur-fast) var(--ease-out);
}
.zx-bp-more__list a:hover .zx-bp-more__title { color: var(--primary); }
.zx-bp-more__meta {
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  letter-spacing: var(--ls-label);
  color: var(--muted);
}

/* ── ARTICLE BODY ──────────────────────────────────────────── */
.zx-bp-body { min-width: 0; max-width: none; }
/* scroll-margin so anchor jumps and scroll-spy don't hide headings
   under the fixed nav */
.zx-bp-body :where(h2, h3) { scroll-margin-top: calc(var(--nav-height) + var(--s5)); }
.zx-bp-body :where(h2) {
  margin: var(--s8) 0 var(--s4);
  font-size: var(--fs-h2);
  line-height: var(--lh-heading);
  letter-spacing: var(--ls-heading);
}
.zx-bp-body > :where(h2):first-child { margin-top: 0; }
.zx-bp-body :where(h3) {
  margin: var(--s6) 0 var(--s3);
  font-size: var(--fs-h4);
  line-height: var(--lh-sub);
}
.zx-bp-body :where(p) {
  margin-bottom: var(--s4);
  color: var(--muted);
  font-size: 1.125rem;          /* larger, more readable body copy */
  line-height: 1.72;
}
.zx-bp-body :where(strong) { color: var(--text); font-weight: var(--fw-bold); }
.zx-bp-body :where(em) { color: var(--text); }
/* content links read as links — underlined, ember, thickens on hover.
   :not(.direct-link) keeps the quiet heading-anchor # from getting an underline. */
.zx-bp-body :where(a):not(.direct-link) {
  color: var(--primary);
  text-decoration: underline;
  text-decoration-color: rgba(var(--ember-rgb, 239, 90, 25), .4);
  text-decoration-thickness: 1.5px;
  text-underline-offset: 3px;
  transition: color var(--dur-fast) var(--ease-out),
              text-decoration-color var(--dur-fast) var(--ease-out);
}
.zx-bp-body :where(a):not(.direct-link):hover {
  color: var(--primary-hover);
  text-decoration-color: currentColor;
}
.zx-bp-body :where(blockquote) {
  margin: var(--s6) 0;
  padding: var(--s5) var(--s6);
  border-left: 3px solid var(--ember-500);
  border-radius: 0 var(--r-md) var(--r-md) 0;
  background: var(--surface);
}
.zx-bp-body :where(blockquote p) {
  margin-bottom: var(--s3);
  color: var(--text);
  font-size: var(--fs-lead);
  line-height: var(--lh-small);
}
.zx-bp-body :where(blockquote p:last-child) { margin-bottom: 0; }
.zx-bp-body :where(ul, ol) { margin: 0 0 var(--s4); padding-left: var(--s5); color: var(--muted); }
.zx-bp-body :where(li) { margin-bottom: var(--s2); font-size: 1.125rem; line-height: 1.7; }
.zx-bp-body :where(li strong) { color: var(--text); }
.zx-bp-body :where(hr) { margin: var(--s7) 0; border: 0; border-top: 1px solid var(--border); }
.zx-bp-body :where(table) {
  width: 100%;
  margin: var(--s5) 0;
  border-collapse: collapse;
  font-size: 1.125rem;          /* match body copy */
  line-height: 1.55;
}
.zx-bp-body :where(th) {
  padding: var(--s3);
  text-align: left;
  border-bottom: 1px solid var(--border-strong);
  font-size: 1.125rem;          /* match body copy */
  font-weight: var(--fw-bold);
  color: var(--text);
}
.zx-bp-body :where(td) { padding: var(--s3); border-bottom: 1px solid var(--border); font-size: 1.125rem; color: var(--muted); }
.zx-bp-body :where(td strong) { color: var(--primary); }

/* ---- tag row under the article ---- */
.zx-bp-tags {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2);
  margin-top: var(--s7);
  padding-top: var(--s6);
  border-top: 1px solid var(--border);
}
.zx-bp-tag {
  display: inline-flex;
  align-items: center;
  min-height: 24px;
  padding: var(--s1) var(--s3);
  border-radius: var(--r-chip);
  background: var(--chip);
  border: 1px solid var(--border);
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--muted);
}

/* ── 3 · AUTHOR + SHARE FOOTER ─────────────────────────────────
   One strip, not two stacked outlined boxes: author on the left,
   share cluster on the right, split by a soft top rule. */
.zx-bp-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;   /* author hard-left, share hard-right */
  flex-wrap: wrap;
  gap: var(--s5);
  margin-top: var(--s8);
  padding-top: var(--s6);
  border-top: 1px solid var(--border);
}
.zx-bp-foot__author { display: flex; align-items: center; gap: var(--s4); min-width: 0; }
.zx-bp-foot__avatar {
  display: grid;
  place-items: center;
  width: 56px; height: 56px;
  flex: none;
  border-radius: var(--r-full);
  overflow: hidden;
  /* soft ember tint + primary monoline icon — a clean avatar chip, flat */
  background: rgba(239, 90, 25, .10);
  color: var(--primary);
  box-shadow: inset 0 0 0 1px rgba(239, 90, 25, .20);
}
.zx-bp-foot__avatar img { width: 100%; height: 100%; object-fit: cover; }
.zx-bp-foot__who { display: flex; flex-direction: column; min-width: 0; }
.zx-bp-foot__tag {
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 2px;
}
.zx-bp-foot__who strong { font-size: var(--fs-lead); color: var(--text); line-height: 1.2; }
.zx-bp-foot__role { font-size: var(--fs-small); color: var(--muted); }

.zx-bp-foot__share { display: flex; align-items: center; gap: var(--s3); flex: none; }
.zx-bp-foot__sharelabel {
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--muted);
}
.zx-bp-foot__share .zx-bp-share__row { display: flex; gap: var(--s2); }

/* other-articles sits full-width below the footer */
.zx-bp-more--bottom {
  margin-top: var(--s7);
  padding-top: var(--s6);
  border-top: 1px solid var(--border);
}

/* ── RESPONSIVE ────────────────────────────────────────────────
   Two rails need roughly 1200px to hold their width without
   squeezing the reading column. Below that the right rail drops
   under the article and the left rail's contents list goes with it. */
@media (max-width: 1199px) {
  .zx-bp-wrap { grid-template-columns: 1fr; }
  .zx-bp-body { margin-inline: auto; }
  /* Right rail moves below the article, full width, un-stuck. */
  .zx-bp-rail--right {
    grid-column: 1 / -1;
    margin-top: var(--s7);
  }
  .zx-bp-rail--right .zx-bp-rail__stick {
    position: static;
    max-height: none;
    overflow: visible;
    flex-direction: row;
    flex-wrap: wrap;
  }
  .zx-bp-rail--right .zx-bp-more { flex: 1 1 260px; }
}
@media (max-width: 1023px) {
  .zx-bp-hero__in { grid-template-columns: 1fr; gap: var(--s7); }
  .zx-bp-hero__media { order: -1; }         /* image leads on narrow */
  .zx-bp-wrap { grid-template-columns: 1fr; }
  /* Sticky is pointless once a rail is a full-width block above the
     article — it would pin a tall panel over the reading column. */
  .zx-bp-rail__stick {
    position: static;
    max-height: none;
    overflow: visible;
  }
  /* The contents list is the left rail's only occupant, and the rolling
     readout needs the sticky column to make any sense. Hiding the list
     alone would leave the rail behind as an empty column still holding
     its grid track and its gap, so the whole rail goes. */
  .zx-bp-rail--left { display: none; }
  .zx-bp-body { order: 1; max-width: none; }
  .zx-bp-rail--right { order: 2; margin-top: 0; }
}
@media (max-width: 767px) {
  .zx-bp-hero { padding-block: calc(var(--nav-height) + var(--s6)) var(--s7); }
  /* footer stacks: author over share, share left-aligned */
  .zx-bp-foot { flex-direction: column; align-items: flex-start; gap: var(--s4); }

  /* TABLES: horizontally-scrollable card so columns keep their width and
     stay readable. Cells don't wrap — the reader swipes sideways; the
     rounded frame + faint scrollbar signal it. */
  .zx-bp-body :where(table) {
    display: block;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    white-space: nowrap;
    font-size: 1rem;
    border: 1px solid var(--border);
    border-radius: var(--r-md);
    scrollbar-width: thin;
  }
  .zx-bp-body :where(th, td) { padding: var(--s3) var(--s4); }
  /* first column often holds the row label — let it wrap so rows stay short */
  .zx-bp-body :where(td:first-child, th:first-child) { white-space: normal; min-width: 8rem; }
}

@media (prefers-reduced-motion: reduce) {
  .zx-bp-toc__nowtxt { transition: none; }
}

/* ── markdown heading anchors ───────────────────────────────────
   The markdown plugin appends `<a class="direct-link">#</a>` to every
   heading for deep-linking. Unstyled it renders as a full-size glyph in
   the heading's own colour — a large orange # after each title. Keep the
   affordance, make it quiet: hidden until the heading is hovered or the
   link itself is focused.

   opacity:0 rather than display:none on purpose — it stays in the tab
   order, and focus brings it back for keyboard users. */
.zx-bp-body .direct-link {
  margin-left: var(--s2);
  font-weight: var(--fw-medium);
  color: var(--muted);
  text-decoration: none;
  opacity: 0;
  transition: opacity var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out);
}
.zx-bp-body :where(h2, h3):hover .direct-link,
.zx-bp-body .direct-link:focus-visible { opacity: 1; }
.zx-bp-body .direct-link:hover { color: var(--primary); }

@media (prefers-reduced-motion: reduce) {
  .zx-bp-body .direct-link { transition: none; }
}
