/* ============================================================
   blog.css: News and Downloads. LIGHT WORLD, LIVE GROUND.

   This page runs the shared field (field-bg.js, data-field-bg="sme")
   locked to the light extreme, so the ground is not a colour, it is
   a moving canvas fixed behind the document. Nothing here paints an
   opaque full-bleed panel over it. Every block of reading matter is
   a component floating on the field: its own white ground, a
   hairline, a soft lift, and real gutters so the field is visible
   between and around the components rather than only at the page
   edges.

   At the light extreme the field's own ground is flat --paper by
   construction (see the note at the top of field-bg.js: the warp
   front has left the viewport, so localT is constant). What moves
   over it is the particle and link mesh. That is what the worst
   case sampling has to account for, and it is why text never sits
   directly on the field: everything that has to be read sits on a
   component's own white ground.

   The separation mechanism also had to change coming from dark.

   ON DARK, objects read by VALUE: a card is lighter than the
   ground and the eye finds it instantly. On paper there is almost
   nowhere lighter to go, so that mechanism is unavailable. This
   sheet swaps it for three others:

     1. GROUND AND OBJECT SWAP ROLES. On dark the card was the lit
        thing on a void. Here the ground is the tint (--paper) and
        the object is true white (--cloud). The step is small, so
        it is always carried by a hairline as well.
     2. WEIGHT, NOT VALUE, CARRIES HOVER. Nothing can brighten, so
        a hover is a faint accent wash or a lift in the shadow.
     3. THE ACCENT DOES THE POINTING. Teal on paper is a mark, not
        a glow.

   Two light values are in play, both brand tokens:
     --paper #f7fafb  the field's own ground, and the body's
                      fallback if the field never mounts
     --cloud #ffffff  every floating component

   TWO OBJECT LANGUAGES

   The dark build separated articles from documents by corner
   radius: articles were square cells in a 1px lattice, documents
   were rounded cards. The lattice cannot survive a live ground,
   because a lattice is a single sheet and a single sheet is the
   opaque panel this page must not have. So the distinction moves
   off the corner and onto weight, and the rounding becomes
   consistent across everything that floats:

     articles  white, 8px, hairline, a SHALLOW lift. They are the
               page's default object and they should sit close to
               the field.
     documents white, 8px, hairline, a DEEPER lift and a 3px
               accent left edge. The edge is now the mark of a
               document and means nothing else, on either half of
               a pair, so the featured article gave its edge up.
   ============================================================ */

/* ------------------------------------------------------------
   LIGHT TOKENS
   Scoped to the body class so nothing here can reach another
   page. Everything below reads these, so the sheet has one place
   to change.

   ON THE TWO GREENS. --teal-deep #00866a is the light world's
   accent and it stays the accent here: rules, bars, marks, the
   focus ring, hover borders. As TEXT it measures 4.55:1 on white
   but only 4.34:1 on the paper tint, which is under the 4.5
   floor. So accent text uses --accent-ink #00755b, the same hue
   one step down: 5.68:1 on white, 5.42:1 on paper, 5.12:1 on the
   masthead band. The two are a step apart in luminance and never
   read as different colours, but every label now clears AA on
   whichever of the three grounds it lands on.

   ON THE SHADOW. The house shadow 0 5px 16px rgba(0,0,0,.32) was
   tuned for dark, where a black spread just deepens the void. On
   paper it prints as a bruise. These are shorter, much lower in
   alpha, and tinted with the ink hue rather than pure black, so
   the card lifts off the paper instead of staining it.
   ------------------------------------------------------------ */
body.blog-paper {
  --ground: var(--paper);
  --sheet: var(--cloud);

  --accent: var(--teal-deep);
  --accent-ink: #00755b;
  --accent-wash: rgba(0, 134, 106, .05);
  --accent-wash-2: rgba(0, 134, 106, .09);
  --accent-edge: rgba(0, 134, 106, .30);

  --hair: var(--rule-l);

  --lift: 0 1px 2px rgba(13, 27, 36, .04), 0 8px 22px -14px rgba(13, 27, 36, .28);
  --lift-h: 0 2px 4px rgba(13, 27, 36, .06), 0 16px 32px -18px rgba(13, 27, 36, .34);

  /* The gutter the field shows through. */
  --gut: clamp(.9rem, 2vw, 1.25rem);

  /* ONE INNER PADDING FOR EVERY PLATE THAT CARRIES A MEASURE.
     The masthead plate and the article reading sheet are both
     children of .wrap, so their border boxes are already the same
     box. Giving them the same inner padding as well is the second
     half of the same idea: it puts the h1 inside the masthead and
     the first paragraph inside the sheet on one left edge, with no
     arithmetic to keep in sync. Its value is the masthead plate's
     original horizontal padding, so nothing on the index moves. */
  --plate-pad: clamp(1.4rem, 4vw, 2.6rem);

  /* Fallback only. The field host is fixed at inset:0 behind the
     document and paints its own ground, so this is what a visitor
     sees if the script never runs. */
  background: var(--ground);
  color: var(--ink);
}

/* The lead paragraph and any muted copy on a light ground.
   styles.css sets .lead to --snow, which is invisible here. */
.blog-paper .lead { color: var(--ink); }
.blog-paper .muted { color: var(--ink-soft); }

/* THE MASTHEAD DOES NOT GROUND ITSELF, IT FLOATS.

   styles.css paints .phero.light a solid --cloud with an accent
   aurora over it. Both are full bleed and together they hide the
   field across the whole top of the page, which is the thing being
   corrected elsewhere on the site. So the section gives up its
   fill and its aurora, and the masthead's own content moves onto a
   plate instead: the same white component language as everything
   else, with the field running above it, below it and down both
   sides.

   This is not decoration, it is the measurement. The light field's
   ground is a flat #f7fafb across 97% of its area, but the mesh it
   draws over that ground reaches rgb(58,117,114) at the core of a
   hub node. Sampled across the whole canvas over six points in the
   animation, text on the bare field measures against that darkest
   mark as:

     --ink        3.31:1     large display only, and thin at that
     --ink-soft   1.15:1     fails
     --accent-ink 1.07:1     fails

   Those marks are sparse, roughly a fifth of one per cent of the
   area, but sparse is not an argument: a node passing under a word
   makes that word unreadable while it is there. So no text on this
   page sits directly on the field. Every text element has a
   component under it, and the field is seen around them. */
.blog-paper .phero.light {
  background: transparent;
  border-bottom: 0;
}

.blog-paper .phero.light::after { content: none; }

/* THE MASTHEAD PLATE, AND THE PAGE'S ONE CONTENT MEASURE.

   The plate used to be .wrap itself, given a width of
   calc(100% - 2 * the wrap gutter). That produced a second measure:
   .wrap's border box, 1180px, against the .wrap CONTENT box the two
   columns below are laid out in, 1180px less two 48px gutters. The
   plate therefore hung 48px past the News column on the left and
   48px past the Downloads column on the right, which is exactly
   what the review flagged.

   So the plate is now a child of .wrap, and .wrap goes back to
   being nothing but the measure. The plate's border box IS the
   wrap content box, which is the same box .blog-layout fills, so
   the masthead, News and Downloads share one pair of edges at
   every width with no arithmetic to keep in sync.

   The article pages use the same plate for their own masthead, for
   the same reason and for one more: before this, the article hero
   was the only text on either page sitting directly on the bare
   field, where --ink-soft measures 1.15:1 against the mesh's
   darkest mark. */
.blog-paper .masthead-plate {
  background: var(--sheet);
  border: 1px solid var(--hair);
  border-radius: 8px;
  box-shadow: var(--lift);
  padding: clamp(1.8rem, 4vw, 2.8rem) var(--plate-pad) clamp(1.6rem, 3vw, 2.2rem);
}

.blog-paper .phero.light .eyebrow { color: var(--accent-ink); }
.blog-paper .phero.light .eyebrow::before { background: var(--accent-ink); }

/* The filter bar closes the plate, so its rule is the plate's own
   internal division rather than a line drawn across the page. */
.blog-paper .blog-filters {
  border-bottom: 0;
  padding-bottom: 0;
  border-top: 1px solid var(--hair);
  padding-top: clamp(1.4rem, 3vw, 1.9rem);
  margin-top: clamp(1.6rem, 3.5vw, 2.2rem);
}

/* The mark's nodes are painted --teal by styles.css. That is
   2.42:1 on paper. While the header is over the band it takes the
   accent; once the header scrolls it goes dark again and the
   original teal is correct, so this is scoped to the unscrolled
   state. */
.blog-paper header.site:not(.scrolled):not(.nav-open) .mark .node { fill: var(--accent); }

/* FOCUS. The site ring is --teal, which is 2.42:1 on paper: a ring
   tuned for dark that all but disappears here. The accent measures
   4.34:1 on paper and 4.10:1 on the band, both clear of the 3:1
   floor for a non-text indicator. Inside the dark regions of these
   pages, the footer, the closing block and the signal plate, the
   original teal ring is still the right one. */
.blog-paper :focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.blog-paper footer.site :focus-visible,
.blog-paper .contact :focus-visible,
.blog-paper .signal-callout :focus-visible { outline-color: var(--teal); }

/* DARK REGIONS INSIDE A LIGHT PAGE.
   The article pages still close on the shared dark "Talk to us"
   block before the footer, which is the right ending: the reading
   surface is paper, the site chrome is ink. But the two rules
   above are page-wide, so they have to be handed back at the edge
   of any dark region or the lead and the muted copy would print
   ink on ink. Colour belongs to the local ground. */
.blog-paper .contact .lead,
.blog-paper .contact h2 { color: var(--snow); }
.blog-paper .contact .muted,
.blog-paper .contact .note { color: var(--snow-soft); }

/* The primary button keeps its teal fill and dark label, which is
   6.95:1 and is how the button reads everywhere else on the site.
   Only the hover glow needs retuning: a wide --teal bloom is a
   dark-world effect and looks like a smudge on paper. */
.blog-paper .btn:hover { box-shadow: 0 8px 20px -10px rgba(0, 134, 106, .55); }

/* Scroll rail. The shared rail is white at 12% with a glowing
   #3ff0cf dot, both dark-world objects. The dot takes a white ring
   rather than an accent halo, because the thing behind it is the
   field and the field is moving: a ring in the ground colour holds
   the dot apart from whatever passes under it. */
.blog-paper .sc-rail { background: var(--hair); }
.blog-paper .sc-dot {
  background: var(--accent);
  box-shadow: 0 0 0 3px rgba(255, 255, 255, .92);
}

/* ---- Filter bar ---- */
.blog-filters {
  display: flex;
  flex-wrap: wrap;
  gap: .55rem;
  margin-top: clamp(2.4rem, 5vw, 3.6rem);
  padding-bottom: clamp(2rem, 4vw, 3rem);
  border-bottom: 1px solid var(--hair);
}

.filter-btn {
  font-family: var(--mono);
  font-size: .72rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ink-soft);
  background: transparent;
  border: 1px solid var(--hair);
  padding: .55em 1.1em;
  cursor: pointer;
  transition: color .2s, border-color .25s, background .25s;
  line-height: 1;
}

.filter-btn:hover {
  color: var(--ink);
  border-color: var(--accent-edge);
  background: var(--accent-wash);
}

/* The selected filter is printed in ink. On dark this was a teal
   fill, which on paper would put small dark type on a bright
   field and read as a highlighter stripe. Ink at 15.8:1 is
   unmistakable and leaves the accent free to point at content. */
.filter-btn.is-active {
  color: var(--snow);
  background: var(--deep);
  border-color: var(--deep);
}

.filter-btn.is-active:hover {
  color: var(--snow);
  background: var(--deep);
}

.filter-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

/* ---- Featured post ----
   An article, so it floats on the shallow lift and carries no
   accent edge. It leads its column by size and by the tick on its
   kicker, not by borrowing the document mark. */
.featured-post {
  display: grid;
  grid-template-columns: 200px 1fr;
  gap: clamp(1.8rem, 4vw, 3.6rem);
  background: var(--sheet);
  border: 1px solid var(--hair);
  border-radius: 8px;
  box-shadow: var(--lift);
  padding: clamp(1.8rem, 3.5vw, 2.8rem) clamp(1.4rem, 3vw, 2.4rem);
  margin-top: clamp(2rem, 4vw, 3rem);
  text-decoration: none;
  color: inherit;
  transition: box-shadow .3s var(--e-out), background .3s var(--e-out);
  position: relative;
  overflow: hidden;
}

/* Nothing can brighten past white, so a hover on this page is a
   faint accent wash plus a lift off the field. */
.featured-post:hover {
  background: var(--accent-wash);
  box-shadow: var(--lift-h);
}

/* Hover reveal rule under the title */
.featured-post::after {
  content: "";
  position: absolute;
  bottom: 0; left: 0; right: 0;
  height: 2px;
  background: linear-gradient(90deg, var(--accent), transparent 60%);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform .4s var(--e-out);
}

.featured-post:hover::after {
  transform: scaleX(1);
}

/* The meta column sits at the TOP of the card, not spread down it.
   The date used to carry margin-top:auto, which pushed it to the
   bottom of a 480px tall card and left roughly 340px of white
   between the category and the date: the largest hole on the page,
   and one that grows every time the standfirst gets longer. The
   two labels belong together as one small block against the
   headline, and the card's own height is set by the body opposite.
   The rule above the date goes with it, since it was drawn to
   close a gap that no longer exists. */
.featured-meta {
  display: flex;
  flex-direction: column;
  gap: .55rem;
  padding-top: .2rem;
}

.featured-meta .post-date {
  margin-top: 0;
  padding-top: 0;
  border-top: 0;
}

.featured-body {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

/* The tick. A short accent bar marks the anchor item of a group:
   the lead article here, the paired document in the resources
   column, the signal on an article page. It is the one structural
   mark this page repeats, and it always means the same thing. */
.featured-kicker {
  font-family: var(--mono);
  font-size: .66rem;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--accent-ink);
  display: flex;
  align-items: center;
  gap: .6em;
}

.featured-kicker::before {
  content: "";
  display: inline-block;
  width: 18px;
  height: 2px;
  background: var(--accent);
  flex: none;
}

.featured-title {
  font-family: var(--exp);font-stretch:125%;
  font-weight: 800;
  font-size: clamp(1.5rem, 1rem + 2vw, 2.2rem);
  letter-spacing: -.025em;
  line-height: 1.08;
  color: var(--ink);
  text-wrap: pretty;
  margin: 0;
}

.featured-standfirst {
  font-size: 1.02rem;
  line-height: 1.6;
  color: var(--ink-soft);
  margin: 0;
}

.featured-link {
  display: inline-flex;
  align-items: center;
  gap: .5em;
  font-weight: 600;
  font-size: .94rem;
  color: var(--accent-ink);
  margin-top: .4rem;
}

.featured-link .arw {
  transition: transform .3s var(--e-out);
}

.featured-post:hover .featured-link .arw {
  transform: translateX(5px);
}

/* ---- Post cards grid ----
   The dark build ran these as a 1px lattice: one sheet, ruled. A
   lattice cannot float, because the gap between two cells is the
   sheet showing through and the sheet is opaque. So the lattice
   becomes real gutters and each article stands on its own, with
   the field running between them. */
.post-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--gut);
  background: transparent;
  border: 0;
  margin-top: var(--gut);
}

/* An odd number of cards leaves the last row half empty, and that
   empty half sits directly under a card rather than at the edge of
   the layout, so it reads as a missing card instead of as margin.
   The trailing card takes the whole row instead and closes the
   stream deliberately. Counted on the element type so the
   .no-results paragraph at the end of the grid is not what the
   rule lands on. */
.post-grid > a.post-card:nth-of-type(odd):nth-last-of-type(1) {
  grid-column: 1 / -1;
}

.post-card {
  background: var(--sheet);
  border: 1px solid var(--hair);
  border-radius: 8px;
  box-shadow: var(--lift);
  padding: clamp(1.6rem, 3vw, 2.2rem);
  display: flex;
  flex-direction: column;
  gap: .75rem;
  text-decoration: none;
  color: inherit;
  transition: background .3s var(--e-out), box-shadow .3s var(--e-out);
  position: relative;
  overflow: hidden;
}

.post-card::before {
  content: "";
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 2px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform .35s var(--e-out);
}

.post-card:hover {
  background: var(--accent-wash);
  box-shadow: var(--lift-h);
}

.post-card:hover::before {
  transform: scaleX(1);
}

.post-cat {
  font-family: var(--mono);
  font-size: .68rem;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--accent-ink);
  line-height: 1;
}

.post-title {
  font-family: var(--exp);font-stretch:125%;
  font-weight: 700;
  font-size: clamp(1.05rem, 1rem + .6vw, 1.3rem);
  letter-spacing: -.015em;
  line-height: 1.15;
  color: var(--ink);
  text-wrap: pretty;
  margin: 0;
}

.post-standfirst {
  font-size: .95rem;
  line-height: 1.6;
  color: var(--ink-soft);
  margin: 0;
}

.post-date {
  font-family: var(--mono);
  font-size: .7rem;
  color: var(--ink-soft);
  margin-top: auto;
  padding-top: .8rem;
  border-top: 1px solid var(--hair);
  display: flex;
  align-items: center;
  gap: 1rem;
}

/* An ink separator at 40% opacity drops to roughly 2:1 on white.
   It carries no meaning on its own, but it should still be
   readable as a mark, so it is held at 55%. */
.post-date .sep {
  opacity: .55;
}

/* No-results message. It replaces the cards, so it takes their
   ground rather than dropping the reader onto the bare field. */
.no-results {
  grid-column: 1 / -1;
  padding: 3rem 2rem;
  text-align: center;
  font-family: var(--mono);
  font-size: .82rem;
  color: var(--ink-soft);
  background: var(--sheet);
  border: 1px solid var(--hair);
  border-radius: 8px;
  box-shadow: var(--lift);
  letter-spacing: .08em;
  display: none;
}

/* ---- Post card hidden state ---- */
.post-card.is-hidden,
.featured-post.is-hidden {
  display: none;
}

/* ---- Blog result count ---- */
.blog-count {
  font-family: var(--mono);
  font-size: .74rem;
  color: var(--ink-soft);
  letter-spacing: .08em;
  margin-top: 1.4rem;
}

.blog-count strong {
  color: var(--ink);
  font-weight: 600;
}

/* ============================================================
   BLOG LAYOUT: the article stream beside the resources column

   Two real columns at desktop. The resources column is a peer of
   the article stream, not a decorative rail: it carries its own
   heading, its own rules and its own object language (documents
   are cards with an 8px radius; articles are hairline cells).
   Below 1040px the resources column falls in underneath the
   stream with a full-width rule above it.
   ============================================================ */

/* News takes the room. Downloads was running at 340px against a
   693px News column at 1280, roughly 2:1, and the review read that
   as News being cramped rather than Downloads being generous. The
   document column holds one card with a full width button, a short
   spec row and a note, so 300px carries it comfortably and it is
   still well clear of the 264px floor where the button label would
   start to wrap. Pulling the column gap in a notch as well takes
   News to about 746px, near 2.5:1, without letting the two columns
   collide. */
.blog-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(264px, 300px);
  gap: clamp(1.8rem, 3vw, 3rem);
  align-items: start;
}

.blog-articles,
.blog-resources {
  min-width: 0;
}

/* Inside a column the featured post follows the column head, so it
   takes the gutter rather than its standalone top margin. */
.blog-articles > .featured-post {
  margin-top: var(--gut);
}

/* No position:sticky on the resources column. styles.css sets
   overflow-x:hidden on body, which makes body the scrolling
   ancestor and stops sticky resolving at all. The column is a
   similar height to the article stream anyway, so it stays in
   normal flow. */

/* ---- Column heads ----
   The page is News on the left and Downloads on the right, so both
   columns carry the same head: a mono label, a live count, a
   hairline. Identical treatment is what makes them read as two
   halves of one page rather than a column with a rail beside it. */
.col-head {
  background: var(--sheet);
  border: 1px solid var(--hair);
  border-radius: 8px;
  box-shadow: var(--lift);
  padding: .95rem 1.15rem 1rem;
}

.col-head-row {
  display: flex;
  align-items: baseline;
  gap: .8rem;
}

.col-head h2 {
  font-family: var(--mono);
  font-weight: 500;
  font-size: .72rem;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--accent-ink);
  margin: 0;
}

.col-count {
  font-family: var(--mono);
  font-size: .66rem;
  letter-spacing: .1em;
  color: var(--ink-soft);
  margin-left: auto;
}

/* Lives inside the Downloads head plate, so the column opens with
   one component rather than a label floating above a paragraph
   floating above the card. */
.col-head .res-col-intro {
  font-size: .88rem;
  line-height: 1.6;
  color: var(--ink-soft);
  margin: .8rem 0 0;
  padding-top: .8rem;
  border-top: 1px solid var(--hair);
}

/* ---- Resource entries ----
   Documents: the deeper lift and the 3px accent left edge. The
   edge is the document mark and appears nowhere else, so the same
   object is recognisable on the article page too. */
.res-list {
  display: grid;
  gap: var(--gut);
  margin-top: var(--gut);
}

.res-item {
  border: 1px solid var(--hair);
  border-left: 3px solid var(--accent);
  border-radius: 8px;
  background: var(--sheet);
  box-shadow: var(--lift-h);
  padding: 1.3rem 1.35rem 1.4rem;
  transition: box-shadow .3s var(--e-out), border-color .3s;
}

.res-item:hover {
  box-shadow: 0 3px 6px rgba(13, 27, 36, .07), 0 24px 44px -20px rgba(13, 27, 36, .40);
}

.res-item-kind {
  font-family: var(--mono);
  font-size: .66rem;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--accent-ink);
  line-height: 1;
}

.res-item-title {
  font-family: var(--exp);font-stretch:125%;
  font-weight: 700;
  font-size: 1.12rem;
  letter-spacing: -.015em;
  line-height: 1.18;
  color: var(--ink);
  text-wrap: pretty;
  margin: .7rem 0 0;
}

.res-item-desc {
  font-size: .89rem;
  line-height: 1.58;
  color: var(--ink-soft);
  margin: .6rem 0 0;
}

.res-item-spec {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .35rem .7rem;
  font-family: var(--mono);
  font-size: .66rem;
  letter-spacing: .06em;
  color: var(--ink-soft);
  margin: 1rem 0 0;
  padding-top: .85rem;
  border-top: 1px solid var(--hair);
}

.res-item-spec .sep {
  opacity: .55;
}

.res-item-cta {
  margin-top: 1.1rem;
}

.res-item-cta .btn {
  width: 100%;
  justify-content: center;
}

.res-item-note {
  font-family: var(--mono);
  font-size: .64rem;
  letter-spacing: .06em;
  line-height: 1.5;
  color: var(--ink-soft);
  margin: .7rem 0 0;
}

/* ---- Follow along: the rail's closing block ----
   This is what is left of the LinkedIn band. That band was a full
   width strip under both columns built to hold pinned post embeds,
   and it never held one, so it shipped as three stacked plates
   saying nothing. LinkedIn has no free live feed widget, and its
   per post embed is a fixed width iframe that will not reflow
   inside a 300px rail, so the embeds cannot move here either.

   What is real is the three profiles. As a rail block they stack
   into one column of full width pills, which also gives the
   Downloads column something to end on now that the article
   stream is the taller of the two. */
.res-follow {
  margin-top: var(--gut);
  background: var(--sheet);
  border: 1px solid var(--hair);
  border-radius: 8px;
  box-shadow: var(--lift);
  padding: 1.1rem 1.2rem 1.2rem;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: .55rem;
}

.res-follow-k {
  font-family: var(--mono);
  font-size: .64rem;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin-bottom: .25rem;
}

/* ---- The LinkedIn pills, used by .res-follow above ----
   Kept from the retired LinkedIn band. Everything else that band
   needed (the grid, the embed frame with its standing label, the
   per post footer) went with it; it is in git history if pinned
   post embeds are ever wanted back. */
.li-link {
  display: inline-flex;
  align-items: center;
  gap: .5em;
  font-family: var(--mono);
  font-size: .72rem;
  letter-spacing: .06em;
  color: var(--accent-ink);
  text-decoration: none;
  border: 1px solid var(--accent-edge);
  border-radius: 6px;
  padding: .65em .9em;
  line-height: 1;
  transition: background .25s, border-color .25s;
}

.li-link svg {
  width: 15px;
  height: 15px;
  flex: none;
}

.li-link:hover {
  background: var(--accent-wash);
  border-color: var(--accent);
}

/* ============================================================
   PAIRING: the tie between a piece of writing and its document

   The same element appears on both halves of the pair, so the
   relationship reads as one object split across two places: on
   the resource entry it names the article, on the article it
   names the resource. Publishing is one motion, and the layout
   is built to show it.
   ============================================================ */
.paired {
  margin-top: 1rem;
  padding-top: .85rem;
  border-top: 1px solid var(--hair);
}

.paired-k {
  display: flex;
  align-items: center;
  gap: .6em;
  font-family: var(--mono);
  font-size: .62rem;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--accent-ink);
}

/* Same tick as the featured kicker, same meaning. */
.paired-k::before {
  content: "";
  display: block;
  width: 14px;
  height: 2px;
  background: var(--accent);
  flex: none;
}

.paired-t {
  display: block;
  font-family: var(--exp);font-stretch:125%;
  font-weight: 700;
  font-size: .92rem;
  line-height: 1.3;
  letter-spacing: -.01em;
  color: var(--ink);
  text-wrap: pretty;
  margin-top: .5rem;
  text-decoration: none;
}

a.paired-t:hover {
  color: var(--accent-ink);
}

a.paired-t:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

/* The marker on a post card is plain text: the card is already a
   link, so it must not carry a second one. The resources column
   holds the clickable half of the pair. */
.post-card .paired {
  margin-top: 0;
  padding-top: 0;
  border-top: 0;
}

.post-card .paired-t {
  font-family: var(--sans);
  font-weight: 500;
  font-size: .82rem;
  color: var(--ink-soft);
  margin-top: .35rem;
}

/* ============================================================
   Article page styles
   ============================================================ */

/* Article hero: extends .phero */
.article-hero .article-hero-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .5rem 1.4rem;
  margin-top: 1.4rem;
  font-family: var(--mono);
  font-size: .76rem;
  color: var(--ink-soft);
  letter-spacing: .04em;
}

.article-hero .article-hero-meta .sep {
  opacity: .5;
}

.article-hero .article-hero-cat {
  color: var(--accent-ink);
  font-weight: 600;
  letter-spacing: .18em;
  text-transform: uppercase;
  font-size: .68rem;
}

/* ---- Article body ----
   THE READING SHEET, AND WHY IT MOVED.

   Long prose cannot sit on a moving ground, so the article gets one
   component to stand on. That part was always right. What was wrong
   was where the component sat.

   The sheet used to be its own 880px measure, centred in the
   viewport, with a three track grid (1fr, prose, 1fr) centring the
   prose inside it. The masthead above it was laid out in .wrap, the
   page's measure. Two measures, neither derived from the other, so
   the body started 223px to the right of the headline at 1280 and
   the article read as two unrelated objects.

   It now follows the index's correction exactly. The sheet is a
   child of .wrap, so its border box IS the wrap content box, the
   same box the masthead plate fills. It carries --plate-pad, the
   same inner padding the masthead plate carries. And the grid drops
   its leading 1fr, so the prose column starts at the sheet's own
   content edge rather than being centred in it. Those three facts
   put the h1 and the first paragraph on one left edge at every
   width, with nothing to keep in sync.

   The prose measure itself is untouched: min(65ch, 100%), exactly
   as before. The trailing 1fr is what is left over, and it is a
   margin, not a column. The signal and the images bleed into it to
   the same 78ch they always did, hung on the same left edge instead
   of centred, so every element in the article shares one axis and
   the sheet's right hand side reads as an asymmetric margin rather
   than an empty second column. */
.article-wrap {
  margin: clamp(1.6rem, 4vw, 3rem) 0;
  padding: 0 var(--plate-pad);
  background: var(--sheet);
  border: 1px solid var(--hair);
  border-radius: 8px;
  box-shadow: var(--lift);
  display: grid;
  grid-template-columns: min(65ch, 100%) minmax(0, 1fr);
}

.article-wrap > * {
  grid-column: 1;
}

/* The wider bleed, hung left rather than centred. */
.article-wrap > .signal-callout,
.article-wrap > .article-image {
  grid-column: 1 / -1;
  max-width: min(78ch, 100%);
  margin-left: 0;
  margin-right: auto;
  width: 100%;
}

.article-body {
  padding: clamp(3rem, 6vw, 5rem) 0;
}

.article-body p {
  font-size: clamp(1.03rem, 1rem + .25vw, 1.16rem);
  line-height: 1.78;
  color: var(--ink);
  margin-bottom: 1.4rem;
  text-wrap: pretty;
}

.article-body p:last-child {
  margin-bottom: 0;
}

.article-body h2 {
  font-family: var(--exp);font-stretch:125%;
  font-weight: 800;
  font-size: clamp(1.4rem, 1rem + 1.4vw, 1.9rem);
  letter-spacing: -.025em;
  line-height: 1.1;
  color: var(--ink);
  margin: 2.4rem 0 1rem;
  text-wrap: pretty;
}

.article-body h3 {
  font-family: var(--sans);
  font-weight: 700;
  font-size: 1.1rem;
  color: var(--ink);
  margin: 1.8rem 0 .7rem;
  letter-spacing: -.01em;
  line-height: 1.2;
}

.article-body strong {
  color: var(--ink);
  font-weight: 600;
}

/* Inline code. The dark build tinted with --teal at 10%, which on
   paper is a pale mint that barely registers. The tint is the
   accent instead, and the type is accent ink so it still clears
   4.5:1 against the tinted patch. */
.article-body code {
  font-family: var(--mono);
  font-size: .88em;
  background: rgba(0, 134, 106, .07);
  color: var(--accent-ink);
  padding: .1em .4em;
  border: 1px solid rgba(0, 134, 106, .22);
}

/* Blockquote */
.article-body blockquote {
  margin: 2rem 0;
  padding: 1.2rem 1.5rem;
  border-left: 3px solid var(--accent);
  background: var(--accent-wash);
}

.article-body blockquote p {
  font-family: var(--exp);font-stretch:125%;
  font-weight: 600;
  font-size: clamp(1.05rem, 1rem + .5vw, 1.2rem);
  line-height: 1.45;
  color: var(--ink);
  margin-bottom: .5rem;
  font-style: normal;
}

.article-body blockquote cite {
  font-family: var(--mono);
  font-size: .74rem;
  letter-spacing: .06em;
  color: var(--ink-soft);
  font-style: normal;
}

/* ---- SIGNAL callout: the house component, rebuilt for paper ----

   This is the single most important sentence on the page and it
   has to look like it. On dark it did that with a 2px teal rule
   across the top, notched open at the left by a bar painted in
   the ground colour, and a large sentence in snow. Two things
   broke in the move:

     the notch was a knockout. It only worked because the bar was
     painted exactly the page's background, so the moment the
     component sits on anything else it shows as a stripe.
     the weight was borrowed from the ground. A teal hairline over
     a void carries real presence. The same hairline over paper is
     a scratch, and the sentence loses its claim on the page.

   So it is not inverted, it is rebuilt. On paper the heaviest
   thing available is a solid block of ink, and this is the one
   place worth spending it: the plate is the only dark object on
   the page and the eye goes straight to it. The knockout becomes
   a positive mark, the same short accent tick used on the
   featured kicker and the pairing marker, which no longer depends
   on matching any background.

   Inside the plate the local ground is dark again, so hairlines
   revert to --rule-d and the accent goes back to full --teal.
   Rule colour follows its own ground, not the page. */
.signal-callout {
  margin: 2.8rem 0;
  padding: clamp(1.6rem, 3.5vw, 2.2rem) clamp(1.5rem, 3.5vw, 2.3rem);
  background: var(--deep);
  color: var(--snow);
  border: 0;
  border-radius: 8px;
  box-shadow: 0 2px 4px rgba(13, 27, 36, .07), 0 22px 44px -24px rgba(13, 27, 36, .55);
  position: relative;
  overflow: hidden;
}

.signal-callout::after {
  content: "";
  position: absolute;
  top: 0; left: 0;
  width: 64px;
  height: 3px;
  background: var(--teal);
}

.signal-eyebrow {
  font-family: var(--mono);
  font-size: .66rem;
  letter-spacing: .26em;
  text-transform: uppercase;
  color: var(--teal);
  margin-bottom: 1rem;
  display: flex;
  align-items: center;
  gap: .7em;
}

.signal-eyebrow::after {
  content: "";
  display: block;
  flex: 1;
  height: 1px;
  background: var(--rule-d);
}

.signal-sentence {
  font-family: var(--exp);font-stretch:125%;
  font-weight: 700;
  font-size: clamp(1.2rem, 1rem + 1.1vw, 1.6rem);
  letter-spacing: -.025em;
  line-height: 1.25;
  color: var(--snow);
  text-wrap: pretty;
  margin: 0;
}

/* ---- Article image + caption ---- */
.article-image {
  margin: 2rem 0;
}

.article-image img {
  width: 100%;
  height: auto;
  display: block;
  border: 1px solid var(--hair);
  border-radius: 8px;
}

.article-image figcaption {
  font-family: var(--mono);
  font-size: .74rem;
  color: var(--ink-soft);
  margin-top: .65rem;
  line-height: 1.5;
  letter-spacing: .02em;
}

/* ---- Linked resource on an article page ----
   The article half of the pair, so it takes the card language the
   resources column uses: white, 8px radius, soft lift. Sits at the
   prose measure the .article-wrap grid already supplies, so it
   needs no width of its own. Present on any piece that has a
   document attached; left commented out on pieces that do not. */
.linked-resource {
  /* Bottom margin mirrors .article-body's padding, so the block
     does not butt straight into the prev / next nav. */
  margin: 2.8rem 0 clamp(3rem, 6vw, 5rem);
  border: 1px solid var(--hair);
  border-left: 3px solid var(--accent);
  border-radius: 8px;
  /* It sits ON the reading sheet rather than on the field, so it
     needs a step away from white to register. A whisper of the
     accent is the one available direction. */
  background: var(--accent-wash);
  padding: clamp(1.3rem, 3vw, 1.9rem);
  transition: background .3s var(--e-out);
}

.linked-resource:hover {
  background: var(--accent-wash-2);
}

/* .eyebrow is painted --teal by styles.css, which is 2.42:1 on a
   white card. */
.linked-resource .eyebrow {
  color: var(--accent-ink);
}

.linked-resource h2 {
  font-family: var(--exp);font-stretch:125%;
  font-weight: 800;
  font-size: clamp(1.15rem, 1rem + .7vw, 1.4rem);
  letter-spacing: -.02em;
  line-height: 1.15;
  color: var(--ink);
  text-wrap: pretty;
  margin: .9rem 0 0;
}

.linked-resource h2 a {
  color: inherit;
  text-decoration: none;
}

.linked-resource h2 a:hover {
  color: var(--accent-ink);
}

.linked-resource h2 a:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

.linked-resource p {
  font-size: .96rem;
  line-height: 1.62;
  color: var(--ink-soft);
  margin: .7rem 0 0;
}

/* Scoped to the block so they beat .linked-resource p, which is
   more specific than a bare .lr-spec and was silently overriding
   both sizes back up to the body measure. */
.linked-resource .lr-spec {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .35rem .7rem;
  font-family: var(--mono);
  font-size: .68rem;
  letter-spacing: .06em;
  color: var(--ink-soft);
  margin: 1.1rem 0 0;
  padding-top: .9rem;
  border-top: 1px solid var(--hair);
}

.linked-resource .lr-spec .sep {
  opacity: .55;
}

.linked-resource .lr-actions {
  display: flex;
  flex-wrap: wrap;
  gap: .7rem;
  margin: 1.2rem 0 0;
}

.linked-resource .lr-note {
  font-family: var(--mono);
  font-size: .66rem;
  letter-spacing: .06em;
  color: var(--ink-soft);
  margin: .8rem 0 0;
}

/* ---- Article nav (prev / next) ----
   Articles, so they float on the shallow lift like the cards on
   the index. The full width lattice the dark build used is gone
   for the same reason the post grid's is. It is a child of .wrap
   too, so the pair of cards ends on the same edges as the sheet
   above them. */
.article-nav {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--gut);
  background: transparent;
  border: 0;
  /* The article pages carry no contact reveal, so this nav is the
     last thing before the dark footer and it was butting straight
     into it: the two white cards ended exactly on the footer's top
     edge. It needs the same room underneath it that the reading
     sheet gives it above. */
  margin-bottom: clamp(2.4rem, 5vw, 4rem);
}

.article-nav-item {
  background: var(--sheet);
  border: 1px solid var(--hair);
  border-radius: 8px;
  box-shadow: var(--lift);
  padding: 1.4rem clamp(1rem, 3vw, 1.6rem);
  display: flex;
  flex-direction: column;
  gap: .4rem;
  text-decoration: none;
  color: inherit;
  transition: background .25s, box-shadow .3s var(--e-out);
}

a.article-nav-item:hover {
  background: var(--accent-wash);
  box-shadow: var(--lift-h);
}

.article-nav-item.next {
  text-align: right;
  align-items: flex-end;
}

.article-nav-item .nav-dir {
  font-family: var(--mono);
  font-size: .66rem;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.article-nav-item .nav-title {
  font-family: var(--exp);font-stretch:125%;
  font-weight: 700;
  font-size: .98rem;
  color: var(--ink);
  line-height: 1.2;
  text-wrap: pretty;
}

.article-nav-item .nav-cat {
  font-family: var(--mono);
  font-size: .66rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--accent-ink);
}

/* The dead half of the nav on the first and last pieces. */
.article-nav-item .nav-title.is-quiet {
  color: var(--ink-soft);
  font-weight: 500;
}

/* ---- Back to blog link ----
   display:flex, not inline-flex. As an inline box it sat on the
   same line as the category eyebrow that follows it, and the two
   ran together as one string: "← News AI in real estate". They are
   different things and belong on different lines. width:fit-content
   keeps the hit area on the words rather than the full measure. */
.back-to-blog {
  display: flex;
  width: fit-content;
  align-items: center;
  gap: .5em;
  font-family: var(--mono);
  font-size: .74rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin-bottom: 1.6rem;
  text-decoration: none;
  transition: color .2s;
}

.back-to-blog:hover {
  color: var(--accent-ink);
}

.back-to-blog .arw {
  transition: transform .2s;
}

.back-to-blog:hover .arw {
  transform: translateX(-3px);
}

/* ---- Responsive ---- */

/* The two columns become one stack. Resources sit below the
   article stream, full width, introduced by their own rule so
   the section still reads as a peer rather than a leftover. */
@media (max-width: 1040px) {
  .blog-layout {
    grid-template-columns: 1fr;
    gap: 0;
  }

  .blog-resources {
    margin-top: clamp(2.6rem, 6vw, 4rem);
  }

  /* Room for more than one document once more exist. */
  .res-list {
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  }

  /* The rail is full width here, so the follow pills go back to a
     row. Stacked full width pills only make sense in a 300px
     column; across 1000px they would read as three buttons. */
  .res-follow {
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    gap: .7rem .9rem;
  }

  .res-follow-k {
    margin-bottom: 0;
  }
}

@media (max-width: 780px) {
  .featured-post {
    grid-template-columns: 1fr;
    gap: 1rem;
  }

  .featured-meta {
    flex-direction: row;
    align-items: center;
    flex-wrap: wrap;
    gap: .5rem 1.2rem;
  }

  .featured-meta .post-date {
    margin-top: 0;
    padding-top: 0;
    border-top: 0;
  }

  .featured-title {
    font-size: 1.4rem;
  }

  .post-grid {
    grid-template-columns: 1fr;
  }

  /* One track. The sheet still does not go edge to edge: it is a
     child of .wrap now, so .wrap's own 20px gutter keeps the field
     visible beside it and the hand tuned margin it used to carry is
     no longer needed. Padding stays on --plate-pad so the prose and
     the masthead h1 keep their shared left edge here too. */
  .article-wrap {
    grid-template-columns: 1fr;
  }

  .article-wrap > .signal-callout,
  .article-wrap > .article-image {
    grid-column: 1;
    max-width: 100%;
  }

  .article-nav {
    grid-template-columns: 1fr;
  }

  .article-nav-item.next {
    text-align: left;
    align-items: flex-start;
  }
}

@media (max-width: 520px) {
  .featured-post {
    padding: 1.4rem;
  }

  .blog-filters {
    gap: .4rem;
  }

  .filter-btn {
    font-size: .65rem;
    padding: .5em .9em;
  }

  /* The plate keeps its presence at 375px but loses the wide
     padding that would squeeze the sentence into a column. */
  .signal-callout {
    padding: 1.4rem 1.25rem;
  }
}

@media (prefers-reduced-motion: reduce) {
  .featured-post,
  .featured-post::after,
  .post-card,
  .post-card::before,
  .res-item,
  .li-link,
  .linked-resource,
  .article-nav-item,
  .back-to-blog .arw,
  .featured-link .arw {
    transition: none;
    animation: none;
  }
}
