/* ============================================================
   THEORIA
   Light editorial newsletter theme. Mobile-first.
   Four reader-selectable schemes driven by [data-theme] on <html>.
   Never hardcode a color below this token block — extend the tokens.
   ============================================================ */

:root {
  /* Two widths. The article stays at a comfortable measure — past roughly
     75 characters a line gets hard to track back from. The page chrome
     (masthead, footer) runs wider so the site fills the screen instead of
     sitting in a narrow strip. */
  --measure: 46rem;          /* reading column */
  --measure-wide: 64rem;     /* masthead + footer */
  --gutter: 1.25rem;
  --radius: 10px;
  --tap: 44px;               /* minimum touch target */

  /* Ghost Admin can override these two under Design → Brand → Fonts.
     Our own tokens fall back to them, so a font chosen in Admin wins. */
  --gh-font-heading: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --gh-font-body: 'Source Serif 4', Georgia, 'Times New Roman', serif;

  --font-ui: var(--gh-font-heading, 'Inter', -apple-system, BlinkMacSystemFont, sans-serif);
  --font-read: var(--gh-font-body, 'Source Serif 4', Georgia, serif);

  --step--1: clamp(0.78rem, 0.76rem + 0.10vw, 0.84rem);
  --step-0:  clamp(1.02rem, 0.99rem + 0.16vw, 1.13rem);

  /* ONE size for every piece of prose inside an issue: the reflection, all
     four callouts, and the closing question. They used to sit on two different
     steps — the reflection on --step-1 (~22.7px) and the callouts on --step-0
     (~17.9px) — which made the same kind of text look like two kinds.

     Landing at ~20px rather than at either old value is deliberate. The card's
     inner width is about 690px at desktop; at 17.9px that is roughly 77
     characters a line, past the 75 where the eye starts losing its place on
     the return sweep, and at 22.7px a one-line Candy note reads like a pull
     quote. ~20px puts every card near 69 characters.

     Change this one value and every block moves together — that is the point. */
  --step-read: clamp(1.13rem, 1.08rem + 0.22vw, 1.28rem);
  --leading-read: 1.7;
  --step-1:  clamp(1.18rem, 1.10rem + 0.38vw, 1.42rem);
  --step-2:  clamp(1.45rem, 1.30rem + 0.72vw, 2.00rem);
  --step-3:  clamp(1.75rem, 1.50rem + 1.20vw, 2.75rem);
}

/* ---------- Scheme: Lilac (default) ---------- */
:root[data-theme="lilac"] {
  --on-accent: #FFFFFF;   /* text on an accent fill */
  --scroll-thumb: rgba(106, 69, 201, 0.28);
  --scroll-thumb-hover: rgba(106, 69, 201, 0.48);
  --card: #FFFFFF;
  --quote-bg: #E9E1FA;
  --bg: #F7F4FD;
  --surface: #FFFFFF;
  --surface-2: #E6DDFA;
  --text: #191426;
  --text-soft: #3A3350;
  --muted: #5F5878;
  --accent: #6A45C9;
  --accent-soft: rgba(106, 69, 201, 0.10);
  --rule: #DFD6F2;
  --mark: rgba(167, 139, 250, 0.42);
  --shadow: 0 1px 2px rgba(40, 24, 80, 0.06);
}

/* ---------- Scheme: Paper (clean white) ---------- */
:root[data-theme="paper"] {
  --on-accent: #FFFFFF;   /* text on an accent fill */
  --scroll-thumb: rgba(25, 20, 38, 0.22);
  --scroll-thumb-hover: rgba(25, 20, 38, 0.38);
  --card: #FBFAFD;
  --quote-bg: #F1EEFA;
  --bg: #FFFFFF;
  --surface: #FFFFFF;
  --surface-2: #F5F2FB;
  --text: #16161C;
  --text-soft: #3C3A49;
  --muted: #64607A;
  --accent: #6A45C9;
  --accent-soft: rgba(106, 69, 201, 0.09);
  --rule: #E7E4F0;
  --mark: rgba(167, 139, 250, 0.38);
  --shadow: 0 1px 2px rgba(24, 20, 40, 0.05);
}

/* ---------- Scheme: Ink (violet-tinted dark) ---------- */
:root[data-theme="ink"] {
  --on-accent: #FFFFFF;   /* text on an accent fill */
  --scroll-thumb: rgba(233, 231, 240, 0.22);
  --scroll-thumb-hover: rgba(233, 231, 240, 0.38);
  --card: #1E1B2A;
  --quote-bg: #272334;
  --bg: #17151F;
  --surface: #1E1B2A;
  --surface-2: #262233;
  --text: #E9E7F0;
  --text-soft: #C9C5D6;
  --muted: #A29CB5;
  --accent: #B69BF5;
  --accent-soft: rgba(182, 155, 245, 0.15);
  --rule: rgba(255, 255, 255, 0.11);
  --mark: rgba(167, 139, 250, 0.32);
  --shadow: none;
}

/* ---------- Scheme: Black (OLED) ---------- */
:root[data-theme="black"] {
  --on-accent: #FFFFFF;   /* text on an accent fill */
  --scroll-thumb: rgba(237, 237, 237, 0.24);
  --scroll-thumb-hover: rgba(237, 237, 237, 0.42);
  --card: #0B0A0F;
  --quote-bg: #141220;
  --bg: #000000;
  --surface: #0B0A0F;
  --surface-2: #141220;
  --text: #EDEDED;
  --text-soft: #CFCCD8;
  --muted: #9C98A8;
  --accent: #B49BF2;
  --accent-soft: rgba(180, 155, 242, 0.16);
  --rule: rgba(255, 255, 255, 0.15);
  --mark: rgba(167, 139, 250, 0.28);
  --shadow: none;
}

/* ============================================================
   Base
   ============================================================ */
*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* A thin overlay-style scrollbar instead of the chunky default gutter. */
  scrollbar-width: thin;
  scrollbar-color: var(--scroll-thumb) transparent;
  scrollbar-gutter: stable;
}

/* WebKit needs the long form. The transparent border + background-clip is what
   turns the thumb into a floating pill rather than a boxy full-width block. */
::-webkit-scrollbar { width: 12px; height: 12px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: var(--scroll-thumb);
  border-radius: 99px;
  border: 4px solid transparent;
  background-clip: content-box;
}
::-webkit-scrollbar-thumb:hover { background: var(--scroll-thumb-hover); background-clip: content-box; }
::-webkit-scrollbar-corner { background: transparent; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-ui);
  font-size: var(--step-0);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  padding-bottom: env(safe-area-inset-bottom);
}

a { color: var(--accent); }

img { max-width: 100%; height: auto; display: block; }

.wrap {
  width: 100%;
  max-width: var(--measure);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

/* Masthead and footer span the wider track. */
.masthead .wrap,
.site-footer .wrap,
.mobile-menu.wrap { max-width: var(--measure-wide); }

.skip-link {
  position: absolute; left: -9999px; top: 0;
  background: var(--accent); color: var(--on-accent);
  padding: 12px 18px; z-index: 200; border-radius: 0 0 var(--radius) 0;
}
.skip-link:focus { left: 0; }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 4px;
}

.progress {
  position: fixed; inset: 0 auto auto 0;
  height: 3px; width: 0%;
  background: var(--accent);
  z-index: 100;
  transition: width .1s linear;
}

.label {
  font-family: var(--font-ui);
  font-size: var(--step--1);
  font-weight: 500;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--muted);
}

/* ---------- Section headings ----------
   The names of the parts of an issue: MY REFLECTION, CANDY, CONNECTION,
   APHORISM, DEEP THINKING PROMPT, REPLIES.

   These are lavender, and they get there through var(--accent) rather than a
   literal colour — which is the whole point. --accent is redefined in each of
   the four scheme blocks, so one rule covers all four: violet #6A45C9 on
   Lilac and Paper, a lighter #B69BF5 / #B49BF2 on Ink and Black so it stays
   legible against a dark card. Change scheme, the headings follow.

   Verified against WCAG AA (4.5:1) on every surface they land on, in all four
   schemes. Worst case is accent on the quote tint in Lilac at 5.02:1.

   Deliberately scoped to these six, NOT to .label globally: the issue eyebrow,
   the date/reading-time meta and the prev/next labels are secondary
   information. Turning those lavender too would leave nothing quiet on the
   page for the headings to stand out against. */
.margin-note__head .label,
.reflection__label,
.prompt__label,
#issue-thread .label {
  color: var(--accent);
  font-weight: 700;
  letter-spacing: .13em;      /* uppercase needs more tracking than lowercase */
  font-size: clamp(0.76rem, 0.73rem + 0.14vw, 0.85rem);
  /* Uppercase here is presentational only — the DOM text stays "Candy", so a
     screen reader says "Candy" and not "C A N D Y". */
  text-transform: uppercase;
  font-feature-settings: "kern" 1;
}

/* ============================================================
   Header
   ============================================================ */
.masthead {
  border-bottom: 1px solid var(--rule);
}

/* The site's ONLY navigation: a pill on the SAME ROW as the wordmark.
   Wordmark left, pill right. Below 40em the pill is replaced by the
   sandwich. There is deliberately no second menu anywhere. */
.navpill {
  display: none;                      /* mobile: the sandwich takes over */
  align-items: center; gap: .15rem;
  padding: .3rem .45rem;
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: 999px;
  box-shadow: var(--shadow);
  max-width: 100%;
}
.navpill ul {
  list-style: none; display: flex; align-items: center; gap: .1rem;
  margin: 0; padding: 0;
}
.navpill a,
.navpill__theme {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 32px; padding: 0 .7rem;
  border: 0; border-radius: 999px; background: transparent;
  color: var(--muted); text-decoration: none; cursor: pointer;
  font-family: var(--font-ui); font-size: var(--step--1); font-weight: 500;
  white-space: nowrap;
}
.navpill a:hover,
.navpill__theme:hover { color: var(--text); background: var(--surface-2); }

/* Current page and current scheme both read as a filled accent pill. */
.navpill a[aria-current="page"],
.navpill__theme[aria-checked="true"] {
  background: var(--accent); color: var(--on-accent);
}

.navpill__sep {
  width: 1px; height: 18px; background: var(--rule);
  margin-inline: .3rem; flex: none;
}
.navpill__themes { display: flex; align-items: center; gap: .1rem; }
.navpill__icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 32px; height: 32px; padding: 0; border-radius: 50%;
  color: var(--muted); flex: none;
}
.navpill__icon:hover { color: var(--accent); background: var(--surface-2); }
.navpill__icon svg { width: 17px; height: 17px; }

/* MOBILE: the wordmark is centred in the header and the sandwich sits
   absolutely on the right, so the logo is optically centred in the viewport
   rather than pushed off-centre by the button's width. Desktop reverts to
   wordmark-left / pill-right at 40em. */
.masthead__inner {
  position: relative;
  display: flex; align-items: center; justify-content: center;
  gap: 1rem 1.5rem; flex-wrap: wrap;
  padding-block: 1.1rem 1.15rem;
}
.masthead__inner .nav-toggle {
  position: absolute; right: var(--gutter); top: 50%;
  transform: translateY(-50%);
}
/* The byline sits above the issue number. Muted like the other label text so
   it frames the title rather than competing with it, and the name itself picks
   up the accent so it reads as the one link in the header. */
.issue__byline { display: block; margin-bottom: .45rem; }
.issue__byline a { color: var(--accent); text-decoration: none; }
.issue__byline a:hover { text-decoration: underline; }

/* ---------- Brand ----------
   The wordmark is live text, not an image: it recolours with the scheme,
   scales with the reader's font size, and stays selectable. The SVG lockups
   in assets/brand/ are for places HTML can't go — email, social, favicon. */
/* text-align:center centres the slogan under the wordmark. .brand is an
   inline-block that shrinks to the wordmark's width, so "centred in .brand"
   and "centred under the wordmark" are the same thing. */
.brand {
  text-decoration: none; display: inline-block; line-height: 1;
  text-align: center;
}
.brand__logo { max-height: 40px; width: auto; }
.brand__word {
  display: block;
  font-family: 'EB Garamond', var(--font-read);
  font-weight: 500;
  /* Lower floor than a short name would need: "The Theoria" is 11 characters
     and has to sit beside the sandwich button at 360px. */
  font-size: clamp(1.05rem, 0.86rem + 0.95vw, 1.8rem);
  letter-spacing: .13em;      /* tracking matched to the outlined SVG */
  text-transform: uppercase;
  color: var(--text);
  white-space: nowrap;
}
.brand__slogan {
  display: block;
  margin-top: .45em;
  font-family: var(--font-ui);
  font-size: .62rem;
  font-weight: 500;
  letter-spacing: .24em;
  text-transform: uppercase;
  color: var(--muted);
}

/* Legacy alias, kept so any hand-written markup using .wordmark still works. */
.wordmark {
  font-family: 'EB Garamond', var(--font-read);
  font-weight: 500;
  font-size: var(--step-1);
  color: var(--text);
  text-decoration: none;
  letter-spacing: .14em;
  text-transform: uppercase;
}
.masthead__tools { display: flex; align-items: center; gap: .35rem; }

.icon-btn {
  min-width: var(--tap); min-height: var(--tap);
  display: inline-flex; align-items: center; justify-content: center;
  background: transparent; border: 1px solid transparent;
  border-radius: var(--radius); color: var(--text-soft);
  cursor: pointer; padding: 0;
}
.icon-btn:hover { background: var(--surface-2); }
.icon-btn svg { width: 20px; height: 20px; }

/* Sandwich becomes a close icon while the menu is open. */
.nav-toggle[aria-expanded="true"] { color: var(--accent); }
.nav-toggle svg[hidden] { display: none; }

.nav { display: none; }
.nav ul { list-style: none; display: flex; gap: 1.35rem; margin: 0; padding: 0; }
.nav a {
  display: inline-block; padding-block: .3rem;
  color: var(--muted); text-decoration: none;
  font-family: var(--font-ui); font-size: var(--step--1); font-weight: 500;
  letter-spacing: .07em; text-transform: uppercase;
}
.nav a:hover { color: var(--accent); }
.nav a[aria-current="page"] { color: var(--text); }

.mobile-menu {
  display: none;
  border-top: 1px solid var(--rule);
  padding-block: .75rem 1.25rem;
}
.mobile-menu[data-open="true"] { display: block; }
.mobile-menu ul { list-style: none; margin: 0 0 .5rem; padding: 0; }
.mobile-menu li a {
  display: block; padding: .7rem 0; text-decoration: none;
  color: var(--text); font-weight: 500;
  border-bottom: 1px solid var(--rule);
}

/* ---------- Theme picker ---------- */
.picker { position: relative; }
.picker__panel {
  position: absolute; right: 0; top: calc(100% + .4rem);
  background: var(--surface); border: 1px solid var(--rule);
  border-radius: var(--radius); box-shadow: var(--shadow);
  padding: .5rem; z-index: 60; min-width: 210px;
  display: none;
}
.picker__panel[data-open="true"] { display: block; }
.picker__title { padding: .35rem .5rem .5rem; }
.picker__opt {
  display: flex; align-items: center; gap: .65rem; width: 100%;
  min-height: var(--tap); padding: 0 .5rem;
  background: transparent; border: 0; border-radius: 8px;
  color: var(--text); font-family: var(--font-ui); font-size: var(--step-0);
  cursor: pointer; text-align: left;
}
.picker__opt:hover { background: var(--surface-2); }
.picker__opt[aria-checked="true"] { background: var(--accent-soft); font-weight: 600; }
.picker__opt .swatch {
  width: 20px; height: 20px; border-radius: 50%;
  border: 1px solid var(--rule); flex: none;
}
.swatch--lilac { background: #E6DDFA; }
.swatch--paper { background: #FFFFFF; }
.swatch--ink   { background: #17151F; }
.swatch--black { background: #000000; }
.picker__opt .check { margin-left: auto; opacity: 0; font-size: 14px; }
.picker__opt[aria-checked="true"] .check { opacity: 1; }

/* In the mobile menu the picker renders inline, not as a dropdown */
.mobile-menu .picker__panel {
  position: static; display: block; border: 0; box-shadow: none;
  padding: 0; min-width: 0; background: transparent;
}

/* ============================================================
   Homepage / archive list
   ============================================================ */
.intro {
  padding-block: 2rem 1rem;
  color: var(--muted);
  font-size: var(--step-0);
}
.intro h1 {
  font-family: var(--font-read);
  font-size: var(--step-2);
  color: var(--text);
  margin: 0 0 .4rem;
  letter-spacing: -0.015em;
}

.issue-list { padding-bottom: 2rem; }

.issue-card {
  display: block; text-decoration: none; color: inherit;
  padding-block: 1.5rem;
  border-bottom: 1px solid var(--rule);
}
.issue-card:hover .issue-card__title { color: var(--accent); }
.issue-card__eyebrow { display: block; margin-bottom: .5rem; }
.issue-card__title {
  font-family: var(--font-ui);
  font-size: var(--step-1);
  font-weight: 700;
  letter-spacing: -0.02em;
  margin: 0 0 .4rem;
  line-height: 1.25;
}
.issue-card__quote {
  font-family: var(--font-read);
  font-style: italic;
  color: var(--text-soft);
  margin: 0 0 .6rem;
}
.issue-card__meta { font-size: var(--step--1); color: var(--muted); }

/* ============================================================
   The issue (post)
   ============================================================ */
.issue { padding-block: 2rem 1rem; }

.issue__header { text-align: center; margin-bottom: 2rem; }
.issue__eyebrow { display: block; margin-bottom: .75rem; }
.issue__title {
  font-family: var(--font-ui);
  font-size: var(--step-3);
  font-weight: 700;
  letter-spacing: -0.03em;
  line-height: 1.15;
  margin: 0 0 .75rem;
}
.issue__meta { font-size: var(--step--1); color: var(--muted); }
.issue__meta a { color: var(--muted); }

.issue__feature { margin-bottom: 2rem; border-radius: var(--radius); overflow: hidden; }

/* ============================================================
   Section cards
   Every section is its own visibly separated card: own surface,
   own border, own padding. The quote sits on a deeper tint so it
   still reads as the hero of the issue.
   ============================================================ */
/* blockquote is excluded — it carries .block too, and this rule's higher
   specificity was overriding the quote's own tinted surface. */
.post-content > .block:not(blockquote),
.post-content > .block-shell,
#issue-thread {
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  padding: 1.35rem;
  margin: 0 0 1.15rem;
  box-shadow: var(--shadow);
}

/* ---------- The quote (hero block) ---------- */
.post-content blockquote,
.quote-card {
  position: relative;
  background: var(--quote-bg);
  border: 1px solid var(--rule);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius);
  margin: 0 0 1.15rem;
  padding: 1.5rem 1.5rem 1.25rem;
}

/* Quotation marks are CSS generated content on purpose: generated text is
   excluded from textContent, so Copy, Share and the shareable PNG still
   read the quote WITHOUT them. Put real “ ” characters in the markup and
   every copied quote comes out double-quoted. */
.post-content blockquote p:first-of-type::before,
.quote-card p:first-of-type::before {
  content: '\201C';
  color: var(--accent);
  margin-left: -0.42em;   /* hangs the mark so the first letter stays aligned */
}
.post-content blockquote p:last-of-type::after,
.quote-card p:last-of-type::after {
  content: '\201D';
  color: var(--accent);
}

/* Inside the tinted card the pills go transparent — white chips on a tint
   read as a second layer stacked on the quote. */
.post-content blockquote .act,
.quote-card .act { background: transparent; }
/* Koenig renders a blockquote as bare text, so the type has to sit on the
   element itself as well as on any paragraph inside it. */
.post-content blockquote,
.post-content blockquote p,
.quote-card p {
  font-family: var(--font-read);
  font-style: italic;
  font-size: var(--step-2);
  line-height: 1.45;
  color: var(--text);
  margin: 0 0 .5rem;
  letter-spacing: -0.01em;
}
.post-content blockquote cite,
.quote-card cite {
  display: block;
  font-family: var(--font-ui);
  font-style: normal;
  font-size: var(--step--1);
  color: var(--muted);
}

/* ---------- Reflection ---------- */
.reflection { margin-bottom: 0; }

/* ---------- Reflection shell ----------
   The card is the shell; the paragraph inside is plain. Without this the
   paragraph would keep its own margin and push a gap inside the card. */
.reflection-shell > [data-block-type="reflection"] {
  background: none;
  border: 0;
  border-radius: 0;
  padding: 0;
  margin: 0;
  box-shadow: none;
}

/* Legacy: the label used to be a bare sibling span above the card. Kept so a
   cached page mid-deploy still renders sensibly, and harmless once every page
   has the new markup. */
.reflection__label { display: block; margin: 0 0 .5rem .15rem; }
/* ---------- Reflection ----------
   Styled off the data attribute FIRST, and this is not a preference.

   main.js identifies the reflection by position (the paragraph after the
   blockquote), then inserts a "My reflection" label span *between* the two.
   That insertion breaks `blockquote + p` — the adjacency the selector needs is
   gone the moment the label lands. The paragraph then silently fell back to
   body defaults: step-0 instead of step-1, 1.6 leading instead of 1.72. On the
   longest continuous read in every issue, and with no error anywhere, because
   a selector that stops matching is not an error.

   `[data-block-type="reflection"]` is set by the same function that inserts the
   label, so the two cannot disagree. The adjacency selector stays as the
   no-JavaScript fallback: with JS off no label is inserted, so adjacency holds
   and the paragraph still gets its proper type. */
.post-content [data-block-type="reflection"],
.reflection p,
.post-content blockquote + p {
  font-family: var(--font-read);
  font-size: var(--step-read);
  line-height: var(--leading-read);
  color: var(--text);
  margin: 0;
  /* Balances the rag and avoids a one-word last line. Ignored by browsers that
     don't support it, so it costs nothing. */
  text-wrap: pretty;
}

/* Reader marks */
mark.mk {
  background: var(--mark);
  color: inherit;
  padding: .05em 0;
  border-radius: 2px;
}
mark.mk[data-style="underline"] {
  background: transparent;
  border-bottom: 2px solid var(--accent);
  border-radius: 0;
}
.sentence { cursor: pointer; }
.sentence:hover { background: var(--accent-soft); border-radius: 3px; }

/* ---------- Marginalia notes (Candy / Connection / Aphorism) ----------
   One column at every width. Each note is its own stacked section,
   separated by a hairline rule rather than sitting in a grid. */
.margin-note__head {
  display: flex; align-items: center; gap: .5rem; margin-bottom: .7rem;
}
.margin-note__head svg {
  width: 15px; height: 15px; flex: none;
  color: var(--accent);        /* the icon tracks the heading, not the body */
}

/* A hairline trailing the heading out to the edge of the card. Editorial
   section rule, and it does the separating work a heavier heading would
   otherwise have to do. Generated content on purpose: decorative, so it stays
   out of textContent (Copy / Share) and out of the accessibility tree. */
.margin-note__head::after {
  content: '';
  flex: 1 1 auto;
  height: 1px;
  min-width: 1rem;
  background: linear-gradient(to right, var(--rule), transparent);
}

.margin-note__body {
  font-size: var(--step-read);
  color: var(--text-soft);
  margin: 0;
  line-height: var(--leading-read);
}

/* ---------- Deep thinking prompt ---------- */
.prompt {
  text-align: center;
  padding-block: 1.75rem;
}
.prompt .margin-note__head { justify-content: center; margin-bottom: .9rem; }
.prompt .actions { justify-content: center; }
.prompt__label { display: block; margin-bottom: .75rem; }
.prompt__q {
  font-family: var(--font-read);
  font-style: italic;
  font-size: var(--step-read);
  line-height: var(--leading-read);
  color: var(--text);
  margin: 0 0 1.25rem;
  text-wrap: balance;         /* a centred question should not rag badly */
  max-width: 34ch;
  margin-inline: auto;
}

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .5rem;
  min-height: var(--tap); padding: 0 1.15rem;
  font-family: var(--font-ui); font-size: var(--step--1); font-weight: 500;
  border-radius: 999px; border: 1px solid var(--rule);
  background: var(--surface); color: var(--text);
  cursor: pointer; text-decoration: none;
}
.btn:hover { border-color: var(--accent); color: var(--accent); }
.btn--primary {
  background: var(--accent); border-color: var(--accent); color: var(--on-accent);
}
.btn--primary:hover { color: var(--on-accent); opacity: .92; }
.btn svg { width: 15px; height: 15px; }

/* ============================================================
   Koenig editor cards
   ============================================================ */
.post-content { overflow-wrap: break-word; }

.post-content p,
.post-content ul,
.post-content ol,
.post-content h2,
.post-content h3 {
  font-family: var(--font-read);
  line-height: 1.65;
}
.post-content h2,
.post-content h3 {
  font-family: var(--font-ui);
  letter-spacing: -0.02em;
  margin-top: 2rem;
}
.post-content h2 { font-size: var(--step-2); }
.post-content h3 { font-size: var(--step-1); }
.post-content a { color: var(--accent); }
.post-content hr { border: 0; border-top: 1px solid var(--rule); margin: 2rem 0; }

.post-content figure { margin: 1.75rem 0; }
.post-content figcaption {
  font-family: var(--font-ui);
  font-size: var(--step--1);
  color: var(--muted);
  text-align: center;
  padding-top: .5rem;
}

/* Wide and full-width cards break out of the reading column. */
.kg-width-wide {
  width: 100%;
  max-width: min(56rem, 100vw - (var(--gutter) * 2));
  margin-inline: auto;
}
.kg-width-full {
  width: 100vw;
  max-width: 100vw;
  margin-inline: calc(50% - 50vw);
  border-radius: 0;
}
.kg-width-full img { width: 100%; }

.kg-image-card img, .kg-gallery-image img { border-radius: var(--radius); }
.kg-width-full .kg-image-card img { border-radius: 0; }

.kg-gallery-container { display: flex; flex-direction: column; gap: .5rem; }
.kg-gallery-row { display: flex; gap: .5rem; }
.kg-gallery-image { flex: 1; }

.kg-embed-card, .kg-video-card, .kg-audio-card { margin: 1.75rem 0; }
.kg-embed-card iframe { max-width: 100%; }

.kg-button-card { text-align: center; margin: 1.75rem 0; }
.kg-btn {
  display: inline-flex; align-items: center; min-height: var(--tap);
  padding: 0 1.25rem; border-radius: 999px; text-decoration: none;
  background: var(--accent); color: var(--on-accent); font-family: var(--font-ui);
  font-size: var(--step--1); font-weight: 500;
}

.kg-toggle-card { border-bottom: 1px solid var(--rule); padding: 1rem 0; }
.kg-toggle-heading { display: flex; justify-content: space-between; gap: 1rem; align-items: center; }

.kg-bookmark-card a.kg-bookmark-container {
  display: flex; text-decoration: none; color: inherit;
  border: 1px solid var(--rule); border-radius: var(--radius); overflow: hidden;
}
.kg-bookmark-content { padding: 1rem; }
.kg-bookmark-title { font-weight: 600; }
.kg-bookmark-description { color: var(--muted); font-size: var(--step--1); }

/* Callout cards become the marginalia notes. Color is only an authoring
   signal here — the design distinguishes them by label and icon. */
.post-content .kg-callout-card {
  display: block;
  background: var(--card);
}
.post-content .kg-callout-emoji { display: none; }
/* Ghost's cards.min.css sets `display:flex` on the callout card for its
   emoji-beside-text layout. We stack a heading above the text, so say block
   outright — this currently resolves to block anyway, and depending on that
   is depending on luck. */
.post-content .kg-callout-card { display: block; }
/* Specificity is deliberate and load-bearing here — do not "simplify" it.

   package.json sets card_assets:true, so Ghost injects cards.min.css BEFORE
   this file, and it contains:

       .kg-callout-card div.kg-callout-text { font-size: .95em; line-height: 1.5em }

   That selector scores (0,2,1). The obvious `.post-content .kg-callout-text`
   scores (0,2,0) and LOSES, so callout text rendered at 16.99px/25.49 while the
   reflection sat at 20.1px/34.16 — the two-sizes bug, back again, on the live
   site only. Adding `.kg-callout-card` takes this to (0,3,0); class count
   dominates over the element selector, so it wins cleanly without !important.

   This did not show up in the local preview because that harness loads only the
   theme's CSS. Ghost's card CSS exists solely on a real Ghost install, so this
   whole class of conflict is invisible until the theme is live. */
.post-content .kg-callout-card .kg-callout-text {
  font-family: var(--font-read);
  font-size: var(--step-read);
  color: var(--text-soft);
  line-height: var(--leading-read);
  text-wrap: pretty;
}
/* A callout can hold more than one paragraph. Without this they run together
   into one grey slab. */
.post-content .kg-callout-text p { margin: 0 0 .75em; }
.post-content .kg-callout-text p:last-child { margin-bottom: 0; }
/* The prompt stays set apart by italic and full-strength text colour, NOT by
   size — size is shared with every other block. Same specificity story as
   above; this one already outranked Ghost, but it is written to match so the
   two rules cannot drift into disagreeing. */
.post-content .kg-callout-card.kg-callout-card-purple .kg-callout-text {
  font-style: italic;
  font-size: var(--step-read);
  color: var(--text);
}

/* ============================================================
   Per-block interactions
   ============================================================ */
.block { position: relative; scroll-margin-top: 1.5rem; }

.block--flash {
  animation: flash 1.6s ease;
}
@keyframes flash {
  0%, 100% { background: transparent; }
  15%      { background: var(--accent-soft); }
}

.actions {
  display: flex; align-items: center; flex-wrap: wrap; gap: .3rem;
  margin-top: .6rem;
}
/* On the quote, actions sit on the attribution row, right-aligned. */
.quote-actions {
  display: flex; align-items: center; justify-content: space-between;
  gap: .75rem; flex-wrap: wrap; margin-top: .5rem;
}
.quote-actions .actions { margin-top: 0; }

.act {
  display: inline-flex; align-items: center; gap: .35rem;
  min-height: 36px; padding: 0 .7rem;
  background: var(--surface); border: 1px solid var(--rule);
  border-radius: 999px; color: var(--text-soft);
  font-family: var(--font-ui); font-size: var(--step--1);
  cursor: pointer; white-space: nowrap;
}
.act:hover { border-color: var(--accent); color: var(--accent); }
.act svg { width: 14px; height: 14px; flex: none; }
.act[aria-pressed="true"] {
  color: var(--accent); border-color: var(--accent); background: var(--accent-soft);
}
.act__count { font-variant-numeric: tabular-nums; }
.act__count:empty { display: none; }

/* Touch targets get bigger on coarse pointers AND on narrow screens.
   Pointer type alone isn't enough — some touch devices report a fine
   pointer, and they still get thumbs. */
@media (pointer: coarse), (max-width: 40em) {
  .act { min-height: var(--tap); padding-inline: .85rem; }
}

/* Labelled pills need ~425px; the padded card gives far less than that below
   40em, so they wrapped to two rows anywhere in the mobile band — not just on
   the narrowest phones. Icon-only for the whole band, matching the sandwich
   breakpoint. Counts stay; aria-label carries the name. The bottom sheet keeps
   its labels: it has room and it is the discoverable surface. */
@media (max-width: 40em) {
  .act:not(.sheet .act) { padding-inline: .7rem; gap: .3rem; }
  .actions .act .act__txt { display: none; }
}

/* ---------- Selection popover (desktop) ---------- */
.popover {
  position: absolute; z-index: 80;
  display: none; gap: .15rem;
  background: var(--surface); border: 1px solid var(--rule);
  border-radius: 999px; box-shadow: var(--shadow); padding: .25rem;
}
.popover[data-open="true"] { display: flex; }
.popover button {
  min-height: 36px; padding: 0 .7rem;
  background: transparent; border: 0; border-radius: 999px;
  color: var(--text); font-family: var(--font-ui); font-size: var(--step--1);
  cursor: pointer;
}
.popover button:hover { background: var(--surface-2); color: var(--accent); }

/* ---------- Bottom sheet (mobile block actions) ---------- */
.sheet {
  position: fixed; inset: auto 0 0 0; z-index: 90;
  background: var(--surface);
  border-top: 1px solid var(--rule);
  border-radius: 16px 16px 0 0;
  padding: .75rem var(--gutter) calc(1rem + env(safe-area-inset-bottom));
  transform: translateY(110%);
  transition: transform .22s ease;
  box-shadow: 0 -8px 30px rgba(0,0,0,.12);
}
.sheet[data-open="true"] { transform: translateY(0); }
.sheet__grip {
  width: 36px; height: 4px; border-radius: 99px; background: var(--rule);
  margin: 0 auto .75rem;
}
.sheet__excerpt {
  font-family: var(--font-read); font-style: italic; color: var(--muted);
  font-size: var(--step--1); margin: 0 0 .75rem;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.sheet__row { display: grid; grid-template-columns: repeat(2, 1fr); gap: .5rem; }
.sheet__row .act { justify-content: center; min-height: var(--tap); }
.sheet-backdrop {
  position: fixed; inset: 0; z-index: 85;
  background: rgba(0,0,0,.35);
  opacity: 0; pointer-events: none; transition: opacity .22s ease;
}
.sheet-backdrop[data-open="true"] { opacity: 1; pointer-events: auto; }

/* ---------- Replies (whole-issue thread) ---------- */
#issue-thread { margin-top: 1.75rem; }
#issue-thread .label { display: block; margin-bottom: .75rem; }

/* ---------- Comments ---------- */
.thread {
  margin-top: .75rem; padding: .9rem;
  background: var(--surface-2); border-radius: var(--radius);
  display: none;
}
.thread[data-open="true"] { display: block; }
.thread__list { margin: 0 0 .9rem; padding: 0; list-style: none; }
.thread__empty { color: var(--muted); font-size: var(--step--1); margin: 0 0 .9rem; }
.comment { padding-block: .6rem; border-bottom: 1px solid var(--rule); }
.comment:last-child { border-bottom: 0; }
.comment__who { font-size: var(--step--1); font-weight: 600; }
.comment__when { font-size: var(--step--1); color: var(--muted); margin-left: .4rem; font-weight: 400; }
.comment__body { margin: .25rem 0 0; color: var(--text-soft); }
.thread__form textarea {
  width: 100%; min-height: 84px; resize: vertical;
  font-family: var(--font-ui); font-size: var(--step-0);
  padding: .65rem; border-radius: 8px;
  border: 1px solid var(--rule); background: var(--surface); color: var(--text);
  margin-bottom: .5rem;
}
.thread__note { font-size: var(--step--1); color: var(--muted); margin: .5rem 0 0; }

/* ============================================================
   Subscribe / CTA / footer
   ============================================================ */
.cta {
  text-align: center; padding: 2rem 1.25rem;
  background: var(--surface-2); border-radius: var(--radius);
  margin-block: 2rem;
}
.cta h2 {
  font-family: var(--font-read); font-size: var(--step-1);
  margin: 0 0 .5rem; font-weight: 600;
}
.cta p { color: var(--muted); margin: 0 0 1.1rem; font-size: var(--step--1); }

.subscribe-form { display: flex; flex-direction: column; gap: .5rem; }
.subscribe-form input[type="email"] {
  width: 100%; min-height: var(--tap); padding: 0 1rem;
  font-family: var(--font-ui); font-size: var(--step-0);
  border: 1px solid var(--rule); border-radius: 999px;
  background: var(--surface); color: var(--text);
}
.subscribe-form button {
  min-height: var(--tap); padding: 0 1.25rem;
  font-family: var(--font-ui); font-size: var(--step--1); font-weight: 500;
  background: var(--accent); color: var(--on-accent);
  border: 0; border-radius: 999px; cursor: pointer;
}

.site-footer {
  border-top: 1px solid var(--rule);
  margin-top: 2rem;
  padding-block: 2rem 3rem;
  text-align: center;
}
.site-footer__tagline { font-family: var(--font-read); font-size: var(--step-1); margin: 0 0 1.25rem; }
.footer-nav ul {
  list-style: none; display: flex; flex-wrap: wrap; gap: 1rem;
  justify-content: center; margin: 0 0 1.25rem; padding: 0;
}
.footer-nav a { color: var(--muted); text-decoration: none; font-size: var(--step--1); }
.footer-nav a:hover { color: var(--accent); }
.footer-meta { font-size: var(--step--1); color: var(--muted); }

/* ---------- Social follow row ---------- */
.social {
  display: flex; flex-wrap: wrap; gap: .35rem;
  justify-content: center; margin-bottom: 1.25rem;
}
.social:empty { display: none; }
.social__link {
  display: inline-flex; align-items: center; justify-content: center;
  width: var(--tap); height: var(--tap);
  border-radius: 50%; color: var(--muted);
}
.social__link:hover { color: var(--accent); background: var(--surface-2); }
.social__link svg { width: 19px; height: 19px; }

/* ---------- Subscribe page ---------- */
.signup { max-width: 30rem; }
.signup__form { display: flex; flex-direction: column; gap: .75rem; }
.signup__form .label { display: block; }
.signup__form input[type="email"] {
  width: 100%; min-height: var(--tap); padding: 0 1rem;
  font-family: var(--font-ui); font-size: var(--step-0);
  border: 1px solid var(--rule); border-radius: 999px;
  background: var(--card); color: var(--text);
}
.signup__letters {
  border: 1px solid var(--rule); border-radius: var(--radius);
  background: var(--card); padding: 1rem; margin: .25rem 0 0;
}
.signup__letters legend { padding: 0 .4rem; }
.signup__letter {
  display: flex; gap: .7rem; align-items: flex-start;
  padding: .5rem 0; cursor: pointer;
}
.signup__letter input { margin-top: .25rem; accent-color: var(--accent); }
.signup__letter-name { display: block; font-weight: 600; font-size: var(--step-0); }
.signup__letter-desc { display: block; font-size: var(--step--1); color: var(--muted); }
.signup__msg { font-size: var(--step--1); color: var(--accent); margin: 0; }
.signup__msg:empty { display: none; }
.signup__note { font-size: var(--step--1); color: var(--muted); margin: .25rem 0 0; }
.signup__alt { font-size: var(--step--1); color: var(--muted); margin-top: 1.25rem; }

/* ---------- Toast ---------- */
.toast {
  position: fixed; left: 50%; bottom: calc(1.25rem + env(safe-area-inset-bottom));
  transform: translate(-50%, 150%);
  background: var(--text); color: var(--bg);
  padding: .65rem 1.1rem; border-radius: 999px;
  font-size: var(--step--1); z-index: 120;
  transition: transform .25s ease;
  max-width: calc(100vw - 2rem);
}
.toast[data-open="true"] { transform: translate(-50%, 0); }

/* ---------- Archive ---------- */
.archive { padding-bottom: 1rem; }
.archive-row {
  display: grid;
  grid-template-columns: 1fr;
  gap: .3rem;
  padding: 1.15rem 0;
  border-bottom: 1px solid var(--rule);
  text-decoration: none; color: inherit;
}
.archive-row:hover .archive-row__title { color: var(--accent); }
.archive-row__no {
  font-family: var(--font-ui); font-size: var(--step--1); font-weight: 500;
  letter-spacing: .09em; text-transform: uppercase; color: var(--muted);
}
.archive-row__title {
  display: block;
  font-family: var(--font-ui); font-size: var(--step-1); font-weight: 600;
  letter-spacing: -0.02em; line-height: 1.3;
}
.archive-row__meta { font-size: var(--step--1); color: var(--muted); }

@media (min-width: 40em) {
  .archive-row {
    grid-template-columns: 13rem 1fr;
    gap: 1.5rem;
    align-items: baseline;
  }
}

/* ---------- Issue-to-issue navigation ---------- */
.issue-nav {
  display: grid; grid-template-columns: 1fr; gap: .85rem;
  margin-top: 2rem;
}
.issue-nav__link {
  display: block; text-decoration: none; color: inherit;
  background: var(--card); border: 1px solid var(--rule);
  border-radius: var(--radius); padding: 1rem 1.15rem;
}
.issue-nav__link:hover { border-color: var(--accent); }
.issue-nav__link .label { display: block; margin-bottom: .3rem; }
.issue-nav__title {
  font-family: var(--font-read); font-size: var(--step-0); color: var(--text);
}
.issue-nav__link--next { text-align: right; }

@media (min-width: 40em) {
  .issue-nav { grid-template-columns: 1fr 1fr; }
  .issue-nav__link--next:only-child { grid-column: 2; }
}

/* ---------- Podcast ----------
   Hi-Phi Nation's player structure, Theoria's palette. Every value here is a
   token; nothing is invented for this page. */

/* Platform buttons.
   NOTE: these are intentionally NOT Apple's and Spotify's official badges.
   Those are fixed-colour brand assets (purple / green) and would be the only
   off-palette thing on the site. Swap them in only if recognisability beats
   consistency — see ISSUE-WORKFLOW.md. */
.platforms { display: flex; flex-wrap: wrap; gap: .55rem; margin-top: 1.2rem; }
.platform {
  display: inline-flex; align-items: center; gap: .5rem;
  min-height: var(--tap); padding: 0 1.05rem;
  border: 1px solid var(--rule); border-radius: 999px;
  background: var(--card); color: var(--text);
  font-family: var(--font-ui); font-size: var(--step--1); font-weight: 500;
  text-decoration: none; white-space: nowrap;
}
.platform:hover { border-color: var(--accent); color: var(--accent); }
.platform svg { width: 17px; height: 17px; flex: none; color: var(--accent); }
.platform:hover svg { color: var(--accent); }

/* ---- Featured player ---- */
.player {
  display: grid; grid-template-columns: 1fr; gap: 0;
  background: var(--quote-bg);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  overflow: hidden;
  margin: 1.75rem 0 1.5rem;
}
.player--embed { display: block; }
.player--embed iframe {
  /* height is set inline from @custom.podcast_embed_height; 345px matches
     RSS.com's default show player. The value here is only the fallback for
     when the setting is somehow empty. */
  display: block; width: 100%; height: 345px; border: 0; background: var(--card);
}

.player__art { position: relative; aspect-ratio: 1 / 1; background: var(--surface-2); }
.player__art img { width: 100%; height: 100%; object-fit: cover; display: block; }
.player__art--type {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  height: 100%; padding: 1rem; text-align: center; gap: .5rem;
}
.player__art-word {
  /* .brand__word carries the family, weight, case and tracking — size only. */
  font-size: clamp(1rem, 3.2vw, 1.35rem);
  color: var(--text);
  line-height: 1.1;
}
.player__art-sub {
  font-family: var(--font-ui); font-size: .58rem; font-weight: 500;
  letter-spacing: .2em; text-transform: uppercase; color: var(--muted);
}

/* The monogram, wherever it appears in a template. */
.mark { display: block; width: 1em; height: 1em; }

.player__main { padding: 1.1rem 1.15rem 1.25rem; min-width: 0; }
.player__now { display: flex; align-items: center; gap: .85rem; }
.player__play {
  width: 46px; height: 46px; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  border: 0; border-radius: 50%;
  background: var(--accent); color: var(--on-accent); cursor: pointer;
}
.player__play:hover { opacity: .92; }
.player__play svg { width: 22px; height: 22px; }
.player__play[hidden] { display: none; }

.player__meta { min-width: 0; flex: 1; }
.player__show {
  display: block;
  /* .brand__word supplies the family, tracking and case; only the size
     changes here, so the player's logo IS the header's logo. */
  font-size: .78rem;
  color: var(--muted);
  margin-bottom: .15rem;
}
.player__title {
  display: block; font-family: var(--font-ui); font-weight: 600;
  font-size: var(--step-0); letter-spacing: -0.01em; line-height: 1.3;
  color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.player__sub {
  display: block; font-size: var(--step--1); color: var(--muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.player__time {
  font-family: var(--font-ui); font-size: var(--step--1); color: var(--muted);
  font-variant-numeric: tabular-nums; flex: none;
}

.player__bar {
  position: relative; height: 4px; margin-top: 1rem;
  background: var(--rule); border-radius: 99px; cursor: pointer;
}
.player__fill {
  position: absolute; inset: 0 auto 0 0; width: 0%;
  background: var(--accent); border-radius: 99px;
}
.player__bar:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; }

@media (min-width: 40em) {
  .player { grid-template-columns: 180px 1fr; }
  .player__art { aspect-ratio: auto; height: 100%; }
}

/* ---- Season tabs: a control at the top, not stacked sections ---- */
.season-tabs {
  display: flex; flex-wrap: wrap; gap: .3rem;
  padding-bottom: .9rem; margin-bottom: .25rem;
  border-bottom: 1px solid var(--rule);
}
.season-tab {
  min-height: 34px; padding: 0 .8rem;
  background: transparent; border: 1px solid transparent; border-radius: 999px;
  font-family: var(--font-ui); font-size: var(--step--1); font-weight: 500;
  letter-spacing: .07em; text-transform: uppercase;
  color: var(--muted); cursor: pointer; white-space: nowrap;
}
.season-tab:hover { color: var(--text); background: var(--surface-2); }
.season-tab[aria-pressed="true"] {
  color: var(--accent); border-color: var(--accent); background: var(--accent-soft);
}

/* ---- Playlist ---- */
.playlist { margin-top: 1.5rem; }
.playlist__head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 1rem; padding-bottom: .6rem;
}
.episodes { display: block; }

.episode {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center; gap: .9rem;
  padding: .85rem .5rem;
  border-top: 1px solid var(--rule);
  text-decoration: none; color: inherit;
  border-radius: var(--radius);
}
.episode:last-child { border-bottom: 1px solid var(--rule); }
.episode:hover { background: var(--surface-2); }
.episode:hover .episode__title { color: var(--accent); }
.episode[hidden] { display: none; }

.episode__glyph {
  width: 30px; height: 30px; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--rule); border-radius: 50%;
  color: var(--accent); background: var(--card);
}
.episode__glyph svg { width: 13px; height: 13px; margin-left: 1px; }
.episode:hover .episode__glyph { border-color: var(--accent); }

.episode__body { min-width: 0; }
.episode__title {
  display: block; font-family: var(--font-ui); font-weight: 600;
  font-size: var(--step-0); letter-spacing: -0.01em; line-height: 1.35;
}
.episode__no {
  display: block; font-family: var(--font-ui); font-size: var(--step--1);
  letter-spacing: .07em; text-transform: uppercase; color: var(--muted);
  margin-top: .1rem;
}
.episode__len {
  font-size: var(--step--1); color: var(--muted);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}

/* ---------- Ghost's audio card ----------
   package.json sets `card_assets: true`, so Ghost injects its own audio.css
   and audio.js. The player therefore WORKS without us — seeking, volume,
   playback rate, all of it. What we do here is re-tint it, because Ghost's
   default is neutral grey and would sit on an episode page as the one element
   that ignores the reader's colour scheme.

   Restyle, not rebuild. Rebuilding would mean reimplementing the JS too, and
   the day Ghost changes the markup our version silently stops matching. */
.post-content .kg-audio-card {
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  padding: 1rem;
  display: flex;
  align-items: center;
  gap: 1rem;
}

.post-content .kg-audio-thumbnail {
  width: 80px; height: 80px; flex: none;
  border-radius: calc(var(--radius) - 4px);
  object-fit: cover;
}
.post-content .kg-audio-thumbnail.placeholder {
  display: flex; align-items: center; justify-content: center;
  background: var(--surface-2); color: var(--accent);
}
.post-content .kg-audio-thumbnail.placeholder svg { width: 26px; height: 26px; }
.post-content .kg-audio-hide { display: none; }

.post-content .kg-audio-player-container {
  flex: 1 1 auto;
  min-width: 0;
  /* Firefox miscalculates this container at width:100% and the volume slider
     overshoots the card. Documented Ghost bug; 80px thumbnail + 24px of gap
     and padding is the 104px. min-width:0 alone does not fix it in Gecko. */
  max-width: calc(100% - 104px);
}
/* With no thumbnail there is nothing to subtract. */
.post-content .kg-audio-card:has(.kg-audio-thumbnail.kg-audio-hide.placeholder)
  .kg-audio-player-container { max-width: 100%; }

.post-content .kg-audio-title {
  font-family: var(--font-ui);
  font-size: var(--step-0);
  font-weight: 600;
  color: var(--text);
  margin-bottom: .5rem;
}

.post-content .kg-audio-player {
  display: flex; align-items: center; gap: .5rem;
  font-family: var(--font-ui);
  font-size: var(--step--1);
  color: var(--muted);
}

.post-content .kg-audio-play-icon,
.post-content .kg-audio-pause-icon,
.post-content .kg-audio-unmute-icon,
.post-content .kg-audio-mute-icon,
.post-content .kg-audio-playback-rate {
  display: inline-flex; align-items: center; justify-content: center;
  border: 0; background: none; cursor: pointer; padding: .35rem;
  color: var(--accent);
  /* 44px targets would blow the row apart, so the tap area is grown with a
     pseudo-element instead of with box size. */
  position: relative;
}
.post-content .kg-audio-play-icon::after,
.post-content .kg-audio-pause-icon::after,
.post-content .kg-audio-unmute-icon::after,
.post-content .kg-audio-mute-icon::after,
.post-content .kg-audio-playback-rate::after {
  content: ''; position: absolute; inset: 50% auto auto 50%;
  width: var(--tap); height: var(--tap); transform: translate(-50%, -50%);
}
.post-content .kg-audio-play-icon svg,
.post-content .kg-audio-pause-icon svg { width: 16px; height: 16px; }
.post-content .kg-audio-unmute-icon svg,
.post-content .kg-audio-mute-icon svg { width: 15px; height: 15px; }
.post-content .kg-audio-playback-rate {
  font-family: var(--font-ui); font-size: var(--step--1); font-weight: 600;
  min-width: 2.2em;
}

.post-content .kg-audio-current-time,
.post-content .kg-audio-time,
.post-content .kg-audio-duration {
  font-variant-numeric: tabular-nums;   /* stops the row twitching per second */
  color: var(--muted);
}

.post-content .kg-audio-seek-slider,
.post-content .kg-audio-volume-slider {
  -webkit-appearance: none; appearance: none;
  height: 4px; border-radius: 999px;
  background: var(--surface-2);
  cursor: pointer;
}
.post-content .kg-audio-seek-slider { flex: 1 1 auto; min-width: 3rem; }
.post-content .kg-audio-volume-slider { flex: 0 1 4.5rem; min-width: 2.5rem; }
/* Ghost styles the thumb via `.kg-audio-player-container input[type="range"]
   ::-webkit-slider-thumb` and paints it white. Match its shape so the accent
   colour wins; the plain `.kg-audio-seek-slider` form loses. */
.post-content .kg-audio-player-container input[type="range"]::-webkit-slider-thumb,
.post-content .kg-audio-seek-slider::-webkit-slider-thumb,
.post-content .kg-audio-volume-slider::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 13px; height: 13px; border-radius: 50%;
  background: var(--accent); border: 0; cursor: pointer;
}
.post-content .kg-audio-seek-slider::-moz-range-thumb,
.post-content .kg-audio-volume-slider::-moz-range-thumb {
  width: 13px; height: 13px; border-radius: 50%;
  background: var(--accent); border: 0; cursor: pointer;
}

/* The volume control is the first thing to go when the row runs out of room —
   it is the one control the device's own buttons already cover. */
@media (max-width: 34em) {
  .post-content .kg-audio-card { padding: .85rem; gap: .85rem; }
  .post-content .kg-audio-thumbnail { width: 56px; height: 56px; }
  .post-content .kg-audio-player-container { max-width: calc(100% - 72px); }
  .post-content .kg-audio-volume-slider,
  .post-content .kg-audio-unmute-icon,
  .post-content .kg-audio-mute-icon { display: none; }
}

/* ---------- Random issue ---------- */
.random-slot { min-height: 1px; }
.random-slot--in { animation: randomIn .32s ease; }
@keyframes randomIn {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}
.random-card {
  display: block; text-decoration: none; color: inherit;
  background: var(--quote-bg);
  border: 1px solid var(--rule); border-left: 3px solid var(--accent);
  border-radius: var(--radius); padding: 1.6rem 1.5rem;
}
.random-card:hover { border-color: var(--accent); }
.random-card__eyebrow { display: block; margin-bottom: .6rem; }
.random-card__title {
  display: block;
  font-family: var(--font-ui); font-size: var(--step-2); font-weight: 700;
  letter-spacing: -0.025em; line-height: 1.2; margin: 0 0 .6rem;
}
.random-card__excerpt {
  display: block;
  font-family: var(--font-read); font-size: var(--step-0);
  color: var(--text-soft); margin: 0 0 .8rem; line-height: 1.6;
}
.random-card__meta { display: block; font-size: var(--step--1); color: var(--muted); }
.random-actions {
  display: flex; flex-wrap: wrap; gap: .6rem;
  margin: 1.25rem 0 2rem;
}

/* ---------- Saved page ---------- */
.saved-toolbar {
  display: flex; flex-wrap: wrap; gap: .75rem;
  align-items: center; justify-content: space-between;
  padding-bottom: 1rem; margin-bottom: 1.5rem;
  border-bottom: 1px solid var(--rule);
}
.saved-group { margin-bottom: 2.25rem; }
.saved-group__title {
  font-family: var(--font-ui); font-size: var(--step-0); font-weight: 600;
  letter-spacing: -0.01em; margin: 0 0 .85rem;
}
.saved-group__title a { color: var(--text); text-decoration: none; }
.saved-group__title a:hover { color: var(--accent); }

.saved-item {
  background: var(--card);
  border: 1px solid var(--rule);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius);
  padding: 1.15rem 1.25rem;
  margin-bottom: .85rem;
}
/* The heading inside a saved item is the SAME markup as on the issue page
   (.margin-note__head + .label), so it inherits the lavender bold treatment and
   the trailing hairline for free. Only the spacing needs adjusting for the
   tighter card. */
.saved-item .margin-note__head { margin-bottom: .55rem; }

.saved-item__text {
  font-family: var(--font-read);
  font-size: var(--step-read);          /* same reading size as the issue */
  line-height: var(--leading-read);
  margin: 0 0 .75rem;
  color: var(--text);
  /* The snapshot keeps real newlines now — a quote and its attribution are two
     lines, as they are in the issue. Without pre-line they collapse back into
     one run and the attribution welds onto the last word. */
  white-space: pre-line;
  text-wrap: pretty;
}

/* A saved block should read as the kind of block it was.
   Quote and prompt are the two set in italic on the issue page, so they stay
   italic here; the notes stay upright. Same logic, same place. */
.saved-item[data-type="quote"] .saved-item__text,
.saved-item[data-type="prompt"] .saved-item__text { font-style: italic; }
.saved-item[data-type="quote"] .saved-item__text { font-size: var(--step-1); }

/* Quote keeps the tinted surface it has inside an issue; everything else sits
   on the plain card, exactly as the callouts do. */
.saved-item[data-type="quote"] { background: var(--quote-bg); }

/* The notes are the quieter voice in an issue — keep that here too. */
.saved-item[data-type="candy"] .saved-item__text,
.saved-item[data-type="connection"] .saved-item__text,
.saved-item[data-type="aphorism"] .saved-item__text { color: var(--text-soft); }
.saved-item__foot {
  display: flex; flex-wrap: wrap; gap: .6rem;
  align-items: center; justify-content: space-between;
}
.saved-item__src {
  font-size: var(--step--1); color: var(--muted);
}
.saved-item__foot .actions { margin-top: 0; }
.saved-item .act { text-decoration: none; }

@media print {
  .saved-toolbar, .saved-item__foot .actions { display: none !important; }
  .saved-item { border: 0; border-left: 2px solid #999; break-inside: avoid; }
}

/* ---------- Error page ---------- */
.error { text-align: center; padding-block: 4rem; }
.error__mark {
  display: block; width: 56px; margin: 0 auto 1.5rem;
  color: var(--accent);
}
.error__code {
  font-family: var(--font-read); font-size: var(--step-3); margin: 0 0 .5rem;
}
.error__msg { color: var(--muted); margin: 0 0 1.5rem; }

/* ---------- Pagination ---------- */
.pagination {
  display: flex; align-items: center; justify-content: space-between;
  gap: 1rem; padding-block: 2rem;
}
.pagination .page-number { font-size: var(--step--1); color: var(--muted); }

/* ============================================================
   Larger screens
   ============================================================ */
@media (min-width: 40em) {
  :root { --gutter: 1.5rem; }

  /* Desktop: wordmark left, pill right — undo the mobile centring. */
  /* Desktop masthead: the wordmark centred on its own line, the nav pill
     centred beneath it — the same arrangement mobile already had, so the
     header reads identically at every width.

     This replaces the earlier wordmark-left / pill-right row. The reason is
     the wordmark IS the logo: pinned to one corner it competed with the pill
     for the eye, and the publication's name is not a navigation item. Centred
     and alone on its line, it behaves like a masthead.

     column-wrap rather than two containers, so there is one flex context and
     nothing to keep in sync. */
  .masthead__inner {
    position: static;
    flex-direction: column;
    justify-content: center;
    gap: .9rem;
  }
  .masthead__inner .nav-toggle { position: static; transform: none; }
  /* The pill centres itself and only takes the width it needs. */
  .masthead__inner .navpill { margin-inline: auto; }

  .nav { display: block; }
  .navpill { display: flex; }
  .nav-toggle { display: none; }

  .subscribe-form { flex-direction: row; justify-content: center; }
  .subscribe-form input[type="email"] { max-width: 20rem; }

  /* Desktop uses inline actions + the selection popover. !important so a
     stale data-open="true" can never leave the sheet peeking at the bottom. */
  .sheet, .sheet-backdrop { display: none !important; }
}

@media (min-width: 64em) {
  .masthead__inner { padding-block: 1.5rem; }
  .issue { padding-block: 3rem 1rem; }
}

/* ============================================================
   Motion, print, forced colors
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
}

@media print {
  .masthead__tools, .actions, .quote-actions .actions, .sheet, .popover,
  .progress, .cta, .thread, .toast, .skip-link { display: none !important; }
  body { background: #fff; color: #000; }
}

@media (forced-colors: active) {
  .act, .btn, .picker__opt { border: 1px solid ButtonBorder; }
  /* In forced-colors mode the browser replaces our palette wholesale, so the
     lavender heading disappears into the system text colour. Keep the rule
     visible so the sections still read as separated. */
  .margin-note__head::after { background: CanvasText; }
}

/* ---------- Readers who ask the OS for more contrast ----------
   Windows "increase contrast", macOS "Increase contrast", and Android's
   equivalent all surface here. Our defaults already clear WCAG AA; this takes
   the two intentionally softened greys up to full strength for readers who
   have said plainly that soft grey does not work for them. */
@media (prefers-contrast: more) {
  /* Must carry .kg-callout-card too. The base callout rule was raised to
     (0,3,0) to outrank Ghost's card CSS — which means it would also outrank
     THIS override at (0,2,0), and a reader asking their OS for more contrast
     would silently keep the softer grey. Media queries add no specificity. */
  .margin-note__body,
  .post-content .kg-callout-card .kg-callout-text { color: var(--text); }
  .label { color: var(--text-soft); }
  .margin-note__head::after { background: var(--rule); }
  mark.mk { outline: 1px solid var(--accent); }
}

/* ---------- WCAG 1.4.12 Text Spacing ----------
   A reader may override line-height to 1.5, letter-spacing to 0.12em, word
   spacing to 0.16em and paragraph spacing to 2em; no content may be lost.
   Cards are padded and free to grow in height, so text reflows rather than
   clipping. The one place a fixed height existed was the action pills, which
   is why they size from min-height and not height. Kept as a note because it
   is an easy thing to break later with a well-meaning `height:`. */
