/* ============================================
   REPLICO AI — BLOG LAYER
   Additive stylesheet loaded only by /blog/ pages, always AFTER
   replico.css. Adds nothing but blog-specific classes and reuses the
   existing custom properties (--ink-*, --accent, --white-*, --radius-*,
   --border, --ff-h, --ff-b, --transition) so the blog inherits the site's
   typography, colour and spacing language unchanged.

   replico.css is never modified. Removing this file and /blog/ removes
   the blog layer completely.
   ============================================ */

/* ============================================
   ARTICLE MEASURES
   An article page runs on two concentric measures, both centred.

   — The READING measure (808px → 760px of content) carries the featured
     image, the body, the FAQ and the related cards. It is a reading width:
     roughly 75 characters of body copy, and it is not negotiable.

   — The HEADLINE measure (1160px → 1112px of content) carries the hero band
     only. Display type set at a reading width is the thing that makes a
     headline look like a landing-page banner: the line boxes are short, so
     the type has to grow to fill them and the title stacks into five stubby
     lines. Widening the measure is what lets the size come down. At 1112px a
     typical title resolves into two or three long lines at 34px — the
     proportion an editorial masthead actually uses.

   Both values are the containers replico.css already ships (.container-narrow
   and .container), so the hero band lines up with the site's existing grid
   rather than introducing a measure of its own. They are declared as custom
   properties on .post so the whole system is retuned from one place.
   ============================================ */
.post {
  --read-measure: 808px;
  --headline-measure: 1160px;
}
.post .container-narrow { max-width: var(--read-measure, 808px); }

/* ============================================
   ARTICLE HERO
   ============================================ */

/* Equal specificity to .post .container-narrow above, so this wins on source
   order. Below ~1208px the viewport, not the cap, is the constraint and the
   two measures converge — which is why nothing here needs a media query to
   unwind itself on tablet and mobile. */
.post-hero .container-narrow { max-width: var(--headline-measure, 1160px); }

.post-hero { padding-bottom: 40px; }

.post-eyebrow { margin-bottom: 16px; }

.post-category {
  display: inline-block;
  font-family: var(--ff-b);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent);
  background: var(--accent-dim);
  border: 1px solid var(--accent-bdr);
  padding: 4px 11px;
  border-radius: 20px;
}

/* The pill becomes a link only once the category has a real archive page to
   send the reader to; below that threshold it stays a plain span, so the page
   never advertises a URL that does not exist. */
a.post-category { text-decoration: none; }
a.post-category:hover {
  color: var(--ink);
  background: var(--accent);
  border-color: var(--accent);
}

/* The headline is the system: a flat 34px over the 1112px headline measure.

   Flat, not clamped. The mobile rule below already tops out at 34px, so the
   two meet exactly at the 768px breakpoint and the headline never jumps size
   as the viewport crosses it. Between 769px and ~1208px the measure narrows
   with the viewport while the size holds, so a title simply takes an extra
   line instead of shrinking — the size is a typographic decision, not a
   function of screen width.

   34px is 1.3x the 26px of a body h2, which is the whole hierarchy the page
   needs: the title outranks the section headings clearly and stops there. The
   old 46px outranked them by 1.8x, which is a poster, not an article.

   Leading is tight (1.08) because long lines at a calm size need less air
   between them than short lines at a loud one; the block reads as a single
   typographic unit. Tracking is in em, so it stays optically constant if the
   size is ever retuned.

   The measure, not a wrapping algorithm, is what produces the composition —
   no hard break in the markup and nothing tuned to one headline. At 1112px the
   ordinary greedy pass already breaks this title into two even lines (1031px
   and 1074px) and keeps "Real Estate CRM" whole, because the following word
   cannot fit. text-wrap: pretty is layered on only to protect the last line
   from a one-word orphan.

   Measured, not assumed: balance was tried first and is worse here. It is a
   no-op at 1160px and above, where the greedy break is already even, but once
   the band narrows to three lines it splits "Real Estate" across a line break
   chasing equal line widths. pretty keeps the phrase whole at every width. */
.post-hero h1 {
  font-family: var(--ff-h);
  font-size: 34px;
  font-weight: 800;
  line-height: 1.08;
  letter-spacing: -0.025em;
  color: var(--white);
  margin-bottom: 22px;
  max-width: var(--headline-measure, 1160px);
  text-wrap: pretty;
}

/* Everything under the headline is deliberately held to a reading measure,
   well inside the 1112px the headline is allowed. The supporting text shares
   the headline's left edge but stops far short of its right one, so the eye
   reads one long line of display type and then drops to a narrow column —
   the headline is the only element in the band that spans it. Matching the
   standfirst to the headline's width is what would make the two compete. */
.post-hero .page-hero-sub {
  max-width: 620px;
  font-size: 17px;
  line-height: 1.65;
  margin-bottom: 0;
}

/* ============================================
   BREADCRUMB
   The full title is the desktop crumb; on mobile it is swapped for the
   article category so the trail stays one short, readable line. Only one
   of the two is ever in the DOM flow, so the accessibility tree and
   aria-current="page" stay unambiguous, and the machine-readable
   BreadcrumbList in the page's JSON-LD always carries the full title.
   ============================================ */
.post-hero .breadcrumb { flex-wrap: wrap; row-gap: 4px; }
.breadcrumb-current { min-width: 0; }
.breadcrumb-short { display: none; }

.post-meta {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 28px;
  font-size: 13px;
  color: var(--white-50);
}
/* Each line is its own flex row, so name/role and date/read-time are
   separated by real layout gaps rather than by markup whitespace — they
   cannot concatenate when the rows wrap. */
.post-meta-line {
  display: inline-flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  min-width: 0;
}
.post-meta time { color: var(--white-50); }
.post-meta-sep { color: var(--white-30); }
.post-author { color: var(--white-70); }
.post-updated { color: var(--accent); opacity: 0.85; }
.post-readtime { color: var(--white-50); }

/* ============================================
   FEATURED IMAGE
   ============================================ */
.post-figure-wrap { padding: 0 0 8px; }
.post-featured {
  margin: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: var(--ink-2);
  box-shadow: var(--shadow-sm);
}
.post-featured img { width: 100%; height: auto; display: block; }
.post-featured figcaption {
  font-size: 12.5px;
  color: var(--white-50);
  padding: 12px 18px;
  border-top: 1px solid var(--border);
}

/* ============================================
   ARTICLE BODY
   Builds on .doc-section (paragraphs, ul, strong, links) and adds the
   elements legal pages never needed: h2/h3 rhythm, ol, tables, quotes,
   code and figures.
   ============================================ */
.post-body-section { padding-top: 44px; }
.post-body { margin-bottom: 0; }

.post-body > h2 {
  font-size: 26px;
  letter-spacing: -0.5px;
  margin: 48px 0 16px;
  padding-top: 0;
  scroll-margin-top: 100px;
}
.post-body > h2:first-child { margin-top: 0; }

.post-body > h3 {
  font-size: 18px;
  color: var(--white);
  margin: 32px 0 12px;
  scroll-margin-top: 100px;
}

.post-body > h4 {
  font-family: var(--ff-h);
  font-size: 15px;
  font-weight: 700;
  color: var(--white-90);
  margin: 24px 0 10px;
  scroll-margin-top: 100px;
}

.post-body p { font-size: 15.5px; line-height: 1.85; margin-bottom: 18px; }
.post-body ul { margin: 0 0 20px; }
.post-body ul li { font-size: 15.5px; line-height: 1.8; }

/* .doc-section styles ul only — ordered lists are new here. */
.post-body ol {
  margin: 0 0 20px;
  padding: 0;
  counter-reset: post-ol;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.post-body ol > li {
  position: relative;
  counter-increment: post-ol;
  padding-left: 34px;
  font-size: 15.5px;
  line-height: 1.8;
  color: var(--white-70);
  font-weight: 300;
}
.post-body ol > li::before {
  content: counter(post-ol);
  position: absolute;
  left: 0;
  top: 2px;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--accent-dim);
  border: 1px solid var(--accent-bdr);
  color: var(--accent);
  font-family: var(--ff-h);
  font-size: 11px;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
}
.post-body li > ul,
.post-body li > ol { margin-top: 10px; margin-bottom: 0; }

.post-body blockquote {
  margin: 28px 0;
  padding: 18px 22px;
  background: var(--white-04);
  border-left: 3px solid var(--accent);
  border-radius: 0 var(--radius-md) var(--radius-md) 0;
}
.post-body blockquote p {
  margin-bottom: 0;
  font-size: 16px;
  font-style: italic;
  color: var(--white-90);
  font-weight: 300;
}
.post-body blockquote p + p { margin-top: 12px; }

.post-body hr {
  border: none;
  border-top: 1px solid var(--border);
  margin: 44px 0;
}

.post-body figure { margin: 32px 0; }
.post-body img {
  width: 100%;
  height: auto;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--ink-2);
}
.post-body figcaption {
  font-size: 12.5px;
  color: var(--white-50);
  margin-top: 10px;
  text-align: center;
}

.post-body code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.88em;
  background: var(--white-06);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 2px 6px;
  color: var(--accent);
}
.post-body pre {
  background: var(--ink-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 18px 20px;
  overflow-x: auto;
  margin: 0 0 22px;
}
.post-body pre code {
  background: none;
  border: none;
  padding: 0;
  color: var(--white-90);
  font-size: 13px;
  line-height: 1.7;
}

/* ============================================
   TABLES
   Wide tables scroll inside their own container so the page body never
   scrolls horizontally on mobile.
   ============================================ */
.table-scroll {
  overflow-x: auto;
  margin: 0 0 24px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--white-04);
  -webkit-overflow-scrolling: touch;
}
.post-body table {
  width: 100%;
  border-collapse: collapse;
  font-size: 14px;
  min-width: 460px;
}
.post-body thead th {
  font-family: var(--ff-h);
  font-size: 11.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--white-70);
  text-align: left;
  padding: 13px 16px;
  background: var(--white-06);
  border-bottom: 1px solid var(--border-2);
  white-space: nowrap;
}
.post-body tbody td {
  padding: 13px 16px;
  color: var(--white-70);
  font-weight: 300;
  line-height: 1.65;
  border-bottom: 1px solid var(--border);
  vertical-align: top;
}
.post-body tbody tr:last-child td { border-bottom: none; }
.post-body tbody tr:hover td { background: var(--white-04); }
.post-body tbody td strong { color: var(--white); font-weight: 500; }

/* ============================================
   TABLE OF CONTENTS
   Rendered only on articles long enough to have earned one, and built from
   the article's H2 headings. Two renderings sit in the markup and exactly
   one of them is ever in the layout: an always-open editorial panel from
   769px up, a collapsed <details> below it. The other is display:none, so it
   is also out of the accessibility tree — which is what lets the whole
   component behave responsively with no JavaScript at all.
   ============================================ */
.post-toc {
  margin: 0 0 34px;
  background: var(--white-04);
  border: 1px solid var(--border);
  border-left: 2px solid var(--accent-bdr);
  border-radius: var(--radius-md);
}

.post-toc-static { padding: 18px 22px; }

.post-toc-title {
  font-family: var(--ff-b);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--white-50);
  margin: 0 0 13px;
}

.post-toc-list {
  list-style: none;
  counter-reset: toc;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 9px;
}
.post-toc-list li {
  counter-increment: toc;
  display: flex;
  gap: 11px;
  min-width: 0;
}
.post-toc-list li::before {
  content: counter(toc, decimal-leading-zero);
  flex: none;
  font-size: 11px;
  line-height: 1.9;
  color: var(--white-30);
  font-variant-numeric: tabular-nums;
}
.post-toc-list a {
  font-size: 14px;
  line-height: 1.55;
  font-weight: 300;
  color: var(--white-70);
  text-decoration: none;
  border-bottom: 1px solid transparent;
  overflow-wrap: break-word;
  min-width: 0;
}
.post-toc-list a:hover {
  color: var(--accent);
  border-bottom-color: var(--accent-bdr);
}

/* Mobile rendering — collapsed until asked for, so it costs one line above
   the article instead of a screenful. */
.post-toc-collapsible { display: none; }
.post-toc-collapsible > summary {
  padding: 14px 44px 14px 18px;
  margin: 0;
  cursor: pointer;
  list-style: none;
  position: relative;
  color: var(--white-70);
}
.post-toc-collapsible > summary::-webkit-details-marker { display: none; }
.post-toc-collapsible > summary::after {
  content: '';
  position: absolute;
  right: 19px;
  top: 50%;
  width: 8px;
  height: 8px;
  margin-top: -6px;
  border-right: 2px solid var(--accent);
  border-bottom: 2px solid var(--accent);
  transform: rotate(45deg);
  transition: var(--transition);
}
.post-toc-collapsible[open] > summary::after {
  transform: rotate(-135deg);
  margin-top: -2px;
}
.post-toc-collapsible[open] { border-color: var(--border-2); }
.post-toc-collapsible .post-toc-list { padding: 0 18px 16px; }

/* ============================================
   READING PROGRESS
   A 3px line pinned directly BELOW the fixed header, scaled by a single
   custom property that assets/js/replico-blog.js writes once per animation
   frame. Nothing else about it changes: transform on a compositor-friendly
   property, no width, no layout, no repaint of the page beneath it.

   PLACEMENT. --read-progress-top is the header's own height: .nav-inner is
   68px at every breakpoint and the scrolled nav adds a 1px hairline beneath
   it, so 69px is the first row of pixels the header does not occupy. The
   line therefore starts where the header ends and cannot cross the logo or
   the links at any width. z-index keeps that true even if the arithmetic
   ever drifts: the nav (1000) and the mobile drawer (999) both paint over
   this, so the line can never sit on top of site navigation.

   It measures the article body, not the document, so it completes as the
   last line of the article reaches the bottom of the viewport rather than
   somewhere inside the FAQ, the related cards and the footer.

   aria-hidden is the accessible choice rather than a shortcut past one: a
   progressbar role whose value changes on every frame is noise in a screen
   reader, and it would be announcing scroll position — something the
   reader's own software already reports more usefully. There is no text,
   no counter, and it never takes a pointer event.
   ============================================ */
.read-progress {
  --read-progress-top: 69px;
  position: fixed;
  top: var(--read-progress-top);
  left: 0;
  right: 0;
  height: 3px;
  z-index: 998;
  pointer-events: none;
}
.read-progress-bar {
  display: block;
  height: 100%;
  background: var(--accent);
  transform: scaleX(var(--read-progress, 0));
  transform-origin: 0 50%;
  transition: transform 0.12s linear;
  will-change: transform;
}

/* ============================================
   BACK TO TOP
   Two renderings of one button. This is the floating one, used from 900px
   up: hidden until roughly a screen of article has gone past, then a small
   quiet square in the corner — the same panel treatment as the nav's
   scrolled state, not a floating action button. visibility:hidden rather
   than opacity alone, so it is genuinely absent from the tab order until
   there is somewhere to go back from.

   900px is where the corner stops being free space. The article measure is
   760px and centred, so each margin is (100vw - 760) / 2: at 900px that is
   70px, and a 38px control offset 22px from the edge starts 60px in — clear
   of the text by 10px. Below 900px it would begin to ride over the right
   edge of the article, so the in-flow rendering takes over instead (see
   BACK TO TOP — IN FLOW below).

   z-index sits below the nav (1000) and the mobile drawer (999): the
   control never covers site navigation, and the drawer closes over it.
   ============================================ */
.to-top {
  position: fixed;
  right: 22px;
  bottom: 22px;
  z-index: 900;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  padding: 0;
  color: var(--white-50);
  background: rgba(15, 22, 40, 0.78);
  border: 1px solid var(--border-2);
  border-radius: var(--radius-sm);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  opacity: 0;
  visibility: hidden;
  transform: translateY(6px);
  transition: opacity 0.22s cubic-bezier(0.4, 0, 0.2, 1),
              transform 0.22s cubic-bezier(0.4, 0, 0.2, 1),
              visibility 0.22s,
              color 0.22s cubic-bezier(0.4, 0, 0.2, 1),
              border-color 0.22s cubic-bezier(0.4, 0, 0.2, 1),
              background 0.22s cubic-bezier(0.4, 0, 0.2, 1);
}
.to-top[data-visible="true"] {
  opacity: 1;
  visibility: visible;
  transform: none;
}
.to-top:hover {
  color: var(--accent);
  border-color: var(--accent-bdr);
  background: rgba(15, 22, 40, 0.94);
}
.to-top svg { display: block; }
/* The floating control is a 38px square with an icon in it; the label
   belongs to the in-flow rendering, which has room for words. The button
   carries aria-label either way, so nothing is lost by hiding it here. */
.to-top-label { display: none; }

/* ============================================
   BACK TO TOP — IN FLOW (below 900px)
   Under 900px there is no margin beside the article wide enough to hold the
   control, and a fixed one would pass over the right edge of the text on
   every scroll. Shrinking it only makes that overlap smaller, so it stops
   floating altogether: it renders where it sits in the markup, between the
   article's closing CTA and the footer, and cannot be on top of anything.

   It also stops hiding. Appearing and disappearing is behaviour a floating
   control needs because it covers the page; a control that is part of the
   page has nothing to hide from, so it is simply present — which is also
   why the data-visible attribute the script writes has no effect here.
   ============================================ */
@media (max-width: 899px) {
  .to-top,
  .to-top[data-visible="false"] {
    position: static;
    width: fit-content;
    height: auto;
    gap: 9px;
    margin: 30px auto calc(34px + env(safe-area-inset-bottom, 0px));
    padding: 10px 17px;
    font-family: var(--ff-b);
    font-size: 13px;
    font-weight: 400;
    opacity: 1;
    visibility: visible;
    transform: none;
  }
  .to-top-label { display: inline; }
}

/* The headline is the focus target after the control is used. The page
   arriving back at the top is the feedback; it does not also need a ring
   drawn around the title. */
.post-hero h1[tabindex="-1"]:focus { outline: none; }

/* ============================================
   READING LAYER — REDUCED MOTION
   The progress line still tracks the reader exactly; it just stops easing
   between frames. The control appears and disappears outright, and the
   button scrolls the page instantly (handled in replico-blog.js, which
   passes behavior:"instant" to override the site's smooth scrolling).
   ============================================ */
@media (prefers-reduced-motion: reduce) {
  .read-progress-bar { transition: none; }
  .to-top {
    transform: none;
    transition: opacity 0.01ms, visibility 0.01ms, color 0.22s, border-color 0.22s;
  }
}

/* ============================================
   TAGS
   ============================================ */
.post-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 40px 0 0;
  padding-top: 28px;
  border-top: 1px solid var(--border);
}
.post-tag {
  font-size: 11.5px;
  color: var(--white-50);
  background: var(--white-04);
  border: 1px solid var(--border);
  border-radius: 20px;
  padding: 4px 11px;
}

/* ============================================
   AUTHOR
   A byline, not a profile. Three lines of information — who wrote it, what
   they do, and when it was published — sitting in a quiet strip rather
   than a card that competes with the article above it.

   The role appears once, and there is no bio: "Founder of Replico AI."
   underneath "Founder, Replico AI" said nothing the line above it had not
   already said.

   Layout is a two-column strip on desktop (identity left, publication
   facts right) that stacks on small screens.
   ============================================ */
.post-author-card {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 20px;
  margin: 36px 0 0;
  padding: 16px 18px;
  background: var(--white-04);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
}
/* "Written by" spans the full width above the identity: it labels the block
   rather than sitting in the reading order between name and role. */
.post-author-label {
  flex-basis: 100%;
  margin: 0 0 2px;
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--white-30);
}
.post-author-identity {
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
  flex: 1 1 auto;
}
.post-author-avatar {
  flex-shrink: 0;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  background: var(--accent-dim);
  border: 1px solid var(--accent-bdr);
  color: var(--accent);
  font-family: var(--ff-h);
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: 0.02em;
  display: flex;
  align-items: center;
  justify-content: center;
}
.post-author-info { min-width: 0; }
.post-author-name {
  font-family: var(--ff-h);
  font-size: 14.5px;
  font-weight: 700;
  line-height: 1.35;
  color: var(--white);
  margin: 0;
}
.post-author-title {
  font-size: 12.5px;
  line-height: 1.45;
  color: var(--white-50);
  margin: 0;
}
/* Publication facts, repeated from the article header so the byline is
   complete on its own. Machine-readable dates stay in the header. */
.post-author-facts {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 7px;
  margin: 0;
  font-size: 12.5px;
  color: var(--white-40);
  font-variant-numeric: tabular-nums;
}
.post-author-facts time { color: var(--white-40); }

/* ============================================
   FAQ
   Rendered only when the article declares faq front matter.
   ============================================ */
.faq-list { display: flex; flex-direction: column; gap: 10px; }
.faq-item {
  background: var(--white-04);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  overflow: hidden;
  transition: var(--transition);
}
.faq-item[open] { border-color: var(--border-2); background: var(--white-06); }
.faq-q {
  font-family: var(--ff-h);
  font-size: 15px;
  font-weight: 700;
  color: var(--white);
  padding: 17px 46px 17px 20px;
  cursor: pointer;
  position: relative;
  list-style: none;
  line-height: 1.5;
}
.faq-q::-webkit-details-marker { display: none; }
.faq-q::after {
  content: '';
  position: absolute;
  right: 20px;
  top: 50%;
  width: 9px;
  height: 9px;
  margin-top: -6px;
  border-right: 2px solid var(--accent);
  border-bottom: 2px solid var(--accent);
  transform: rotate(45deg);
  transition: var(--transition);
}
.faq-item[open] .faq-q::after { transform: rotate(-135deg); margin-top: -2px; }
.faq-q:hover { color: var(--accent); }
.faq-a {
  padding: 0 20px 18px;
  font-size: 14.5px;
  color: var(--white-70);
  line-height: 1.8;
  font-weight: 300;
}
.faq-a a { color: var(--accent); border-bottom: 1px solid var(--accent-bdr); }
.faq-a strong { color: var(--white); font-weight: 500; }

/* ============================================
   RELATED ARTICLES
   Rendered only when the article lists related slugs.
   ============================================ */
.related-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 16px;
}
.related-card {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 22px;
  background: var(--white-04);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  transition: var(--transition);
}
.related-card:hover {
  background: var(--white-06);
  border-color: var(--accent-bdr);
  transform: translateY(-2px);
}
.related-category {
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent);
}
.related-title {
  font-family: var(--ff-h);
  font-size: 16px;
  font-weight: 700;
  color: var(--white);
  line-height: 1.35;
}
.related-desc {
  font-size: 13.5px;
  color: var(--white-70);
  line-height: 1.65;
  font-weight: 300;
}
.related-date { font-size: 12px; color: var(--white-50); margin-top: auto; padding-top: 4px; }

/* ============================================
   BLOG INDEX
   ============================================ */
.blog-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 24px;
}

.blog-card {
  background: var(--white-04);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  overflow: hidden;
  transition: var(--transition);
  display: flex;
}
.blog-card:hover {
  background: var(--white-06);
  border-color: var(--accent-bdr);
  transform: translateY(-3px);
  box-shadow: var(--shadow-sm);
}
.blog-card-link {
  display: flex;
  flex-direction: column;
  width: 100%;
}

.blog-card-media {
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background: var(--ink-2);
  border-bottom: 1px solid var(--border);
}
.blog-card-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.4s cubic-bezier(0.4, 0, 0.2, 1);
}
.blog-card:hover .blog-card-media img { transform: scale(1.04); }

/* Fallback panel when an article has no featured image — keeps the grid
   even without inventing an image. */
.blog-card-media-fallback {
  display: flex;
  align-items: center;
  justify-content: center;
  background:
    radial-gradient(circle at 30% 30%, rgba(221, 255, 71, 0.10), transparent 60%),
    var(--ink-2);
}
.blog-card-mark {
  font-family: var(--ff-h);
  font-size: 40px;
  font-weight: 800;
  color: var(--accent);
  opacity: 0.22;
}

.blog-card-body {
  padding: 22px;
  display: flex;
  flex-direction: column;
  gap: 9px;
  flex: 1;
}
.blog-card-category {
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent);
}
.blog-card-title {
  font-family: var(--ff-h);
  font-size: 18px;
  font-weight: 700;
  color: var(--white);
  line-height: 1.32;
  letter-spacing: -0.3px;
}
.blog-card:hover .blog-card-title { color: var(--accent); }
.blog-card-desc {
  font-size: 13.5px;
  color: var(--white-70);
  line-height: 1.7;
  font-weight: 300;
}
.blog-card-meta {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
  color: var(--white-50);
  margin-top: auto;
  padding-top: 10px;
}

.blog-empty {
  font-size: 15px;
  color: var(--white-50);
  text-align: center;
  padding: 60px 0;
  border: 1px dashed var(--border-2);
  border-radius: var(--radius-lg);
}

/* ============================================
   CATEGORY NAVIGATION
   A single editorial rail of chips, never a sidebar and never a WordPress
   filter bar. On /blog/ the chips are :target filters over the card grid —
   the empty .cat-target stubs are the anchors and the per-category rules are
   generated into that page's head, because the selectors depend on the
   category slugs, which are data. That is what lets every category be
   browsable before any of them has earned an archive page, with no script
   and no link that leads nowhere.
   ============================================ */
.cat-target {
  display: block;
  height: 0;
  /* Activating a chip scrolls its stub to the top; the offset keeps the rail
     clear of the fixed site navigation. */
  scroll-margin-top: 96px;
}

.blog-filter {
  margin: 0 0 28px;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--border);
  /* The chips scroll inside their own rail. They never wrap into a growing
     block and never widen the page. */
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}
.blog-filter::-webkit-scrollbar { display: none; }

.blog-filter-track {
  display: flex;
  align-items: center;
  gap: 8px;
  width: max-content;
  min-width: 100%;
}

.blog-filter-chip {
  flex: none;
  display: inline-flex;
  align-items: center;
  font-family: var(--ff-b);
  font-size: 12.5px;
  font-weight: 500;
  letter-spacing: 0.01em;
  color: var(--white-70);
  background: var(--white-04);
  border: 1px solid var(--border);
  border-radius: 20px;
  padding: 7px 15px;
  white-space: nowrap;
  text-decoration: none;
  transition: var(--transition);
}
.blog-filter-chip:hover {
  color: var(--white);
  background: var(--white-06);
  border-color: var(--border-2);
}

/* "All" is the page's default state, so it starts active and steps back only
   once another category is targeted. The active state of the others comes
   from the generated rules in the page head. Where :has() is unsupported the
   All chip simply stays highlighted — cosmetic, and the filter still works. */
.blog-filter-chip.is-all,
.blog-filter-chip[aria-current="page"] {
  color: var(--ink);
  background: var(--accent);
  border-color: var(--accent);
}
.blog-index-body:has(> .cat-target:not(#cat-all):target) .blog-filter-chip.is-all {
  color: var(--white-70);
  background: var(--white-04);
  border-color: var(--border);
}
.blog-index-body:has(> .cat-target:not(#cat-all):target) .blog-filter-chip.is-all:hover {
  color: var(--white);
  background: var(--white-06);
  border-color: var(--border-2);
}

/* Revealed by the generated filter CSS only while its own category is the
   active filter, and only emitted at all for a category that has an archive
   page. Hidden by default, so the unfiltered index carries no stray link. */
.blog-archive-link { display: none; margin-top: 28px; }
.blog-archive-back { margin-top: 34px; }
.blog-archive-link a,
.blog-archive-back a {
  font-size: 13.5px;
  color: var(--accent);
  text-decoration: none;
  border-bottom: 1px solid var(--accent-bdr);
  padding-bottom: 2px;
}
.blog-archive-link a:hover,
.blog-archive-back a:hover { border-bottom-color: var(--accent); }

/* ============================================
   RESPONSIVE — matches replico.css breakpoints
   ============================================ */
@media (max-width: 1024px) {
  .blog-grid { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 768px) {
  /* ---- Article header ----
     The headline is the tallest element on a phone: a long editorial title
     wraps to seven or more lines. Tightening the size and leading and
     pulling in the surrounding rhythm keeps it a strong, dominant block
     without letting the header eat the whole first viewport. */
  .post-hero { padding: 108px 0 28px; }

  .post-hero .breadcrumb { font-size: 11.5px; gap: 7px; margin-bottom: 16px; }
  .breadcrumb-full { display: none; }
  .breadcrumb-short { display: inline; }

  .post-eyebrow { margin-bottom: 14px; }

  .post-hero h1 {
    font-size: clamp(25px, 6.9vw, 34px);
    line-height: 1.1;
    letter-spacing: -0.4px;
    margin-bottom: 14px;
  }

  /* Leading and the zeroed bottom margin now come from the base rule. */
  .post-hero .page-hero-sub { font-size: 15px; }

  /* Tablet still has room for a single meta row. */
  .post-meta { margin-top: 20px; font-size: 12.5px; gap: 8px; }

  .post-body-section { padding-top: 32px; }
  .post-body > h2 { font-size: 21px; margin: 36px 0 14px; }
  .post-body > h3 { font-size: 16.5px; margin: 26px 0 10px; }
  .post-body p,
  .post-body ul li,
  .post-body ol > li { font-size: 15px; }

  /* Tablet and below: the publication facts drop under the identity rather
     than being squeezed beside it. */
  .post-author-card { gap: 12px 16px; padding: 15px 16px; }
  .post-author-identity { flex-basis: 100%; }

  .blog-grid { grid-template-columns: 1fr; gap: 18px; }
  .related-grid { grid-template-columns: 1fr; }

  /* Swap the always-open panel for the collapsed one. */
  .post-toc-static { display: none; }
  .post-toc-collapsible { display: block; }
  .post-toc { margin-bottom: 26px; }

  /* The rail runs edge to edge so a scrolled chip is visibly cut off rather
     than looking like the last one. The negative margins exactly cancel the
     container's 24px padding, so the page itself still cannot scroll
     sideways. */
  .blog-filter {
    margin-left: -24px;
    margin-right: -24px;
    padding-left: 24px;
    padding-right: 24px;
    margin-bottom: 22px;
  }
  .blog-archive-link { margin-top: 24px; }

  .faq-q { font-size: 14.5px; padding: 15px 42px 15px 17px; }
  .faq-a { padding: 0 17px 16px; font-size: 14px; }

  /* ---- Reading layer ----
     The progress line drops to a 2px hairline. It is fixed and takes no
     layout space at any size, so "subtle on mobile" is about how much of
     the screen it draws attention to, not how much of it the line occupies.
     Its offset is unchanged: the header is the same 68px on a phone, so the
     line still starts on the first pixel row the header does not occupy.

     "Back to top" is not adjusted here: below 900px it has already left the
     fixed layer for the in-flow rendering at the end of the page. */
  .read-progress { height: 2px; }
}

@media (max-width: 560px) {
  .post-featured { border-radius: var(--radius-md); }
  .post-body pre { padding: 14px 15px; }

  .blog-filter-chip { font-size: 12px; padding: 6px 13px; }
  .post-toc-collapsible > summary { padding: 13px 40px 13px 16px; }
  .post-toc-collapsible .post-toc-list { padding: 0 16px 15px; }
  .post-toc-list a { font-size: 13.5px; }

  .post-hero { padding: 104px 0 26px; }
  .post-hero .page-hero-sub { font-size: 14.5px; line-height: 1.68; }
  /* Phones: byline and article facts stack as two clean rows —
     "Rahul Kukadiya · Founder" over "August 26, 2026 · 10 min read". */
  .post-meta {
    flex-direction: column;
    align-items: flex-start;
    gap: 6px;
    font-size: 12px;
  }
  .post-meta-sep-block { display: none; }
  .post-meta-line { gap: 7px; }
}

/* Narrowest phones (320px): the headline is size-floored by the clamp, so
   only the tracking and the header's vertical rhythm are trimmed further. */
@media (max-width: 360px) {
  .post-hero { padding: 100px 0 24px; }
  .post-hero h1 { letter-spacing: -0.2px; margin-bottom: 12px; }
  .post-hero .breadcrumb { font-size: 11px; margin-bottom: 14px; }
  .post-eyebrow { margin-bottom: 12px; }
  .post-hero .page-hero-sub { font-size: 14.5px; }

  .blog-filter-chip { font-size: 11.5px; padding: 6px 12px; }
  .blog-filter-track { gap: 7px; }
}

/* ============================================
   PRINT
   ============================================ */
@media print {
  .nav, .cta-band, footer, .post-author-card, .related-grid, .skip-link,
  .blog-filter, .post-toc, .blog-archive-link, .blog-archive-back,
  .read-progress, .to-top { display: none; }
  .post-body, .post-body p, .post-body li { color: #000; }
}
