/* ── Inter (self-hosted variable font, 400-800) ─────────────────
   Served from /fonts (public/) instead of the Google Fonts CDN so no
   visitor IP is ever sent to Google (GDPR — the LG Muenchen problem).
   Two subsets with unicode-range: latin-ext only downloads on pages
   that actually use Polish diacritics. font-display: swap. */
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url("/fonts/inter-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url("/fonts/inter-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* Google Fonts — Inter loaded via <link> in layout head */

/* ── CSS Variables ─────────────────────────────────────── */
:root {
  --accent:      #23476F;
  --accent-soft: #E9EEF5;
  --ink:         #16202C;
  --bg:          #FFFFFF;
  --card:        #FFFFFF;
  --line:        #E8ECF1;
  --muted:       #5A6470;
  --radius:      14px;
  --radius-sm:   10px;

  /* ── Sticky-header geometry ───────────────────────────
     CODE REVIEW 2026-07-31 (findings 1, 3, 4). THE definition of how tall the
     sticky header is. It is not a measurement copied off the rendered page:
     `.blog-header__inner` DERIVES its height from this variable, so the header
     and everything that has to clear it move together and cannot drift apart.
     Change this one value and the header, the ToC's sticky offset and every
     anchor jump all follow.

     Three separate constants were previously written against the assumption
     that the header was ~24px tall. It is 61px, so ToC links landed their
     target heading entirely underneath it and the pinned ToC lost its own
     title behind it. --header-border is separate only because the border box
     is what actually occupies the viewport. */
  --header-border: 1px;
  --header-h:      61px;
  /* Clearance for anything that must sit or land BELOW the sticky header. */
  --header-offset: calc(var(--header-h) + 16px);
}

/* ── Reset ────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }


/* ── A11y utilities ───────────────────────────────────── */
.visually-hidden {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  clip-path: inset(50%); overflow: hidden; white-space: nowrap;
}
.skip-link {
  position: absolute; left: -9999px; top: 0;
  background: var(--accent); color: #fff;
  padding: 10px 16px; border-radius: 0 0 var(--radius-sm) 0;
  z-index: 100; text-decoration: none; font-size: 14px;
}
.skip-link:focus { left: 0; }

/* ── Empty state ──────────────────────────────────────── */
.empty-state {
  text-align: center; padding: 56px 20px;
  border: 1px dashed var(--line); border-radius: var(--radius);
  margin: 8px 0 24px;
}
.empty-state__title { font-size: 17px; font-weight: 600; color: var(--ink); margin-bottom: 6px; }
.empty-state__sub   { font-size: 14px; color: var(--muted); }

/* ── Flash messages ───────────────────────────────────── */
.flash {
  margin: 16px 0;
  padding: 12px 16px;
  border-radius: var(--radius-sm);
  font-size: 14.5px;
  border: 1px solid var(--line);
}
.flash--notice { background: #EDF7EE; border-color: #CDE8D0; color: #1E5A28; }
.flash--alert  { background: #FCEEEE; border-color: #F2D4D4; color: #8A2626; }

/* ── Base ─────────────────────────────────────────────── */
body {
  font-family: 'Inter', system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
  color: var(--ink);
  background: var(--bg);
  line-height: 1.65;
  font-size: 16px;
  -webkit-font-smoothing: antialiased;
}

a { color: inherit; text-decoration: none; }

/* ── Header ───────────────────────────────────────────── */
.blog-header {
  border-bottom: var(--header-border) solid var(--line);
  background: var(--bg);
  position: sticky;
  top: 0;
  z-index: 100;
}

/* Height comes FROM --header-h (minus the border, which sits outside this box)
   rather than emerging from padding — that is what makes the variable the
   single definition instead of a copy of a measured value. */
.blog-header__inner {
  max-width: 1100px;
  margin: 0 auto;
  height: calc(var(--header-h) - var(--header-border));
  padding: 0 24px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
}

.blog-wordmark {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 15px;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--ink);
  text-decoration: none;
  flex-shrink: 0;
}

.blog-icon-wrap {
  width: 34px;
  height: 34px;
  background: var(--accent);
  border-radius: 10px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.blog-nav {
  display: flex;
  align-items: center;
  gap: 24px;
}

.blog-nav a {
  font-size: 13.5px;
  font-weight: 500;
  color: var(--muted);
  text-decoration: none;
  white-space: nowrap;
  transition: color 0.15s;
}

.blog-nav a:hover { color: var(--ink); }

.blog-nav a:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 3px;
  color: var(--ink);
}

/* ── Shared wrappers ──────────────────────────────────── */
.blog-wrap {
  max-width: 720px;
  margin: 0 auto;
  padding: 0 20px;
}

.blog-wrap--wide {
  max-width: 1100px;
  margin: 0 auto;
  padding: 0 24px;
}

/* ── Section header row ───────────────────────────────── */
.section-header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  padding: 40px 0 20px;
}

.section-heading {
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}

.section-all {
  font-size: 13px;
  font-weight: 600;
  color: var(--accent);
  text-decoration: none;
  transition: opacity 0.15s;
}

.section-all:hover { opacity: 0.75; }

/* ── Shared thumbnail wrapper ─────────────────────────── */
.thumb-wrap {
  position: relative;
  width: 100%;
  overflow: hidden;
  background: var(--accent-soft);
}

.thumb-wrap--16-9 { padding-top: 56.25%; }
.thumb-wrap--3-2  { padding-top: 66.67%; }

.thumb-wrap > * {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
}

.thumb-wrap > img { object-fit: cover; }

/* ── Shared badge & meta accents ─────────────────────── */
.post-badge {
  display: inline-block;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--accent);
  background: var(--accent-soft);
  padding: 3px 8px;
  border-radius: 5px;
}

.meta-time {
  color: var(--accent);
  font-weight: 600;
}

/* ── Featured 2-up row ────────────────────────────────── */
.featured-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20px;
  margin-bottom: 20px;
}

.featured-card {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  text-decoration: none;
  color: inherit;
  background: var(--card);
  transition: border-color 0.2s, box-shadow 0.2s;
}

.featured-card:hover,
.featured-card:focus-visible {
  border-color: var(--accent);
  box-shadow: 0 4px 18px rgba(35,71,111,0.09);
}

.featured-card:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.featured-card__body {
  padding: 18px 20px 20px;
  display: flex;
  flex-direction: column;
  flex: 1;
}

.featured-card__title {
  font-size: 19px;
  font-weight: 700;
  line-height: 1.3;
  letter-spacing: -0.01em;
  color: var(--ink);
  margin: 8px 0 8px;
}

.featured-card__excerpt {
  font-size: 14px;
  color: var(--muted);
  line-height: 1.55;
  margin-bottom: 12px;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  flex: 1;
}

.featured-card__meta {
  font-size: 12px;
  color: var(--muted);
  margin-top: auto;
}

/* ── Posts grid ───────────────────────────────────────── */
.posts-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;
  margin-bottom: 52px;
}

.grid-card {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  text-decoration: none;
  color: inherit;
  background: var(--card);
  transition: border-color 0.2s, box-shadow 0.2s;
}

.grid-card:hover,
.grid-card:focus-visible {
  border-color: var(--accent);
  box-shadow: 0 3px 12px rgba(35,71,111,0.07);
}

.grid-card:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.grid-card__body {
  padding: 14px 16px 16px;
  display: flex;
  flex-direction: column;
  flex: 1;
}

.grid-card__title {
  font-size: 14.5px;
  font-weight: 600;
  line-height: 1.35;
  color: var(--ink);
  margin: 8px 0 auto;
  padding-bottom: 10px;
}

.grid-card__meta {
  font-size: 11.5px;
  color: var(--muted);
  margin-top: auto;
}

/* ── Post show ────────────────────────────────────────── */
.post {
  padding: 36px 0 64px;
}

.post-header-image {
  border-radius: var(--radius);
  overflow: hidden;
  margin-bottom: 28px;
}

.post__title {
  font-size: 30px;
  font-weight: 800;
  line-height: 1.25;
  letter-spacing: -0.02em;
  color: var(--ink);
  margin: 10px 0 10px;
}

.post__meta {
  font-size: 13px;
  color: var(--muted);
  margin-bottom: 24px;
}

.back-link {
  display: inline-block;
  font-size: 13px;
  font-weight: 500;
  color: var(--muted);
  text-decoration: none;
  margin-bottom: 28px;
  transition: color 0.15s;
}

.back-link:hover { color: var(--ink); }

/* ── Author box ───────────────────────────────────────── */
.author-box {
  display: flex;
  align-items: center;
  gap: 13px;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  padding: 14px 0;
  margin-bottom: 32px;
}

.author-avatar {
  width: 42px;
  height: 42px;
  border-radius: 50%;
  background: var(--accent-soft);
  border: 1.5px solid var(--line);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.author-name {
  font-size: 14px;
  font-weight: 600;
  color: var(--ink);
  line-height: 1.3;
}

.author-bio {
  font-size: 12px;
  color: var(--muted);
  margin-top: 2px;
}

/* ── Article body ─────────────────────────────────────── */
.post-body {
  font-size: 16.5px;
  line-height: 1.77;
  color: var(--ink);
}

.post-body h2 {
  font-size: 22px;
  font-weight: 700;
  letter-spacing: -0.01em;
  margin: 42px 0 12px;
  line-height: 1.3;
}

.post-body h3 {
  font-size: 18px;
  font-weight: 600;
  margin: 32px 0 10px;
  line-height: 1.35;
}

.post-body p { margin-bottom: 20px; }

.post-body ul,
.post-body ol {
  margin: 0 0 20px 22px;
}

.post-body li { margin-bottom: 7px; }

.post-body a {
  color: var(--accent);
  text-decoration: underline;
  text-decoration-color: rgba(35,71,111,0.3);
  text-underline-offset: 3px;
}

.post-body a:hover { text-decoration-color: var(--accent); }

.post-body blockquote {
  border-left: 3px solid var(--accent);
  margin: 28px 0;
  padding: 6px 0 6px 20px;
  color: var(--muted);
  font-style: italic;
}

/* One-line disclosure above the post body (compact variant) */
.post-disclosure--top {
  font-size: 12.5px;
  color: var(--muted);
  font-style: italic;
  line-height: 1.5;
  margin: -18px 0 22px;
  opacity: 0.8;
}

/* Disclosure fine print — rendered at the bottom of the post */
.post-disclosure {
  margin-top: 40px;
}

.post-disclosure__rule {
  border: none;
  border-top: 1px solid var(--line);
  margin: 0 0 14px;
}

.post-disclosure__text {
  font-size: 13px;
  color: var(--muted);
  font-style: italic;
  line-height: 1.55;
  opacity: 0.75;
}

/* ── Product comparison (COMPARE-1) ───────────────────────
   REVIEW-2026-07-24: this whole block was MISSING. The comparison table —
   the post's money surface, one "View →" per row straight into /go/ —
   shipped with zero stylesheet rules: a bare 4-column HTML table with no
   borders, no spacing, a CTA indistinguishable from body text, and
   `comparison-row--unavailable` / `comparison-name--struck` (the honest
   out-of-stock marker the ERB deliberately renders) having no visual
   effect whatsoever. */
.post-comparison {
  margin: 40px 0;
  padding: 26px 24px;
  background: var(--accent-soft);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}

.comparison-heading {
  font-size: 19px;
  font-weight: 700;
  color: var(--ink);
  letter-spacing: -0.01em;
  margin-bottom: 16px;
}

/* Never let the table push the page sideways at tablet widths. */
.comparison-scroll { overflow-x: auto; }

.comparison-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 14.5px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  overflow: hidden;
}

.comparison-table th {
  text-align: left;
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted);
  padding: 11px 14px;
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
}

.comparison-table td {
  padding: 13px 14px;
  border-bottom: 1px solid var(--line);
  vertical-align: top;
  line-height: 1.45;
}

.comparison-table tbody tr:last-child td { border-bottom: none; }

.comparison-name { font-weight: 600; color: var(--ink); }

/* Out of stock / withdrawn from the feed: the row STAYS (the link still
   redirects) but the visitor is told before they click. */
.comparison-row--unavailable { opacity: 0.72; }
.comparison-name--struck { text-decoration: line-through; color: var(--muted); }

.comparison-unavailable,
.comparison-note {
  display: block;
  font-size: 12.5px;
  color: var(--muted);
  margin-top: 3px;
}
.comparison-note { font-style: italic; }

.verdict {
  display: inline-block;
  font-size: 12.5px;
  font-weight: 600;
  line-height: 1.3;
  padding: 4px 9px;
  border-radius: 999px;
  border: 1px solid transparent;
}
.verdict--meets      { background: #EDF7EE; border-color: #CDE8D0; color: #1E5A28; }
.verdict--below      { background: #FCEEEE; border-color: #F2D4D4; color: #8A2626; }
.verdict--undeclared { background: #FFF6E5; border-color: #F0E0BE; color: #7A5A15; }

.comparison-cta { white-space: nowrap; }

.comparison-link {
  display: inline-block;
  background: var(--accent);
  color: #fff;
  font-size: 13.5px;
  font-weight: 600;
  text-decoration: none;
  padding: 8px 14px;
  border-radius: var(--radius-sm);
}
.comparison-link:hover { opacity: 0.88; }
.comparison-link:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
}

.comparison-disclosure {
  font-size: 12.5px;
  color: var(--muted);
  font-style: italic;
  line-height: 1.5;
  margin-top: 12px;
  opacity: 0.85;
}

/* ── Email signup ─────────────────────────────────────── */
.email-signup {
  background: var(--accent-soft);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 32px 28px;
  margin: 40px 0;
}

.email-signup__icon {
  font-size: 20px;
  margin-bottom: 10px;
}

.email-signup__headline {
  font-size: 18px;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--ink);
  margin-bottom: 6px;
}

.email-signup__sub {
  font-size: 14px;
  color: var(--muted);
  margin-bottom: 18px;
  line-height: 1.6;
}

.email-signup__form {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  margin-bottom: 10px;
}

.email-signup__input {
  flex: 1;
  min-width: 220px;
  padding: 11px 14px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  font-size: 14px;
  font-family: inherit;
  background: var(--bg);
  color: var(--ink);
  outline: none;
  transition: border-color 0.15s, box-shadow 0.15s;
}

.email-signup__input:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(35,71,111,0.1);
}

.email-signup__input::placeholder { color: var(--muted); }

.email-signup__btn {
  padding: 11px 22px;
  background: var(--accent);
  color: #fff;
  border: none;
  border-radius: var(--radius-sm);
  font-size: 14px;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
  white-space: nowrap;
  transition: opacity 0.15s;
  letter-spacing: 0.01em;
}

.email-signup__btn:hover { opacity: 0.88; }

.email-signup__btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.email-signup__zero-spam {
  font-size: 11.5px;
  font-weight: 600;
  color: var(--accent);
  margin-bottom: 6px;
}

.email-signup__micro {
  font-size: 11px;
  color: var(--muted);
  line-height: 1.55;
}

.email-signup__micro a {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* ── About page ───────────────────────────────────────── */
.about-page {
  padding-top: 48px;
}

.about-hero {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 12px;
  margin-bottom: 40px;
}

.about-hero__avatar {
  width: 88px;
  height: 88px;
  border-radius: 50%;
  background: var(--accent-soft);
  border: 2px solid var(--line);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.about-hero__name {
  font-size: 26px;
  font-weight: 800;
  letter-spacing: -0.02em;
  color: var(--ink);
  line-height: 1.2;
}

.about-hero__subtitle {
  font-size: 13.5px;
  color: var(--muted);
  line-height: 1.5;
}

.about-lead {
  font-size: 19px;
  font-weight: 600;
  line-height: 1.6;
  color: var(--ink);
  letter-spacing: -0.01em;
  margin-bottom: 24px;
}

@media (max-width: 640px) {
  .about-hero__name   { font-size: 22px; }
  .about-lead         { font-size: 17px; }
}

/* ── PUBLIC-UI-1: article layout + right rail ─────────────
   The post page uses the wide container (set in posts/show). `minmax(0, 720px)`
   keeps the reading measure EXACTLY what it was before the rail existed — the
   page gains a sidebar, the prose does not get wider.

   ONE COLUMN BY DEFAULT. The rail track is added only by --with-rail, which
   posts/show sets from `toc.render?` — the same decision that decides whether
   the ToC partial emits anything, so the track and its content can never
   disagree.

   CODE REVIEW 2026-07-31 (finding 4): this rule used to declare the 260px track
   unconditionally. A grid track is sized whether or not anything occupies it,
   so every post with fewer than 3 headings reserved an empty 260px rail and
   rendered its article 150px left of centre with blank space beside it — a page
   that simply reads as broken. (The old comment claimed justify-content
   prevented this; it centres the TRACKS, empty ones included.) */
.post-layout {
  display: grid;
  grid-template-columns: minmax(0, 720px);
  gap: 40px;
  justify-content: center;
  align-items: start;
}

.post-layout--with-rail { grid-template-columns: minmax(0, 720px) 260px; }

.post-main    { grid-column: 1; grid-row: 1; min-width: 0; }

/* ── Table of contents (PUBLIC-UI-1 FEATURE 1) ────────────
   A <details> element: collapsible with ZERO JavaScript, which is what lets
   this ship under a CSP with no unsafe-inline for scripts. Placed in column 2
   by CSS while sitting FIRST in the DOM, so on a phone it collapses above the
   article instead of being buried under it. */
.post-toc {
  grid-column: 2;
  grid-row: 1;
  position: sticky;
  /* Clears the sticky header. At the old flat 24px the pinned panel lost its
     top 37px — including its own "Spis treści" title — behind the header. */
  top: var(--header-offset);
  margin-top: 96px;
  padding: 18px 20px;
  background: var(--accent-soft);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  max-height: calc(100vh - var(--header-offset) - 24px);
  overflow-y: auto;
}

.post-toc__summary {
  font-size: 13px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--accent);
  cursor: pointer;
  list-style: none;
}

/* The default disclosure triangle is replaced by a caret that flips on open. */
.post-toc__summary::-webkit-details-marker { display: none; }
.post-toc__summary::after {
  content: "▾";
  float: right;
  font-size: 11px;
  transition: transform 0.15s;
}
.post-toc[open] .post-toc__summary::after { transform: rotate(180deg); }

.post-toc__nav  { margin-top: 12px; }
.post-toc__list { list-style: none; margin: 0; padding: 0; }

.post-toc__item { margin-bottom: 9px; line-height: 1.4; }
.post-toc__item--h3 { padding-left: 14px; }

.post-toc__link {
  font-size: 13.5px;
  color: var(--muted);
  text-decoration: none;
  transition: color 0.15s;
}

.post-toc__link:hover { color: var(--accent); text-decoration: underline; }

/* Anchored headings must not land under the sticky header.
   CODE REVIEW 2026-07-31 (finding 1): at the old flat 24px they landed
   COMPLETELY under it — the header is 61px, so a heading jumped to y=24 sat
   entirely inside the header's band. Clicking a ToC entry scrolled the reader
   to an invisible heading and dropped them on the paragraph after it, which
   makes the feature worse than not having it. */
.post-body h2[id],
.post-body h3[id] { scroll-margin-top: var(--header-offset); }

/* ── Popular articles carousel (PUBLIC-UI-1 FEATURE 2) ────
   CSS-ONLY. scroll-snap + overflow-x, no JavaScript and no external asset:
   native momentum scrolling on touch, shift+wheel and keyboard on desktop. An
   inline arrow handler would violate the app's CSP (script-src has no
   unsafe-inline precisely so those get caught). */
.post-popular { margin: 44px 0; }

.post-popular__heading {
  font-size: 19px;
  font-weight: 700;
  color: var(--ink);
  letter-spacing: -0.01em;
  margin-bottom: 16px;
}

.post-popular__track {
  display: flex;
  gap: 16px;
  list-style: none;
  margin: 0;
  padding: 4px 0 12px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: thin;
  -webkit-overflow-scrolling: touch;
}

.post-popular__card {
  flex: 0 0 240px;
  scroll-snap-align: start;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  transition: border-color 0.15s;
}

.post-popular__card:hover { border-color: var(--accent); }

.post-popular__link {
  display: block;
  text-decoration: none;
  color: inherit;
  height: 100%;
}

.post-popular__thumb { border-bottom: 1px solid var(--line); }

.post-popular__title {
  font-size: 15px;
  font-weight: 700;
  line-height: 1.35;
  color: var(--ink);
  margin: 12px 14px 6px;
}

.post-popular__excerpt {
  font-size: 13px;
  line-height: 1.55;
  color: var(--muted);
  margin: 0 14px 10px;
}

.post-popular__meta {
  font-size: 11.5px;
  color: var(--muted);
  margin: 0 14px 14px;
}


/* ── More from this brand (PUBLIC-UI-1 FEATURE 3) ─────────
   Every card here is an AffiliateProduct the operator promoted out of the feed
   by hand; staging rows can never reach this markup. */
.post-merchant {
  margin: 40px 0;
  padding: 26px 24px;
  background: var(--accent-soft);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}

.post-merchant__heading {
  font-size: 19px;
  font-weight: 700;
  color: var(--ink);
  letter-spacing: -0.01em;
  margin-bottom: 16px;
}

.post-merchant__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 14px;
  list-style: none;
  margin: 0;
  padding: 0;
}

.post-merchant__card {
  display: flex;
  flex-direction: column;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  overflow: hidden;
}

/* Out of stock is MARKED, never hidden — a silently removed row is not honest. */
.post-merchant__card--unavailable { opacity: 0.72; }

.post-merchant__thumb {
  aspect-ratio: 1 / 1;
  background: var(--accent-soft);
  display: flex;
  align-items: center;
  justify-content: center;
}

.post-merchant__img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.post-merchant__body {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 12px 13px 13px;
  flex: 1;
}

.post-merchant__name {
  font-size: 13.5px;
  font-weight: 600;
  line-height: 1.35;
  color: var(--ink);
}

.post-merchant__card--unavailable .post-merchant__name {
  text-decoration: line-through;
  text-decoration-color: var(--muted);
}

.post-merchant__unavailable {
  font-size: 11.5px;
  font-weight: 600;
  color: #9A4B2F;
}

.post-merchant__price {
  font-size: 14.5px;
  font-weight: 700;
  color: var(--accent);
}

.post-merchant__cta {
  margin-top: auto;
  padding-top: 8px;
  font-size: 13px;
  font-weight: 600;
  color: var(--accent);
  text-decoration: none;
}

.post-merchant__cta:hover { text-decoration: underline; }

.post-merchant__disclosure {
  font-size: 11.5px;
  color: var(--muted);
  margin-top: 14px;
  line-height: 1.5;
}

/* ── Footer ───────────────────────────────────────────── */
.blog-footer {
  border-top: 1px solid var(--line);
  margin-top: 20px;
}

.blog-footer__inner {
  max-width: 1100px;
  margin: 0 auto;
  padding: 18px 24px;
  font-size: 12px;
  color: var(--muted);
  display: flex;
  gap: 20px;
  flex-wrap: wrap;
  align-items: center;
}

.blog-footer a {
  color: var(--muted);
  text-decoration: none;
  transition: color 0.15s;
}

.blog-footer a:hover { color: var(--ink); }

/* ── Responsive ───────────────────────────────────────── */
@media (max-width: 900px) {
  .posts-grid { grid-template-columns: repeat(2, 1fr); }
}

/* PUBLIC-UI-1: below the width that fits an article plus a rail, the layout
   collapses to one column and the ToC becomes the collapsible panel ABOVE the
   article — which is why it is first in the DOM. It stops being sticky here:
   a sticky panel on a phone eats the viewport it is supposed to help navigate. */
@media (max-width: 1040px) {
  .post-layout,
  .post-layout--with-rail { grid-template-columns: minmax(0, 720px); }
  .post-toc, .post-main { grid-column: 1; }
  .post-toc  { grid-row: 1; position: static; margin: 24px 0 0; max-height: none; }
  .post-main { grid-row: 2; }
}

@media (max-width: 640px) {
  /* Padding-x only: the height stays governed by --header-h at every breakpoint,
     so the anchor/sticky offsets derived from it hold on mobile too (the header
     is sticky there as well). */
  .blog-header__inner { padding: 0 16px; gap: 12px; }
  .blog-nav { gap: 16px; }
  .blog-wrap        { padding: 0 16px; }
  .blog-wrap--wide  { padding: 0 16px; }
  .featured-row     { grid-template-columns: 1fr; }
  .posts-grid       { grid-template-columns: 1fr; }
  .section-header   { padding: 28px 0 16px; }
  .post__title      { font-size: 24px; }
  .email-signup     { padding: 22px 16px; }
  .email-signup__form      { flex-direction: column; }
  .email-signup__btn       { width: 100%; text-align: center; }

  /* Comparison table → stacked cards. A 4-column table cannot be read on a
     phone, and phones are where nearly all the Pinterest traffic lands. Each
     row becomes a card; each cell prints its own column name from data-label
     (set in posts/_comparison), so no header is lost. */
  .post-comparison  { padding: 20px 16px; }
  .post-merchant    { padding: 20px 16px; }
  .post-merchant__grid { grid-template-columns: repeat(2, 1fr); }
  /* Cards narrow enough that two peek at the edge — the affordance that tells
     a reader the row scrolls, without a JS arrow. */
  .post-popular__card  { flex: 0 0 200px; }
  .comparison-table,
  .comparison-table tbody,
  .comparison-table tr,
  .comparison-table td { display: block; width: 100%; }
  .comparison-table thead { display: none; }
  .comparison-table { border: none; background: transparent; }
  .comparison-table tr {
    background: var(--card);
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    padding: 6px 0;
    margin-bottom: 12px;
  }
  .comparison-table tbody tr:last-child { margin-bottom: 0; }
  .comparison-table td { border-bottom: none; padding: 7px 14px; }
  .comparison-table td[data-label]::before {
    content: attr(data-label);
    display: block;
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--muted);
    margin-bottom: 3px;
  }
  .comparison-cta   { white-space: normal; }
  .comparison-link  { display: block; text-align: center; }
}
