/* ============================================================================
   blog.css — /docs/blog, CMS-fed editorial posts.

   A SUPPLEMENT to marketing.css, not a replacement. Blog pages load
   marketing.css and chrome.css first (same as the 15 existing .mkt-guide pages),
   which already supply the :root tokens, the body rule, the nav and the footer.
   Redefining any of that here would create two sources of truth for the same
   colours and guarantee eventual drift, so this file adds only what is missing.

   Everything is scoped to .blog-post. marketing.css styles .mkt-guide-inner for
   exactly h1, h2, p, a, ul, li and strong, because a hand-authored data module
   never emitted anything else. Markdown from a CMS emits h3, h4, ol, blockquote,
   hr, code, pre, img, figure and bare tables, all of which would otherwise fall
   back to browser defaults. Scoping to .blog-post rather than widening
   .mkt-guide-inner keeps 15 live pages byte-identical in appearance: two of them
   already carry an unstyled <img> and a bare <table>, and silently restyling
   those is a separate decision from shipping a blog.
   ============================================================================ */

.blog-post {
  --blog-measure: 940px;
}

/* marketing.css pins .mkt-guide-inner to 720px. A post overrides it so the
   prose column and the body diagrams are the same width. The index sets its
   own wider measure further down and is unaffected. */
.mkt-guide-inner.blog-post {
  max-width: var(--blog-measure);
}

/* A 940px column at marketing.css's 18px runs about 109 characters per line,
   well past the 65-75 that reads comfortably. Rather than narrow the column
   and reintroduce the diagram overhang, the type grows: 21px brings it to
   roughly 93 characters, which is the measure long-form editorial sites run.
   Readability is bought from the type, not the layout.

   Scoped to DIRECT children so it applies to the CMS body prose only. The
   sources list and, on the index, the card deks are nested deeper and keep
   their own smaller sizes. */
.mkt-guide-inner.blog-post > p,
.mkt-guide-inner.blog-post > ul > li,
.mkt-guide-inner.blog-post > ol > li {
  font-size: 21px;
  line-height: 1.62;
}
/* The dek must stay larger than the body it introduces. Targeted through
   .blog-headcard because the redesign moved the dek inside that element, so the
   old direct-child selector stopped matching and the dek fell through to
   .mkt-guide-inner p at 18px, which is SMALLER than the 21px body prose it
   introduces: the exact inversion this rule exists to prevent. */
.mkt-guide-inner.blog-post > .blog-headcard > p.blog-dek {
  font-size: 24px;
  line-height: 1.45;
}
@media (max-width: 780px) {
  .mkt-guide-inner.blog-post > p,
  .mkt-guide-inner.blog-post > ul > li,
  .mkt-guide-inner.blog-post > ol > li {
    font-size: 18px;
    line-height: 1.6;
  }
  .mkt-guide-inner.blog-post > .blog-headcard > p.blog-dek {
    font-size: 19px;
  }
}

/* --- Headings markdown produces that marketing.css never needed ---------- */

.blog-post h3 {
  font-size: clamp(18px, 1.8vw, 20px);
  font-weight: 600;
  letter-spacing: -0.01em;
  line-height: 1.3;
  color: hsl(var(--foreground));
  margin: 32px 0 12px;
}
.blog-post h4 {
  font-size: 17px;
  font-weight: 600;
  line-height: 1.35;
  color: hsl(var(--foreground));
  margin: 26px 0 10px;
}

/* --- Ordered lists. marketing.css styles ul and li but not ol. ----------- */

.blog-post ol {
  margin: 0 0 20px;
  padding-left: 22px;
}
/* Nested lists tighten rather than inheriting the 20px block margin. */
.blog-post li > ul,
.blog-post li > ol {
  margin: 10px 0 0;
}
.blog-post em {
  font-style: italic;
}

/* --- Blockquote ---------------------------------------------------------- */

.blog-post blockquote {
  margin: 0 0 24px;
  padding: 4px 0 4px 20px;
  border-left: 3px solid hsl(var(--border));
}
.blog-post blockquote p {
  color: hsl(var(--foreground) / 0.7);
  margin: 0 0 10px;
}
.blog-post blockquote p:last-child {
  margin-bottom: 0;
}

/* --- Horizontal rule ----------------------------------------------------- */

.blog-post hr {
  border: 0;
  border-top: 1px solid hsl(var(--border));
  margin: 40px 0;
}

/* --- Code. JetBrains Mono matches the docs convention. ------------------- */

.blog-post code {
  font-family: "JetBrains Mono", monospace;
  font-size: 0.88em;
  background: hsl(var(--foreground) / 0.05);
  border-radius: 4px;
  padding: 2px 5px;
}
.blog-post pre {
  margin: 0 0 24px;
  padding: 16px 18px;
  background: hsl(var(--foreground) / 0.04);
  border: 1px solid hsl(var(--border));
  border-radius: var(--radius);
  overflow-x: auto;
}
.blog-post pre code {
  background: none;
  border-radius: 0;
  padding: 0;
  font-size: 14px;
  line-height: 1.6;
}

/* --- Images. No max-width anywhere in marketing.css, so a CMS body image
       overflows the 720px measure. Figures carry the photo credit. -------- */

.blog-post img {
  display: block;
  max-width: 100%;
  height: auto;
  border-radius: var(--radius);
  margin: 0 auto;
}
.blog-post figure {
  margin: 0 0 28px;
}

/* Body images sit flush with the text, not outdented past it.
   An earlier version broke wide diagrams out beyond the prose column, which
   fixed legibility and created a worse problem: every diagram overhung the
   text on both sides and read as a layout error. Text and image now share one
   width, so they align by construction rather than by two numbers that have to
   be kept in agreement.

   --blog-measure is the single knob. 940px suits the 2:1 diagrams (they render
   about 435px tall) and is wide for prose: roughly 100 characters per line at
   18px, against the 65-75 that reads most comfortably. Lower it to ~820px if
   the lines feel long; both the column and the images follow. */
.blog-post > img,
.blog-post > p > img {
  margin-bottom: 28px;
}
.blog-post figcaption {
  font-size: 14px;
  line-height: 1.5;
  color: hsl(var(--foreground) / 0.6);
  margin-top: 10px;
  text-align: center;
}

/* --- Tables. marketing.css styles only `.mkt-guide-table table`, so a bare
       <table> from GFM markdown was unstyled and overflowed the measure. The
       generator wraps each table in .mkt-guide-table for the scroll container;
       these rules make a bare table correct even if it does not. ---------- */

.blog-post table {
  width: 100%;
  border-collapse: collapse;
  font-size: 16px;
  margin: 0 0 24px;
}
.mkt-guide-table .blog-post table,
.blog-post .mkt-guide-table table {
  margin-bottom: 0;
}
.blog-post th,
.blog-post td {
  text-align: left;
  padding: 12px 16px;
  border-bottom: 1px solid hsl(var(--border));
  color: hsl(var(--foreground) / 0.82);
  vertical-align: top;
  line-height: 1.5;
}
.blog-post th {
  color: hsl(var(--foreground));
  font-weight: 600;
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

/* --- Post header: dek and byline row ----------------------------- */

.blog-dek {
  font-size: 20px;
  line-height: 1.5;
  color: hsl(var(--foreground) / 0.7);
  margin: 0 0 28px;
}
.blog-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  font-size: 14px;
  color: hsl(var(--foreground) / 0.6);
  margin: 0 0 32px;
  padding-bottom: 24px;
  border-bottom: 1px solid hsl(var(--border));
}

/* --- Sources block, rendered from paper_trail ---------------------------- */

.blog-related,
.blog-sources {
  margin: 44px 0 0;
  padding-top: 24px;
  border-top: 1px solid hsl(var(--border));
}
.blog-related-label,
.blog-sources-label {
  font-size: 13px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: hsl(var(--foreground) / 0.6);
  margin: 0 0 12px;
}
.blog-related ul,
.blog-sources ol {
  margin: 0;
  padding-left: 20px;
}
.blog-related li,
.blog-sources li {
  font-size: 15px;
  line-height: 1.5;
  margin: 0 0 8px;
  word-break: break-word;
}

/* --- Index: an editorial layout, not a list of links --------------------- */

/* The index gets a wider measure than an article. 720px is the right column
   for reading prose and the wrong container for a card grid. */
/* marketing.css pads .mkt-guide 64px, which leaves an h1 sitting almost on the
   navbar. Every blog surface needs more than that. The first pass fixed only
   the index and left the post pages cramped, which is the more read of the two. */
/* The navbar is position:fixed at var(--nav-h), so it OVERLAYS the content.
   A flat padding-top is therefore half-eaten: 128px looked generous in the
   stylesheet and rendered as 64px of visible gap, which is why the first two
   attempts at this did not fix anything.

   The site already has an idiom for it. docs.css sets
   `max(calc(var(--doc-navbar-h) + 56px), 14vh)` on .doc-header: clear the nav
   first, then add real space, with a viewport floor so it scales up on tall
   screens. Same shape here, with more room, since a blog h1 is the first thing
   on the page rather than sitting under a breadcrumb. */
.blog-article,
.blog-index {
  padding-top: max(calc(var(--nav-h) + 96px), 18vh);
}
@media (max-width: 640px) {
  .blog-article,
  .blog-index {
    padding-top: calc(var(--nav-h) + 40px);
  }
}
@media (max-width: 640px) {
  .blog-index {
    padding-top: 72px;
  }
}
/* The index is a card grid, not a reading column, so it sets its own wider
   measure. It does not carry .blog-post: every element on it is classed apart
   from the h1, so it needs none of the post's element rules, and keeping the
   class off means the post's prose sizing cannot leak into the cards. */
.blog-index .mkt-guide-inner {
  max-width: 1080px;
}

.blog-index-head {
  margin: 0 0 56px;
  padding-bottom: 28px;
  border-bottom: 1px solid hsl(var(--border));
}

/* Small caps label above a heading. Borrowed from the kicker pattern
   Letterstory's own hosted sites use above each headline. */
.blog-kicker {
  font-family: "Space Grotesk", sans-serif;
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.09em;
  color: hsl(var(--trust-link));
  margin: 0 0 12px;
}

/* --- The grid the cards sit in ------------------------------------------- */

.blog-grid {
  display: grid;
  gap: 28px 26px;
  grid-template-columns: 1fr;
}
@media (min-width: 700px) {
  .blog-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}
@media (min-width: 1060px) {
  .blog-grid {
    grid-template-columns: repeat(3, 1fr);
  }
}

@media (max-width: 640px) {
  .blog-dek {
    font-size: 18px;
  }
  .blog-post li {
    font-size: 17px;
  }
  /* ...but not the citation and related lists, which are reference matter and
     were rendering LARGER on mobile (17px) than on desktop (15px) because the
     rule above sits later at equal specificity. */
  .blog-sources li,
  .blog-related li {
    font-size: 15px;
  }
}

/* --- Structured blocks added by scripts/blog/overrides/<slug>.mjs ---------
   The FAQ and the table reuse .mkt-guide-faq, .mkt-faq-item and
   .mkt-guide-table from marketing.css unchanged, so they look identical to the
   592 generated /docs pages. Only the summary box above the body is new, and
   only the two rules below are needed to keep the shared blocks legible against
   this page's larger body type. */

/* Answer-first summary, directly above the CMS body. Card rather than plain
   list: it has to read as a distinct object, not as the article's first
   paragraph, or a reader skims past it and an extraction tool folds it into the
   prose. */
.blog-keypoints {
  margin: 0 0 34px;
  padding: 22px 26px 8px;
  border: 1px solid hsl(var(--border));
  border-left: 3px solid hsl(var(--violet) / 0.55);
  border-radius: var(--radius);
  background: hsl(var(--card));
}
.blog-keypoints-label {
  font-size: 13px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: hsl(var(--foreground) / 0.6);
  margin: 0 0 12px;
}
.blog-keypoints ul,
.blog-keypoints ol {
  margin: 0;
  padding-left: 20px;
}
.blog-keypoints li {
  font-size: 17px;
  line-height: 1.55;
  color: hsl(var(--foreground) / 0.86);
  margin: 0 0 12px;
}
@media (max-width: 780px) {
  .blog-keypoints {
    padding: 18px 20px 6px;
  }
  .blog-keypoints li {
    font-size: 16px;
  }
}

/* marketing.css centres .mkt-faq inside a 760px column and gives the guide FAQ
   an 8px top margin, both tuned to the 720px .mkt-guide-inner. A post runs
   940px, so the FAQ needs the full measure and a heading gap that matches the
   rest of the page. */
.blog-post .mkt-guide-faq,
.blog-post .mkt-guide-table {
  margin: 8px 0 0;
  max-width: none;
}
/* Only the two values that need to change against 21px body prose. Padding,
   margin and line-height stay with marketing.css so there is one source of
   truth for the accordion's box. */
.blog-post .mkt-faq-answer {
  font-size: 17px;
  color: hsl(var(--foreground) / 0.78);
}

/* ============================================================================
   Cards. One object per post, carrying everything about it.

   The previous index printed tag, title, dek and date as plain text and set a
   coloured tile beside them whose only content was the tag. On a collection
   using two tags that produced four cards in a row reading the same two words,
   so the artwork labelled the posts identically instead of telling them apart.
   Colour now belongs to the card, and the card carries the text.

   Each card gets --card-ink / --card-mid / --card-tint inline, from the same
   nine accent families in theme.css that the share images use, chosen by a hash
   of the slug so a post keeps its colour forever.
   ============================================================================ */

.blog-card {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: 26px 28px 24px;
  border: 1px solid hsl(var(--border));
  border-left: 4px solid var(--card-ink, hsl(var(--foreground)));
  border-radius: var(--radius);
  background: linear-gradient(150deg, var(--card-tint, hsl(var(--card))) 0%, hsl(var(--card)) 58%);
  transition: border-color 0.18s ease, transform 0.18s ease;
}
.blog-card:hover {
  border-color: var(--card-ink);
  transform: translateY(-2px);
}
/* The whole card is the hit area, with the real link still on the title so the
   accessible name and the tab order stay correct. */
.blog-card-title a::after {
  content: "";
  position: absolute;
  inset: 0;
}
/* The overlay above covers the whole card, which made every word in it
   unselectable. Lifting just these two back over it keeps the card clickable
   from its title, its padding and its Read label while leaving the text a
   reader might actually want to copy selectable. */
.blog-card-head,
.blog-card-dek {
  position: relative;
  z-index: 1;
}
/* Date only, and the same shape on every card. */
.blog-card-head {
  margin: 0 0 12px;
  font-size: 13px;
  letter-spacing: 0.02em;
  color: hsl(var(--foreground) / 0.5);
}
.blog-card-title {
  font-family: "Space Grotesk", sans-serif;
  font-weight: 600;
  margin: 0 0 10px;
  letter-spacing: -0.02em;
  line-height: 1.18;
}
.blog-card-title a {
  color: hsl(var(--foreground));
  text-decoration: none;
}
.blog-card:hover .blog-card-title a,
.blog-card-title a:focus-visible {
  color: hsl(var(--trust-link));
}
.blog-card-dek {
  margin: 0;
  color: hsl(var(--foreground) / 0.66);
  line-height: 1.55;
}
.blog-card-more {
  margin-top: 18px;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--card-ink);
}
.blog-card-more::after {
  content: " \2192";
}

/* The newest post gets the width and the type size. A blog whose every entry
   has identical weight gives a reader no way in. */
.blog-card--lead {
  padding: 40px 44px 36px;
}
.blog-card--lead .blog-card-title {
  font-size: clamp(28px, 3.4vw, 40px);
}
.blog-card--lead .blog-card-dek {
  font-size: 19px;
  max-width: 62ch;
}
.blog-card--grid .blog-card-title {
  font-size: 21px;
}
.blog-card--grid .blog-card-dek {
  font-size: 15.5px;
}
.blog-lead {
  margin: 0 0 34px;
}

/* ============================================================================
   The article masthead, same card, one per page.
   ============================================================================ */

.blog-headcard {
  padding: 40px 44px 34px;
  margin: 0 0 34px;
  border: 1px solid hsl(var(--border));
  border-left: 4px solid var(--card-ink, hsl(var(--foreground)));
  border-radius: var(--radius);
  background: linear-gradient(150deg, var(--card-tint, hsl(var(--card))) 0%, hsl(var(--card)) 62%);
}
/* Specificity, not styling. marketing.css sets .mkt-guide-inner p (0,1,1), so a
   bare .blog-headcard-kicker (0,1,0) lost every declaration in this block: the
   kicker rendered at 18px in the default ink and the per-post accent reached no
   text at all on any article page. Same trap below for the dek. */
.blog-post .blog-headcard-kicker {
  margin: 0 0 14px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--card-ink);
}
.mkt-guide-inner.blog-post > .blog-headcard > h1 {
  margin: 0 0 14px;
}
.mkt-guide-inner.blog-post > .blog-headcard > p.blog-dek {
  margin: 0 0 20px;
}
.blog-headcard .blog-meta {
  margin: 0;
  border: 0;
  padding: 0;
}
@media (max-width: 780px) {
  .blog-headcard,
  .blog-card--lead {
    padding: 26px 22px 22px;
  }
}
