/* U52 — the blog's own styles.  Redesigned 2026-10-29.
 *
 * ⚠ AUTHORED HERE, IN THE DESIGN SOURCE, NOT IN posplus_pk_flask/static/.
 * tools/sync_templates.py copies css/ js/ assets/ fonts/ from this folder
 * into the app's static/ on every run, so a stylesheet written straight into
 * static/ would survive until the next sync and then quietly diverge from
 * the design source for ever. Design lives here; the app receives it.
 *
 * ⚠ IT LAYERS ON site.css, AND THAT IS NOW THE POINT. The first redesign
 * fixed the typography and the blog still read as a different, smaller
 * website — because it wore a three-item bar and a one-line footer while
 * posplus.pk wears a full nav, a deep-forest hero, a four-column footer and
 * a floating WhatsApp button. Those all come from site.css; the blog now
 * uses them, and this file adds only what a blog needs on top.
 */

/* ---- the article serif ---------------------------------------------------
   Loaded by the BLOG ONLY. It is 122 KB against Inter's 48 KB, and it earns
   that on a 2,000-word article where it is the difference between a web page
   and something that reads like a publication. It earns nothing on a product
   page whose longest text is a feature card — so a product page, which loads
   site.css and not this file, never downloads it.
   Self-hosted, `swap`, real fallback stack. See ../fonts/README.md (OFL 1.1). */
@font-face {
  font-family: "Source Serif 4 var";
  src: url("/fonts/source-serif-4-latin-var.woff2") format("woff2");
  font-weight: 200 900;
  font-style: normal;
  font-display: swap;
}

:root {
  /* The measure. ~68 characters of this serif at this size — the comfort
     band is 60–75, and the page is laid out around this number rather than
     the other way round. */
  --measure: 44rem;
  --side: 20rem;
  --gap: 3rem;
}

/* ---- motion --------------------------------------------------------------
   ⚠ ONE RULE GOVERNS EVERY ANIMATION IN THIS FILE, and it is at the top so
   it cannot be forgotten at the bottom: a reader who has asked their system
   for reduced motion gets none of it. Vestibular disorders are real and this
   is a page of long text, which is exactly where parallax and slide-ins do
   damage. Everything below degrades to "already in its final state". */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
}

/* Cards and sections arrive as the reader reaches them. ⚠ The default state
   is VISIBLE, and blog.js adds `.reveal-armed` to hide them — so with
   JavaScript off, or if the script fails, the page is simply a normal page
   rather than a column of invisible articles. That direction matters more
   than the effect does. */
.reveal-armed .reveal { opacity: 0; transform: translateY(14px); }
.reveal.shown { opacity: 1; transform: none; transition: opacity .55s var(--ease), transform .55s var(--ease); }

/* ---- the hero ------------------------------------------------------------
   The site's deep-forest sky, the same gradient family the umbrella opens
   with, so a reader arriving from the homepage stays in one brand. */
.blog-hero {
  position: relative;
  background: linear-gradient(160deg, var(--navy-1) 0%, var(--navy-2) 55%, #0c3a1e 100%);
  color: #fff;
  padding-block: 72px 86px;
  overflow: hidden;
  isolation: isolate;
}
/* The glow. Two soft radial washes that drift — slowly enough to be felt
   rather than watched, and frozen entirely under reduced motion. */
.bhero-glow {
  position: absolute; inset: -40% -20% auto -20%; height: 150%;
  background:
    radial-gradient(42% 46% at 22% 28%, rgba(34, 197, 94, .38), transparent 70%),
    radial-gradient(38% 40% at 78% 18%, rgba(251, 191, 36, .22), transparent 70%);
  filter: blur(14px);
  animation: drift 22s ease-in-out infinite alternate;
  z-index: -1;
}
@keyframes drift {
  from { transform: translate3d(-2%, -1%, 0) scale(1); }
  to   { transform: translate3d(3%, 2%, 0) scale(1.08); }
}
.bhero-inner { position: relative; text-align: center; }
.blog-hero .pill {
  display: inline-flex; align-items: center; gap: 8px;
  background: rgba(255, 255, 255, .1); border: 1px solid rgba(255, 255, 255, .22);
  color: #d9f7e4; border-radius: 999px; padding: 7px 16px;
  font-size: .82rem; font-weight: 600; letter-spacing: .02em;
  backdrop-filter: blur(6px);
}
.blog-hero .pill svg { width: 15px; height: 15px; }
.blog-hero h1 {
  margin: 22px auto 16px; max-width: 18ch;
  font-size: clamp(2.1rem, 1.2rem + 3.6vw, 3.6rem);
  line-height: 1.08; letter-spacing: -.035em; font-weight: 800;
}
/* The one coloured word, exactly as the umbrella headline does it. */
.blog-hero h1 em {
  font-style: normal;
  background: linear-gradient(100deg, #4ade80, #fbbf24);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.bhero-lead {
  margin: 0 auto; max-width: 56ch; color: #c6dbcd;
  font-size: clamp(1rem, .95rem + .3vw, 1.15rem); line-height: 1.65;
}
.bhero-meta {
  display: flex; gap: 14px; align-items: center; justify-content: center;
  margin-top: 26px; color: #a9c4b3; font-size: .9rem; flex-wrap: wrap;
}
.bhero-meta b { color: #fff; }
.bhero-meta a { color: #8ee6ad; text-decoration: none; }
.bhero-meta a:hover { color: #fff; }
.bhero-meta .sep { width: 4px; height: 4px; border-radius: 50%; background: currentColor; opacity: .5; }

/* The nav's current page. The site's nav has no "here" state because the
   umbrella is one page; the blog has several. */
.nav-links a.here { color: var(--brand-deep); font-weight: 700; }

/* ---- the two-column body -------------------------------------------------
   ⚠ The sidebar DROPS BELOW the content under 1100px rather than squeezing.
   A 20rem rail beside a 44rem column needs 64rem plus gutters; below that
   the measure is what gives, and the measure is the one thing on a blog that
   must not. */
.blog-body { padding-block: 44px 80px; }
@media (min-width: 1100px) {
  .blog-body { display: grid; grid-template-columns: minmax(0, 1fr) var(--side); gap: var(--gap); align-items: start; }
}
.blog-main { min-width: 0; }

/* ---- the sidebar ---------------------------------------------------------- */
.sidebar { display: grid; gap: 18px; align-content: start; }
@media (min-width: 1100px) { .sidebar { position: sticky; top: 92px; } }
.side-card {
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 20px 22px;
}
.side-title {
  display: flex; align-items: center; gap: 9px;
  margin: 0 0 14px; font-size: .78rem; font-weight: 700;
  letter-spacing: .12em; text-transform: uppercase; color: var(--ink-faint);
}
.side-title svg { width: 15px; height: 15px; stroke: var(--brand); fill: none; stroke-width: 2; }
.side-eyebrow {
  display: block; font-size: .72rem; font-weight: 700; letter-spacing: .13em;
  text-transform: uppercase; color: var(--brand-deep); margin-bottom: 8px;
}

/* The product CTA. Tinted, so it reads as an offer rather than as another
   list of links — the one commercial element on a page of plain advice. */
.cta-card {
  background: linear-gradient(170deg, #0f3b22, #0a2a18);
  border-color: #17502f; color: #e8f6ed;
}
.cta-card .side-eyebrow { color: #8ee6ad; }
.cta-card b { display: block; font-size: 1.15rem; color: #fff; margin-bottom: 6px; }
.cta-card p { margin: 0 0 16px; color: #bcd6c6; font-size: .92rem; line-height: 1.55; }
.cta-note { display: block; margin-top: 12px; font-size: .76rem; color: #8fae9c; line-height: 1.5; }
.btn-block { width: 100%; justify-content: center; }
.btn-wa { background: #25d366; color: #05270f; font-weight: 700; }
.btn-wa:hover { background: #1fbe59; }

.side-series { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
.side-series a {
  display: block; text-decoration: none; padding: 11px 13px;
  border: 1px solid var(--line); border-radius: 12px;
  transition: border-color .2s var(--ease), background .2s var(--ease), transform .2s var(--ease);
}
.side-series a:hover { border-color: var(--brand); background: #f3faf5; transform: translateX(3px); }
.s-name { display: block; font-weight: 650; color: var(--ink); font-size: .95rem; line-height: 1.35; }
.s-parts { display: block; margin-top: 3px; font-size: .78rem; color: var(--brand-deep); font-weight: 600; }

.side-posts { list-style: none; margin: 0; padding: 0; display: grid; gap: 13px; }
.side-posts a { text-decoration: none; display: block; }
.side-posts .p-title {
  display: block; color: var(--ink); font-weight: 600; font-size: .93rem; line-height: 1.4;
  transition: color .2s var(--ease);
}
.side-posts a:hover .p-title { color: var(--brand-deep); }
.side-posts time { display: block; margin-top: 2px; font-size: .76rem; color: var(--ink-faint); }
.side-more { display: inline-block; margin-top: 12px; font-size: .86rem; font-weight: 600; color: var(--brand-deep); text-decoration: none; }
.side-more:hover { text-decoration: underline; }

.side-topics { display: flex; flex-wrap: wrap; gap: 8px; }
.topic {
  display: inline-flex; align-items: center; gap: 7px; text-decoration: none;
  background: var(--paper); border: 1px solid var(--line); border-radius: 999px;
  padding: 6px 12px; font-size: .84rem; font-weight: 600; color: var(--ink-soft);
  transition: all .2s var(--ease);
}
.topic:hover { border-color: var(--brand); color: var(--brand-deep); background: #f0f9f3; }
.topic span {
  background: #e8f6ed; color: var(--brand-deep); border-radius: 999px;
  padding: 0 7px; font-size: .72rem; font-weight: 700;
}
.wa-card p { margin: 0 0 15px; color: var(--ink-soft); font-size: .92rem; line-height: 1.55; }

/* ---- the index cards ------------------------------------------------------ */
.bsection-head {
  display: flex; align-items: center; gap: 16px;
  margin: 40px 0 20px; font-size: .78rem; font-weight: 700;
  letter-spacing: .13em; text-transform: uppercase; color: var(--ink-faint);
}
.bsection-head::after { content: ""; flex: 1; height: 1px; background: var(--line); }

.lead-card {
  display: block; background: var(--card); border: 1px solid var(--line);
  border-radius: var(--radius-lg); overflow: hidden; text-decoration: none;
  box-shadow: var(--shadow-1);
  transition: box-shadow .3s var(--ease), transform .3s var(--ease), border-color .3s var(--ease);
}
.lead-card:hover { box-shadow: var(--shadow-2); transform: translateY(-4px); border-color: #cfe3d6; }
.lead-card .shot { display: block; overflow: hidden; }
.lead-card .shot img {
  width: 100%; aspect-ratio: 2 / 1; object-fit: cover; display: block;
  transition: transform .6s var(--ease);
}
.lead-card:hover .shot img { transform: scale(1.04); }
.lead-card .body { padding: 26px 28px 28px; display: block; }
.bkicker {
  display: inline-block; background: var(--brand); color: #fff;
  border-radius: 999px; padding: 3px 11px; margin-bottom: 12px;
  font-size: .7rem; font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
}
.lead-card h2 {
  margin: 0 0 10px; color: var(--ink);
  font-size: clamp(1.35rem, 1rem + 1.5vw, 1.95rem);
  line-height: 1.2; letter-spacing: -.025em; font-weight: 800;
}
.lead-card:hover h2 { color: var(--brand-deep); }
.lead-card p { margin: 0 0 16px; color: var(--ink-soft); font-size: 1.02rem; line-height: 1.6; }
.read-on { margin-left: auto; color: var(--brand-deep); font-weight: 700; font-size: .86rem; }
.lead-card:hover .read-on { text-decoration: underline; }

.post-list { display: grid; gap: 18px; }
.post-card {
  display: grid; background: var(--card); border: 1px solid var(--line);
  border-radius: var(--radius); overflow: hidden;
  transition: box-shadow .3s var(--ease), transform .3s var(--ease), border-color .3s var(--ease);
}
.post-card:hover { box-shadow: var(--shadow-1); transform: translateY(-3px); border-color: #cfe3d6; }
/* ⚠ The two-column layout is OPT-IN. Without this class a card with no hero
   image still reserved the 200px image column and the text landed in it — so
   every title wrapped inside a narrow strip with 60% of the card empty. It
   looked fine in the HTML and fine in the empty state; only a screenshot of
   a populated index showed it. */
.post-card.with-shot { grid-template-columns: 210px 1fr; }
@media (max-width: 620px) { .post-card.with-shot { grid-template-columns: 1fr; } }
.post-card .shot { display: block; background: var(--paper); overflow: hidden; }
.post-card .shot img {
  display: block; width: 100%; height: 100%; aspect-ratio: 16 / 10; object-fit: cover;
  transition: transform .6s var(--ease);
}
.post-card:hover .shot img { transform: scale(1.05); }
.post-card .body { padding: 20px 22px; }
/* ⚠ The body keeps its LEFT padding beside the image. It was zero, which
   on a light screenshot made the text look like it was printed on top of
   the picture — measured and it was not (210px column, body at 325px),
   but the eye reads touching as overlapping, and the eye is the
   customer. */
.post-card.with-shot .body { padding: 20px 22px; }
@media (max-width: 620px) { .post-card.with-shot .body { padding: 0 18px 18px; } }
.post-card h3 { margin: 0 0 7px; font-size: 1.14rem; line-height: 1.32; letter-spacing: -.012em; font-weight: 700; }
.post-card h3 a { color: var(--ink); text-decoration: none; }
.post-card:hover h3 a { color: var(--brand-deep); }
.post-card p { margin: 0 0 11px; color: var(--ink-soft); font-size: .95rem; line-height: 1.55; }

/* The meta line is the same object on a card and on the article itself, so
   it is styled once. Dots between items, never commas — a comma reads as
   part of the preceding word at this size. */
.meta { display: flex; gap: 9px; align-items: center; flex-wrap: wrap; font-size: .82rem; color: var(--ink-faint); }
.meta .bdot { width: 3px; height: 3px; border-radius: 50%; background: currentColor; opacity: .55; }
.tag {
  display: inline-block; background: #e8f6ed; color: var(--brand-deep);
  border-radius: 999px; padding: 2px 10px; font-size: .74rem; font-weight: 700;
}

.blog-empty {
  background: var(--card); border: 1px dashed var(--line); border-radius: var(--radius);
  padding: 34px 28px; text-align: center;
}
.blog-empty h2 { margin: 0 0 8px; font-size: 1.15rem; }
.blog-empty p { margin: 0; color: var(--ink-soft); }

/* ---- series ---------------------------------------------------------------- */
.series-link { color: var(--brand-deep); font-weight: 600; text-decoration: none; }
.series-link:hover { text-decoration: underline; }

.series-list { display: grid; gap: 18px; }
.series-card {
  display: grid; background: var(--card); border: 1px solid var(--line);
  border-radius: var(--radius); overflow: hidden; text-decoration: none;
  grid-template-columns: 210px 1fr;
  transition: box-shadow .3s var(--ease), transform .3s var(--ease), border-color .3s var(--ease);
}
.series-card:hover { box-shadow: var(--shadow-1); transform: translateY(-3px); border-color: #cfe3d6; }
/* A series with no picture must not reserve the picture column — the
   post-card lesson, which only a screenshot of a populated page revealed. */
.series-card:not(:has(.shot)) { grid-template-columns: 1fr; }
@media (max-width: 620px) { .series-card { grid-template-columns: 1fr; } }
.series-card .shot { overflow: hidden; }
.series-card .shot img {
  display: block; width: 100%; height: 100%; aspect-ratio: 16 / 10; object-fit: cover;
  transition: transform .6s var(--ease);
}
.series-card:hover .shot img { transform: scale(1.05); }
.series-card .body { padding: 20px 22px; display: block; }
.series-card .eyebrow { display: block; margin-bottom: 6px; }
.series-title { display: block; font-size: 1.2rem; font-weight: 700; letter-spacing: -.015em; color: var(--ink); line-height: 1.3; }
.series-card:hover .series-title { color: var(--brand-deep); }
.series-blurb { display: block; margin-top: 7px; color: var(--ink-soft); font-size: .95rem; line-height: 1.55; }

/* The numbered parts on a series page. The number is the point — it is what
   tells a reader where to start — so it is a real element, not a list marker
   the browser may or may not show. */
.part-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 12px; }
.part a {
  display: grid; grid-template-columns: 44px 1fr; gap: 16px; align-items: start;
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 18px 20px; text-decoration: none;
  transition: border-color .2s var(--ease), box-shadow .2s var(--ease), transform .2s var(--ease);
}
.part a:hover { border-color: var(--brand); box-shadow: var(--shadow-1); transform: translateX(4px); }
.part-no {
  display: flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; border-radius: 50%;
  background: #e8f6ed; color: var(--brand-deep); font-weight: 800; font-size: .95rem;
}
.part a:hover .part-no { background: var(--brand); color: #fff; }
.part-title { display: block; font-weight: 700; color: var(--ink); line-height: 1.35; font-size: 1.06rem; }
.part a:hover .part-title { color: var(--brand-deep); }
.part-blurb { display: block; color: var(--ink-soft); font-size: .92rem; margin-top: 5px; line-height: 1.5; }
.part .meta { margin-top: 7px; }

/* The badge above an article's title. A reader who lands on part four from a
   search result has to learn there is a part one BEFORE they start. */
.series-badge {
  display: inline-flex; align-items: center; gap: 9px; text-decoration: none;
  background: #e8f6ed; border: 1px solid #c6e6d2; border-radius: 999px;
  padding: 5px 14px 5px 6px; margin-bottom: 16px;
  font-size: .85rem; color: var(--brand-deep); font-weight: 600;
  transition: background .2s var(--ease);
}
.series-badge:hover { background: #d8eee1; }
.series-badge .label {
  background: var(--brand-deep); color: #fff; border-radius: 999px;
  padding: 2px 9px; font-size: .7rem; font-weight: 700;
  letter-spacing: .08em; text-transform: uppercase;
}

/* Prev / next at the foot of a part. Both ends are honest: part one shows no
   "previous" rather than a dead arrow. */
.series-nav { margin-top: 44px; border-top: 1px solid var(--line); padding-top: 24px; }
.series-nav .ends { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
@media (max-width: 620px) { .series-nav .ends { grid-template-columns: 1fr; } }
.series-nav .end {
  display: block; text-decoration: none; background: var(--card);
  border: 1px solid var(--line); border-radius: var(--radius); padding: 14px 18px;
  transition: border-color .2s var(--ease), transform .2s var(--ease);
}
.series-nav .end:hover { border-color: var(--brand); transform: translateY(-2px); }
/* When there is no previous, the next must not stretch across the whole row
   as if it were both. */
.series-nav .end.next:only-child { grid-column: 2; }
@media (max-width: 620px) { .series-nav .end.next:only-child { grid-column: 1; } }
.series-nav .end.next { text-align: right; }
.series-nav .dir { display: block; font-size: .74rem; text-transform: uppercase; letter-spacing: .11em; color: var(--ink-faint); font-weight: 700; margin-bottom: 4px; }
.series-nav .t { display: block; color: var(--ink); font-weight: 600; line-height: 1.35; }
.series-nav .end:hover .t { color: var(--brand-deep); }
.series-nav .all-parts { display: inline-block; margin-top: 16px; color: var(--brand-deep); font-weight: 600; font-size: .92rem; text-decoration: none; }
.series-nav .all-parts:hover { text-decoration: underline; }

/* ---- the article page ------------------------------------------------------ */
.article-head {
  background: linear-gradient(170deg, #f3f8f4, var(--paper));
  border-bottom: 1px solid var(--line);
  padding-block: 34px 30px;
}
/* ⚠ The head band and the article body must share ONE left edge. The band
   was centred on its own narrower wrap, so the headline started ~70px to the
   right of the first paragraph beneath it — a misalignment that is invisible
   in the markup and obvious the moment you look at the whole page. The band
   now uses the site wrap and constrains its CONTENT to the same measure the
   body column uses. */
.article-head .post { max-width: var(--measure); }
.crumbs { font-size: .82rem; color: var(--ink-faint); margin-bottom: 16px; }
.crumbs a { color: var(--ink-soft); text-decoration: none; }
.crumbs a:hover { color: var(--brand); }
.crumbs span { margin: 0 4px; opacity: .6; }

.post h1 {
  font-size: clamp(1.9rem, 1.1rem + 3.2vw, 3rem);
  margin: 0 0 14px; letter-spacing: -.03em; line-height: 1.12; font-weight: 800;
}
/* The standfirst: one sentence, bigger than the body, that tells the reader
   what they will know by the end. It is the EXCERPT, reused — so the index
   card and the article cannot disagree about what the piece is. */
.standfirst {
  font-size: 1.2rem; line-height: 1.5; color: var(--ink-soft);
  margin: 0 0 20px; max-width: 48ch;
}
.byline {
  display: flex; gap: 10px; align-items: center; flex-wrap: wrap;
  color: var(--ink-faint); font-size: .88rem;
}
.byline .who { color: var(--ink-soft); font-weight: 600; }
.byline .bdot { width: 3px; height: 3px; border-radius: 50%; background: currentColor; opacity: .55; }

.article-grid { padding-block: 36px 80px; }
@media (min-width: 1100px) {
  .article-grid { display: grid; grid-template-columns: minmax(0, 1fr) var(--side); gap: var(--gap); align-items: start; }
}
.article-main { min-width: 0; max-width: var(--measure); }

.bfigure { margin: 0 0 32px; }
.bfigure img {
  width: 100%; border-radius: var(--radius-lg); border: 1px solid var(--line);
  aspect-ratio: 2 / 1; object-fit: cover;
}
.bfigure figcaption { font-size: .82rem; color: var(--ink-faint); margin-top: 9px; text-align: center; }

/* ---- the contents list ----------------------------------------------------- */
.toc { font-size: .88rem; background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); padding: 18px 20px; }
.toc-title {
  font-size: .72rem; font-weight: 700; letter-spacing: .13em; text-transform: uppercase;
  color: var(--ink-faint); margin: 0 0 12px;
}
.toc ol { list-style: none; margin: 0; padding: 0; border-left: 2px solid var(--line); }
.toc li { margin: 0; }
.toc li.sub a { padding-left: 26px; font-size: .84rem; color: var(--ink-faint); }
.toc a {
  display: block; padding: 6px 0 6px 14px; margin-left: -2px;
  border-left: 2px solid transparent; color: var(--ink-soft);
  text-decoration: none; line-height: 1.4;
  transition: color .2s var(--ease), border-color .2s var(--ease);
}
.toc a:hover { color: var(--brand-deep); border-left-color: var(--line); }
/* Where the reader IS, not merely where they can go. Set by blog.js. */
.toc a.here { color: var(--brand-deep); font-weight: 700; border-left-color: var(--brand); }

/* ---- the prose -------------------------------------------------------------- */
.prose {
  font-family: "Source Serif 4 var", Georgia, "Times New Roman", serif;
  font-size: 1.16rem; line-height: 1.72; color: #16241b;
  /* The optical-size axis is the point of this family: at body size it opens
     the letterforms up instead of using a shrunk display cut. */
  font-optical-sizing: auto;
}
.prose > :first-child { margin-top: 0; }
.prose p { margin: 0 0 1.2em; }
/* Headings stay in the SANS. The contrast between a sans heading and a serif
   paragraph is what makes the structure of a long article visible at a
   glance; setting both in the serif makes a 2,000-word piece one grey slab. */
.prose h2, .prose h3, .prose h4 {
  font-family: "Inter var", "Segoe UI", system-ui, sans-serif;
  letter-spacing: -.02em; line-height: 1.25; font-weight: 800; color: var(--ink);
  scroll-margin-top: 90px;
}
.prose h2 {
  font-size: 1.52rem; margin: 2em 0 .6em; padding-top: .55em;
  border-top: 1px solid var(--line);
}
.prose h3 { font-size: 1.2rem; margin: 1.7em 0 .45em; font-weight: 700; }
.prose h4 { font-size: 1.04rem; margin: 1.5em 0 .4em; font-weight: 700; }
/* A heading the reader can link to. The anchor is invisible until the
   heading is hovered, so it never competes with the words. */
.prose .anchor {
  margin-left: .35em; color: var(--ink-faint); text-decoration: none;
  opacity: 0; transition: opacity .15s; font-weight: 400;
}
.prose h2:hover .anchor, .prose h3:hover .anchor, .prose .anchor:focus { opacity: 1; }

.prose ul, .prose ol { margin: 0 0 1.2em; padding-left: 1.3em; }
.prose li { margin-bottom: .45em; }
.prose li::marker { color: var(--brand); }
.prose a { color: var(--brand-deep); text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 1.5px; }
.prose a:hover { background: #e8f6ed; }
.prose strong { font-weight: 700; color: var(--ink); }
.prose img { max-width: 100%; height: auto; border-radius: 12px; border: 1px solid var(--line); margin: .6em 0; }

/* A PULL QUOTE, not an indented paragraph. A blockquote in a trade article
   is almost always the shopkeeper's own words, and those are the most
   quotable thing on the page — so it is set large, in the serif, with the
   rule as an accent rather than a cage. */
.prose blockquote {
  margin: 1.8em 0; padding: 2px 0 2px 24px;
  border-left: 3px solid var(--brand);
  font-size: 1.25rem; line-height: 1.5; color: var(--ink); font-style: italic;
}
.prose blockquote p:last-child { margin-bottom: 0; }

/* CALLOUTS. Built at render time from an author's own convention (a quote
   beginning with ⚠ or "Note:"), because the editor cannot emit classes and
   the sanitiser would strip them if it could. See enrich_article() in app.py. */
.prose .callout {
  margin: 1.7em 0; padding: 16px 20px 16px 22px; border-radius: 14px;
  background: #e8f6ed; border: 1px solid #c6e6d2; border-left: 4px solid var(--brand);
  font-family: "Inter var", "Segoe UI", system-ui, sans-serif;
  font-size: 1rem; line-height: 1.6; color: #14361f; font-style: normal;
}
.prose .callout.warn { background: #fffbeb; border-color: #fde68a; border-left-color: #f59e0b; color: #78350f; }
.prose .callout p:last-child { margin-bottom: 0; }
.prose .callout strong { color: inherit; }

.prose code {
  font-size: .9em; background: var(--paper); border: 1px solid var(--line);
  border-radius: 6px; padding: 1px 6px;
  font-family: ui-monospace, "Cascadia Mono", Consolas, monospace;
}
.prose pre {
  background: #0f1c14; color: #e6f2ea; padding: 18px 20px; border-radius: 14px;
  overflow-x: auto; font-size: .92rem; line-height: 1.6;
  font-family: ui-monospace, "Cascadia Mono", Consolas, monospace;
}
.prose pre code { background: none; border: 0; padding: 0; color: inherit; font-size: 1em; }
.prose hr { border: 0; border-top: 1px solid var(--line); margin: 2.4em 0; }

/* A table is the one thing in an article that can be wider than the column,
   so it gets its OWN scroller rather than pushing the page sideways.
   ⚠ The wrapper is added at render time: `display:block` on the <table>
   itself (the old cure) breaks the column widths, because a block table
   stops being a table for layout. */
.prose .table-scroll { overflow-x: auto; margin: 0 0 1.4em; -webkit-overflow-scrolling: touch; border-radius: 12px; border: 1px solid var(--line); }
.prose table { width: 100%; border-collapse: collapse; font-size: .96rem;
  font-family: "Inter var", "Segoe UI", system-ui, sans-serif; }
.prose th, .prose td { border-bottom: 1px solid var(--line); padding: 10px 14px; text-align: left; vertical-align: top; }
.prose th { background: var(--paper); font-weight: 700; font-size: .86rem; letter-spacing: .02em; text-transform: uppercase; color: var(--ink-soft); }
.prose tbody tr:last-child td { border-bottom: 0; }
.prose tbody tr:hover td { background: #f7fbf8; }

.prose figure { margin: 1.6em 0; }
.prose figcaption {
  font-family: "Inter var", "Segoe UI", system-ui, sans-serif;
  font-size: .84rem; color: var(--ink-faint); margin-top: 8px; text-align: center;
}

/* ---- after the article ------------------------------------------------------ */
.to-product {
  display: flex; gap: 18px; align-items: center; justify-content: space-between;
  flex-wrap: wrap; margin: 46px 0 0;
  background: linear-gradient(165deg, #0f3b22, #0a2a18);
  border: 1px solid #17502f; border-radius: var(--radius-lg); padding: 26px 28px;
  color: #e8f6ed;
}
.to-product b { font-size: 1.12rem; color: #fff; }
.to-product p { margin: 5px 0 0; color: #bcd6c6; font-size: .93rem; }

.read-next { margin-top: 38px; border-top: 1px solid var(--line); padding-top: 26px; }
.read-next h2 {
  font-size: .76rem; margin: 0 0 16px; text-transform: uppercase;
  letter-spacing: .13em; color: var(--ink-faint); font-weight: 700;
}
.read-next ul { margin: 0; padding: 0; list-style: none; display: grid; gap: 12px; }
.read-next a {
  color: var(--ink); font-weight: 600; text-decoration: none; line-height: 1.4;
  display: block; padding: 13px 16px; border: 1px solid var(--line);
  border-radius: 12px; background: var(--card);
  transition: border-color .2s var(--ease), transform .2s var(--ease);
}
.read-next a:hover { color: var(--brand-deep); border-color: var(--brand); transform: translateX(4px); }
.read-next .hint { display: block; font-weight: 400; font-size: .85rem; color: var(--ink-faint); margin-top: 3px; }

/* The staff preview bar. Loud on purpose — an author must never mistake a
   preview for the live page and assume the work is published. */
.draft-bar {
  background: #fef9c3; border-bottom: 1px solid #fde047; color: #854d0e;
  padding: 10px 20px; text-align: center; font-size: .9rem;
}

/* The reading-progress line. One pixel of chrome that answers "how much is
   left?" — the question a long article raises and a scrollbar answers badly
   on a page this tall. */
.progress {
  position: fixed; top: 0; left: 0; height: 3px; width: 0;
  background: linear-gradient(90deg, var(--brand), #fbbf24);
  z-index: 60; transition: width .1s linear;
}

@media print {
  .progress, .toc, .read-next, .to-product, .sidebar, .nav, .footer, .wa-fab,
  .blog-hero { display: none !important; }
}

/* The article's right column: the contents list sits above the sidebar
   widgets and both scroll together, so the rail is one object rather than
   two things competing for the same sticky position. */
.article-side { display: grid; gap: 18px; align-content: start; }
@media (min-width: 1100px) { .article-side { position: sticky; top: 92px; } }
.article-side .sidebar { position: static; }

/* The nav gains a shadow once the reader leaves the hero — it is a light bar
   on a dark hero at rest, and needs the edge only when content runs under it. */
.nav.scrolled { box-shadow: 0 1px 0 var(--line), var(--shadow-1); }

/* ---- the footer's product thumbnails ------------------------------------
   `b`-prefixed, like every class the blog INVENTS, because this stylesheet
   layers on site.css and a bare `.foot-prod` is one name collision away from
   the homepage (see the .hero-inner lesson). `.footer` / `.footer-col` are
   deliberately NOT redefined — they are shared on purpose.

   The thumbnail is a 72px asset painted at 34px, so it is already 2x on a
   retina screen. `object-fit: cover` matters: the crop is square but a
   future asset might not be, and a squashed screenshot looks broken in a way
   a cropped one does not. */
.footer-col a.bfoot-prod {
  display: flex; align-items: center; gap: 10px; padding: 5px 0;
}
.footer-col a.bfoot-prod img {
  width: 34px; height: 34px; flex: 0 0 34px; border-radius: 9px;
  object-fit: cover; object-position: left top; background: #fff;
  border: 1px solid rgba(15, 23, 42, .10);
  transition: transform .18s ease, border-color .18s ease;
}
.footer-col a.bfoot-prod:hover img {
  transform: scale(1.06); border-color: rgba(22, 163, 74, .45);
}
@media (prefers-reduced-motion: reduce) {
  .footer-col a.bfoot-prod img { transition: none; }
  .footer-col a.bfoot-prod:hover img { transform: none; }
}
