/* ==========================================================================
   bonu7 game — pages/blog.css
   The journal: listing page (featured lead + card grid + filter chips) and
   the article page (hero, sticky TOC, editorial prose, related rail).

   Built entirely on the existing system. No new colours, no new fonts, no new
   shadows — every value below resolves to a token from tokens.css, and every
   card is a .gem so the facet cut and hairline come for free.

   Thumbnails
   ----------
   Every thumb slot renders a branded facet placeholder UNDERNEATH the <img>.
   Drop a file in assets/images/blog/ and it covers the placeholder; if the
   file is missing or fails, blog.js removes the broken <img> and the
   placeholder shows through. The layout never collapses either way.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Thumbnail slot — shared by every card, the featured lead and the
      article hero. 16:9 everywhere so one uploaded size fits all of them.
   -------------------------------------------------------------------------- */
/* 16:9 EVERYWHERE — card, featured lead and article hero alike, at every
   breakpoint. This is load-bearing, not a style preference. Article artwork is
   a designed banner with a logo, a headline and a device mockup baked into it,
   and object-fit:cover crops whatever does not fit the slot. Give the slot any
   other ratio and the art loses its edges: a 2:1 hero shaved the top and bottom
   off, and a stretched side-by-side lead sliced ~15% off each side, taking the
   logo with it. One ratio, matching the source, crops nothing. */
.thumb {
  display: block;
  position: relative;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background: var(--ink-900);
  isolation: isolate;
}

.thumb__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Belt and braces for a future upload that is not exactly 16:9: crop from
     the centre outward rather than from a corner. */
  object-position: 50% 50%;
  z-index: 2;
  transition: transform 680ms var(--ease);
}

/* The placeholder: facet mesh + a gold rule, so an image-less card still
   reads as "ours" rather than as a broken asset. */
.thumb__ph {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: grid;
  place-items: center;
  background:
    radial-gradient(ellipse 80% 90% at 22% 18%, rgba(229, 52, 44, .16) 0%, transparent 62%),
    radial-gradient(ellipse 70% 80% at 84% 88%, rgba(201, 162, 75, .16) 0%, transparent 60%),
    linear-gradient(152deg, #fbf2f0 0%, #f6e9e6 52%, #f2e0dc 100%);
}
.thumb__ph::before {
  content: '';
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(115deg, transparent 47.4%, rgba(163, 34, 31, .16) 47.6%, rgba(163, 34, 31, .16) 48.2%, transparent 48.4%),
    linear-gradient(65deg, transparent 61.4%, rgba(163, 34, 31, .12) 61.6%, rgba(163, 34, 31, .12) 62.2%, transparent 62.4%),
    linear-gradient(115deg, transparent 74.4%, rgba(201, 162, 75, .22) 74.6%, rgba(201, 162, 75, .22) 75.2%, transparent 75.4%);
}
.thumb__mark {
  position: relative;
  display: grid;
  place-items: center;
  gap: 0.35rem;
  padding: 0.9rem 1.4rem;
  text-align: center;
  background: rgba(255, 255, 255, .62);
  box-shadow: inset 0 0 0 1px var(--stroke);
  clip-path: var(--cut-one);
}
.thumb__mark .ico { width: 26px; height: 26px; color: var(--em-600); }
.thumb__mark b {
  font-family: var(--font-ui);
  font-size: 0.66rem;
  font-weight: 800;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--text-faint);
}

/* Category label. Deliberately NOT floated over the thumbnail: the artwork
   carries its own logo, headline and mockup, so a corner badge lands on top of
   the branding it is meant to sit beside. In the card body it reads cleanly
   against any artwork we ever publish. */
.post-cat {
  display: inline-flex;
  align-items: center;
  gap: 0.42em;
  padding: 0.3em 0.72em;
  font-family: var(--font-ui);
  font-size: 0.68rem;
  font-weight: 800;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--em-800);
  background: rgba(229, 52, 44, .10);
  box-shadow: inset 0 0 0 1px var(--stroke-hot);
  clip-path: var(--cut-one);
  white-space: nowrap;
}
.post-cat .ico { width: 13px; height: 13px; flex: none; }
.post-cat--gold {
  color: var(--gold-lo);
  background: rgba(201, 162, 75, .14);
  box-shadow: inset 0 0 0 1px rgba(143, 111, 44, .34);
}

/* Hover wash. Light: it is an affordance cue, not a scrim for overlaid text,
   and the artwork underneath is already saturated. */
.thumb::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 3;
  background: linear-gradient(180deg, rgba(32, 7, 5, .04) 0%, rgba(32, 7, 5, .26) 100%);
  opacity: 0;
  transition: opacity var(--t-slow) var(--ease);
  pointer-events: none;
}

/* --------------------------------------------------------------------------
   2. Listing — filter chips
   -------------------------------------------------------------------------- */
.blog-filters {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2);
  margin-block-end: var(--sp-6);
  padding-block-end: var(--sp-5);
  border-block-end: 1px solid var(--stroke-soft);
}
.blog-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  padding: 0.52em 1em;
  font-family: var(--font-ui);
  font-size: var(--step--1);
  font-weight: 600;
  color: var(--text-mid);
  background: var(--surface);
  box-shadow: inset 0 0 0 1px var(--stroke);
  clip-path: var(--cut-one);
  cursor: pointer;
  border: 0;
  white-space: nowrap;
  transition: color var(--t) var(--ease), background var(--t) var(--ease), box-shadow var(--t) var(--ease), transform var(--t) var(--ease);
}
.blog-chip:hover { color: var(--em-800); background: rgba(229, 52, 44, .08); transform: translateY(-1px); }
.blog-chip[aria-pressed="true"] {
  color: #fff;
  background: var(--grad-em);
  box-shadow: var(--glow-sm);
}
.blog-chip__n {
  font-size: 0.7rem;
  font-weight: 800;
  padding: 0.1em 0.45em;
  color: var(--text-faint);
  background: var(--ink-750);
  clip-path: polygon(2px 0, 100% 0, 100% calc(100% - 2px), calc(100% - 2px) 100%, 0 100%, 0 2px);
}
.blog-chip[aria-pressed="true"] .blog-chip__n { color: #fff; background: rgba(255, 255, 255, .22); }

/* --------------------------------------------------------------------------
   3. Listing — featured lead
   -------------------------------------------------------------------------- */
.lead-post {
  display: grid;
  /* Media column deliberately the larger share. A 16:9 plate is short for its
     width, so an even split left the image floating in a tall body's worth of
     empty card. 55% is the balance point: enough height to sit level with the
     copy, while the text column stays wide enough to hold the title on two
     lines and the meta row on one. */
  grid-template-columns: minmax(0, 1.1fr) minmax(0, 0.9fr);
  /* center, not stretch. Stretching made the media column as tall as whatever
     the body happened to be, and the 16:9 art was cover-cropped to fill it. */
  align-items: center;
  overflow: hidden;
  transition: transform var(--t-slow) var(--ease), filter var(--t-slow) var(--ease);
}
.lead-post:hover { transform: translateY(-4px); }
.lead-post:hover .thumb__img { transform: scale(1.04); }
/* Stack below 1080, not 880. Between those two widths the text column is too
   narrow to hold the title on two lines, so the body grows tall while the 16:9
   plate shrinks — and the card fills with dead space. Stacked, both are
   full-width and the card reads the same as it does on a phone. */
@media (max-width: 1080px) { .lead-post { grid-template-columns: 1fr; } }

/* Mounted like a framed plate rather than bled to the card edge. The mat is
   what makes a centred 16:9 image read as deliberate when the body column
   happens to run taller than it. */
.lead-post .thumb {
  margin: clamp(0.85rem, 0.5rem + 1.1vw, 1.4rem);
  outline: 1px solid var(--stroke);
  outline-offset: -1px;
}
/* Stacked, the mat stops earning its keep — bleed the plate to the card edge
   so the featured card and the grid cards read identically on a phone. */
@media (max-width: 1080px) {
  .lead-post .thumb { margin: 0; outline: 0; }
}

.lead-post__body {
  display: flex;
  flex-direction: column;
  padding: clamp(1.5rem, 1rem + 2.4vw, 2.6rem);
}
.lead-post__body h2 {
  font-size: var(--step-3);
  letter-spacing: -0.032em;
  margin-block: 0.55em 0.45em;
}
.lead-post__body h2 a { color: var(--text-hi); }
.lead-post__body h2 a:hover { color: var(--em-700); }
.lead-post__body > p { color: var(--text-low); font-size: var(--step-0); }
.lead-post .btn-row { margin-block-start: var(--sp-5); }

/* --------------------------------------------------------------------------
   4. Listing — the grid. One card template, any number of posts.
   -------------------------------------------------------------------------- */
.post-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 320px), 1fr));
  gap: var(--sp-5);
  align-items: stretch;
}

.post-card {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  transition: transform var(--t-slow) var(--ease), filter var(--t-slow) var(--ease);
}
.post-card:hover,
.post-card:focus-within {
  transform: translateY(-5px);
  filter: drop-shadow(0 6px 14px rgba(62, 10, 6, .08)) drop-shadow(0 20px 38px rgba(62, 10, 6, .14));
}
.post-card:hover .thumb__img,
.post-card:focus-within .thumb__img { transform: scale(1.05); }
.post-card:hover .thumb::after,
.post-card:focus-within .thumb::after { opacity: 1; }

.post-card__body {
  display: flex;
  flex-direction: column;
  flex: 1;
  padding: clamp(1.15rem, 1rem + 0.9vw, 1.6rem);
}
.post-card__body h3 {
  font-size: var(--step-1);
  line-height: 1.28;
  letter-spacing: -0.024em;
  margin-block: 0.55em 0.5em;
}
.post-card__body h3 a { color: var(--text-hi); }
.post-card__body h3 a:hover { color: var(--em-700); }
.post-card__body > p {
  flex: 1;
  font-size: var(--step--1);
  line-height: 1.68;
  color: var(--text-low);
  margin-block-end: var(--sp-5);
}
.post-card .btn { margin-block-start: auto; }

/* Byline strip — date · reading time. Used on cards and on the article page. */
.post-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.55em;
  font-family: var(--font-ui);
  font-size: 0.74rem;
  font-weight: 600;
  letter-spacing: .04em;
  color: var(--text-faint);
}
.post-meta > span { display: inline-flex; align-items: center; gap: 0.4em; }
.post-meta .ico { width: 14px; height: 14px; flex: none; }
.post-meta__sep { width: 3px; height: 3px; background: var(--ink-600); border-radius: 50%; }

/* Empty state for the filter chips. */
.no-posts {
  display: none;
  padding: var(--sp-8) var(--sp-5);
  text-align: center;
  color: var(--text-low);
}
.no-posts.is-on { display: block; }
.no-posts .ico { width: 34px; height: 34px; color: var(--ink-600); margin: 0 auto var(--sp-4); }

/* --------------------------------------------------------------------------
   5. Listing — planned coverage rail (no dead links while the archive fills)
   -------------------------------------------------------------------------- */
.queue {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 250px), 1fr));
  gap: var(--sp-4);
}
.queue__item { padding: clamp(1.1rem, 1rem + 0.8vw, 1.5rem); }
.queue__item h3 { font-size: var(--step-0); margin-block: 0.5em 0.35em; }
.queue__item p { font-size: var(--step--1); color: var(--text-low); }
.queue__when {
  font-family: var(--font-ui);
  font-size: 0.68rem;
  font-weight: 800;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--gold-lo);
}

/* --------------------------------------------------------------------------
   6. Article page
   -------------------------------------------------------------------------- */
.article__hero { max-width: 900px; }
/* Same display serif as every other page hero — a headline is the one place
   the house face is meant to show. Only the scale is pulled back: article
   titles run longer than section titles and --step-5 wraps to four lines. */
.article__hero h1 {
  font-size: var(--step-4);
  line-height: 1.06;
  max-width: 26ch;
  margin-block: 0.45em 0;
}
.article__hero .post-meta { margin-block-start: var(--sp-5); font-size: 0.8rem; }
.article__standfirst {
  max-width: 62ch;
  margin-block-start: 0.9em;
  font-size: var(--step-1);
  line-height: 1.62;
  color: var(--text-low);
}

/* The hero plate. Capped rather than full-shell: a 16:9 image across the full
   1240px column stands 697px tall and pushes the article's first paragraph off
   the fold on a laptop. 900px keeps the art large and the opening copy visible.
   No aspect override here — the slot stays 16:9 so nothing is cropped. */
.article__figure {
  max-width: 900px;
  margin-block: var(--sp-6) 0;
  overflow: hidden;
}
.article__figure figcaption {
  padding: 0.85rem 1.1rem;
  font-size: 0.78rem;
  line-height: 1.6;
  color: var(--text-faint);
  border-block-start: 1px solid var(--stroke-soft);
}

/* Body prose. Sits on the .doc grid, so it inherits the sticky TOC and the
   scroll-spy already wired up in main.js. Only the type scale is nudged: an
   article reads longer than a legal clause and wants a touch more air. */
.article__body { max-width: 74ch; min-width: 0; }
.article__body section { scroll-margin-top: calc(var(--header-h) + 24px); }
.article__body section + section { margin-block-start: var(--sp-8); }
.article__body h2 {
  font-size: var(--step-2);
  letter-spacing: -0.03em;
  margin-block-end: 0.7em;
  padding-block-end: 0.5em;
  border-block-end: 1px solid var(--stroke-soft);
}
.article__body h3 {
  font-size: var(--step-1);
  color: var(--em-800);
  margin-block: 1.8em 0.5em;
}
.article__body p { color: var(--text-low); line-height: 1.76; }
.article__body p + p { margin-block-start: 1.1em; }
.article__body ul, .article__body ol { color: var(--text-low); margin-block: 1.2em; }
.article__body li { margin-block: 0.6em; line-height: 1.72; }
.article__body li::marker { color: var(--em-500); }
.article__body strong { color: var(--text-hi); }
.article__body a { text-decoration: underline; text-underline-offset: 3px; }

/* Definition pairs. doc.css styles these only under .doc__body, so the
   article scope needs its own rule rather than inheriting bare browser
   defaults (which indent <dd> and leave <dt> unweighted). */
.article__body dl { margin-block: 1.3em; }
.article__body dt {
  font-family: var(--font-ui);
  font-weight: 700;
  color: var(--text-hi);
  margin-block-start: 1.1em;
}
.article__body dt:first-child { margin-block-start: 0; }
.article__body dd {
  margin: 0.3em 0 0;
  padding-inline-start: 1em;
  border-inline-start: 2px solid var(--stroke-hot);
  color: var(--text-low);
}

/* Opening paragraph of the article gets a raised lede. */
.article__body .lede { font-size: var(--step-1); line-height: 1.68; color: var(--text-mid); }

/* Key takeaways — the summary box that lets a skimmer leave informed. */
.takeaways {
  --gem-fill: linear-gradient(155deg, #fdf8ec 0%, #fbf6ef 46%, #f7f3e8 100%);
  padding: clamp(1.3rem, 1rem + 1.6vw, 2rem);
  margin-block-end: var(--sp-7);
}
.takeaways h2 {
  display: flex;
  align-items: center;
  gap: 0.55em;
  font-size: var(--step-1);
  color: var(--gold-lo);
  border: 0;
  padding: 0;
  margin-block-end: 0.8em;
}
.takeaways h2 .ico { width: 20px; height: 20px; flex: none; }
.takeaways ul { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-3); }
.takeaways li {
  display: flex;
  gap: 0.7em;
  margin: 0;
  font-size: var(--step--1);
  line-height: 1.68;
  color: var(--text-mid);
}
.takeaways li .ico { width: 17px; height: 17px; flex: none; margin-block-start: 5px; color: var(--gold-lo); }

/* Pull-out statistic inside the flow. */
.stat-callout {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  gap: var(--sp-5);
  margin-block: 1.8em;
  padding: clamp(1.2rem, 1rem + 1.2vw, 1.8rem);
}
.stat-callout__n {
  font-family: var(--font-display);
  font-weight: 700;
  font-variation-settings: 'SOFT' 0, 'WONK' 1, 'opsz' 144;
  font-size: var(--step-4);
  line-height: 0.95;
  letter-spacing: -0.04em;
  color: var(--em-700);
  white-space: nowrap;
}
.stat-callout p { font-size: var(--step--1); color: var(--text-low); margin: 0; }
@media (max-width: 520px) { .stat-callout { grid-template-columns: 1fr; gap: var(--sp-3); } }

/* Worked example / comparison table. */
.article__body .resp-table { margin-block: 1.4em; }
.article__body .resp-table td:last-child { text-align: right; }

/* Share row + tag list at the foot of the piece. */
.article__foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  margin-block-start: var(--sp-7);
  padding-block-start: var(--sp-5);
  border-block-start: 1px solid var(--stroke-soft);
}
.tag-list { display: flex; flex-wrap: wrap; gap: var(--sp-2); list-style: none; margin: 0; padding: 0; }
.tag-list li { margin: 0; }
.tag-list a {
  display: inline-block;
  padding: 0.34em 0.8em;
  font-family: var(--font-ui);
  font-size: 0.74rem;
  font-weight: 600;
  color: var(--text-low);
  background: var(--surface);
  box-shadow: inset 0 0 0 1px var(--stroke);
  clip-path: var(--cut-one);
  text-decoration: none;
}
.tag-list a:hover { color: var(--em-800); background: rgba(229, 52, 44, .09); box-shadow: inset 0 0 0 1px var(--stroke-hot); }

/* Author / editorial-standards card under the article. */
.byline-card {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--sp-5);
  align-items: start;
  margin-block-start: var(--sp-6);
  padding: clamp(1.3rem, 1rem + 1.4vw, 1.9rem);
}
.byline-card__ico {
  width: 52px; height: 52px;
  display: grid; place-items: center;
  background: linear-gradient(150deg, rgba(229, 52, 44, .16), rgba(255, 106, 85, .07));
  box-shadow: inset 0 0 0 1px var(--stroke-hot);
  clip-path: var(--cut-one);
  color: var(--em-700);
}
.byline-card__ico .ico { width: 25px; height: 25px; }
.byline-card h2 { font-size: var(--step-0); border: 0; padding: 0; margin-block-end: 0.4em; }
.byline-card p { font-size: var(--step--1); color: var(--text-low); }
@media (max-width: 520px) { .byline-card { grid-template-columns: 1fr; } }

/* Prev / next pager. */
.article__pager {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
  gap: var(--sp-4);
  margin-block-start: var(--sp-6);
}
.pager-link {
  display: block;
  padding: clamp(1.1rem, 1rem + 0.8vw, 1.5rem);
  transition: transform var(--t) var(--ease);
}
.pager-link:hover { transform: translateY(-3px); }
.pager-link span {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  font-family: var(--font-ui);
  font-size: 0.7rem;
  font-weight: 800;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--text-faint);
}
.pager-link span .ico { width: 14px; height: 14px; }
.pager-link strong { display: block; margin-block-start: 0.45em; font-family: var(--font-ui); font-size: var(--step-0); color: var(--text-hi); line-height: 1.35; }
.pager-link:hover strong { color: var(--em-700); }
.pager-link--next { text-align: right; }
.pager-link--next span { flex-direction: row-reverse; }
.pager-link--disabled { opacity: .48; pointer-events: none; }

/* --------------------------------------------------------------------------
   7. Reading progress bar — pinned under the sticky header
   -------------------------------------------------------------------------- */
.readbar {
  position: fixed;
  top: 0; left: 0;
  z-index: calc(var(--z-header) + 1);
  height: 3px;
  width: 100%;
  transform: scaleX(0);
  transform-origin: 0 50%;
  background: var(--grad-em-bright);
  pointer-events: none;
}
