/*
  /p/{slug}/ — the reading layout and body typography.
  design/09-site-decisions.md turns 17–36 are the record. The numbers that matter are settled
  and explicitly not to be re-tuned: 262px rail / 1fr body / 224px notes margin, with the body
  measure landing at 562px (~60ch).
*/

.post {
  background: var(--sh-paper);

  /* --------------------------------------------------------------------------
     Wide-screen centering (Steph, 13 Aug 2026), replacing turn 20's "slack
     accumulates to the RIGHT of the notes margin".

     The columns never moved, so every extra pixel of a wide screen piled up on
     one side: at 1920 the whole apparatus sat against the left edge with a 780px
     void beside it, and a well-set column stranded in the corner of a wide page
     reads as narrow even when the line is 63 characters. Nothing about the
     reading changes here — same 562px measure, same rail, same notes margin.
     Only the empty space moves, and it splits evenly.

     One inset, shared by every block in the article, so the title, the rules, the
     rail and the colored bands all keep the same left edge. `max()` means each
     block keeps its own gutter as the floor, so nothing shifts below ~1268px and
     the mobile rules further down still win outright.

     The colored bands stay full-bleed and centre their CONTENTS instead — a
     tinted breadcrumb or an ink funding band that stopped short of the viewport
     edge would break the flat-block grammar the whole site is built on.
     -------------------------------------------------------------------------- */
  --sh-post-max: 1180px;
  --sh-post-inset: calc((100% - var(--sh-post-max)) / 2);
}

/* --------------------------------------------------------------------------
   Breadcrumb — on a post the section strip becomes the breadcrumb.
   Tint comes from the series.
   -------------------------------------------------------------------------- */

.post__breadcrumb {
  border-bottom: 1px solid var(--sh-ink);
  padding: 9px var(--sh-gutter);
  padding-inline: max(var(--sh-gutter), var(--sh-post-inset));
  display: flex;
  gap: 16px;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  font-family: var(--sh-font-mono);
  font-size: 12px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  background: var(--sh-tint-closed);
}
.post--roundup .post__breadcrumb { background: #cfe1ff; }
.post--bad-job-bingo .post__breadcrumb { background: #fcbcd2; }
.post--deep-dives .post__breadcrumb { background: #e5cde8; }
.post--changelog .post__breadcrumb { background: #e6e4e2; }

/* Links on a tinted surface are ink + underline, never the link purple (00 §2). */
.post__breadcrumb a {
  color: var(--sh-ink);
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* --------------------------------------------------------------------------
   Header — title 76px at 34ch, dek 21px at 82ch (turn 21 addendum).
   Both caps were widened from the old narrow-header values; don't shrink them back.
   -------------------------------------------------------------------------- */

.post__header {
  padding: 44px var(--sh-gutter) 32px;
  padding-inline: max(var(--sh-gutter), var(--sh-post-inset));
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.post__title {
  font-family: var(--sh-font-display);
  font-weight: 400;
  font-size: 76px;
  line-height: 0.95;
  letter-spacing: -0.02em;
  max-width: 34ch;
  text-wrap: pretty;
}

.post__dek {
  font-family: var(--sh-font-body);
  font-size: 21px;
  line-height: 1.5;
  color: var(--sh-grey-on-tint);
  max-width: 82ch;
  text-wrap: pretty;
}

/* No meta rule: 18b settled the facts and their ranking, and the rail redistribution is
   where those facts now live (09, chat 12) — byline and Share/RSS in the rail's WRITTEN BY
   block, read time as the rail countdown, series and date on the breadcrumb. */

/* Tags — an inline comma run, never boxes, never at the foot of the post. FILED UNDER
   closes the header directly under the dek, so it takes over the meta strip's top rule.
   The series tag keeps a 2px underline in its own series tint so it stays findable
   without a box; every other tag is an ordinary purple link. */
.post__tags {
  padding: 14px var(--sh-gutter) 18px;
  padding-inline: max(var(--sh-gutter), var(--sh-post-inset));
  border-top: 1px solid var(--sh-ink);
  border-bottom: 1px solid var(--sh-ink);
  display: flex;
  align-items: baseline;
  gap: 9px;
  flex-wrap: wrap;
}
.post__tags-label {
  font-family: var(--sh-font-mono);
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--sh-grey-on-tint);
  flex: none;
}
.post__tags-list {
  font-family: var(--sh-font-body);
  font-size: 15px;
  line-height: 1.6;
}
/* The ruling above, actually implemented (drift item 74 — the first build gave every tag
   one 1px lavender underline, erasing the findability distinction the ruling exists for).
   Ordinary tags: ordinary purple links. The series tag: ink with the 2px underline in the
   series' own tint — the same three tints the issue-number cells carry. */
.post__tags-list a {
  color: var(--sh-link);
  text-decoration: underline;
  text-underline-offset: 3px;
}
.post__tags-list a[href*="/t/roundup/"],
.post__tags-list a[href*="/t/bad-job-bingo/"],
.post__tags-list a[href*="/t/deep-dives/"] {
  color: var(--sh-ink);
  text-decoration: none;
  border-bottom: 2px solid;
}
.post__tags-list a[href*="/t/roundup/"] { border-bottom-color: #cfe1ff; }
.post__tags-list a[href*="/t/bad-job-bingo/"] { border-bottom-color: #fcbcd2; }
.post__tags-list a[href*="/t/deep-dives/"] { border-bottom-color: #e5cde8; }
.post__tags-list a[href*="/t/roundup/"]:hover,
.post__tags-list a[href*="/t/bad-job-bingo/"]:hover,
.post__tags-list a[href*="/t/deep-dives/"]:hover { border-bottom-color: var(--sh-coral); }

/* --------------------------------------------------------------------------
   The three-column reading layout (turn 20 / turn 21 addenda).
   262 / 1fr / 224 — settled, stop tuning them.

   `overflow: clip` rather than `hidden` on any ancestor: hidden establishes a scroll
   container and silently kills position: sticky. This bug was hit repeatedly during design;
   the note is here so it isn't reintroduced.
   -------------------------------------------------------------------------- */

.post__layout {
  display: grid;
  grid-template-columns: 262px 1fr;
  gap: 26px;
  padding: 26px 30px 34px;
  /* 30px floor is this block's own, not the 44px gutter — turn 20's value. */
  padding-inline: max(30px, var(--sh-post-inset));
  align-items: start;
  border-bottom: 1px solid var(--sh-ink);
  overflow: clip;
}

.post__rail {
  position: sticky;
  top: 16px;
  align-self: start;
  display: flex;
  flex-direction: column;
}
.post__rail[hidden] { display: none; }

/* WRITTEN BY — the byline, share and RSS relocated from the retired meta strip
   (09, chat 12). Renders on every issue, so the rail is never empty. */
.post__rail-byline {
  display: flex;
  flex-direction: column;
  gap: 5px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--sh-ink);
  margin-bottom: 14px;
}
.post__rail-byline-label {
  font-family: var(--sh-font-mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}
.post__rail-byline-name {
  font-family: var(--sh-font-display);
  font-size: 19px;
  line-height: 1.15;
  width: fit-content;
}
.post__rail-byline-actions {
  font-family: var(--sh-font-mono);
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.post__rail-contents[hidden] { display: none; }

/* The rail's <details> wrapper (turn 36). Inert on desktop — the summary hides and the
   element ships open — and a styled 46px disclosure row on mobile, where post.js closes
   it. Ships open in markup so no-JS readers always get the full rail. */
.post__rail-summary { list-style: none; cursor: pointer; }
.post__rail-summary::-webkit-details-marker { display: none; }
@media (min-width: 901px) {
  .post__rail-summary { display: none; }
}

.post__rail-label {
  font-family: var(--sh-font-mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  padding-bottom: 10px;
}

.post__rail-nav { display: flex; flex-direction: column; }

/* All rows sit flush left — the current department is marked by its tint alone, no indent. */
.post__rail-link {
  display: flex;
  gap: 10px;
  align-items: baseline;
  padding: 9px 8px;
  border-top: 1px solid var(--sh-hairline);
  color: var(--sh-ink);
  text-decoration: none;
  /* The rail follows the reader rather than blinking at them (delight pass). The
     current row's tint is set by scroll position, so it changed with a hard cut on
     every department boundary; crossfading makes the rail feel like it is keeping
     up. Color only — the row never moves. */
  transition: background-color 200ms cubic-bezier(0.22, 1, 0.36, 1);
}
.post__rail-link-number {
  font-family: var(--sh-font-mono);
  font-size: 10px;
  color: var(--sh-grey-on-tint);
  flex: none;
}
.post__rail-link-title {
  font-family: var(--sh-font-display);
  font-size: 19px;
  line-height: 1.15;
}
/* On a Roundup the current department is marked by THAT DEPARTMENT'S own tint (09 turn 20;
   drift item 75 — one blanket blue was drift), cycling in the canvas's drawn order like the
   numeral colors above the body do. Department 02's drawn #c9ead6 is Green Means Go's pale
   ground and ramp tints are ratings only, so it takes the teal Steph's 01a §12.2 ruling
   substituted in the identical monogram collision — recorded in 09 turn 20 (10 Aug 2026). */
.post--roundup .post__rail-nav .post__rail-link:nth-of-type(4n + 1)[aria-current] { background: #cfe1ff; }
.post--roundup .post__rail-nav .post__rail-link:nth-of-type(4n + 2)[aria-current] { background: #c6e6e3; }
.post--roundup .post__rail-nav .post__rail-link:nth-of-type(4n + 3)[aria-current] { background: #fbe6d4; }
.post--roundup .post__rail-nav .post__rail-link:nth-of-type(4n + 4)[aria-current] { background: #f0e4f5; }
.post--deep-dives .post__rail-link[aria-current] { background: #e5cde8; }
.post__rail-link[aria-current] { background: var(--sh-tint-closed); }
/* On a Bingo issue the current verdict is marked by its OWN tint (09 turns 30–32),
   never a blanket pink. The classed rules cover the five verdicts; the bare fallback
   below only fires when a body had no recognizable verdicts at all. */
.post--bad-job-bingo .post__rail-link[aria-current] { background: var(--sh-tint-closed); }
.post--bad-job-bingo .post__rail-link--green[aria-current] { background: #c9ead6; }
.post--bad-job-bingo .post__rail-link--fine[aria-current] { background: #fdeadb; }
.post--bad-job-bingo .post__rail-link--tread[aria-current] { background: #f7cac3; }
.post--bad-job-bingo .post__rail-link--bingo[aria-current] { background: #fcbcd2; }
.post--bad-job-bingo .post__rail-link--dont[aria-current] { background: #d6d4d6; }

.post__rail-progress {
  border-top: 1px solid var(--sh-ink);
  margin-top: 14px;
  padding-top: 12px;
  font-family: var(--sh-font-mono);
  font-size: 10px;
  line-height: 1.6;
  text-transform: uppercase; /* READING 01 OF 04 — the mono meta voice is caps (09 t20) */
  color: var(--sh-grey-on-paper);
}
.post__rail-progress:empty { display: none; }

/* On an issue with no departments (17d — every Deep Dive, and a changelog note) the
   contents block is hidden, so the byline's bottom rule and this one closed an empty
   28px band. With nothing between them, one rule is the separation. */
.post__rail-contents[hidden] + .post__rail-progress {
  border-top: none;
  margin-top: 0;
  padding-top: 0;
}

/* No series (a changelog note) → no definition copy renders; the rail is unconditional
   now, so an empty definition would otherwise show as a bare rule. */
.post__rail-definition:not(:has(span)) { display: none; }

.post__rail-definition {
  border-top: 1px solid var(--sh-hairline);
  margin-top: 14px;
  padding-top: 12px;
  display: flex;
  flex-direction: column;
  gap: 5px;
  font-family: var(--sh-font-body);
  font-size: 13px;
  line-height: 1.45;
}
.post__rail-definition-label {
  font-family: var(--sh-font-mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.post__body { min-width: 0; }

/* --------------------------------------------------------------------------
   The content column and its notes margin.

   Every direct child of the rendered content sits in column 1 whether or not it has a note
   beside it, so the text column never changes width mid-issue. An issue with no footnotes has
   an empty right margin: "a margin that is sometimes empty is a book; a measure that changes
   per post is a bug."
   -------------------------------------------------------------------------- */

.post__content {
  display: grid;
  /* minmax(0, 562px), NOT 1fr: 09 §"the reading measure" fixes the measure at 562px
     (≈60ch) and "the body never widens" — 1fr let it balloon to ~86ch at 1440 and ~145ch
     at 1920 (critique, 12 Aug 2026). The canvas draws every post frame as an 1180px page;
     with this cap the column computes to exactly 562px there. Below ~1208px viewports the
     track shrinks exactly as 1fr did, so mobile behavior is unchanged. Slack accumulates
     to the RIGHT of the notes margin — fixed columns on wide paper, like the broadsheet
     grammar everywhere else; the notes stay adjacent to the prose they annotate. */
  grid-template-columns: minmax(0, 562px) 224px;
  justify-content: start;
  /* `0 28px`, not `28px`: the 28 is the GUTTER between the text column and the notes
     margin, and the shorthand was applying it to the rows as well. Every block in the
     body was then sitting 48px from the next — the 28px row gap plus its own 20px
     margin — which is not what any of this file's spacing says. Row rhythm belongs to
     the margins below, where it can differ per element (a heading is not a paragraph);
     a grid gap cannot tell them apart. */
  gap: 0 28px;
  padding: 8px 8px 0;
  align-items: start;
}

.post__content > * {
  grid-column: 1;
  min-width: 0;
  margin: 0 0 20px;
}

/* Body copy. 18px / 1.62 at the 562px measure. */
.post__content p {
  font-family: var(--sh-font-body);
  font-size: 18px;
  line-height: 1.62;
}

/* Departments (H2) — oversized numeral in the department's own darkened tint, name beside it.
   No rule, no box, no band (turn 21, 21c). Numbering is generated, so adding or reordering a
   department costs nothing at authoring time and can never drift out of sync. */
.post__content {
  counter-reset: department;
}

.post__content h2 {
  counter-increment: department;
  display: flex;
  align-items: flex-start;
  gap: 18px;
  font-family: var(--sh-font-display);
  font-weight: 400;
  font-size: 40px;
  line-height: 1;
  margin: 36px 0 18px;
  scroll-margin-top: 24px;
}

.post__content h2::before {
  content: counter(department, decimal-leading-zero);
  font-family: var(--sh-font-display);
  font-size: 62px;
  line-height: 0.8;
  flex: none;
  color: var(--sh-grey);
}

/* Department tints cycle in the settled order. A fifth department reuses the first color
   rather than inventing one — the scale is meant to hold without adding bands. */
.post__content h2:nth-of-type(4n + 1)::before { color: #6ea8f5; }
.post__content h2:nth-of-type(4n + 2)::before { color: #7fbf9a; }
.post__content h2:nth-of-type(4n + 3)::before { color: #e09a52; }
.post__content h2:nth-of-type(4n + 4)::before { color: #a879b5; }

/* Story subheads (H3) — the label voice, not the serif. Departments own the serif and the
   color; a story head in the same family at a close size reads as a new department on a long
   scroll, which is the bug this fixed. */
/* The margins are stated in full because the row gap used to supply the missing half:
   a subhead had 28px of grid gap beneath it and no bottom margin of its own, so
   removing the gap left it sitting on top of its own first line. A label belongs to
   what follows it, so it keeps clear air above and closes up below. */
.post__content h3 {
  font-family: var(--sh-font-body);
  font-size: 17px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  line-height: 1.3;
  margin: 16px 0 7px;
}

/* Bad Job Bingo verdict headers are H2s too, but carry the mono meta voice rather than the
   serif — a verdict is a label, not a heading, and it already renders as a mono chip
   everywhere else on the site. 26px is set by one requirement: SERIOUSLY, MAYBE DON'T must
   fit on one line inside the 562px measure. */
.post--bad-job-bingo .post__content h2 {
  font-family: var(--sh-font-mono);
  font-size: 26px;
  font-weight: 700;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  white-space: nowrap;
  align-items: center;
  gap: 12px;
  /* The rule goes BELOW the header, never above: above it separates the header from the
     listing that preceded it; below it separates the header from the title it introduces.
     It stops at the text column, not the outer edge — the notes margin belongs to the body.
     The neutral grey is only the fallback for non-verdict furniture headings an imported
     body may still carry (Get Hired); the five real verdicts override it below. */
  border-bottom: 3px solid var(--sh-grey);
  padding-bottom: 9px;
}
.post--bad-job-bingo .post__content h2::before {
  content: none;
}

/* The 32f composition, keyed by the classes post.js derives from the header text:
   header in the verdict's own darkened tint (26px bold mono is WCAG large text, so the
   display values hold), 30px icon left, derived count right-aligned, 3px rule in the
   verdict's own pale tint. Colors are CLAUDE.md's verdict table, verbatim. */
.post--bad-job-bingo .post__content h2.post__verdict--green { color: #4a8262; border-bottom-color: #c9ead6; }
.post--bad-job-bingo .post__content h2.post__verdict--fine { color: #b0733c; border-bottom-color: #fdeadb; }
.post--bad-job-bingo .post__content h2.post__verdict--tread { color: #c2705f; border-bottom-color: #f7cac3; }
.post--bad-job-bingo .post__content h2.post__verdict--bingo { color: #c05c86; border-bottom-color: #fcbcd2; }
.post--bad-job-bingo .post__content h2.post__verdict--dont { color: #5f5d5f; border-bottom-color: #d6d4d6; }

.post__verdict-icon { width: 30px; height: 30px; flex: none; }

/* The count is ≤15px, so it uses the verdict's small-text value, not the display one. */
.post__verdict-count {
  margin-left: auto;
  font-size: 12px;
  font-weight: 400;
  letter-spacing: 0.08em;
}
.post__verdict--green .post__verdict-count { color: #356048; }
.post__verdict--fine .post__verdict-count { color: #7d5028; }
.post__verdict--tread .post__verdict-count { color: #94493a; }
.post__verdict--bingo .post__verdict-count { color: #8f3a5c; }
.post__verdict--dont .post__verdict-count { color: #4a484a; }

/* Deep Dive subheads (09 §"Deep Dives"): H2s take the same treatment as Roundup story
   heads — the label voice, no numerals. Numbering made the rail read like a Roundup's
   departments, which are a different kind of thing. */
/* Same label voice as a Roundup story head, so the same closing-up below — it was
   leaning on the row gap in exactly the same way. */
.post--deep-dives .post__content h2 {
  display: block;
  font-family: var(--sh-font-body);
  font-size: 17px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  line-height: 1.3;
  margin: 30px 0 7px;
}
.post--deep-dives .post__content h2::before {
  content: none;
}

/* Job titles inside a Bingo issue stay the largest thing in the section — the listings are
   the content and the verdict is the label on them. */
.post--bad-job-bingo .post__content h4 {
  font-family: var(--sh-font-display);
  font-weight: 400;
  font-size: 34px;
  line-height: 1.06;
  margin: 24px 0 4px;
}

/* --------------------------------------------------------------------------
   The department's own address.

   The rail could always jump to a department; a reader could never hand one to
   anybody else. On a Bingo issue that is the unit people actually talk about —
   "look at this listing" — so the heading carries a copyable link to itself.

   Straight from the Footnotes grammar (04a §12): grey at rest and never hidden,
   ink once the hand or the keyboard is near, and the ✓ landing as a one-beat
   stamp at the jobs dauber's −5°. post.js announces the copy through a
   role="status" region, because a glyph swap is silent to a screen reader.
   -------------------------------------------------------------------------- */

.post__heading-anchor {
  border: 0;
  background: none;
  padding: 2px 5px;
  font-family: var(--sh-font-mono);
  font-size: 14px;
  font-weight: 400;
  line-height: 1;
  letter-spacing: 0;
  color: var(--sh-grey-on-paper);
  cursor: pointer;
  text-transform: none;
  flex: none;
  align-self: center;
  transition: color 0.18s cubic-bezier(0.25, 1, 0.5, 1);
}
.post__content h2:hover .post__heading-anchor,
.post__heading-anchor:focus-visible { color: var(--sh-ink); }
.post__heading-anchor.is-copied { animation: sh-anchor-stamp 0.18s cubic-bezier(0.25, 1, 0.5, 1); }
@keyframes sh-anchor-stamp { from { transform: scale(1.5) rotate(-5deg); } }

/* On a Roundup the anchor trails the department name; on Bingo the count is
   already pushed right by margin-left:auto, so the anchor follows it and the
   pair sits together at the end of the rule. */
.post--bad-job-bingo .post__content h2 .post__heading-anchor { margin-left: 8px; }
.post__content h2:not(.post__verdict) .post__heading-anchor { margin-left: 4px; }

/* --------------------------------------------------------------------------
   Quotes — two devices, and they must not look alike.
   The rule that falls out: a left bar means someone else is talking. Steph's own words
   never take one.
   -------------------------------------------------------------------------- */

/* Someone else's words. Mirrors Footnotes exactly. Indented 22px so a Bingo issue's
   quote-then-reply alternation reads as a two-level rhythm while scrolling. */
.post__content blockquote {
  margin: 6px 0 20px 22px;
  border-left: 2px solid var(--sh-grey);
  padding-left: 14px;
  /* The voice sits on the blockquote itself, not only on its paragraphs. An
     imported quote is bare text and <br>s with no <p> to hang it on, and the
     Their-Words Rule must not depend on how the body was pasted; post.js
     wraps those runs into paragraphs, and this is what holds if it never runs.

     Normal flow, NOT flex: a flex blockquote makes every inline child its own
     flex item, so a quoted sentence carrying a link breaks into gapped chunks
     mid-line. Same bug and same fix as the list rows (drift item 114) — the
     spacing that flex was providing is the paragraph margin below. */
  font-family: var(--sh-font-display);
  font-style: italic;
  font-size: 21px;
  line-height: 1.34;
}
.post--roundup .post__content blockquote { border-left-color: #6ea8f5; }
.post--bad-job-bingo .post__content blockquote { border-left-color: #fcbcd2; border-left-width: 3px; }
.post--deep-dives .post__content blockquote { border-left-color: #a879b5; }

/* Re-declared rather than inherited: .post__content p sets the body face at a
   lower specificity than this, so a quote's paragraphs need it said again. */
.post__content blockquote p {
  font-family: var(--sh-font-display);
  font-style: italic;
  font-size: 21px;
  line-height: 1.34;
  margin: 0 0 10px;
}
.post__content blockquote p:last-child { margin-bottom: 0; }

/* Steph emphasizing her own line — a pull quote. Bold body sans, never italic, never a bar.
   Authored as a blockquote carrying the .sh-pull class via Ghost's markdown/HTML card. */
.post__content .sh-pull {
  border-left: none;
  margin: 10px 0 20px;
  padding-left: 0;
  /* Flex is declared here rather than inherited from the blockquote rule: this
     device really is a row — glyph, then line — and it is the only quote shape
     that wants one. font-style resets so the ✦ glyphs stay upright. */
  display: flex;
  flex-direction: row;
  gap: 14px;
  align-items: flex-start;
  font-style: normal;
}
.post__content .sh-pull::before {
  content: "✦";
  font-family: var(--sh-font-display);
  font-size: 26px;
  line-height: 1;
  color: var(--sh-coral);
  flex: none;
  padding-top: 4px;
}
.post__content .sh-pull p {
  font-family: var(--sh-font-body);
  font-style: normal;
  font-weight: 700;
  font-size: 27px;
  line-height: 1.24;
  letter-spacing: -0.01em;
}

/* The mark opens AND closes the line (25b) — the closing ✦ trails the text inline rather than
   sitting in its own column, so it hugs the end of the sentence wherever it wraps to. */
.post__content .sh-pull p::after {
  content: "✦";
  font-family: var(--sh-font-display);
  font-weight: 400;
  font-size: 26px;
  color: var(--sh-coral);
  padding-left: 10px;
  /* Decorative: the highlight must not paint behind it. Since turn 38 the paint sits on an
     inner span and this pseudo is outside it, so that is now structural rather than a reset —
     kept because it also covers a hand-authored <mark> that swallows the whole line. */
  background: none;
}

/* THE MARKER HIGHLIGHT — turn 38, `38a` adopted. The line to screenshot, at most once per
   issue: if a second would help, one of them isn't the point.

   Steph's brief was "look like a physically highlighted line in a book". What this replaces was
   a highlight-shaped UNDERLINE: an opaque band under the words, tiled across the full measure,
   so a wrapped quote's last line ran to the margin past its final word. A hand never does that.

   Three things make it physical, and none of them is a new color:

   1. THE INK GOES OVER THE WORDS AND IS TRANSLUCENT — coral at 40–55% alpha, so the type and
      the paper read through it.
   2. IT ENDS WITH THE WORDS. The paint is on an inline span with `box-decoration-break: clone`,
      not on the block, so each line gets its own stroke that stops where the line stops.
   3. TWO PASSES, TILTED A FRACTION APART, the lower one narrower and inset so it stops inside
      the upper at both ends. That overlap is the only dark part and it is the whole effect —
      two strokes of a pen rather than one printed bar. DO NOT tidy 179.1deg/180.9deg to 180deg,
      and do not drop the narrowing: `37b`/`37d` tried both passes at the same width and it read
      as a printed bar again. Superseded, in the canvas as a record.

   The `mark` selector is here too so a hand-authored <mark> inside a pull quote gets the
   display treatment by position rather than by size guess. */
.post__content .sh-pull--marked .sh-mark,
.post__content .sh-pull mark {
  background-color: transparent;   /* the UA default is yellow */
  color: inherit;
  /* Values in main.css :root — one device, one definition. See the note there. */
  background-image: var(--sh-mark-two-pass);
  background-size: var(--sh-mark-two-pass-size);
  background-position: var(--sh-mark-two-pass-pos);
  background-repeat: no-repeat;
  box-decoration-break: clone;
  -webkit-box-decoration-break: clone;
  padding: 0.02em 0.24em 0.05em 0.14em;
  margin: 0 -0.14em;
}

/* BODY SIZE — one pass (`37a`). 24px is a hard floor and `38b` is the frame that proves it:
   below it the tilt between the two passes is about a pixel and the thing reads as a smudge.
   One pass at 55% instead, because a single stroke has no overlap to darken it.

   This selector did not exist. Body-size <mark> fell through to the UA yellow. */
.post__content mark,
.post__content .sh-mark--sm {
  background-color: transparent;
  color: inherit;
  background-image: var(--sh-mark-one-pass);
  background-repeat: no-repeat;
  box-decoration-break: clone;
  -webkit-box-decoration-break: clone;
  padding: 0.02em 0.16em 0.05em;
  margin: 0 -0.12em;
}

/* The swipe lands when the reader reaches it (delight pass). This is "the line to
   screenshot", at most once per issue (turn 25d) — so it is the one place on the page
   where a moment is affordable, and a highlighter is a thing a hand DOES, not a color
   that was always there. post.js adds the class from a one-shot observer, the same
   mechanism as the sign-off twinkle.

   The painted state is the DEFAULT above, so a hidden tab, a headless renderer and a print
   all get the finished swipe; this only animates how it arrives, and the reduced-motion
   blanket zeroes it.

   WHAT CHANGED AT TURN 38: the paint moved off the block onto an inline span, and on a pull
   quote that span is injected by post.js — so **with JavaScript off the quote now renders with
   no highlight at all**, where it used to keep the old band. That is deliberate rather than an
   oversight. The block-level fallback can only be the treatment turn 38 rejected — a stripe
   running past the last word to the margin — and degrading to a rejected treatment is worse
   than degrading to a plain pull quote, which still reads as one: bold 27px sans between two
   coral glyphs. An author who wants the highlight without JS can write <mark> inside the
   quote; the selector above catches it. */
@keyframes sh-pull-swipe {
  from { background-size: 0% 100%, 0% 100%; }
  to   { background-size: var(--sh-mark-two-pass-size); }
}
.post__content .sh-pull--marked.sh-pull--swiped .sh-mark {
  animation: sh-pull-swipe 0.62s cubic-bezier(0.22, 1, 0.36, 1) both;
}

/* --------------------------------------------------------------------------
   Lists — style chosen by length (turn 26).
   Five or more items → ruled rows, because the shoutout list runs 20+ names and people scan
   it for themselves. Fewer than five → hanging markers; ruled rows read as a table, which is
   wrong for a three-item flag list.

   CSS can't count list items, so the ruled treatment is the default (the long lists are the
   common case) and .sh-list-short opts a short list out.
   -------------------------------------------------------------------------- */

.post__content ul,
.post__content ol {
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
}

/* The marker is absolutely positioned rather than a flex item. A flex `li` makes every inline
   child — every link, every bare text node — its own flex item, which breaks a sentence into
   gapped chunks. Ghost's editor emits `li` with raw inline content, so the row has to stay
   normal inline flow. Turn 26's geometry survives the mechanism swap (drift item 114, and
   the dated note in 09 turn 26): the numeral keeps its 18px box so digits stay aligned,
   the gutter its 9px — realised here as an 18px marker box + 27px text inset. */
.post__content li {
  font-family: var(--sh-font-body);
  font-size: 18px;
  line-height: 1.55;
  display: block;
  position: relative;
  padding: 10px 0 10px 27px;
  border-top: 1px solid var(--sh-hairline);
}

.post__content ul li::before {
  content: "✦";
  position: absolute;
  left: 0;
  top: 10px;
  font-family: var(--sh-font-display);
  font-size: 15px;
  line-height: 1.55;
  color: var(--sh-coral);
}

.post__content ol {
  counter-reset: ordered;
}
.post__content ol li {
  counter-increment: ordered;
}
.post__content ol li::before {
  content: counter(ordered, decimal-leading-zero);
  position: absolute;
  left: 0;
  top: 10px;
  width: 18px; /* turn 26: the numeral keeps an 18px box so digits stay aligned */
  font-family: var(--sh-font-mono);
  font-size: 11px;
  line-height: 2.4;
  color: var(--sh-purple-display);
}

.post__content .sh-list-short li {
  border-top: none;
  padding-top: 3px;
  padding-bottom: 3px;
}
.post__content .sh-list-short li::before { top: 3px; }

/* --------------------------------------------------------------------------
   Tables (27a) — hairline rows: no verticals, no fill, no zebra.
   Three columns is the ceiling. On mobile the table keeps its columns and scrolls inside its
   own box rather than reflowing into stacked pairs, which would destroy the comparison the
   table exists to make.
   -------------------------------------------------------------------------- */

.post__content table {
  width: 100%;
  border-collapse: collapse;
  font-family: var(--sh-font-body);
}
.post__content th {
  font-family: var(--sh-font-mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  text-align: left;
  border-bottom: 2px solid var(--sh-ink);
  padding: 8px 10px 8px 0;
}
.post__content td {
  font-size: 17px;
  border-bottom: 1px solid var(--sh-hairline);
  padding: 10px 10px 10px 0;
}
.post__content td:not(:first-child) {
  font-family: var(--sh-font-mono);
  font-size: 15px;
  font-variant-numeric: tabular-nums;
  text-align: right;
}

/* --------------------------------------------------------------------------
   Upcoming Events inside an issue (28b, adopted by 09 turn 28; drift item 79 — the
   treatment had no implementation, so the section could only ever degrade to 28a prose).
   Date column in Space Mono at the left, title in Instrument Serif 25px, host and
   Register → beneath, one hairline per event. Authored via the Ghost snippet whose five
   fields — date, place/time, title, host, link — are documented in docs/migration-todo.md;
   a body without the snippet still degrades to 28a prose gracefully.
   -------------------------------------------------------------------------- */

.post__content .sh-events { display: flex; flex-direction: column; }
.post__content .sh-event {
  display: grid;
  grid-template-columns: 116px 1fr;
  gap: 16px;
  align-items: baseline;
  padding: 13px 0;
  border-top: 1px solid var(--sh-hairline);
  margin: 0;
}
.post__content .sh-event__when {
  font-family: var(--sh-font-mono);
  font-size: 11px;
  font-weight: 700;
  line-height: 1.5;
  margin: 0;
}
.post__content .sh-event__when span {
  font-weight: 400;
  color: var(--sh-grey-on-tint);
}
.sh-event__main {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.post__content .sh-event__title {
  font-family: var(--sh-font-display);
  font-size: 25px;
  line-height: 1.1;
  margin: 0;
}
.post__content .sh-event__host {
  font-family: var(--sh-font-body);
  font-size: 15px;
  line-height: 1.45;
  margin: 0;
}

/* --------------------------------------------------------------------------
   Images (turn 35). All body images are centered in the column, figure and caption alike.
   A GIF is never upscaled past natural width — a flex/grid parent stretches it otherwise,
   which is a bug that appeared twice during design.
   -------------------------------------------------------------------------- */

.post__content figure {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
}
/* Height is deliberately NOT set here. The reset's `img { height: auto }` is weak enough
   (one type selector) to lose to any class that wants a fixed image height, which is what
   keeps the 30px verdict icons at 30px — they live inside .post__content too, and are
   sized by `.post__verdict-icon { height: 30px }` with the width below following the
   ratio. Adding `height: auto` to this rule outranks that class and blows the icons up to
   their natural 100px. The reset handles the body images; this rule handles their width. */
.post__content img {
  width: auto;
  max-width: 100%;
  align-self: center;
}

/* Captions give the SOURCE, not a description — the description always lives in alt. */
.post__content figcaption {
  font-family: var(--sh-font-mono);
  font-size: 12px;
  color: var(--sh-grey-on-paper);
  text-align: center;
}

/* The closing meme (09 turn 35): "a position, not a treatment" — regular width capped
   ~420px, 30px of air above rather than the body rhythm, so it reads as the issue
   exhaling. post.js adds the class to the body's last image card when nothing but the
   notes block follows it (drift item 77) — no authoring hook to remember. */
.post__content figure.post__meme {
  max-width: 420px;
  margin-top: 30px;
  margin-left: auto;
  margin-right: auto;
}

/* Ghost's own card widths, mapped onto this grid. Regular is the 562px measure; Wide spans
   BOTH flanks — "the notes margin and contents rail" (09 turn 35; drift item 76 — the first
   build stopped at the notes margin). The rail lives in the outer .post__layout grid, so the
   only way across it from in here is the negative margin: 262px rail + 26px gap. The sticky
   rail can sit over a Wide card while the reader is scrolled beside it — that is inherent in
   the ruled extent, and Wide is a deliberate exception by the same turn. Full is deliberately
   not used on posts — a viewport-bleeding body image fights the three-column grid — so it is
   clamped to Wide rather than allowed to escape. */
.post__content .kg-width-wide,
.post__content .kg-width-full {
  grid-column: 1 / -1;
  width: auto;
  /* 262px rail + 26px layout gap + the content grid's own 8px side padding */
  margin-left: -296px;
}

/* --------------------------------------------------------------------------
   Footnotes.
   Markers are superscript numerals in the link purple. The NOTES block at the foot is the
   source of truth and is always printed — email, RSS and print all get it. On desktop,
   assets/js/post.js clones each note into the margin at its marker's offset.
   -------------------------------------------------------------------------- */

/* Ghost emits the marker as `a > sup` — the anchor WRAPS the numeral — so neither
   original selector (`sup a`, `[data-note-ref]`) matched a real body, and every marker
   on the site shipped as an ordinary 15px Helvetica link rather than the mono numeral
   this section describes. The type now goes on the numeral itself, which is the one
   element present in all three shapes; the color goes on whatever is the anchor. */
.post__content sup,
.post__content a[data-note-ref] {
  font-family: var(--sh-font-mono);
  font-size: 12px;
  font-weight: 700;
}
.post__content a[data-note-ref] { vertical-align: super; }

.post__content a[data-note-ref],
.post__content sup a,
.post__content a:has(> sup) {
  color: var(--sh-link);
  text-decoration: none;
}

/* The margin copies. Absolutely positioned inside a relative aside at each marker's own
   offset — never with stacked padding, which was introduced and fixed three separate times
   during design. Spacing is derived from rendered height because note clusters are normal. */
.post__notes-margin {
  grid-column: 2;
  grid-row: 1 / -1;
  position: relative;
  align-self: stretch;
}

.post__note-margin {
  position: absolute;
  left: 0;
  width: 100%;
  display: flex;
  gap: 10px;
  align-items: flex-start;
}
.post__note-margin-number {
  font-family: var(--sh-font-mono);
  font-size: 12px;
  font-weight: 700;
  color: var(--sh-link);
  flex: none;
  padding-top: 10px;
}
.post__note-margin-body {
  font-family: var(--sh-font-body);
  font-size: 13px;
  line-height: 1.5;
  padding-top: 10px;
  border-top: 1px solid var(--sh-hairline);
}

/* --------------------------------------------------------------------------
   A marker and its note are one thing (delight pass, 09 §"the page keeps up").

   28px of gutter separate a numeral in the text from the note that answers it, and
   nothing joined them: on a page with four notes the reader matched numerals by eye.
   Pointing at either half — or tabbing to the marker — lights both.

   The lit marker stops being a link and becomes the thing itself: the series tint
   behind it, ink on top. That is the site's own rule for a link on a tinted surface,
   and the tints are the three the breadcrumb, the rail and the quote bars already use.
   Negative margins cancel the padding, so nothing shifts when the block appears.
   -------------------------------------------------------------------------- */

.post { --sh-post-note-tint: var(--sh-tint-closed); }
.post--roundup { --sh-post-note-tint: #cfe1ff; }
.post--bad-job-bingo { --sh-post-note-tint: #fcbcd2; }
.post--deep-dives { --sh-post-note-tint: #e5cde8; }

/* The block is padded on the TRAILING side only. A symmetric one bled 3px to the left,
   where the marker's neighbor is the word it annotates — the tint painted over the
   comma or colon the numeral follows (Steph, 13 Aug 2026). The space after a marker is
   the only side with room to give, and the negative margin there keeps the sentence
   from shifting when the block appears. */
.post__content .post__note-mark {
  padding: 1px 3px 1px 0;
  margin-right: -3px;
  transition: background-color 160ms cubic-bezier(0.22, 1, 0.36, 1),
              color 160ms cubic-bezier(0.22, 1, 0.36, 1);
}
/* `--here` is the same paint held open by the hash rather than by the pointer: on
   desktop the foot list is hidden, so clicking a marker had nothing to show for
   itself — the note it points at is already in the margin. Now that note lights and
   stays lit, which is the desktop half of the same "here" the phone gets from
   :target. Separate class so a passing pointer can't clear a pinned note. */
.post__content .post__note-mark--lit,
.post__content .post__note-mark--here {
  background: var(--sh-post-note-tint);
  color: var(--sh-ink);
}

/* The note answers with the same wash a note you jumped to takes, so "the one I'm
   attending to is tinted" means one thing on this page whether the reader pointed at
   it or arrived at it. The rule above it goes ink at the same time — hairline to ink
   is how this system has always said "this one". The 8px of padding is canceled by
   the matching negative margin, so the note's text stays on its own left edge and the
   tint simply grows around it. */
.post__note-margin-number,
.post__note-margin-body {
  transition: color 160ms cubic-bezier(0.22, 1, 0.36, 1),
              border-color 160ms cubic-bezier(0.22, 1, 0.36, 1),
              background-color 160ms cubic-bezier(0.22, 1, 0.36, 1);
}
.post__note-margin-body {
  padding-left: 8px;
  padding-right: 8px;
  padding-bottom: 8px;
  margin: 0 -8px;
}
.post__note-margin--lit .post__note-margin-number,
.post__note-margin--here .post__note-margin-number { color: var(--sh-ink); }
.post__note-margin--lit .post__note-margin-body,
.post__note-margin--here .post__note-margin-body {
  border-top-color: var(--sh-ink);
  background: var(--sh-post-note-tint);
}
.post__note-margin--here .post__note-margin-body {
  animation: sh-note-arrive 0.5s cubic-bezier(0.25, 1, 0.5, 1);
}

/* A caption mirrored into the margin (turn 35: the default for Regular-width images).
   Space Mono 12px #6b6b6b, per the record; the in-body figcaption hides while mirrored
   so the caption exists exactly once. Shares the notes' collision flow in post.js. */
.post__caption-margin {
  position: absolute;
  left: 0;
  width: 100%;
  font-family: var(--sh-font-mono);
  font-size: 12px;
  line-height: 1.5;
  color: var(--sh-grey-on-paper);
}
.post__content figure[data-caption-mirrored] figcaption { display: none; }

/* --------------------------------------------------------------------------
   The Bingo standing note (09 turn 33, 33a). Quieter and distinctly shaped —
   never louder: hairlines above and below, STANDING NOTE in a 96px left
   gutter, body at 15px #3a3a3a, the past-contestants line demoted to 11px
   mono. Wrapped by post.js from the fixture paragraphs (or authored as
   .sh-standing directly).
   -------------------------------------------------------------------------- */
.sh-standing {
  display: grid;
  grid-template-columns: 96px minmax(0, 1fr);
  border-top: 1px solid var(--sh-hairline);
  border-bottom: 1px solid var(--sh-hairline);
  padding: 14px 0 16px;
  margin: 6px 0 26px;
}
.sh-standing__label {
  font-family: var(--sh-font-mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  padding: 3px 12px 0 0;
}
.sh-standing__body p {
  font-size: 15px;
  line-height: 1.6;
  color: var(--sh-grey-on-tint);
  margin: 0 0 10px;
}
.sh-standing__body p:last-child { margin-bottom: 0; }
.sh-standing__body .sh-standing__past {
  font-family: var(--sh-font-mono);
  font-size: 11px;
}

/* The foot-of-page notes list. Omitted entirely rather than rendered with a heading and
   nothing beneath it when an issue has no notes. */
.post__content .sh-notes {
  grid-column: 1;
  border-top: 1px solid var(--sh-ink);
  margin-top: 30px;
  padding-top: 16px;
}
/* The 27px text inset is turn 26's list geometry (18px numeral box + 9px gutter) and it
   has to survive here: the shorthand was resetting padding-left to 0 while the numeral
   stayed absolutely positioned at left 0, so every note printed its own number on top of
   its first word — on a phone, in print, and on desktop any time the margin isn't built. */
.post__content .sh-notes li {
  font-size: 15px;
  border-top: none;
  padding: 6px 0 6px 27px;
  scroll-margin-top: 24px;
}
.post__content .sh-notes li::before {
  color: var(--sh-link);
}

/* The note you jumped to says "here" (delight pass). This is the whole footnote
   experience on a phone — the margin doesn't exist there, so tapping a marker drops
   the reader at the foot of a list of notes that all look alike. The house arrival
   grammar answers it: the series tint washes in from paper, same 500ms curve as a
   Footnotes entry. Server-rendered ids, so :target works natively and needs no class
   twin (unlike /footnotes/, where the entries arrive by fetch — 04a §12). */
.post__content .sh-notes li:target {
  background: var(--sh-post-note-tint);
  animation: sh-note-arrive 0.5s cubic-bezier(0.25, 1, 0.5, 1);
}
@keyframes sh-note-arrive { from { background: var(--sh-paper); } }

/* Hidden at desktop only when the margin copies are actually in place, so a JS failure leaves
   the foot notes visible rather than removing the only copy. */
.post__content .sh-notes[data-mirrored="true"] {
  display: none;
}

/* --------------------------------------------------------------------------
   Sign-off (29c) — a halftone blush note. Capped at the 562px text column for the same
   reason the verdict rules are: it belongs to the text, so it should not reach across the
   margin the footnotes live in. And because it belongs to the text, it LIVES in the text:
   inside .post__body, closing on the last thing in the body directly (09 turn 35 — the
   closing meme, most issues; drift item 78 moved it back in from below the layout's
   full-width rule, where it left-aligned under the rail).
   -------------------------------------------------------------------------- */

.post__signoff {
  /* The 8px sides mirror .post__content's own padding, so the note's left edge sits
     exactly on the text column's. */
  margin: 24px 8px 0;
  max-width: 562px;
  background: var(--sh-tint-newsletter);
  padding: 20px 22px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  position: relative;
  overflow: clip;
}
.post__signoff::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: radial-gradient(var(--sh-ink) 0.6px, transparent 0.7px);
  background-size: 5px 5px;
  opacity: 0.14;
  pointer-events: none;
}
.post__signoff-label,
.post__signoff-body {
  position: relative;
}
.post__signoff-label {
  font-family: var(--sh-font-mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  display: flex;
  align-items: baseline;
  gap: 10px;
}
/* The finish line twinkles once when the reader actually reaches it (post.js adds the
   class via a one-shot observer) — the peak-end moment of an issue, in the system's own
   glyph. Keyframes live in main.css; the reduced-motion blanket zeroes it. */
.post__signoff--arrived .sh-twinkle {
  display: inline-block;
  animation: sh-twinkle-glint 0.55s cubic-bezier(0.22, 1, 0.36, 1) 0.2s 1 both;
}
.post__signoff-body {
  display: flex;
  flex-direction: column;
  gap: 11px;
  font-family: var(--sh-font-body);
  font-size: 17px;
  line-height: 1.55;
}
/* Links sit on a tint here, so they take ink + underline rather than the link purple. */
.post__signoff-body a {
  color: var(--sh-ink);
  text-decoration: underline;
  text-underline-offset: 3px;
}
.post__signoff-close {
  font-family: var(--sh-font-display);
  font-style: italic;
  font-size: 19px;
  line-height: 1.35;
}

/* --------------------------------------------------------------------------
   Subscribe band
   -------------------------------------------------------------------------- */

/* --------------------------------------------------------------------------
   The subscribe block — paper, not an ink band (Steph, 13 Aug 2026).

   It shipped as a full-bleed ink slab, which put a hard stop in the middle of
   the paper run: body → sign-off → BLACK → comments → more reading → black foot.
   Two dark bands were doing different jobs on one page, and the heavier
   treatment sat on the LIGHTER of the two asks — this one is free, no gate, no
   schedule, while the funding band below asks for money.

   Ink now means one thing on this page: the foot, the end. The block keeps its
   position, its copy and its order — after the sign-off, where "that's the
   issue" is followed by "here's how to get the next one", which is why it has
   never read as pressure. Only the weight comes off.

   The layout above already closes on an ink rule, so a matching rule below is
   what separates this from the comments panel — the same top-and-bottom pair
   FILED UNDER uses.
   -------------------------------------------------------------------------- */
.post__subscribe {
  background: var(--sh-paper);
  color: var(--sh-ink);
  border-bottom: 1px solid var(--sh-ink);
  padding: 30px var(--sh-gutter);
  padding-inline: max(var(--sh-gutter), var(--sh-post-inset));
  display: grid;
  grid-template-columns: 1fr 400px;
  gap: 56px;
  align-items: center;
}
.post__subscribe-heading {
  font-family: var(--sh-font-display);
  font-size: 34px;
  line-height: 1.04;
}
.post__subscribe-sub {
  font-family: var(--sh-font-body);
  font-size: 15px;
  line-height: 1.55;
  color: var(--sh-grey-on-paper);
  max-width: 48ch;
  margin-top: 10px;
}
.post__subscribe-action {
  display: flex;
  flex-direction: column;
  gap: 14px;
  align-items: flex-start;
}
.post__subscribe-button {
  background: var(--sh-ink);
  color: var(--sh-paper);
  text-decoration: none;
  padding: 13px 22px;
  font-family: var(--sh-font-body);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
/* The house button hover: ground shifts to #6b6b6b, text stays paper (00 §5). */
.post__subscribe-button:hover { background: var(--sh-grey-on-paper); color: var(--sh-paper); }
.post__subscribe-rss {
  font-family: var(--sh-font-mono);
  font-size: 11px;
  letter-spacing: 0.06em;
  color: var(--sh-link);
}

/* --------------------------------------------------------------------------
   Comments — the theme-side shell (Comments.dc.html 1a/1d). The panel, its header, the 21b
   rules strip and the foot-of-thread contact line live here in ordinary page HTML; everything
   Ghost renders sits inside the comments-ui iframe between the strip and the foot line, styled
   by css/comments.css, which assets/js/comments.js injects into the (same-origin) iframe.
   -------------------------------------------------------------------------- */

/* The panel centres rather than sharing the article's left edge (Steph, 13 Aug 2026).
   It is the one block narrower than the reading area — 780px inside an 1180px inset —
   so aligning it left left a void down its right side while everything above and below
   it ran the full width. `auto` centres it in the same box the rest of the article
   centres in; the 18px mobile rule below still wins outright. */
.post__comments {
  margin: 30px auto 48px;
  max-width: 780px;
  border: 1px solid var(--sh-ink);
  background: var(--sh-paper);
  padding: 26px 30px 30px;
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.post__comments-header {
  border-bottom: 1px solid var(--sh-ink);
  padding-bottom: 14px;
}
.post__comments-title {
  font-family: var(--sh-font-display);
  font-weight: 400;
  font-size: 34px;
  line-height: 1;
}

/* 1d's lede — Steph speaking, so body sans. */
.post__comments-lede {
  font-family: var(--sh-font-body);
  font-size: 16px;
  line-height: 1.55;
}

/* The 21b strip. #fff6ef is the strip's own paper-adjacent warm tint from the canvas —
   deliberately not a section tint, so the strip reads as a note rather than chrome. */
.comment-rules {
  border: 1px solid var(--sh-ink);
  background: #fff6ef;
  padding: 15px 17px;
  display: flex;
  flex-direction: column;
  gap: 7px;
}
.comment-rules--job { background: var(--sh-tint-jobs); }
.comment-rules__label {
  font-family: var(--sh-font-body);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}
.comment-rules__text {
  font-family: var(--sh-font-body);
  font-size: 15px;
  line-height: 1.55;
  /* The panel is 780px wide, which ran this paragraph to ~91 characters a line —
     half again the measure the issue above it holds itself to. */
  max-width: 64ch;
}
/* Links on a tinted surface are ink + underline, never the link purple (00 §2). */
.comment-rules__text a {
  color: var(--sh-ink);
  text-decoration: underline;
  text-underline-offset: 3px;
}
/* Their words in Instrument Serif italic — the hypothetical commenter quotes in 1d. */
.comment-rules--job .comment-rules__text em {
  font-family: var(--sh-font-display);
  font-style: italic;
  font-size: 17px;
}

/* The comments-ui iframe sizes itself; keep it from adding stray inline-gap below. */
.post__comments iframe { display: block; width: 100%; }

.post__comments-foot {
  border-top: 1px solid var(--sh-ink);
  padding-top: 14px;
  font-family: var(--sh-font-mono);
  font-size: 11px;
  line-height: 1.7;
  color: var(--sh-grey-on-paper);
}

/* --------------------------------------------------------------------------
   390px (turn 36). Three columns collapse to one; both rails have to go somewhere.
   The contents rail becomes a collapsed <details> under the header, and footnotes move to the
   foot — which is where they already are, so the margin copies simply never get built.
   Type steps down one notch, not two.
   -------------------------------------------------------------------------- */

@media (max-width: 900px) {
  .post__breadcrumb,
  .post__header,
  .post__tags {
    padding-left: 18px;
    padding-right: 18px;
  }

  .post__title { font-size: 40px; line-height: 1; }
  .post__dek { font-size: 18px; }

  .post__layout {
    grid-template-columns: 1fr;
    gap: 0;
    padding: 0 18px 24px;
  }

  .post__rail {
    position: static;
    border-bottom: 1px solid var(--sh-ink);
    margin: 0 -18px;
    padding: 0 18px 0;
  }

  /* Turn 36: the rail is a closed disclosure here (post.js removes the shipped open).
     The summary is the 46px row; the open state gets its padding back. */
  .post__rail-summary {
    display: flex;
    justify-content: space-between;
    align-items: center;
    min-height: 46px;
    font-family: var(--sh-font-mono);
    font-size: 13px;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
  }
  .post__rail-details[open] .post__rail-summary-mark { transform: rotate(180deg); }
  .post__rail-details[open] { padding-bottom: 14px; }

  /* The summary row is the label here, so the inner one would say "In this
     issue" twice in a row the moment the reader opens it. */
  .post__rail-label { display: none; }

  /* WRITTEN BY now sits above the disclosure rather than inside it, so its own
     rule and the summary row would otherwise stack two separations. */
  .post__rail-byline { margin-bottom: 0; }

  /* The standing note's 96px gutter is a fifth of a 390px screen — stack instead. */
  .sh-standing { grid-template-columns: 1fr; row-gap: 8px; }

  .post__content {
    grid-template-columns: 1fr;
    gap: 0;
    padding: 20px 0 0;
  }

  .post__content p,
  .post__content li { font-size: 17px; }
  .post__content h2 { font-size: 30px; gap: 14px; }
  .post__content h2::before { font-size: 44px; }
  .post--bad-job-bingo .post__content h2 { font-size: 22px; white-space: normal; }
  .post__content h3 { font-size: 15px; }
  .post__content .sh-pull p { font-size: 22px; }
  /* 22px on ALL post templates, no mobile carve-out (09). The size steps down
     on the element and its paragraphs alike, so a bare imported quote follows. */
  .post__content blockquote { margin-left: 22px; font-size: 19px; }
  .post__content blockquote p { font-size: 19px; }

  /* A table keeps its columns and scrolls inside its own box. If a table cannot survive
     358px with three columns, it should have been a list. */
  .post__content table { display: block; overflow-x: auto; }

  /* The margin never exists here, so the foot notes are the only copy and must stay. */
  .post__notes-margin { display: none; }
  .post__content .sh-notes[data-mirrored="true"] { display: block; }

  /* One column: there is no rail to span, so Wide's reach-across margin resets. */
  .post__content .kg-width-wide,
  .post__content .kg-width-full { margin-left: 0; }

  /* In-issue events (28b): the date column stacks above its entry on a phone. */
  .post__content .sh-event { grid-template-columns: 1fr; gap: 6px; }

  /* Content loses its 8px side padding here, so the sign-off's mirror of it goes too. */
  .post__signoff { margin-left: 0; margin-right: 0; }

  .post__subscribe {
    grid-template-columns: 1fr;
    gap: 24px;
    padding: 24px 18px;
  }

  /* 1f: the panel tightens, the title steps down one notch, the strip's text follows.
     It stays centered here too: a flat 18px margin left it hard against the left edge
     with up to 84px of air on the right through the 816–900px band, because 780px of
     max-width still fits. min() keeps the 18px edge on a phone and centres above it. */
  .post__comments {
    margin-inline: auto;
    max-width: min(780px, calc(100% - 36px));
    padding: 18px;
    gap: 16px;
  }
  .post__comments-title { font-size: 28px; }
  .comment-rules { padding: 13px 14px; }
  .comment-rules__text { font-size: 14px; line-height: 1.5; }
}


/* --------------------------------------------------------------------------
   Single-column body — used by page.hbs, which has no contents rail and no notes margin.
   Same typography as an issue so a quote or a list reads identically; only the grid changes.
   -------------------------------------------------------------------------- */

.post__content--single {
  grid-template-columns: 1fr;
  max-width: 680px;
  padding: 0;
}
.post__content--single > * { grid-column: 1; }

/* --------------------------------------------------------------------------
   Cited videos (record 22; values from design/video-embeds-spec.md; drift item 123).
   A video is a quotation: their material, then hers. Four treatments — A wide
   (YouTube/Vimeo, 16:9, label above, caption below), B vertical (300px column,
   survival line right), C the click-to-load facade (TikTok/Instagram ONLY — their
   script is ABSENT until the reader presses play; assets/js/video-embeds.js injects
   it), D the removed-video card (manual swap; nothing detects a dead embed).

   The aspect floor on bare kg-embed iframes is the no-JS/undecorated guarantee:
   Ghost emits <figure class="kg-embed-card"> with no wrapper, and without this an
   embed collapses to the squat default box (22 §5). Scoped to YouTube/Vimeo srcs so
   an unsanctioned embed type is left alone rather than forced to 16:9. The
   nocookie/dnt rewrite happens in default.hbs's parse-time guard, not here.
   -------------------------------------------------------------------------- */

.kg-embed-card iframe[src*="youtube-nocookie.com/embed/"],
.kg-embed-card iframe[src*="youtube.com/embed/"],
.kg-embed-card iframe[src*="player.vimeo.com/video/"] {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
  border: 0;
  background: #0f0f0f;
}

/* A — wide. video-embeds.js decorates a plain editor card with the class + label;
   an authored HTML card may carry the full spec markup (__frame wrapper) instead. */
.sh-video { margin: 0; }
.sh-video__label {
  font-family: var(--sh-font-mono);
  font-size: 10px;
  font-weight: 700;
  line-height: 1;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--sh-grey-on-tint);
  margin-bottom: 10px;
}
.sh-video__frame { position: relative; aspect-ratio: 16 / 9; background: #0f0f0f; }
.sh-video__frame iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
.sh-video figcaption {
  font-family: var(--sh-font-mono);
  font-size: 12px;
  line-height: 1.5;
  color: var(--sh-grey-on-paper);
  border-top: 1px solid var(--sh-hairline);
  padding-top: 10px;
  margin-top: 10px;
  text-align: left;
}

/* B — vertical. Video left at 300px, survival line + reaction right; stacks to the
   centered 320px card below 620px (the spec's own breakpoint, not the site's 900). */
.sh-video--vertical {
  display: grid;
  grid-template-columns: 300px 1fr;
  gap: 26px;
  align-items: start;
}
.sh-video__summary { border-top: 1px solid var(--sh-ink); padding-top: 12px; }
.sh-video__summary-label {
  font-family: var(--sh-font-mono);
  font-size: 10px;
  font-weight: 700;
  line-height: 1;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--sh-grey-on-tint);
}
.sh-video__summary-text {
  font-family: var(--sh-font-display);
  font-size: 19px;
  line-height: 1.3;
  margin: 8px 0 0;
}
@media (max-width: 620px) {
  .sh-video--vertical { grid-template-columns: 1fr; }
  .sh-video--vertical .sh-video__media { max-width: 320px; margin: 0 auto; }
}

/* C — the facade. Same 300px column, same 9:16 box the loaded card takes. The note
   copy is flat, not alarmed — it states what happens next (spec §C). */
.sh-video__facade { border: 1px solid var(--sh-ink); background: var(--sh-paper); cursor: pointer; }
.sh-video__facade-head {
  border-bottom: 1px solid var(--sh-ink);
  padding: 9px 12px;
  display: flex;
  justify-content: space-between;
  gap: 10px;
  font-family: var(--sh-font-mono);
  font-size: 10px;
  line-height: 1;
  letter-spacing: 0.1em;
}
.sh-video__facade-head span:first-child { font-weight: 700; text-transform: uppercase; }
.sh-video__facade-head span:last-child { color: var(--sh-grey-on-tint); letter-spacing: 0.06em; }
.sh-video__facade-body {
  aspect-ratio: 9 / 16;
  padding: 20px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 16px;
  text-align: center;
}
.sh-video__facade-play {
  width: 56px;
  height: 56px;
  border: 1px solid var(--sh-ink);
  border-radius: 50%; /* the play circle is a glyph, not a container — outside the
                         no-radii rule the same way the rating icons are */
  display: flex;
  align-items: center;
  justify-content: center;
}
.sh-video__facade-play::before {
  content: "";
  border-left: 16px solid var(--sh-ink);
  border-top: 10px solid transparent;
  border-bottom: 10px solid transparent;
  margin-left: 5px; /* optical centering */
}
.sh-video__facade-cta {
  font-family: var(--sh-font-body);
  font-size: 13px;
  font-weight: 700;
  line-height: 1;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}
.sh-video__facade-note {
  font-family: var(--sh-font-body);
  font-size: 13px;
  line-height: 1.5;
  color: var(--sh-grey-on-tint);
  text-wrap: pretty;
}

/* Once loaded, the platform card renders inside __media with its chrome intact —
   attribution is the point; nothing inside it is ours to restyle (22 §4). */
.sh-video__media > blockquote { margin: 0; max-width: 100%; min-width: 0; }
.sh-video__media iframe { max-width: 100%; }

/* D — removed video. Grey tint, chip, survival line promoted to serif, provenance
   in mono #3a3a3a — deliberate and not adjustable: #6b6b6b is the floor on paper
   only and this sits on a tint (spec §D). */
.sh-video-removed {
  border: 1px solid var(--sh-ink);
  background: var(--sh-tint-closed);
  padding: 20px 22px;
}
.sh-video-removed__chip {
  display: inline-block;
  border: 1px solid var(--sh-ink);
  font-family: var(--sh-font-mono);
  font-size: 10px;
  line-height: 1;
  letter-spacing: 0.06em;
  padding: 3px 8px;
  text-transform: uppercase;
}
.sh-video-removed__line {
  font-family: var(--sh-font-display);
  font-size: 21px;
  line-height: 1.3;
  margin: 12px 0 0;
}
.sh-video-removed__meta {
  font-family: var(--sh-font-mono);
  font-size: 12px;
  line-height: 1.5;
  color: var(--sh-grey-on-tint);
  margin: 12px 0 0;
}

/* --------------------------------------------------------------------------
   Print — the reading page.

   The one rule that matters: THE FOOTNOTES MUST COME BACK. On desktop the
   foot-of-page list is display:none because post.js has mirrored each note
   into the margin, and the margin is absolutely positioned inside a grid that
   has no meaning on paper. So print un-hides the list and drops the margin —
   the same trade the 390px breakpoint already makes, for the same reason.
   Without this a printed issue lost its notes entirely, while `09` claimed
   print was one of the three places they always survive.

   Everything else here is the screen furniture coming off: the contents rail
   (anchors nobody can click), the listen band (a player on paper), the
   subscribe band, and the comments panel.
   -------------------------------------------------------------------------- */

@media print {
  .post__rail,
  .post__listen,
  .post__subscribe,
  .post__comments,
  .post__notes-margin,
  .post__caption-margin { display: none !important; }

  /* The notes are the source of truth again. */
  .post__content .sh-notes[data-mirrored="true"] { display: block; }

  /* A caption was hidden while its copy sat in the margin; the margin is gone. */
  .post__content figure[data-caption-mirrored] figcaption { display: block; }

  /* Three columns collapse to the page. The measure is still a measure: letting
     the text run the full width of A4 gives ~95 characters a line at 11pt, well
     past where a printed line stops being comfortable. 140mm lands around 72,
     which is the paper equivalent of the 60ch the screen holds. */
  .post__layout {
    display: block;
    padding: 0;
    border-bottom: 0;
  }
  .post__content {
    display: block;
    max-width: 140mm;
    padding: 0;
  }
  .post__content .kg-width-wide,
  .post__content .kg-width-full { margin-left: 0; }

  /* Type steps down to paper sizes — 76px of display serif is a screen scale. */
  .post__title { font-size: 40px; }
  .post__dek { font-size: 16px; }
  .post__content p,
  .post__content li { font-size: 11pt; line-height: 1.5; }
  .post__content h2 { font-size: 22pt; }
  .post--bad-job-bingo .post__content h2 { font-size: 15pt; white-space: normal; }
  .post__content .sh-notes li { font-size: 9pt; }

  /* An image that fills a screen column can run off a page; cap by height so a
     portrait meme cannot take a whole sheet on its own. */
  .post__content img { max-height: 10cm; }
  .post__meme { max-width: 300px; }

  /* The breadcrumb keeps series and date — that is the dateline, and a printed
     page needs it more than a screen does. Its "All issues" and "Previous" links
     do not survive the trip to paper. */
  .post__breadcrumb-back,
  .post__breadcrumb-prev { display: none; }

  /* The sign-off closes the article and carries the no-obligation line, so it
     prints — but the halftone screen is 14% ink across a block for no reason
     on paper. */
  .post__signoff::before { display: none; }

  /* A reader who prints an issue is holding the source, not a link to it. */
  .post__content a { text-decoration: underline; }
}

/* --------------------------------------------------------------------------
   "More from <series>" — the issue's page foot (partials/issue-nearby.hbs).
   Deliberately the same object as the library's Nearby and the board's Similar,
   down to the 2px ink rule under a 36px serif heading and the hairline rows: a
   reader who has met one of them has met all three.
   -------------------------------------------------------------------------- */

.issuenearby {
  padding: 34px var(--sh-gutter) 48px;
  padding-inline: max(var(--sh-gutter), var(--sh-post-inset));
}
.issuenearby__head {
  display: flex;
  align-items: baseline;
  padding-bottom: 9px;
  border-bottom: 2px solid var(--sh-ink);
}
.issuenearby__heading {
  font-family: var(--sh-font-display);
  font-weight: 400;
  font-size: 36px;
  line-height: 1;
  letter-spacing: -0.015em;
  margin: 0;
}
.issuenearby__heading .sh-twinkle { color: var(--sh-coral); font-size: 26px; }
.issuenearby__row {
  display: flex;
  align-items: baseline;
  gap: 14px;
  padding: 12px 0;
  border-bottom: 1px solid var(--sh-hairline);
  text-decoration: none;
  color: var(--sh-ink);
}
.issuenearby__row:hover .issuenearby__title,
.issuenearby__row:focus-visible .issuenearby__title { text-decoration: underline; text-underline-offset: 3px; }
.issuenearby__title {
  font-family: var(--sh-font-display);
  font-size: 24px;
  line-height: 1.06;
}
.issuenearby__meta {
  font-family: var(--sh-font-mono);
  font-size: 10px;
  color: var(--sh-grey-on-paper);
  margin-left: auto;
  white-space: nowrap;
  flex: none;
}

@media (max-width: 900px) {
  .issuenearby { padding: 26px 18px 36px; }
  .issuenearby__heading { font-size: 28px; }
  .issuenearby__title { font-size: 20px; }
  /* The date stops fighting the title for the row and takes its own line. */
  .issuenearby__row { flex-wrap: wrap; gap: 4px 14px; }
  .issuenearby__meta { margin-left: 0; width: 100%; }
}

/* Paper gets the reading, not the next click. */
@media print {
  .issuenearby { display: none !important; }
}

/* --------------------------------------------------------------------------
   The quote bar — what appears when a reader highlights a passage.

   A flat ink block with paper text: the same object as the masthead's Subscribe
   and the active chip, which is the site's one "this is a control" surface. Hard
   edges, no shadow, no radius; it sits ON the page rather than floating above it.

   Desktop only, and that is deliberate rather than lazy — iOS and Android put
   their own menu on a selection, and a second one fighting it is worse than
   none. The same reason the notes margin is desktop-only.

   z-index 80 keeps it under the skip link (100) and the mobile nav (90): it is
   transient furniture and must never cover the way out of the page.
   -------------------------------------------------------------------------- */

.post__quotebar {
  position: fixed;
  z-index: 80;
  display: flex;
  /* A COLUMN, not a row (16 Aug 2026). The bar lives in the notes margin, which is
     ~224px wide; two controls fitted across it and the card made a third, taking the
     bar to 258px — wider than the column it sits in, so it was clamped against the
     viewport edge and the last control fell off unless the window was widened.
     Stacking fits the shape of the space it was moved into, and it takes a fourth
     control without this happening again. */
  flex-direction: column;
  align-items: stretch;
  background: var(--sh-ink);
  color: var(--sh-paper);
  opacity: 0;
  transform: translateY(4px);
  pointer-events: none;
  transition: opacity 140ms cubic-bezier(0.22, 1, 0.36, 1),
              transform 140ms cubic-bezier(0.22, 1, 0.36, 1);
}
.post__quotebar--open {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}
.post__quotebar button {
  border: 0;
  background: none;
  color: var(--sh-paper);
  font-family: var(--sh-font-mono);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding: 10px 14px;
  cursor: pointer;
  white-space: nowrap;
}
/* A hairline in paper divides them — the ink block's own internal rule. Horizontal,
   because the bar stacks. */
.post__quotebar button + button { border-top: 1px solid var(--sh-grey-on-ink); }
/* Left-aligned rather than centered: stacked labels of different lengths read as a list
   off a common edge, the way the margin's notes already do. */
.post__quotebar button { text-align: left; }
.post__quotebar button:hover { background: var(--sh-grey-on-ink); color: var(--sh-ink); }
.post__quotebar button:focus-visible { outline-offset: -3px; }

/* The ✓ lands as the same one-beat stamp the heading anchors and the Footnotes
   # button use, so every copy on the site confirms itself the same way. */
.post__quotebar button.is-copied { animation: sh-anchor-stamp 0.18s cubic-bezier(0.25, 1, 0.5, 1); }

@media (max-width: 900px) {
  .post__quotebar { display: none !important; }
}
@media print {
  .post__quotebar { display: none !important; }
}

/* The funding band is shared with page.hbs, so the centering is scoped to an issue
   (partials/funding-band.hbs renders inside article.post here and outside it there).
   The band itself stays full-bleed ink; only its contents move. */
.post .funding-band {
  padding-inline: max(var(--sh-gutter), var(--sh-post-inset));
}
@media (max-width: 900px) {
  .post .funding-band { padding-inline: 18px; }
}

/* --------------------------------------------------------------------------
   READER QUOTE CARDS (16 Aug 2026) — the two offer surfaces and the sheet.

   Desktop takes a third control on the quote bar above; only the touch popover and
   the sheet need shapes of their own. No new colors: ink ground, paper text, the
   mono label voice, hard edges.
   -------------------------------------------------------------------------- */

/* The bar's card control is the wider one, so it gets the ✦ and a little more room. */
.post__quotebar-card { letter-spacing: 0.08em; }

/* The touch offer. Fixed, because it is positioned against the viewport rect of a
   selection that the OS may be scrolling under its own handles. */
.post__cardoffer {
  position: fixed;
  z-index: 80;
  display: flex;
  flex-direction: column;
  gap: 2px;
  background: var(--sh-ink);
  color: var(--sh-paper);
  padding: 0;
  max-width: min(300px, calc(100vw - 16px));
  opacity: 0;
  transform: translateY(4px);
  pointer-events: none;
  transition: opacity 140ms cubic-bezier(0.22, 1, 0.36, 1),
              transform 140ms cubic-bezier(0.22, 1, 0.36, 1);
}
.post__cardoffer--open { opacity: 1; transform: translateY(0); pointer-events: auto; }
.post__cardoffer-go {
  border: 0;
  background: none;
  color: var(--sh-paper);
  font-family: var(--sh-font-mono);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  /* 40px tall per the spec, and comfortably past the 24px hit-area floor. */
  padding: 12px 16px;
  min-height: 40px;
  cursor: pointer;
  white-space: nowrap;
}
/* A decline is this same popover in another state — never a dialog, and the
   selection is left alone so trimming is a drag rather than a restart. */
.post__cardoffer--declined { padding: 12px 16px 14px; }
.post__cardoffer-head {
  font-family: var(--sh-font-body);
  font-size: 15px;
  font-weight: 700;
  line-height: 1.3;
}
.post__cardoffer-sub {
  font-family: var(--sh-font-mono);
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  /* The floor on this ground — it cannot get quieter. */
  color: var(--sh-grey-on-ink);
}
.post__cardoffer-head:empty,
.post__cardoffer-sub:empty { display: none; }

/* The sheet: the card at full width, then one action and a way out. */
.post__cardsheet {
  border: 1px solid var(--sh-ink);
  background: var(--sh-paper);
  color: var(--sh-ink);
  padding: 18px;
  max-width: min(520px, calc(100vw - 32px));
  width: 100%;
}
.post__cardsheet::backdrop { background: rgba(3, 2, 3, 0.72); }
.post__cardsheet-img {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--sh-ink);
}
.post__cardsheet-row { display: flex; gap: 10px; margin-top: 14px; }
.post__cardsheet-go,
.post__cardsheet-close {
  font-family: var(--sh-font-body);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding: 12px 16px;
  cursor: pointer;
  border: 1px solid var(--sh-ink);
}
.post__cardsheet-go { background: var(--sh-ink); color: var(--sh-paper); flex: 1; }
.post__cardsheet-close { background: var(--sh-paper); color: var(--sh-ink); }
