/* ============================================================================
   bastian — a Ghost theme
   ----------------------------------------------------------------------------
   MOOD:           quiet, confident
   COLOR STRATEGY: near-monochrome. Ink on paper. The Ghost accent is reserved
                   for interactive affordances, the pull-quote mark, and one
                   accent moment per view. Primary buttons are solid ink pills.
   CARD STYLE:     image card at radius/2, author avatars overlaid on the
                   image's bottom-left, tag pills, bold headline, 3-line excerpt
   CORNER RADIUS:  one token; cards take radius/2, controls take 100px pills
   TYPOGRAPHY:     display sets two weights in the SAME line, 400 then 700,
                   at -0.03em tracking and 1.05 leading
   DISTINCTIVE:    two-tone weight headlines announced beneath a full-width
                   hairline rule, label pinned left, controls pinned right

   There is no build step. This file is authored, not generated.

   A NOTE ON DEFAULTS
   Every variant that is driven by a tweak-file attribute is written so the
   SHIPPED DEFAULT IS THE PLAIN RULE and the attribute is only ever an override.
   Written the other way round, a visitor with JavaScript disabled would get no
   variant at all — and you would not notice, because you test with JS on.
   ========================================================================== */

/* ---------------------------------------------------------------- 1. tokens */
:root {
  --bg: #ffffff;
  --bg2: #f7f7f5;
  --bg3: #f2f0f2;
  --bg4: #e8e8e6;
  --text: #151618;
  --text2: #1a1b1e;
  --text3: #797c82;
  --border: #e6e6ea;
  --border-2: #d9d9d8;
  --accent: #ff4d82;
  --accent-soft: #ffe8ef;
  --accent2: #151618;
  --accent3: #61d6ad;
  --page-bg: #ffffff;
  --footer-bg-start: #ffffff;
  --footer-bg-end: #f7f7f5;
  --cta-start: #f2f0f2;
  --cta-end: #e8e8e6;
  --footer-text: #151618;
  --cta-text: #151618;
  --on-accent: #ffffff;
  --on-accent2: #ffffff;
  --on-accent3: #151618;
  --scrim-1: linear-gradient(to top, rgba(21, 22, 24, .62), rgba(21, 22, 24, 0) 62%);
  --scrim-2: linear-gradient(to top, rgba(21, 22, 24, .85), rgba(21, 22, 24, .15));
  --scrim-3: radial-gradient(120% 90% at 50% 100%, rgba(21, 22, 24, .55), rgba(21, 22, 24, 0));
  --on-media: #ffffff;
  --ok: #61d6ad;
  --err: #ff6c78;

  --radius: 26px;
  --r-card: calc(var(--radius) / 2);
  --r-chip: 100px;
  --r-sm: calc(var(--radius) / 4);

  --container: 1536px;
  --gutter: 1rem;
  --post-w: 720px;
  --grid-gap: 16px;

  /* Ghost injects --gh-font-heading / --gh-font-body when the site picks fonts
     in Settings, Design, Brand. Those must win over the theme's pairing. */
  --font-display: var(--gh-font-heading, 'Inter Tight'), 'Inter Tight', system-ui, sans-serif;
  --font-body: var(--gh-font-body, 'Inter'), 'Inter', system-ui, sans-serif;
  --font-mono: 'JetBrains Mono', ui-monospace, monospace;

  --shadow-1: 0 1px 2px rgba(21, 22, 24, .05);
  --shadow-2: 0 12px 32px -12px rgba(21, 22, 24, .18);
  --shadow-3: 0 28px 64px -24px rgba(21, 22, 24, .28);

  --dur: .42s;
  --ease: cubic-bezier(.22, 1, .36, 1);
}

[data-theme="dark"] {
  --bg: #1a1b1e;
  --bg2: #212225;
  --bg3: #292a2d;
  --bg4: #2b2d31;
  --text: #f7f7f5;
  --text2: #e2e2df;
  --text3: #9a9ea3;
  --border: #34363a;
  --border-2: #4b4f52;
  --accent-soft: #3a1f28;
  --accent2: #f7f7f5;
  --on-accent2: #151618;
  --page-bg: #1a1b1e;
  --footer-bg-start: #212225;
  --footer-bg-end: #151618;
  --cta-start: #2b2d31;
  --cta-end: #151618;
  --footer-text: #f7f7f5;
  --cta-text: #f7f7f5;
  --scrim-1: linear-gradient(to top, rgba(10, 10, 12, .72), rgba(10, 10, 12, 0) 62%);
  --scrim-2: linear-gradient(to top, rgba(10, 10, 12, .9), rgba(10, 10, 12, .2));
  --scrim-3: radial-gradient(120% 90% at 50% 100%, rgba(10, 10, 12, .65), rgba(10, 10, 12, 0));
  --on-media: #f7f7f5;
  --shadow-1: 0 1px 2px rgba(0, 0, 0, .3);
  --shadow-2: 0 12px 32px -12px rgba(0, 0, 0, .6);
  --shadow-3: 0 28px 64px -24px rgba(0, 0, 0, .75);
}

@media (min-width: 640px)  { :root { --gutter: 1.5rem } }
@media (min-width: 1024px) { :root { --gutter: 2rem } }
@media (min-width: 1280px) { :root { --gutter: 3rem } }
@media (min-width: 1536px) { :root { --gutter: 4rem } }

/* Ghost's Portal renders in an iframe whose document declares no color-scheme.
   When the embedding page declares one, Chrome stops compositing that iframe as
   transparent and paints an opaque light canvas behind it — a white slab around
   the floating Subscribe button. Scoped so the rest of the theme keeps its dark
   scrollbars and form controls. */
#ghost-portal-root,
#ghost-portal-root iframe { color-scheme: normal }

/* -------------------------------------------------------------- 2. base */
* { box-sizing: border-box }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth }

body {
  margin: 0;
  background: var(--page-bg);
  color: var(--text);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.65;
  font-weight: 400;
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

img, svg, video { display: block; max-width: 100% }
a { color: inherit; text-decoration: none }
button, input, select, textarea { font: inherit; color: inherit }
h1, h2, h3, h4, h5, h6 { margin: 0; font-family: var(--font-display); font-weight: 700 }
p { margin: 0 }
ul, ol { margin: 0 }

:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 4px }
::selection { background: var(--accent); color: var(--on-accent) }

/* ----------------------------------------------- 3. the layout contract */
/* Backgrounds run edge to edge; the gutter caps and centres the content, so a
   band can carry its own background AND keep its content on the measure. */
.pad { padding-inline: max(var(--gutter), calc((100% - var(--container)) / 2)) }
.bleed { --container: 100% }
.band.pad { max-width: 100% }
.measure { max-width: var(--post-w); margin-inline: auto }

.section { padding-block: clamp(3rem, 7vw, 6rem) }
.section-tight { padding-block: clamp(2rem, 4vw, 3.25rem) }

.surface-1 { background: var(--bg) }
.surface-2 { background: var(--bg2) }
.surface-3 { background: var(--bg3) }

/* ------------------------------------------------------------ 4. typography */
.display { font-family: var(--font-display); letter-spacing: -.03em; line-height: 1.05; font-weight: 400 }
/* THE distinctive move: two weights in one line. */
.display b, .display strong, .display .hv { font-weight: 700 }

.t-hero    { font-size: clamp(2.5rem, 6.1vw, 6.4rem) }
.t-xl      { font-size: clamp(2rem, 4.4vw, 3.9rem) }
.t-lg      { font-size: clamp(1.6rem, 3vw, 2.6rem) }
.t-md      { font-size: clamp(1.25rem, 1.8vw, 1.65rem); line-height: 1.15 }
.t-card    { font-size: clamp(1.05rem, 1.15vw, 1.3rem); line-height: 1.22; font-weight: 700; letter-spacing: -.02em; font-family: var(--font-display) }
.t-card-sm { font-size: .93rem; line-height: 1.28; font-weight: 700; letter-spacing: -.01em; font-family: var(--font-display) }

.lede { font-size: clamp(1rem, 1.15vw, 1.2rem); color: var(--text2); line-height: 1.6; max-width: 62ch }
.excerpt { font-size: .9rem; line-height: 1.55; color: var(--text3); max-width: 60ch }
.meta { font-size: .8rem; color: var(--text3) }
.clamp-2 { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden }
.clamp-3 { display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden }
.clamp-4 { display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden }

/* ---------------------------------------------------- 4b. font pairings */
/* Fifteen pairings, one loaded — the <link> for the active pairing is the only
   one emitted in the head.

   Every pairing keeps Ghost's own fonts as the PREFERRED value, so a face
   chosen in Settings, Design, Brand still wins. That is correct behaviour, and
   it looks like a bug if nobody writes it down, so it is in the README too.

   The distinctive move — 400 and 700 of the same family inside one headline —
   needs both weights to exist. Anton (brutalist) ships only one, so its bold
   half is synthesised; every other pairing carries a real 700. */
body.fp-modern     { --font-display: var(--gh-font-heading, 'Inter Tight'), 'Inter Tight', system-ui, sans-serif;     --font-body: var(--gh-font-body, 'Inter'), 'Inter', system-ui, sans-serif }
body.fp-grotesk    { --font-display: var(--gh-font-heading, 'Space Grotesk'), 'Space Grotesk', system-ui, sans-serif; --font-body: var(--gh-font-body, 'Inter'), 'Inter', system-ui, sans-serif }
body.fp-swiss      { --font-display: var(--gh-font-heading, 'Manrope'), 'Manrope', system-ui, sans-serif;             --font-body: var(--gh-font-body, 'Manrope'), 'Manrope', system-ui, sans-serif }
body.fp-neo        { --font-display: var(--gh-font-heading, 'Archivo'), 'Archivo', system-ui, sans-serif;             --font-body: var(--gh-font-body, 'Archivo'), 'Archivo', system-ui, sans-serif }
body.fp-geometric  { --font-display: var(--gh-font-heading, 'Poppins'), 'Poppins', system-ui, sans-serif;             --font-body: var(--gh-font-body, 'Inter'), 'Inter', system-ui, sans-serif }
body.fp-humanist   { --font-display: var(--gh-font-heading, 'Outfit'), 'Outfit', system-ui, sans-serif;               --font-body: var(--gh-font-body, 'Karla'), 'Karla', system-ui, sans-serif }
body.fp-editorial  { --font-display: var(--gh-font-heading, 'Fraunces'), 'Fraunces', Georgia, serif;                  --font-body: var(--gh-font-body, 'Instrument Serif'), 'Instrument Serif', Georgia, serif }
body.fp-classic    { --font-display: var(--gh-font-heading, 'Playfair Display'), 'Playfair Display', Georgia, serif;  --font-body: var(--gh-font-body, 'Source Serif 4'), 'Source Serif 4', Georgia, serif }
body.fp-literary   { --font-display: var(--gh-font-heading, 'Libre Baskerville'), 'Libre Baskerville', Georgia, serif; --font-body: var(--gh-font-body, 'Libre Franklin'), 'Libre Franklin', system-ui, sans-serif }
body.fp-warm       { --font-display: var(--gh-font-heading, 'Newsreader'), 'Newsreader', Georgia, serif;              --font-body: var(--gh-font-body, 'Nunito Sans'), 'Nunito Sans', system-ui, sans-serif }
body.fp-serif-sans { --font-display: var(--gh-font-heading, 'Lora'), 'Lora', Georgia, serif;                          --font-body: var(--gh-font-body, 'Work Sans'), 'Work Sans', system-ui, sans-serif }
body.fp-display    { --font-display: var(--gh-font-heading, 'Bricolage Grotesque'), 'Bricolage Grotesque', system-ui, sans-serif; --font-body: var(--gh-font-body, 'Inter'), 'Inter', system-ui, sans-serif }
body.fp-condensed  { --font-display: var(--gh-font-heading, 'Oswald'), 'Oswald', system-ui, sans-serif;               --font-body: var(--gh-font-body, 'Roboto'), 'Roboto', system-ui, sans-serif }
body.fp-brutalist  { --font-display: var(--gh-font-heading, 'Anton'), 'Anton', system-ui, sans-serif;                 --font-body: var(--gh-font-body, 'IBM Plex Sans'), 'IBM Plex Sans', system-ui, sans-serif }
body.fp-tech       { --font-display: var(--gh-font-heading, 'JetBrains Mono'), 'JetBrains Mono', ui-monospace, monospace; --font-body: var(--gh-font-body, 'JetBrains Mono'), 'JetBrains Mono', ui-monospace, monospace }

/* content width — the container every band centres against */
body.cw-narrow   { --container: 1100px }
body.cw-standard { --container: 1280px }
body.cw-wide     { --container: 1536px }
body.cw-full     { --container: 100% }

/* post measure, from the tweak file */
body[data-postw="narrow"] { --post-w: 640px }
body[data-postw="wide"]   { --post-w: 840px }

/* --------------------------------- 5. section furniture — ONE treatment */
.sec-head {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  border-top: 1px solid var(--border);
  padding-top: .7rem;
  margin-bottom: 1.6rem;
}
.sec-head .sec-label { font-size: .8125rem; font-weight: 400; color: var(--text2); letter-spacing: -.005em }
.sec-head .sec-label b { font-weight: 700; color: var(--text) }
.sec-head .sec-tools { display: flex; align-items: center; gap: .4rem; flex: 0 0 auto }

.sec-head-lg {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 2rem; flex-wrap: wrap; margin-bottom: 2rem;
}

.rail-btn {
  width: 34px; height: 34px; display: grid; place-items: center;
  border: 1px solid var(--border-2); border-radius: var(--r-chip);
  background: transparent; color: var(--text2); cursor: pointer;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.rail-btn:hover { background: var(--accent2); color: var(--on-accent2); border-color: var(--accent2) }
.rail-btn svg { width: 15px; height: 15px }

/* ---------------------------------------------------------- 6. controls */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .5rem;
  min-height: 44px; padding: 0 1.4rem;
  border-radius: var(--r-chip); border: 1px solid transparent;
  font-size: .9rem; font-weight: 500; cursor: pointer; white-space: nowrap;
  transition: transform var(--dur) var(--ease), background var(--dur) var(--ease), color var(--dur) var(--ease), border-color var(--dur) var(--ease), opacity var(--dur) var(--ease);
}
.btn:active { transform: scale(.97) }
.btn-ink { background: var(--accent); color: var(--on-accent) }
.btn-ink:hover { opacity: .82 }
.btn-line { background: transparent; border-color: var(--border-2); color: var(--text) }
.btn-line:hover { border-color: var(--accent2); background: var(--accent2); color: var(--on-accent2) }
.btn-accent { background: var(--accent); color: var(--on-accent) }
.btn-accent:hover { filter: brightness(1.08) }
.btn-sm { min-height: 36px; padding: 0 1rem; font-size: .82rem }

.chip {
  display: inline-flex; align-items: center; gap: .3rem;
  padding: .28rem .66rem; border-radius: var(--r-chip);
  background: var(--bg3); color: var(--text2);
  font-size: .72rem; font-weight: 500; line-height: 1.3;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
a.chip:hover { background: var(--accent2); color: var(--on-accent2) }
.chip svg { width: 12px; height: 12px }

.field {
  min-height: 44px; padding: 0 1.1rem;
  border-radius: var(--r-chip); border: 1px solid var(--border);
  background: var(--bg2); color: var(--text);
  font-size: .9rem; width: 100%;
}
.field::placeholder { color: var(--text3) }
.field:focus { outline: none; border-color: var(--accent3); background: var(--bg) }
textarea.field { min-height: 120px; padding: .8rem 1.1rem; border-radius: var(--r-card); resize: vertical }

/* form shapes — inline (default) / stacked / boxed.
   The <form> is a column so the success panel and the error line can sit under
   the fields; .form-fields is the row that actually carries the shape. */
.subform { display: flex; flex-direction: column; gap: .4rem; width: 100%; max-width: 520px }
.subform .form-fields { display: flex; gap: .5rem; width: 100% }
.subform .form-fields .field { flex: 1 1 auto }
.subform .form-fields .btn { flex: 0 0 auto }
[data-form="stacked"] .subform .form-fields { flex-direction: column; align-items: stretch }
[data-form="stacked"] .subform .form-fields .btn { width: 100% }
[data-form="boxed"] .subform .form-fields {
  flex-direction: column; align-items: stretch; gap: .6rem;
  padding: 1.1rem; border: 1px solid var(--border); border-radius: var(--r-card); background: var(--bg2);
}
[data-form="boxed"] .subform .form-fields .btn { width: 100% }

/* Both are shipped shown, expressed as plain rules; the attributes are written
   by the tweak file and only ever hide. */
[data-footform="hide"] .foot-form { display: none }
[data-newsletter="hide"] .cta-band { display: none }
/* asking someone to subscribe twice on one screen is noise */
.page-membership .cta-band { display: none }

/* ------------------------------------------------- 6b. members form state */
/* Ghost toggles .loading / .success / .error on the <form> itself and does
   nothing else. Scoped to the ATTRIBUTE, not to any one card's class, so the
   footer form and the newsletter band are covered as well as the auth pages —
   otherwise those submit, get a 201, and appear to do nothing at all. */
[data-members-form] .form-fields { display: flex; gap: .5rem; width: 100% }
[data-members-form] .form-fields-stack { flex-direction: column; gap: .7rem }
[data-members-form] .form-sent { display: none }
[data-members-form] [data-members-error] { display: none; color: var(--err); font-size: .82rem; margin-top: .1rem }

[data-members-form].error [data-members-error] { display: block }
[data-members-form].success .form-sent { display: block }
[data-members-form].success .form-fields { display: none }
[data-members-form].loading button[type="submit"] { opacity: .6; pointer-events: none }

.form-note { font-size: .8rem; color: var(--text3) }
.form-sent { text-align: center; padding: 1.6rem 0 }
.form-sent .ic {
  width: 54px; height: 54px; border-radius: 100px;
  background: var(--accent3); color: var(--on-accent3);
  display: grid; place-items: center; margin: 0 auto 1rem;
}
.form-sent .ic svg { width: 22px; height: 22px }

/* ----------------------------------------------------------------- 7. cards */
/* One markup, three archive layouts. The text stack always lives in .card-body,
   so turning a card horizontal is a flex-direction change rather than a second
   partial that drifts from the first. */
.card { display: flex; flex-direction: column; gap: .75rem; min-width: 0 }
.card-link { display: block; min-width: 0 }
.card-body { display: flex; flex-direction: column; gap: .5rem; min-width: 0; flex: 1 1 auto }

/* display:block is load-bearing, for the same reason it is on .bubble .ring:
   this is a <span>, and an INLINE box ignores width, height and aspect-ratio
   outright. Without it the media box computes to 0x0, the img inside it — sized
   at 100%/100% — collapses with it, and the card silently renders as text with
   no picture. It survived this long because the layouts that set an explicit
   height (bento, the magazine side rail) masked it. */
.card-media {
  display: block;
  position: relative; border-radius: var(--r-card); overflow: hidden;
  background: var(--bg3); aspect-ratio: 4 / 3; isolation: isolate;
}
.card-media > img,
.card-media > .ph { width: 100%; height: 100%; object-fit: cover; transition: transform .7s var(--ease) }
.card:hover .card-media > img,
.card:hover .card-media > .ph { transform: scale(1.045) }
.card-media[data-ratio="16/9"] { aspect-ratio: 16 / 9 }
.card-media[data-ratio="3/2"]  { aspect-ratio: 3 / 2 }
.card-media[data-ratio="1/1"]  { aspect-ratio: 1 / 1 }
.card-media[data-ratio="21/9"] { aspect-ratio: 21 / 9 }

/* author avatars overlaid on the image, bottom-left — reference card anatomy */
.avatars { position: absolute; left: .6rem; bottom: .6rem; display: flex; z-index: 2 }
.avatars .av {
  width: 26px; height: 26px; border-radius: 100px; border: 2px solid var(--bg);
  overflow: hidden; background: var(--bg4); margin-left: -8px; flex: 0 0 auto;
  display: grid; place-items: center; color: var(--text3);
}
.avatars .av:first-child { margin-left: 0 }
.avatars .av img { width: 100%; height: 100%; object-fit: cover }
.avatars .av svg { width: 13px; height: 13px }
.avatars-lg .av { width: 40px; height: 40px }
.avatars-lg .av svg { width: 18px; height: 18px }

.card-tags { display: flex; flex-wrap: wrap; gap: .3rem }
.card-title a {
  background-image: linear-gradient(currentColor, currentColor);
  background-size: 0% 1px; background-repeat: no-repeat; background-position: 0 100%;
  transition: background-size var(--dur) var(--ease);
}
.card:hover .card-title a { background-size: 100% 1px }

.card-lock {
  position: absolute; top: .6rem; right: .6rem; z-index: 2;
  background: var(--accent3); color: var(--on-accent3);
  width: 28px; height: 28px; border-radius: 100px; display: grid; place-items: center;
}
.card-lock svg { width: 13px; height: 13px }

.card-badge {
  position: absolute; left: .6rem; top: .6rem; z-index: 2;
  background: var(--bg); color: var(--text);
  font-size: .68rem; font-weight: 600; padding: .2rem .55rem; border-radius: var(--r-chip);
}

/* the neutral block a missing image falls back to — never a placeholder service */
.ph { display: block; width: 100%; height: 100%; background: var(--bg3) }

/* ------------------------------------------------------------ 8. card grids */
.grid-cards { display: grid; gap: calc(var(--grid-gap) * 1.6) var(--grid-gap); grid-template-columns: 1fr }
@media (min-width: 700px)  { .grid-cards { grid-template-columns: repeat(2, minmax(0, 1fr)) } }
@media (min-width: 1024px) { .grid-cards { grid-template-columns: repeat(var(--cols, 3), minmax(0, 1fr)) } }
@media (min-width: 1440px) { .grid-cards { grid-template-columns: repeat(var(--cols-xl, var(--cols, 3)), minmax(0, 1fr)) } }

/* list layout — the media sits inside its own <a>, so the ANCHOR is the flex
   item that has to carry the width, not the .card-media inside it */
.list-cards { display: flex; flex-direction: column; gap: 1.6rem }
.list-cards .card { flex-direction: row; gap: 1.2rem; align-items: flex-start; padding-bottom: 1.6rem; border-bottom: 1px solid var(--border) }
.list-cards .card:last-child { border-bottom: 0; padding-bottom: 0 }
.list-cards .card > .card-link { flex: 0 0 clamp(110px, 26vw, 300px) }
.list-cards .card-media { aspect-ratio: 1 / 1 }
.list-cards .excerpt { -webkit-line-clamp: 2 }

/* the archive feed takes its shape from the tweak file; grid is the shipped
   default, expressed as the plain rule so it holds with JavaScript disabled */
.archive-feed { display: grid; gap: calc(var(--grid-gap) * 1.6) var(--grid-gap); grid-template-columns: 1fr }
@media (min-width: 700px)  { .archive-feed { grid-template-columns: repeat(2, minmax(0, 1fr)) } }
@media (min-width: 1024px) { .archive-feed { grid-template-columns: repeat(var(--cols, 3), minmax(0, 1fr)) } }
[data-layout="list"] .archive-feed { display: flex; flex-direction: column; gap: 1.6rem }
[data-layout="list"] .archive-feed .card { flex-direction: row; gap: 1.2rem; align-items: flex-start; padding-bottom: 1.6rem; border-bottom: 1px solid var(--border) }
[data-layout="list"] .archive-feed .card > .card-link { flex: 0 0 clamp(110px, 26vw, 300px) }
[data-layout="list"] .archive-feed .card-media { aspect-ratio: 1 / 1 }
[data-layout="list"] .archive-feed .excerpt { -webkit-line-clamp: 2 }

/* magazine layout — first card runs wide, the rest fall into the grid */
.mag-cards,
[data-layout="magazine"] .archive-feed { display: grid; gap: calc(var(--grid-gap) * 1.6) var(--grid-gap); grid-template-columns: 1fr }
@media (min-width: 900px) {
  .mag-cards,
  [data-layout="magazine"] .archive-feed { grid-template-columns: repeat(6, minmax(0, 1fr)) }
  .mag-cards > *,
  [data-layout="magazine"] .archive-feed > * { grid-column: span 2 }
  .mag-cards > *:first-child,
  [data-layout="magazine"] .archive-feed > *:first-child {
    grid-column: span 6;
    display: grid; grid-template-columns: 1.15fr 1fr; gap: .6rem 1.8rem; align-content: center;
  }
  .mag-cards > *:first-child > .card-link,
  [data-layout="magazine"] .archive-feed > *:first-child > .card-link { grid-column: 1; grid-row: 1 / -1; align-self: center }
  .mag-cards > *:first-child > .card-body,
  [data-layout="magazine"] .archive-feed > *:first-child > .card-body { grid-column: 2 }
  .mag-cards > *:first-child .card-media,
  [data-layout="magazine"] .archive-feed > *:first-child .card-media { aspect-ratio: 3 / 2 }
  .mag-cards > *:first-child .card-title,
  [data-layout="magazine"] .archive-feed > *:first-child .card-title { font-size: clamp(1.6rem, 2.6vw, 2.4rem); line-height: 1.08 }
  .mag-cards > *:first-child .excerpt,
  [data-layout="magazine"] .archive-feed > *:first-child .excerpt { font-size: 1rem }
}

/* horizontal rail */
.rail {
  display: flex; gap: var(--grid-gap);
  overflow-x: auto; scroll-snap-type: x mandatory;
  scrollbar-width: none; -ms-overflow-style: none; padding-bottom: .25rem;
}
.rail::-webkit-scrollbar { display: none }
.rail > * { scroll-snap-align: start; flex: 0 0 auto; width: clamp(230px, 24vw, 340px) }
.rail-sm > * { width: clamp(150px, 15vw, 210px) }
/* Centring a rail: auto-margin pseudo-elements absorb slack and collapse to
   zero on overflow. justify-content:center would clip the leading items. */
.rail-center::before, .rail-center::after { content: ''; margin: auto; flex: 0 0 0 }

/* ----------------------------------------------------------- 9. site header */
.site-header { position: relative; z-index: 9050; background: var(--page-bg); border-bottom: 1px solid var(--border) }
.site-header .hdr-inner {
  display: grid; grid-template-columns: 1fr auto 1fr;
  align-items: center; gap: 1rem; min-height: 72px;
}
.brand {
  font-family: var(--font-display); font-weight: 700; font-size: 1.32rem;
  letter-spacing: -.05em; font-style: italic; text-transform: uppercase; white-space: nowrap;
}
.brand img { max-height: 34px; width: auto }
.hdr-left  { display: flex; align-items: center; gap: .5rem; justify-self: start }
.hdr-mid   { justify-self: center }
.hdr-right { display: flex; align-items: center; gap: .5rem; justify-self: end }

/* Measured, not assumed: with a six-item nav the last link collides with the
   action cluster at 900 / 960 / 1000px and is only clear at 1100. */
.nav-main { display: none; position: relative; align-items: center; gap: .2rem }
@media (min-width: 1100px) { .nav-main { display: flex } .burger { display: none } }
.nav-main a {
  position: relative; z-index: 1; padding: .45rem .8rem;
  font-size: .875rem; color: var(--text2);
  border-radius: var(--r-chip); white-space: nowrap;
  transition: color var(--dur) var(--ease);
}
.nav-main a:hover { color: var(--text) }
.nav-main a[aria-current="page"] { color: var(--text); font-weight: 500 }
/* the underline is the reference's own active treatment; the pill is the option */
body[data-nav="none"] .nav-main a[aria-current="page"]::after {
  content: ''; position: absolute; left: .8rem; right: .8rem; bottom: .2rem; height: 1.5px; background: currentColor;
}
.nav-pill {
  position: absolute; z-index: 0; top: 0; left: 0; height: 100%;
  border-radius: var(--r-chip); background: var(--bg3); opacity: 0;
  transition: transform .45s var(--ease), width .45s var(--ease), opacity .3s var(--ease);
  pointer-events: none;
}
body[data-nav="none"] .nav-pill { display: none }

.burger { display: inline-flex }
.icon-btn {
  width: 44px; height: 44px; display: inline-grid; place-items: center;
  border-radius: var(--r-chip); border: 1px solid transparent; background: transparent;
  color: var(--text); cursor: pointer; transition: background var(--dur) var(--ease);
}
.icon-btn:hover { background: var(--bg3) }
.icon-btn svg { width: 19px; height: 19px }

.search-trigger {
  display: none; align-items: center; gap: .45rem;
  min-height: 40px; padding: 0 .95rem;
  border-radius: var(--r-chip); border: 1px solid var(--border);
  background: var(--bg2); color: var(--text3); font-size: .82rem; cursor: pointer;
}
@media (min-width: 700px) { .search-trigger { display: inline-flex } }
.search-trigger:hover { color: var(--text); border-color: var(--border-2) }
.search-trigger svg { width: 14px; height: 14px }

/* header variants */
body[data-header="minimal"] .site-header { border-bottom-color: transparent }
body[data-header="minimal"] .site-header .hdr-inner { min-height: 62px }
body[data-header="sticky"] .site-header { position: sticky; top: 0 }
body[data-header="glass"] .site-header {
  position: sticky; top: 0; background: transparent; border-bottom-color: transparent;
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease), backdrop-filter var(--dur) var(--ease);
}
body[data-header="glass"] .site-header.is-tinted {
  background: color-mix(in srgb, var(--page-bg) 82%, transparent);
  backdrop-filter: blur(18px) saturate(1.4);
  border-bottom-color: var(--border);
}

/* adaptive capsule: bar for the first viewport, then a floating pill */
.capsule-bar {
  position: fixed; top: 1rem; left: 50%;
  transform: translate(-50%, -80px); z-index: 9100;
  display: none; align-items: center; gap: .35rem;
  padding: .4rem .5rem .4rem 1.1rem;
  border-radius: var(--r-chip); border: 1px solid var(--border);
  background: color-mix(in srgb, var(--page-bg) 84%, transparent);
  backdrop-filter: blur(20px) saturate(1.5);
  box-shadow: var(--shadow-2); opacity: 0;
  transition: transform .5s var(--ease), opacity .4s var(--ease);
  max-width: calc(100vw - 2rem);
}
body[data-header="capsule"] .capsule-bar { display: flex }
body[data-header="capsule"] .capsule-bar.is-docked { transform: translate(-50%, 0); opacity: 1 }
.capsule-bar .brand { font-size: 1.02rem }
.capsule-bar .cap-links { display: none; align-items: center; gap: .1rem }
@media (min-width: 700px) { .capsule-bar .cap-links { display: flex } }
.capsule-bar .cap-links a { padding: .35rem .65rem; font-size: .82rem; color: var(--text2); border-radius: var(--r-chip) }
.capsule-bar .cap-links a:hover { background: var(--bg3); color: var(--text) }

/* A parked off-canvas drawer widens the page: position:fixed + translateX(100%)
   is NOT clipped by body{overflow-x:hidden}. The wrapper does the clipping. */
.drawer-wrap { position: fixed; inset: 0; overflow: hidden; z-index: 9300; pointer-events: none; visibility: hidden }
.drawer-wrap.is-open { pointer-events: auto; visibility: visible }
.drawer-scrim { position: absolute; inset: 0; background: rgba(10, 10, 12, .5); backdrop-filter: blur(3px); opacity: 0; transition: opacity var(--dur) var(--ease) }
.drawer-wrap.is-open .drawer-scrim { opacity: 1 }
.drawer {
  position: absolute; top: 0; right: 0; bottom: 0; z-index: 9400;
  width: min(370px, 88vw);
  background: var(--bg); border-left: 1px solid var(--border);
  transform: translateX(100%); transition: transform .48s var(--ease);
  display: flex; flex-direction: column; overflow-y: auto;
}
.drawer-wrap.is-open .drawer { transform: translateX(0) }
.drawer nav a {
  display: block; padding: .85rem 0; font-size: 1.35rem;
  font-family: var(--font-display); letter-spacing: -.02em; border-bottom: 1px solid var(--border);
}
.drawer nav a:hover { color: var(--accent2) }

/* ----------------------------------------------------- 10. search overlay */
.search-overlay { position: fixed; inset: 0; z-index: 9500; display: none }
.search-overlay.is-open { display: block }
.search-overlay .so-scrim { position: absolute; inset: 0; background: rgba(10, 10, 12, .55); backdrop-filter: blur(6px) }
/* every overlay panel gets its OWN opaque surface — a blur is not a background */
.search-overlay .so-panel {
  position: relative; background: var(--bg);
  border: 1px solid var(--border); box-shadow: var(--shadow-3); overflow: hidden;
}
body[data-search="fullscreen"] .so-panel { position: absolute; inset: 0; border: 0; border-radius: 0; display: flex; flex-direction: column }
body[data-search="modal"] .so-panel { width: min(640px, calc(100vw - 2rem)); margin: 12vh auto 0; border-radius: var(--r-card) }
body[data-search="dropdown"] .so-panel { width: min(560px, calc(100vw - 2rem)); margin: 5rem auto 0; border-radius: var(--r-card) }
.so-results { background: var(--bg); overflow-y: auto }
.so-row { display: flex; gap: .9rem; align-items: center; padding: .75rem 0; border-bottom: 1px solid var(--border) }
.so-row:last-child { border-bottom: 0 }
.so-row .thumb { width: 62px; height: 47px; border-radius: var(--r-sm); overflow: hidden; flex: 0 0 auto; background: var(--bg3) }
.so-row .thumb img { width: 100%; height: 100%; object-fit: cover }
.so-row[hidden] { display: none }

/* ---------------------------------------------------------------- 11. footer */
/* The footer gradient paints EVERY footer variant — gating it behind one style
   left two Ghost settings doing nothing at the default. --footer-text is
   computed from the two stops, so any pair stays readable. */
.site-footer {
  margin-top: 0;
  background: linear-gradient(160deg, var(--footer-bg-start), var(--footer-bg-end));
  color: var(--footer-text);
  border-top: 1px solid var(--border);
}
.site-footer .excerpt, .site-footer .foot-bottom, .site-footer .meta { color: inherit; opacity: .68 }
.site-footer .foot-col a { color: inherit; opacity: .68 }
.site-footer .foot-col a:hover { opacity: 1 }
.site-footer .foot-col h4, .site-footer .brand { color: inherit }
.site-footer .foot-bottom { border-top-color: color-mix(in srgb, var(--footer-text) 18%, transparent) }
.site-footer .field {
  background: color-mix(in srgb, var(--footer-text) 8%, transparent);
  border-color: color-mix(in srgb, var(--footer-text) 22%, transparent);
  color: inherit;
}
.site-footer .field::placeholder { color: inherit; opacity: .5 }
/* The footer and CTA bands used to compute their own button colour from the
   band's own luminance, which meant those two buttons ignored the site accent
   entirely — they were the "fixed colours" in the bug report. Both now follow
   @site.accent_color like every other filled control. --on-accent is derived
   from the accent's luminance in site-head, so a pale accent gets ink text
   rather than unreadable white. */
.site-footer .btn-ink { background: var(--accent); color: var(--on-accent) }
.site-footer .chip { background: color-mix(in srgb, var(--footer-text) 12%, transparent); color: inherit }
.foot-cols { display: grid; gap: 2.2rem; grid-template-columns: 1fr }
@media (min-width: 760px)  { .foot-cols { grid-template-columns: 1.4fr 1fr 1fr } }
@media (min-width: 1100px) { .foot-cols { grid-template-columns: 1.6fr repeat(3, minmax(0, 1fr)) } }
.foot-col h4 { font-size: .78rem; font-weight: 700; letter-spacing: .02em; margin-bottom: .8rem }
.foot-col a { display: block; padding: .28rem 0; font-size: .85rem }
.foot-col ul { list-style: none; padding: 0 }
.foot-bottom {
  display: flex; flex-wrap: wrap; gap: 1rem; align-items: center; justify-content: space-between;
  border-top: 1px solid var(--border); padding-block: 1.4rem; font-size: .8rem;
}
.brand-svg { display: inline-flex; align-items: center; gap: .45rem }
.brand-svg svg { width: 15px; height: 15px; flex: 0 0 auto }
.foot-links { display: flex; gap: 1.2rem; flex-wrap: wrap; font-size: .85rem; list-style: none; padding: 0 }

/* ------------------------------------------------------ 12. ticker + bubbles */
.ticker { border-bottom: 1px solid var(--border); background: var(--bg2); overflow: hidden; position: relative }
.ticker-track { display: flex; gap: 2.4rem; width: max-content; animation: tickerScroll var(--ticker-dur, 34s) linear infinite }
.ticker:hover .ticker-track { animation-play-state: paused }
.ticker-item { display: inline-flex; align-items: center; gap: .55rem; padding-block: .6rem; font-size: .8rem; color: var(--text2); white-space: nowrap }
.ticker-item .dot { width: 5px; height: 5px; border-radius: 100px; background: var(--accent); flex: 0 0 auto }
@keyframes tickerScroll { from { transform: translateX(0) } to { transform: translateX(-50%) } }

/* the tag capsules — a rail of TAGS, each borrowing an image from its posts.
   The shape is the design's own pill token, not a new value: at 88px wide a
   100px radius clamps to half the width, which is what gives the fully rounded
   ends. Nothing here introduces a radius, colour or spacing step that is not
   already in the token block.

   The earlier build drew these as 68px circles inside a conic-gradient accent
   ring — an Instagram story ring. That ring was the only place on the landing
   page where the accent appeared as decoration rather than as an interactive
   affordance, which is the one thing COLOR STRATEGY rules out. */
.caps { display: flex; gap: 1.1rem; overflow-x: auto; scrollbar-width: none; padding-block: 1.25rem }
.caps::-webkit-scrollbar { display: none }

.cap {
  flex: 0 0 auto; position: relative; display: block;
  width: 88px; height: 176px;
  /* the tick marks sit outside the capsule, so the link box has to make room
     for them or they collide with the band above and below */
  margin-block: 14px;
}

/* the ticks. Two hairlines per capsule, centred, one above and one below.
   Drawn on the link rather than the image wrapper so the capsule's own
   overflow:hidden cannot clip them. */
.cap::before,
.cap::after {
  content: ""; position: absolute; left: 50%; translate: -50% 0;
  width: 1px; height: 8px; background: var(--border-2);
}
.cap::before { top: -14px }
.cap::after  { bottom: -14px }

.cap-img {
  display: block; box-sizing: border-box; width: 100%; height: 100%;
  border-radius: var(--r-chip); overflow: hidden;
  background: var(--bg3);
  /* a tag whose posts carry no feature_image keeps a tinted capsule rather than
     collapsing — the reference rail mixes photographic and flat-colour cells,
     so an image-less capsule reads as designed rather than as a failed load */
}
/* HOVER STYLE is 'lift — the image scales inside its clipped radius while the
   card stays put'. Same treatment as .post-card, so the rail does not invent a
   second hover language. */
.cap img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform var(--dur-slow, .5s) var(--ease);
}
.cap:hover img, .cap:focus-visible img { transform: scale(1.06) }
.cap:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: var(--r-chip) }

@media (prefers-reduced-motion: reduce) {
  .cap img { transition: none }
  .cap:hover img, .cap:focus-visible img { transform: none }
}


/* ---- varied card image ratios -------------------------------------------
   The reference feeds are not a uniform grid: every card carries a different
   image shape, so a row staggers and the page reads as composed rather than
   stamped out. Cards are top-aligned, so a taller image pushes its own text
   down instead of stretching its neighbours.

   The mix is re-drawn on every page load, but only ONE random number is drawn —
   in the blocking head script, written to <html data-cardmix>. Everything after
   that is plain CSS on :nth-child. That is what keeps it free of layout shift:
   assigning ratios from theme.js would re-shape every card after first paint.

   :not([data-ratio]) leaves explicitly-set ratios alone, so the hero lead, the
   bento tiles and the carousel keep the shapes their templates ask for, and the
   list/minimal archive layouts keep their own 1:1 override. */
.archive-feed { align-items: start }
.grid-cards { align-items: start }
.related-grid { align-items: start }

[data-cardmix="0"] .archive-feed > *:nth-child(4n+1) .card-media:not([data-ratio]),
[data-cardmix="0"] .grid-cards > *:nth-child(4n+1) .card-media:not([data-ratio]),
[data-cardmix="0"] .related-grid > *:nth-child(4n+1) .card-media:not([data-ratio]) { aspect-ratio: 4 / 3 }
[data-cardmix="0"] .archive-feed > *:nth-child(4n+2) .card-media:not([data-ratio]),
[data-cardmix="0"] .grid-cards > *:nth-child(4n+2) .card-media:not([data-ratio]),
[data-cardmix="0"] .related-grid > *:nth-child(4n+2) .card-media:not([data-ratio]) { aspect-ratio: 3 / 4 }
[data-cardmix="0"] .archive-feed > *:nth-child(4n+3) .card-media:not([data-ratio]),
[data-cardmix="0"] .grid-cards > *:nth-child(4n+3) .card-media:not([data-ratio]),
[data-cardmix="0"] .related-grid > *:nth-child(4n+3) .card-media:not([data-ratio]) { aspect-ratio: 1 / 1 }
[data-cardmix="0"] .archive-feed > *:nth-child(4n) .card-media:not([data-ratio]),
[data-cardmix="0"] .grid-cards > *:nth-child(4n) .card-media:not([data-ratio]),
[data-cardmix="0"] .related-grid > *:nth-child(4n) .card-media:not([data-ratio]) { aspect-ratio: 16 / 9 }

[data-cardmix="1"] .archive-feed > *:nth-child(4n+1) .card-media:not([data-ratio]),
[data-cardmix="1"] .grid-cards > *:nth-child(4n+1) .card-media:not([data-ratio]),
[data-cardmix="1"] .related-grid > *:nth-child(4n+1) .card-media:not([data-ratio]) { aspect-ratio: 3 / 4 }
[data-cardmix="1"] .archive-feed > *:nth-child(4n+2) .card-media:not([data-ratio]),
[data-cardmix="1"] .grid-cards > *:nth-child(4n+2) .card-media:not([data-ratio]),
[data-cardmix="1"] .related-grid > *:nth-child(4n+2) .card-media:not([data-ratio]) { aspect-ratio: 1 / 1 }
[data-cardmix="1"] .archive-feed > *:nth-child(4n+3) .card-media:not([data-ratio]),
[data-cardmix="1"] .grid-cards > *:nth-child(4n+3) .card-media:not([data-ratio]),
[data-cardmix="1"] .related-grid > *:nth-child(4n+3) .card-media:not([data-ratio]) { aspect-ratio: 16 / 9 }
[data-cardmix="1"] .archive-feed > *:nth-child(4n) .card-media:not([data-ratio]),
[data-cardmix="1"] .grid-cards > *:nth-child(4n) .card-media:not([data-ratio]),
[data-cardmix="1"] .related-grid > *:nth-child(4n) .card-media:not([data-ratio]) { aspect-ratio: 4 / 3 }

[data-cardmix="2"] .archive-feed > *:nth-child(4n+1) .card-media:not([data-ratio]),
[data-cardmix="2"] .grid-cards > *:nth-child(4n+1) .card-media:not([data-ratio]),
[data-cardmix="2"] .related-grid > *:nth-child(4n+1) .card-media:not([data-ratio]) { aspect-ratio: 1 / 1 }
[data-cardmix="2"] .archive-feed > *:nth-child(4n+2) .card-media:not([data-ratio]),
[data-cardmix="2"] .grid-cards > *:nth-child(4n+2) .card-media:not([data-ratio]),
[data-cardmix="2"] .related-grid > *:nth-child(4n+2) .card-media:not([data-ratio]) { aspect-ratio: 16 / 9 }
[data-cardmix="2"] .archive-feed > *:nth-child(4n+3) .card-media:not([data-ratio]),
[data-cardmix="2"] .grid-cards > *:nth-child(4n+3) .card-media:not([data-ratio]),
[data-cardmix="2"] .related-grid > *:nth-child(4n+3) .card-media:not([data-ratio]) { aspect-ratio: 4 / 3 }
[data-cardmix="2"] .archive-feed > *:nth-child(4n) .card-media:not([data-ratio]),
[data-cardmix="2"] .grid-cards > *:nth-child(4n) .card-media:not([data-ratio]),
[data-cardmix="2"] .related-grid > *:nth-child(4n) .card-media:not([data-ratio]) { aspect-ratio: 3 / 4 }

[data-cardmix="3"] .archive-feed > *:nth-child(4n+1) .card-media:not([data-ratio]),
[data-cardmix="3"] .grid-cards > *:nth-child(4n+1) .card-media:not([data-ratio]),
[data-cardmix="3"] .related-grid > *:nth-child(4n+1) .card-media:not([data-ratio]) { aspect-ratio: 16 / 9 }
[data-cardmix="3"] .archive-feed > *:nth-child(4n+2) .card-media:not([data-ratio]),
[data-cardmix="3"] .grid-cards > *:nth-child(4n+2) .card-media:not([data-ratio]),
[data-cardmix="3"] .related-grid > *:nth-child(4n+2) .card-media:not([data-ratio]) { aspect-ratio: 4 / 3 }
[data-cardmix="3"] .archive-feed > *:nth-child(4n+3) .card-media:not([data-ratio]),
[data-cardmix="3"] .grid-cards > *:nth-child(4n+3) .card-media:not([data-ratio]),
[data-cardmix="3"] .related-grid > *:nth-child(4n+3) .card-media:not([data-ratio]) { aspect-ratio: 3 / 4 }
[data-cardmix="3"] .archive-feed > *:nth-child(4n) .card-media:not([data-ratio]),
[data-cardmix="3"] .grid-cards > *:nth-child(4n) .card-media:not([data-ratio]),
[data-cardmix="3"] .related-grid > *:nth-child(4n) .card-media:not([data-ratio]) { aspect-ratio: 1 / 1 }

/* One column of alternating tall and short images just reads as inconsistent,
   so below the two-column breakpoint every card returns to the primary 4:3. */
@media (max-width: 699px) {
  .archive-feed > * .card-media:not([data-ratio]),
  .grid-cards   > * .card-media:not([data-ratio]),
  .related-grid > * .card-media:not([data-ratio]) { aspect-ratio: 4 / 3 }
}


/* ---------------------------------------------------- style guide page */
/* Shares the CTA band's two stops so the masthead re-tints with the theme, and
   --cta-text is already derived from those stops, so the type stays readable
   whichever pair the owner picks. No new colour is introduced here. */
.sg-hero {
  background: linear-gradient(120deg, var(--cta-start), var(--cta-end));
  color: var(--cta-text);
  padding-block: clamp(3rem, 8vw, 6rem);
  margin-bottom: clamp(2rem, 5vw, 3.5rem);
}
/* The masthead is centred. It is a title page for the document below it rather
   than an article opening, so it does not follow the left-aligned editorial
   rhythm the rest of the site uses.

   Centring is auto margins on the measure-capped children, not text-align
   alone: the dek keeps its 54ch measure and sits in the middle, instead of
   stretching to the full container and merely centring its last line. */
.sg-hero .pad { text-align: center }
.sg-kicker {
  font-size: .72rem; letter-spacing: .14em; text-transform: uppercase;
  opacity: .7; margin-bottom: .9rem;
}
.sg-title { max-width: 18ch; margin-inline: auto; color: inherit }
.sg-dek { max-width: 54ch; margin: 1.1rem auto 0; font-size: 1.05rem; line-height: 1.6; opacity: .82 }
.sg-meta {
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: .6rem 1.4rem; margin-top: 1.6rem;
  font-size: .78rem; opacity: .66;
}

/* The post page's reading layout, reproduced. It deliberately does NOT reuse
   .post-layout / .toc-rail: those are driven by the Table of Contents setting,
   and a reader who switched the TOC off on posts should still get one here — a
   style guide with no contents list is just a very long scroll. */
.sg-layout { display: grid; gap: 2.5rem; grid-template-columns: 1fr; align-items: start }
@media (min-width: 1150px) { .sg-layout { grid-template-columns: 230px minmax(0, 1fr) } }

.sg-toc { position: sticky; top: 100px; align-self: start; z-index: 40 }
.sg-toc:not(:has(a)) { display: none }
@media (max-width: 1149px) {
  .sg-toc { position: static; border: 1px solid var(--border); border-radius: var(--r-card); padding: 1.1rem 1.3rem }
}
.sg-toc-label {
  font-size: .68rem; letter-spacing: .12em; text-transform: uppercase;
  color: var(--text3); margin-bottom: .6rem;
}
/* same active-item treatment as the post rail, so the two pages read as one site */
.sg-toc a {
  display: block; padding: .3rem 0 .3rem .7rem; border-left: 2px solid var(--border);
  font-size: .82rem; color: var(--text3);
  transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.sg-toc a:hover, .sg-toc a.is-active { color: var(--text); border-left-color: var(--accent) }

.sg-body { min-width: 0 }
.sg-tokens { margin-top: clamp(3rem, 7vw, 5rem) }
.sg-swatches { display: grid; gap: var(--grid-gap); grid-template-columns: repeat(auto-fill, minmax(132px, 1fr)); margin-top: 1.2rem }
.sg-swatch { border: 1px solid var(--border); border-radius: var(--r-card); overflow: hidden; background: var(--bg2) }
.sg-swatch-chip { display: block; height: 56px }
.sg-swatch-body { padding: .55rem .7rem }
.sg-swatch-name { display: block; font-size: .72rem; font-weight: 500; color: var(--text) }
.sg-swatch-val { display: block; font-family: var(--font-mono); font-size: .68rem; color: var(--text3) }

/* ---------------------------------------------------- authors index */
.author-index { display: grid; gap: calc(var(--grid-gap) * 1.6) var(--grid-gap); grid-template-columns: 1fr; align-items: start }
@media (min-width: 700px)  { .author-index { grid-template-columns: repeat(2, minmax(0, 1fr)) } }
@media (min-width: 1100px) { .author-index { grid-template-columns: repeat(3, minmax(0, 1fr)) } }

.author-card { display: flex; gap: 1rem; align-items: flex-start; min-width: 0 }
.author-card-link { display: block; flex: 0 0 auto }
.author-card-avatar {
  display: grid; place-items: center; width: 72px; height: 72px;
  border-radius: var(--r-chip); overflow: hidden;
  background: var(--bg3); border: 1px solid var(--border);
}
.author-card-avatar img { width: 100%; height: 100%; object-fit: cover }
.author-card-avatar svg { width: 24px; height: 24px; color: var(--text3) }
.author-card-body { min-width: 0; display: flex; flex-direction: column; gap: .4rem; align-items: flex-start }
/* the body is a flex column, so without this the Website chip stretches to
   the full card width instead of hugging its own label */
.author-card-body .chip { align-self: flex-start }
.author-card-body h2 { margin: 0 }
.author-card-count { font-size: .78rem }

/* ---------------------------------------------------- topics index */
.topic-cloud { display: flex; flex-wrap: wrap; gap: .55rem }
.topic-chip {
  display: inline-flex; align-items: center; gap: .5rem;
  padding: .45rem .5rem .45rem .9rem;
  border: 1px solid var(--border); border-radius: var(--r-chip);
  font-size: .85rem; color: var(--text2); background: var(--bg);
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.topic-chip:hover { background: var(--accent2); color: var(--on-accent2); border-color: var(--accent2) }
.topic-chip-n {
  display: inline-grid; place-items: center; min-width: 1.5rem; height: 1.5rem;
  padding-inline: .35rem; border-radius: var(--r-chip);
  background: color-mix(in srgb, currentColor 12%, transparent);
  font-size: .7rem; font-variant-numeric: tabular-nums;
}

/* the tag cloud — sizes alternate by position so the block reads as a cloud
   rather than a list, without needing a per-tag weight from anywhere */
.tag-cloud { display: flex; flex-wrap: wrap; gap: .7rem 1.4rem; align-items: baseline }
.tag-cloud a { font-size: 1.5rem; font-weight: 400; color: var(--text2); transition: color var(--dur) var(--ease) }
.tag-cloud a:hover { color: var(--accent) }
.tag-cloud a:nth-child(4n+1) { font-size: 2.6rem; font-weight: 700; color: var(--text) }
.tag-cloud a:nth-child(4n+3) { font-size: 2.1rem; font-weight: 700 }
.tag-cloud a:nth-child(3n+2) { color: var(--text3) }

/* ------------------------------------------------------------ 13. hero blocks */
.hero { position: relative }
.hero-text-lockup { padding-block: clamp(3rem, 8vw, 7rem) }

.hero-split { display: grid; gap: 2rem; align-items: center; grid-template-columns: 1fr }
@media (min-width: 900px) { .hero-split { grid-template-columns: 55fr 45fr; gap: 3rem } }

.bento { display: grid; gap: var(--grid-gap); grid-template-columns: 1fr }
@media (min-width: 760px) {
  .bento { grid-template-columns: repeat(4, minmax(0, 1fr)); grid-auto-rows: minmax(150px, auto) }
  .bento > :nth-child(1) { grid-column: span 2; grid-row: span 2 }
  .bento > :nth-child(2) { grid-column: span 2 }
  .bento > :nth-child(3) { grid-column: span 1 }
  .bento > :nth-child(4) { grid-column: span 1 }
  .bento > :nth-child(5) { grid-column: span 4 }
}
@media (min-width: 1100px) {
  .bento { grid-template-columns: repeat(6, minmax(0, 1fr)) }
  .bento > :nth-child(1) { grid-column: span 3; grid-row: span 2 }
  .bento > :nth-child(2) { grid-column: span 3 }
  .bento > :nth-child(3) { grid-column: span 1 }
  .bento > :nth-child(4) { grid-column: span 1 }
  .bento > :nth-child(5) { grid-column: span 1; grid-row: span 1 }
}
.bento .card-media { aspect-ratio: auto; height: 100%; min-height: 150px }
.bento .card { height: 100%; position: relative }
.bento-cap { position: absolute; inset: auto 0 0 0; padding: 1rem; z-index: 2; color: var(--on-media); background: var(--scrim-1); border-radius: 0 0 var(--r-card) var(--r-card) }

.hero-full { position: relative; min-height: 100dvh; display: grid; align-items: end; overflow: hidden }
.hero-full .kb { position: absolute; inset: 0; z-index: 0 }
.hero-full .kb img, .hero-full .kb .ph { width: 100%; height: 100%; object-fit: cover; animation: kenburns 22s ease-in-out infinite alternate }
@keyframes kenburns { from { transform: scale(1) translate(0, 0) } to { transform: scale(1.12) translate(-1.5%, -1.5%) } }
.hero-full::after { content: ''; position: absolute; inset: 0; background: var(--scrim-2); z-index: 1 }
.hero-full > .hero-full-body { position: relative; z-index: 2; color: var(--on-media); padding-block: clamp(3rem, 8vw, 6rem) }

.hero-carousel .rail > * { width: min(88vw, 1100px) }
.hero-carousel .card-media { aspect-ratio: 21 / 9 }
@media (max-width: 700px) { .hero-carousel .card-media { aspect-ratio: 4 / 3 } }

.hero-mag { display: grid; gap: 2rem; grid-template-columns: 1fr }
@media (min-width: 950px) { .hero-mag { grid-template-columns: 60fr 40fr; gap: 2.4rem } }
.hero-mag .side { display: flex; flex-direction: column; gap: 1.1rem }
.hero-mag .side .card { flex-direction: row; gap: .9rem; padding-bottom: 1.1rem; border-bottom: 1px solid var(--border) }
.hero-mag .side .card:last-child { border-bottom: 0; padding-bottom: 0 }
.hero-mag .side .card > .card-link { flex: 0 0 96px }
.hero-mag .side .card-media { aspect-ratio: 1 / 1 }
.hero-mag .side .excerpt { -webkit-line-clamp: 2 }

.hero-float { position: relative; padding-block: clamp(3rem, 8vw, 6rem) }
.hero-float .floats { display: grid; gap: 1rem; grid-template-columns: repeat(3, minmax(0, 1fr)); margin-top: 2.6rem }
.hero-float .floats > * { transition: transform .6s var(--ease) }
@media (min-width: 900px) {
  .hero-float .floats > :nth-child(1) { transform: rotate(-4deg) translateY(12px) }
  .hero-float .floats > :nth-child(2) { transform: rotate(1.5deg) translateY(-14px) }
  .hero-float .floats > :nth-child(3) { transform: rotate(5deg) translateY(6px) }
  .hero-float .floats > *:hover { transform: rotate(0) translateY(-4px) }
}
@media (max-width: 899px) { .hero-float .floats { grid-template-columns: 1fr } }

/* -------------------------------------------------------------- 14. pagination */
.pager { display: flex; align-items: center; justify-content: center; gap: .4rem; flex-wrap: wrap; padding-top: 2.4rem }
.pager .pg {
  min-width: 44px; min-height: 44px; padding: 0 .85rem;
  display: inline-flex; align-items: center; justify-content: center; gap: .4rem;
  border-radius: var(--r-chip); border: 1px solid var(--border-2);
  font-size: .85rem; color: var(--text2); cursor: pointer; background: transparent;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.pager .pg:hover { border-color: var(--text); color: var(--text) }
.pager .pg[aria-current="page"] { background: var(--accent); color: var(--on-accent); border-color: var(--accent) }
.pager .pg-gap { color: var(--text3); padding: 0 .3rem }
.pager svg { width: 14px; height: 14px }
.pager-top { padding-top: 0; padding-bottom: 1.6rem }

/* Shipped default is bottom-only, expressed as a plain rule so it holds with
   JavaScript disabled. The attribute is written by the tweak file and only ever
   overrides. */
.pg-top { display: none }
[data-pgpos="top"]  .pg-top    { display: block }
[data-pgpos="top"]  .pg-bottom { display: none }
[data-pgpos="both"] .pg-top    { display: block }

/* ------------------------------------------------------------- 15. ad slots */
/* built into the layout, shipped hidden, cleared site-wide from one key */
.ad-slot { display: none }
body[data-ads="show"] .ad-slot { display: block }
.ad-box {
  display: grid; place-items: center;
  border: 1px dashed var(--border-2); border-radius: var(--r-card);
  background: var(--bg2); color: var(--text3);
  font-size: .7rem; letter-spacing: .14em; text-transform: uppercase;
  margin-inline: auto; width: 100%;
}
.ad-lead { max-width: 970px; aspect-ratio: 970 / 90 }
.ad-mpu  { max-width: 300px; aspect-ratio: 300 / 250 }
.ad-half { max-width: 300px; aspect-ratio: 300 / 600 }
.ad-inline { max-width: 728px; aspect-ratio: 728 / 90 }
@media (max-width: 640px) { .ad-lead, .ad-inline { aspect-ratio: 320 / 100 } }

/* ------------------------------------------------- 15b. newsletter CTA band */
.cta-band { background: linear-gradient(120deg, var(--cta-start), var(--cta-end)); color: var(--cta-text) }
.cta-band .field {
  background: color-mix(in srgb, var(--cta-text) 8%, transparent);
  border-color: color-mix(in srgb, var(--cta-text) 24%, transparent);
  color: inherit;
}
.cta-band .field::placeholder { color: inherit; opacity: .55 }
.cta-band .btn-ink { background: var(--accent); color: var(--on-accent) }
.cta-band .excerpt, .cta-band .meta { color: inherit; opacity: .7 }

/* -------------------------------------------------------------- 16. post page */
.post-head-split { display: grid; gap: 2rem; align-items: center; grid-template-columns: 1fr }
@media (min-width: 950px) { .post-head-split { grid-template-columns: 58fr 42fr; gap: 3rem } }

.post-cover { position: relative; border-radius: var(--r-card); overflow: hidden; aspect-ratio: 21 / 9; background: var(--bg3) }
.post-cover > img, .post-cover > .ph { width: 100%; height: 100%; object-fit: cover }
.post-cover .cover-body { position: absolute; inset: auto 0 0 0; z-index: 2; padding: clamp(1.2rem, 4vw, 3rem); color: var(--on-media); background: var(--scrim-2) }
@media (max-width: 700px) { .post-cover { aspect-ratio: 4 / 5 } }

.post-layout { display: grid; gap: 2.5rem; grid-template-columns: 1fr; align-items: start }
/* default is a left rail; the attribute only ever overrides */
@media (min-width: 1150px) {
  .post-layout { grid-template-columns: 230px minmax(0, 1fr) }
  body[data-toc="right"] .post-layout { grid-template-columns: minmax(0, 1fr) 230px }
  body[data-toc="right"] .post-layout .toc-rail { order: 2 }
  body[data-toc="top"] .post-layout,
  body[data-toc="off"] .post-layout { grid-template-columns: minmax(0, 1fr) }
}
body[data-toc="off"] .toc-rail { display: none }
.toc-rail { position: sticky; top: 100px; z-index: 40; align-self: start }
body[data-toc="top"] .toc-rail { position: static; border: 1px solid var(--border); border-radius: var(--r-card); padding: 1.1rem 1.3rem; margin-bottom: 2rem }
.toc-rail a { display: block; padding: .3rem 0 .3rem .7rem; border-left: 2px solid var(--border); font-size: .82rem; color: var(--text3); transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease) }
.toc-rail a:hover, .toc-rail a.is-active { color: var(--text); border-left-color: var(--accent) }
.toc-rail:not(:has(a)) { display: none }
@media (max-width: 1149px) { .toc-rail { position: static; border: 1px solid var(--border); border-radius: var(--r-card); padding: 1.1rem 1.3rem } }

/* reading progress — bar is the shipped default */
.progress-bar { position: fixed; top: 0; left: 0; height: 3px; width: 0; background: var(--accent); z-index: 9999; display: block }
body[data-progress="circle"] .progress-bar, body[data-progress="off"] .progress-bar { display: none }
.progress-ring { position: fixed; right: 1.25rem; bottom: 1.25rem; width: 46px; height: 46px; z-index: 9200; display: none; background: var(--bg); border-radius: 100px; box-shadow: var(--shadow-2) }
body[data-progress="circle"] .progress-ring { display: block }
.progress-ring circle { fill: none; stroke-width: 3 }
.progress-ring .track { stroke: var(--border) }
.progress-ring .fill { stroke: var(--accent); stroke-linecap: round; transform: rotate(-90deg); transform-origin: 50% 50% }

/* share — float is the shipped default. The floating rail needs a real gutter:
   a 40px rail does not fit a 3rem one, and the gutter only grows once the
   viewport exceeds the container. */
/* The floating rail is hidden until theme.js has MEASURED that it clears the
   reading column. A media query cannot decide this: the clearance depends on
   the content_width setting, so with the wide container it only fits at about
   1684px, while with the narrow one it fits from about 1248px. Measured on the
   default container it collided at 1400, 1440, 1536 and 1600 and was only
   clear at 1684 — which is precisely the kind of overlap that
   scrollWidth === clientWidth never catches, because body has overflow-x hidden.

   With JavaScript off the rail simply never appears, and the inline share row
   under the article is a complete treatment on its own. */
.share-float {
  position: fixed; left: 1rem; top: 50%; transform: translateY(-50%); z-index: 60;
  display: none; flex-direction: column; gap: .35rem;
  background: var(--bg); border: 1px solid var(--border); border-radius: var(--r-chip);
  padding: .35rem; box-shadow: var(--shadow-1);
}
.share-float.is-clear { display: flex }
body[data-share="inline"] .share-float.is-clear,
body[data-share="off"] .share-float.is-clear { display: none }
.share-inline { display: flex; gap: .4rem; align-items: center; flex-wrap: wrap }
body[data-share="off"] .share-inline { display: none }
/* The share/social button sits on three different surfaces: the page, the footer
   band and the CTA band. Those two bands redefine the TEXT colour for their own
   background but not --bg, so a hardcoded `background: var(--bg);
   color: var(--text2)` produced a near-white glyph on a near-white circle the
   moment anyone set a dark footer gradient. The icon was still there — just
   invisible, which is how it got reported as "not showing".

   Deriving both from currentColor fixes every surface at once: the circle is a
   translucent wash of the band's own text colour, the glyph is that colour at
   full strength, and no band-specific override is needed. */
.share-btn {
  width: 40px; height: 40px; display: grid; place-items: center;
  border-radius: var(--r-chip); color: inherit;
  border: 1px solid color-mix(in srgb, currentColor 30%, transparent);
  background: color-mix(in srgb, currentColor 8%, transparent);
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
@supports not (color: color-mix(in srgb, red 50%, transparent)) {
  .share-btn { border-color: var(--border); background: transparent; color: var(--text2) }
}
.share-btn:hover { background: var(--accent2); color: var(--on-accent2); border-color: var(--accent2) }
.share-btn svg { width: 15px; height: 15px }

/* author box — bottom is the shipped default */
.author-box { display: flex; gap: 1.1rem; align-items: flex-start; padding: 1.5rem; border: 1px solid var(--border); border-radius: var(--r-card); background: var(--bg2) }
.author-box-top { display: none }
body[data-authorbox="top"] .author-box-top,
body[data-authorbox="both"] .author-box-top { display: flex }
body[data-authorbox="top"] .author-box-bottom,
body[data-authorbox="off"] .author-box-bottom { display: none }
body[data-authorbox="off"] .author-box-top { display: none }

/* related posts.

   Handlebars cannot ask "did the first query return anything?" across two
   sibling blocks, but CSS can: the tag-matched block, when it is present,
   always precedes the fallback in the DOM. So the fallback is only visible
   when no tag-matched block was rendered. Verify this with computed styles,
   not with markup — on a tagged post there are TWO blocks and ONE visible. */
.related-primary ~ .related-fallback { display: none }
[data-related="off"] .related-section { display: none }

.related-grid { display: grid; gap: calc(var(--grid-gap) * 1.6) var(--grid-gap); grid-template-columns: 1fr }
@media (min-width: 700px)  { .related-grid { grid-template-columns: repeat(2, minmax(0, 1fr)) } }
@media (min-width: 1024px) { .related-grid { grid-template-columns: repeat(4, minmax(0, 1fr)) } }

[data-related="list"] .related-grid { display: flex; flex-direction: column; gap: 1.6rem }
[data-related="list"] .related-grid .card { flex-direction: row; gap: 1.2rem; align-items: flex-start; padding-bottom: 1.6rem; border-bottom: 1px solid var(--border) }
[data-related="list"] .related-grid .card > .card-link { flex: 0 0 clamp(110px, 26vw, 300px) }
[data-related="list"] .related-grid .card-media { aspect-ratio: 1 / 1 }

/* minimal — title and nothing else, on one rule per row */
[data-related="minimal"] .related-grid { display: grid; grid-template-columns: 1fr; gap: 0 }
[data-related="minimal"] .related-grid .card { flex-direction: row; align-items: center; justify-content: space-between; gap: 1rem; padding: .85rem 0; border-bottom: 1px solid var(--border) }
[data-related="minimal"] .related-grid .card > .card-link { display: none }
[data-related="minimal"] .related-grid .card-tags { display: none }

/* the excerpt-driven summary block; it renders only when there is a custom
   excerpt to put in it, so it needs no setting of its own */
.ai-summary { border: 1px solid var(--border); border-radius: var(--r-card); background: var(--bg2); padding: 1.3rem 1.5rem }
.ai-summary .ai-kicker { display: inline-flex; align-items: center; gap: .4rem; font-size: .7rem; letter-spacing: .12em; text-transform: uppercase; color: var(--text3); margin-bottom: .6rem }
.ai-summary .ai-kicker svg { width: 13px; height: 13px; color: var(--accent) }

/* the first and last post of a site have only one neighbour, and a section
   containing nothing at all should not paint a band */
.prevnext-section:not(:has(.prevnext a)) { display: none }
.prevnext { display: grid; gap: 1rem; grid-template-columns: 1fr }
@media (min-width: 800px) { .prevnext { grid-template-columns: 1fr 1fr } }
.prevnext a { display: flex; gap: .9rem; align-items: center; padding: 1rem; border: 1px solid var(--border); border-radius: var(--r-card); transition: border-color var(--dur) var(--ease) }
.prevnext a:hover { border-color: var(--text) }
.prevnext .thumb { width: 60px; height: 60px; border-radius: var(--r-sm); overflow: hidden; flex: 0 0 auto; background: var(--bg3) }
.prevnext .thumb img { width: 100%; height: 100%; object-fit: cover }
.prevnext .next-side { flex-direction: row-reverse; text-align: right }

/* post sidebar rail — shipped hidden */
.post-sidebar { display: none }
body[data-sidebar="show"] .post-sidebar { display: block }
@media (min-width: 1400px) { body[data-sidebar="show"] .post-layout { grid-template-columns: 230px minmax(0, 1fr) 300px } }
@media (max-width: 1399px) { .post-sidebar { display: none !important } }

/* ================================================ 17. Ghost editor cards */
/* Ghost emits its OWN markup for every card and none of the theme's utility
   classes are on it. Every rule below targets Ghost's real class names, taken
   from the renderers in kg-default-nodes, and is scoped under TWO classes
   because cards.min.css loads after this file and its own selectors are two
   deep — a single-class scope loses. */

/* A break-out grid rather than the usual margin-inline: calc(50% - 50vw).

   That trick only centres when the element's container is itself centred in the
   viewport — and here it is not: the contents rail pushes the reading column
   off-centre, so a "full width" card landed 135px to the right and pushed the
   whole page sideways. The named columns below hold in any layout, need no
   viewport unit, and cannot be thrown off by a scrollbar. */
.post-content {
  display: grid;
  grid-template-columns:
    [full-start] minmax(0, 1fr)
    [content-start] min(100%, var(--post-w)) [content-end]
    minmax(0, 1fr) [full-end];
  font-size: 1.0625rem;
  line-height: 1.75;
  color: var(--text2);
}
.post-content > * { grid-column: content }
.post-content > * + * { margin-top: 1.5rem }
.post-content h2 { font-size: clamp(1.5rem, 2.4vw, 2rem); letter-spacing: -.025em; line-height: 1.15; color: var(--text); margin-top: 2.8rem }
.post-content h3 { font-size: clamp(1.2rem, 1.7vw, 1.45rem); letter-spacing: -.02em; color: var(--text); margin-top: 2.2rem }
.post-content h4, .post-content h5, .post-content h6 { color: var(--text); margin-top: 1.8rem }
.post-content a { color: var(--text); text-decoration: underline; text-underline-offset: 3px; text-decoration-color: var(--border-2) }
.post-content a:hover { text-decoration-color: var(--accent); color: var(--accent) }
.post-content ul, .post-content ol { padding-left: 1.3rem; display: flex; flex-direction: column; gap: .5rem }
.post-content li::marker { color: var(--text3) }
.post-content figcaption { font-size: .78rem; color: var(--text3); text-align: center; margin-top: .6rem }
.post-content figcaption a { color: var(--text3) }

/* Grid items do NOT collapse margins, so a card carrying both a top and a
   bottom margin puts 4.4rem between two adjacent cards instead of 2.2rem.
   Spacing is expressed one-sided, exactly like the sibling rule above it. */
.post-content.gh-content .kg-card { margin-block: 0 }
.post-content.gh-content > * + .kg-card,
.post-content.gh-content > .kg-card + * { margin-top: 2.2rem }
.post-content.gh-content .kg-hr,
.post-content.gh-content hr { border: 0; border-top: 1px solid var(--border); margin-block: 2.6rem }

/* --- widths, expressed as grid columns.
   Wide overflows the measure but stays centred on it; full takes the whole
   width the content area has to give. Neither uses a viewport unit, so neither
   can be pushed sideways by a scrollbar. */
.post-content.gh-content > .kg-width-wide {
  grid-column: full;
  width: min(calc(var(--post-w) + 260px), 100%);
  margin-inline: auto;
}
.post-content.gh-content > .kg-width-full {
  grid-column: full;
  width: 100%;
  max-width: none;
  margin-inline: 0;
}

/* --- image */
.post-content.gh-content .kg-image-card img,
.post-content.gh-content img.kg-image { border-radius: var(--r-card); width: 100%; height: auto }
.post-content.gh-content .kg-width-full img.kg-image,
.post-content.gh-content .kg-width-full .kg-image { border-radius: 0 }

/* --- gallery */
.post-content.gh-content .kg-gallery-container { display: flex; flex-direction: column; gap: .5rem }
.post-content.gh-content .kg-gallery-row { display: flex; gap: .5rem }
.post-content.gh-content .kg-gallery-image { flex: 1 1 0; border-radius: var(--r-sm); overflow: hidden; background: var(--bg3) }
.post-content.gh-content .kg-gallery-image img { width: 100%; height: 100%; object-fit: cover; display: block }

/* --- callout. Ghost gives editors nine named colours; keeping them
   distinguishable matters more than tinting them all with the accent. */
.post-content.gh-content .kg-callout-card { display: flex; gap: .8rem; align-items: flex-start; padding: 1.1rem 1.3rem; border-radius: var(--r-card); background: var(--bg3) }
.post-content.gh-content .kg-callout-emoji { flex: 0 0 auto; font-size: 1.1rem; line-height: 1.5 }
.post-content.gh-content div.kg-callout-text { font-size: .95rem; color: inherit }
.post-content.gh-content .kg-callout-card-grey   { background: var(--bg3) }
.post-content.gh-content .kg-callout-card-white  { background: var(--bg); box-shadow: inset 0 0 0 1px var(--border) }
.post-content.gh-content .kg-callout-card-blue   { background: color-mix(in srgb, #3b82f6 14%, var(--bg)) }
.post-content.gh-content .kg-callout-card-green  { background: color-mix(in srgb, var(--ok) 20%, var(--bg)) }
.post-content.gh-content .kg-callout-card-yellow { background: color-mix(in srgb, #f5c451 24%, var(--bg)) }
.post-content.gh-content .kg-callout-card-red    { background: color-mix(in srgb, var(--err) 16%, var(--bg)) }
.post-content.gh-content .kg-callout-card-pink   { background: color-mix(in srgb, #ec4899 14%, var(--bg)) }
.post-content.gh-content .kg-callout-card-purple { background: color-mix(in srgb, #8b5cf6 14%, var(--bg)) }
.post-content.gh-content .kg-callout-card-accent { background: var(--accent); color: var(--on-accent) }
.post-content.gh-content .kg-callout-card-accent div.kg-callout-text { color: var(--on-accent) }
.post-content.gh-content .kg-callout-card-accent a { color: var(--on-accent) }

/* --- toggle. Ghost's own toggle.css sets height 0 to auto at specificity
   (0,3,0) and rotates the SVG itself. Three things follow:
     1. beat it with the attribute selector, not another class;
     2. keep grid-template-rows 0fr to 1fr — height:auto cannot animate — but
        an fr row only sizes correctly with ONE child, so theme.js wraps the
        loose content in .kg-toggle-inner;
     3. do not rotate the button as well as the svg, or the two cancel out. */
.post-content.gh-content .kg-toggle-card {
  border: 1px solid var(--border); border-radius: var(--r-card);
  padding: 1.05rem 1.2rem; background: var(--bg); box-shadow: none;
}
.post-content.gh-content .kg-toggle-heading { display: flex; align-items: center; justify-content: space-between; gap: 1rem; cursor: pointer }
.post-content.gh-content h4.kg-toggle-heading-text { font-size: 1.02rem; font-weight: 700; color: var(--text); margin: 0 }
.post-content.gh-content .kg-toggle-card-icon { color: var(--text3); transform: none }
.post-content.gh-content .kg-toggle-heading svg { width: 15px; color: var(--text3); transition: transform var(--dur) var(--ease) }

.post-content.gh-content .kg-toggle-card[data-kg-toggle-state] .kg-toggle-content {
  display: grid;
  grid-template-rows: 1fr;
  height: auto;
  opacity: 1;
  top: 0;
  overflow: hidden;
  transition: grid-template-rows var(--dur) var(--ease), opacity var(--dur) var(--ease);
}
.post-content.gh-content .kg-toggle-card[data-kg-toggle-state="close"] .kg-toggle-content {
  grid-template-rows: 0fr;
  opacity: 0;
  height: auto;
}
.post-content.gh-content .kg-toggle-inner { min-height: 0; overflow: hidden }
.post-content.gh-content .kg-toggle-content .kg-toggle-inner > *:first-child { margin-top: .8rem }

/* --- bookmark */
.post-content.gh-content .kg-bookmark-card a.kg-bookmark-container {
  display: flex; border: 1px solid var(--border); border-radius: var(--r-card);
  overflow: hidden; text-decoration: none; background: var(--bg); color: var(--text);
  transition: border-color var(--dur) var(--ease); box-shadow: none;
}
.post-content.gh-content .kg-bookmark-card a.kg-bookmark-container:hover { border-color: var(--text) }
.post-content.gh-content .kg-bookmark-content { padding: 1.1rem 1.2rem; flex: 1 1 auto; min-width: 0 }
.post-content.gh-content .kg-bookmark-title { font-weight: 700; color: var(--text); font-size: .95rem; font-family: var(--font-display) }
.post-content.gh-content .kg-bookmark-description { font-size: .84rem; color: var(--text3); margin-top: .3rem }
.post-content.gh-content .kg-bookmark-metadata { display: flex; align-items: center; gap: .45rem; margin-top: .7rem; font-size: .76rem; color: var(--text3) }
.post-content.gh-content .kg-bookmark-icon { width: 16px; height: 16px; margin-right: .1rem }
.post-content.gh-content .kg-bookmark-thumbnail { flex: 0 0 34%; max-width: 200px; background: var(--bg3) }
.post-content.gh-content .kg-bookmark-thumbnail img { width: 100%; height: 100%; object-fit: cover }
@media (max-width: 620px) {
  .post-content.gh-content .kg-bookmark-card a.kg-bookmark-container { flex-direction: column-reverse }
  .post-content.gh-content .kg-bookmark-thumbnail { flex: 0 0 auto; max-width: none; aspect-ratio: 16/9 }
}

/* --- button */
.post-content.gh-content .kg-button-card { display: flex; justify-content: center }
.post-content.gh-content .kg-button-card.kg-align-left { justify-content: flex-start }
.post-content.gh-content .kg-button-card a.kg-btn {
  display: inline-flex; align-items: center; min-height: 44px; padding: 0 1.5rem;
  border-radius: var(--r-chip); background: var(--accent); color: var(--on-accent);
  font-size: .9rem; font-weight: 500; text-decoration: none; border: 0;
  transition: opacity var(--dur) var(--ease);
}
.post-content.gh-content .kg-button-card a.kg-btn:hover { opacity: .82; color: var(--on-accent2) }
/* Ghost offers the editor an "accent" button variant, and taking it literally
   paints the button #ff4d82. COLOR STRATEGY forbids exactly that: "Primary
   buttons are solid ink pills, never accent — the single most load-bearing
   colour decision in the design and the easiest one to get wrong." So both of
   Ghost's variants collapse onto --accent2, which is ink at the factory palette
   and follows the owner's Accent 2 if they set a real colour.

   This is deliberate, not an oversight: the two variants look the same here. */
.post-content.gh-content .kg-button-card a.kg-btn-accent { background: var(--accent); color: var(--on-accent) }
.post-content.gh-content .kg-button-card a.kg-btn-accent:hover { color: var(--on-accent2) }

/* --- file */
.post-content.gh-content .kg-file-card a.kg-file-card-container {
  display: flex; gap: 1rem; align-items: center; text-decoration: none;
  border: 1px solid var(--border); border-radius: var(--r-card);
  padding: 1rem 1.2rem; background: var(--bg); color: var(--text);
  transition: border-color var(--dur) var(--ease); box-shadow: none;
}
.post-content.gh-content .kg-file-card a.kg-file-card-container:hover { border-color: var(--text) }
.post-content.gh-content .kg-file-card-contents { flex: 1 1 auto; min-width: 0 }
.post-content.gh-content .kg-file-card-title { font-weight: 700; color: var(--text); font-size: .93rem; font-family: var(--font-display) }
.post-content.gh-content .kg-file-card-caption { font-size: .8rem; color: var(--text3) }
.post-content.gh-content .kg-file-card-metadata { font-size: .74rem; color: var(--text3); margin-top: .25rem }
.post-content.gh-content .kg-file-card-filesize::before { content: '· ' }
.post-content.gh-content .kg-file-card-icon { flex: 0 0 auto; width: 24px; color: var(--text3) }

/* --- product */
.post-content.gh-content .kg-product-card .kg-product-card-container {
  display: flex; flex-direction: column; align-items: stretch; gap: .7rem;
  border: 1px solid var(--border); border-radius: var(--r-card); padding: 1.4rem; background: var(--bg);
}
.post-content.gh-content .kg-product-card-image { border-radius: var(--r-sm); width: 100% }
.post-content.gh-content .kg-product-card-title { font-family: var(--font-display); font-size: 1.15rem; font-weight: 700; color: var(--text); margin: 0 }
.post-content.gh-content .kg-product-card-description { font-size: .9rem; color: var(--text3) }
.post-content.gh-content .kg-product-card-description p { margin: 0 }
.post-content.gh-content .kg-product-card-rating { display: flex; gap: .15rem; color: var(--border-2) }
.post-content.gh-content .kg-product-card-rating-active { color: var(--accent) }
.post-content.gh-content .kg-product-card-rating-star svg { width: 16px; height: 16px; fill: currentColor }
.post-content.gh-content .kg-product-card a.kg-product-card-button {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 44px; padding: 0 1.5rem; align-self: flex-start;
  border-radius: var(--r-chip); background: var(--accent); color: var(--on-accent);
  font-size: .9rem; font-weight: 500; text-decoration: none;
}
/* same rule as the button card above — filled controls are ink, not accent */
.post-content.gh-content .kg-product-card a.kg-product-card-btn-accent { background: var(--accent); color: var(--on-accent) }

/* --- audio and video. Ghost's cards.min.js owns the playback controls; these
   rules only re-skin the container it renders into. */
.post-content.gh-content .kg-audio-card {
  border: 1px solid var(--border); border-radius: var(--r-card); background: var(--bg); padding: 1rem 1.2rem;
}
.post-content.gh-content .kg-audio-thumbnail { border-radius: var(--r-sm); background: var(--bg3) }
.post-content.gh-content .kg-audio-title { font-family: var(--font-display); font-weight: 700; color: var(--text) }
.post-content.gh-content .kg-audio-play-button,
.post-content.gh-content .kg-audio-playback-rate { color: var(--text) }
.post-content.gh-content .kg-audio-seek-slider,
.post-content.gh-content .kg-audio-volume-slider { accent-color: var(--accent) }
.post-content.gh-content .kg-audio-current-time,
.post-content.gh-content .kg-audio-duration { color: var(--text3); font-variant-numeric: tabular-nums }

.post-content.gh-content .kg-video-container { border-radius: var(--r-card); overflow: hidden; background: var(--bg3) }
.post-content.gh-content .kg-width-full .kg-video-container { border-radius: 0 }
.post-content.gh-content .kg-video-seek-slider,
.post-content.gh-content .kg-video-volume-slider { accent-color: var(--accent) }
.post-content.gh-content .kg-video-current-time,
.post-content.gh-content .kg-video-duration { font-variant-numeric: tabular-nums }

/* --- embed */
.post-content.gh-content .kg-embed-card { display: flex; flex-direction: column; align-items: center }
.post-content.gh-content .kg-embed-card iframe { border-radius: var(--r-card); max-width: 100% }

/* ---- collection card -------------------------------------------------------
   An editor can drop a post list into any post, so this has to be styled even
   though no preview page contains one.

   Ghost DOES ship baseline CSS for it in cards.min.css — but every size in that
   file is a rem written against Casper's `html { font-size: 62.5% }`, so on this
   theme's 16px root the whole card renders about 60% oversized: a 2.4rem post
   title lands at 38px inside a 720px reading column. That is why this block
   restates the sizes rather than only re-skinning the colours.

   Inherited from .card-media / .post-card so a collection reads as the same
   publication as the rest of the site: 4:3 media, --r-card corners, the same
   scale-on-hover, no new token. */
.post-content.gh-content .kg-collection-card { margin-top: 2.4rem }
.post-content.gh-content .kg-collection-card + * { margin-top: 2.4rem }

.post-content.gh-content .kg-collection-card-title {
  margin: 0 0 1.2rem; font-family: var(--font-display);
  font-size: 1.05rem; font-weight: 700; letter-spacing: -.01em;
  text-transform: none;              /* Ghost uppercases it; the design does not */
  color: var(--text);
}

.post-content.gh-content .kg-collection-card-list { gap: 1.6rem }
.post-content.gh-content .kg-collection-card-grid { gap: var(--grid-gap, 16px) }

.post-content.gh-content .kg-collection-card-post { gap: 1rem }
.post-content.gh-content .kg-collection-card-list .kg-collection-card-post { gap: 1.2rem }

.post-content.gh-content .kg-collection-card-img {
  aspect-ratio: 4 / 3; border-radius: var(--r-card); overflow: hidden; background: var(--bg3);
}
.post-content.gh-content .kg-collection-card-grid.columns-1 .kg-collection-card-img,
.post-content.gh-content .kg-collection-card-grid.columns-2 .kg-collection-card-img { aspect-ratio: 3 / 2 }
.post-content.gh-content .kg-collection-card-img img { transition: transform .7s var(--ease) }
.post-content.gh-content a.kg-collection-card-post-wrapper:hover img { opacity: 1; transform: scale(1.045) }

.post-content.gh-content .kg-collection-card-content { font-size: .95rem }
.post-content.gh-content h2.kg-collection-card-post-title {
  font-family: var(--font-display); font-weight: 700;
  font-size: 1.15rem; line-height: 1.25; letter-spacing: -.02em; color: var(--text);
}
.post-content.gh-content .kg-collection-card-grid h2.kg-collection-card-post-title { font-size: 1.02rem }
.post-content.gh-content p.kg-collection-card-post-excerpt {
  margin-top: .5rem; font-size: .88rem; line-height: 1.55; color: var(--text3);
}
.post-content.gh-content .kg-collection-card-post-meta {
  margin-top: .5rem; font-size: .78rem; font-weight: 500; color: var(--text3); opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  .post-content.gh-content .kg-collection-card-img img { transition: none }
  .post-content.gh-content a.kg-collection-card-post-wrapper:hover img { transform: none }
}

/* ---- gallery + video -------------------------------------------------------
   Ghost's own cards.min.css does the real work for both (gallery flex rows,
   video player chrome). Only two things need saying here: the gallery's gaps
   are rem against a 62.5% root, so they land ~1.6x loose on this theme, and
   neither card picks up the design's corner radius on its own. */
.post-content.gh-content .kg-gallery-container { gap: var(--grid-gap, 16px) }
.post-content.gh-content .kg-gallery-row { gap: var(--grid-gap, 16px) }
.post-content.gh-content .kg-gallery-card .kg-gallery-image img { border-radius: var(--r-sm) }
.post-content.gh-content .kg-video-card { border-radius: var(--r-card); overflow: hidden }

/* --- header card, both the legacy and the v2 shapes */
.post-content.gh-content .kg-header-card { border-radius: var(--r-card); padding: clamp(2rem, 5vw, 3.4rem); text-align: center; background: var(--bg3) }
.post-content.gh-content .kg-width-full.kg-header-card { border-radius: 0 }
/* kg-header-card-dark-bg was styled here and is not a class Ghost emits, in
   either the legacy or the v2 shape. kg-style-dark is the real one. */
.post-content.gh-content .kg-header-card.kg-style-dark { background: #151618; color: #f7f7f5 }
.post-content.gh-content .kg-header-card.kg-style-accent { background: var(--accent); color: var(--on-accent) }
.post-content.gh-content .kg-header-card h2,
.post-content.gh-content .kg-header-card-heading {
  color: inherit; margin-top: 0;
  font-family: var(--font-display); letter-spacing: -.03em; line-height: 1.05;
  font-size: clamp(1.8rem, 4vw, 3.2rem);
}
.post-content.gh-content .kg-header-card-subheading { color: inherit; opacity: .8; margin-top: .8rem; font-size: 1.05rem }
.post-content.gh-content a.kg-header-card-button {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 44px; padding: 0 1.5rem; margin-top: 1.4rem;
  border-radius: var(--r-chip); background: var(--accent); color: var(--on-accent);
  font-size: .9rem; font-weight: 500; text-decoration: none;
}

/* --- call to action */
.post-content.gh-content .kg-cta-card {
  border-radius: var(--r-card); padding: 1.6rem 1.8rem; background: var(--bg2);
  border: 1px solid var(--border);
}
.post-content.gh-content .kg-cta-card.kg-style-accent { background: var(--accent); color: var(--on-accent); border-color: transparent }
.post-content.gh-content .kg-cta-card.kg-style-accent a { color: var(--on-accent) }
.post-content.gh-content .kg-cta-sponsor-label { font-size: .7rem; letter-spacing: .14em; text-transform: uppercase; color: var(--text3) }
.post-content.gh-content .kg-cta-text { font-size: 1rem }
.post-content.gh-content .kg-cta-image-container img { border-radius: var(--r-sm) }
.post-content.gh-content a.kg-cta-button {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 44px; padding: 0 1.5rem;
  border-radius: var(--r-chip); background: var(--accent); color: var(--on-accent);
  font-size: .9rem; font-weight: 500; text-decoration: none;
}
/* Ghost's divider logic runs the other way round: a CTA with no background gets
   dividers BY DEFAULT and the editor removes them, so the class to match is
   kg-cta-no-dividers, negated. The theme previously styled .kg-cta-has-dividers,
   which Ghost never emits — so the divider treatment never appeared, and turning
   dividers off in the editor did nothing either.

   The 9 kg-cta-bg-* colours are deliberately NOT restated here: unlike the
   callout palette they are alpha rgba in Ghost's own CSS, so they tint over
   whichever surface is behind them and already work in both schemes. */
.post-content.gh-content .kg-cta-card.kg-cta-bg-none:not(.kg-cta-no-dividers) {
  border-block: 1px solid var(--border); border-radius: 0; background: transparent; border-inline: 0;
}
.post-content.gh-content .kg-cta-card.kg-cta-bg-none.kg-cta-no-dividers {
  border: 0; border-radius: 0; background: transparent;
}

/* --- signup card. Ghost renders its own form and states here. */
.post-content.gh-content .kg-signup-card { border-radius: var(--r-card); padding: clamp(1.6rem, 4vw, 3rem) }
.post-content.gh-content .kg-width-full.kg-signup-card { border-radius: 0 }
.post-content.gh-content .kg-signup-card-heading { font-family: var(--font-display); letter-spacing: -.03em; line-height: 1.08; color: inherit }
.post-content.gh-content .kg-signup-card-subheading { color: inherit; opacity: .8 }
.post-content.gh-content .kg-signup-card-input {
  min-height: 44px; padding: 0 1.1rem; border-radius: var(--r-chip);
  border: 1px solid var(--border); background: var(--bg); color: var(--text);
}
.post-content.gh-content button.kg-signup-card-button {
  min-height: 44px; padding: 0 1.5rem; border-radius: var(--r-chip); border: 0;
  background: var(--accent); color: var(--on-accent); font-weight: 500; cursor: pointer;
}
.post-content.gh-content .kg-signup-card-success,
.post-content.gh-content .kg-signup-card-error { font-size: .85rem }
.post-content.gh-content .kg-signup-card-error { color: var(--err) }
.post-content.gh-content .kg-signup-card-disclaimer { font-size: .78rem; opacity: .7 }

/* --- code */
.post-content pre {
  background: #151618; color: #f7f7f5; border-radius: var(--r-card);
  padding: 1.15rem 1.3rem; overflow-x: auto;
  font-family: var(--font-mono); font-size: .84rem; line-height: 1.6;
}
.post-content pre code { background: none; padding: 0; color: inherit; font-size: inherit; white-space: pre }
.post-content code { font-family: var(--font-mono); font-size: .86em; background: var(--bg3); padding: .12em .38em; border-radius: 4px }
.post-content.gh-content .kg-code-card figcaption { margin-top: .55rem }

/* --- quotes */
.post-content blockquote {
  margin: 0; padding-left: 1.1rem;
  border-left: 1px solid var(--border-2);
  font-size: 1.1rem; color: var(--text);
}
.post-content blockquote.kg-blockquote-alt {
  border-left: 0; padding: 0; text-align: center;
  font-family: var(--font-display); font-weight: 700;
  letter-spacing: -.025em; line-height: 1.18;
  font-size: clamp(1.35rem, 2.6vw, 2rem);
}
.post-content blockquote.kg-blockquote-alt::before {
  content: '"'; display: block; color: var(--accent);
  font-size: 2.2rem; line-height: .6; margin-bottom: .9rem;
}

/* --- tables. A wide table has to scroll inside its own box rather than push
   the page sideways. */
/* Tables are the one thing in post content that cannot be made to fit: a
   four-column table has a min-content width no reading column can honour, so on
   a 390px viewport it pushes the whole document sideways. That failure hides
   well — the visible offenders afterwards are the fixed preloader and drawer,
   which inflate to the widened layout viewport and look like the cause.

   theme.js wraps each table in .table-scroll. The `>` selector below is the
   no-JS fallback and switches itself off once the wrapper exists, because the
   table is then no longer a direct child of the content wrapper. */
.post-content.gh-content > table { display: block; overflow-x: auto; max-width: 100% }
.post-content .table-scroll { overflow-x: auto; max-width: 100%; -webkit-overflow-scrolling: touch }
.post-content .table-scroll table { min-width: 100% }
.post-content table { width: 100%; border-collapse: collapse; font-size: .9rem }
.post-content table th, .post-content table td { text-align: left; padding: .7rem .9rem; border-bottom: 1px solid var(--border) }
.post-content table th { font-weight: 700; color: var(--text); background: var(--bg2) }
.post-content .table-scroll,
.post-content .kg-table-wrap { overflow-x: auto; border: 1px solid var(--border); border-radius: var(--r-card) }

/* --- the members paywall Ghost injects mid-post */
.post-content .gh-post-upgrade-cta {
  border: 1px solid var(--border); border-radius: var(--r-card);
  background: var(--bg2); padding: 2rem; text-align: center;
}

/* ------------------------------------------------------- 18. membership page */
.grain {
  position: relative; border-radius: var(--radius); overflow: hidden;
  background:
    radial-gradient(80% 90% at 12% 18%, #6fd3c8 0%, transparent 55%),
    radial-gradient(70% 80% at 82% 22%, #f4a0c8 0%, transparent 58%),
    radial-gradient(90% 90% at 78% 88%, #9b7ff0 0%, transparent 60%),
    radial-gradient(70% 70% at 22% 86%, #6fd3c8 0%, transparent 55%),
    linear-gradient(120deg, #e9d5f5, #cfe9dd);
}
.grain::before {
  content: ''; position: absolute; inset: 0; opacity: .5; mix-blend-mode: overlay; pointer-events: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='.55'/%3E%3C/svg%3E");
}
.grain > * { position: relative; z-index: 1 }

.price-grid { display: grid; gap: 1rem; grid-template-columns: 1fr }
@media (min-width: 860px) { .price-grid { grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)) } }
.price-card { display: flex; flex-direction: column; gap: 1rem; background: var(--bg); border: 1px solid var(--border); border-radius: var(--r-card); padding: 1.5rem }
.price-card .amount { font-family: var(--font-display); font-size: clamp(2.4rem, 4vw, 3.4rem); font-weight: 700; letter-spacing: -.04em; line-height: 1 }
.price-card .amount span { font-size: .95rem; font-weight: 400; letter-spacing: 0; color: var(--text3) }
.price-card ul { display: flex; flex-direction: column; gap: .55rem; list-style: none; padding: 0; border-top: 1px solid var(--border); padding-top: 1rem }
.price-card li { display: flex; gap: .55rem; align-items: flex-start; font-size: .875rem; color: var(--text2) }
.price-card li svg { width: 15px; height: 15px; flex: 0 0 auto; margin-top: .22rem; color: var(--accent3) }
.price-card .btn { margin-top: auto }
.price-card.is-suggested { box-shadow: var(--shadow-3); border-color: var(--text); transform: translateY(-6px) }
@media (max-width: 859px) { .price-card.is-suggested { transform: none } }

body[data-pricing="spotlight"] .price-grid { grid-template-columns: 1fr }
@media (min-width: 900px) {
  body[data-pricing="spotlight"] .price-grid { grid-template-columns: 1fr 1.25fr 1fr; align-items: center }
  body[data-pricing="spotlight"] .price-card.is-suggested { transform: scale(1.05) }
}
body[data-pricing="horizontal"] .price-grid { grid-template-columns: 1fr }
body[data-pricing="horizontal"] .price-card { flex-direction: row; align-items: center; flex-wrap: wrap; gap: 1.4rem }
body[data-pricing="horizontal"] .price-card ul { border-top: 0; padding-top: 0; flex: 1 1 260px }
body[data-pricing="horizontal"] .price-card .btn { margin-top: 0 }
body[data-pricing="horizontal"] .price-card.is-suggested { transform: none }

/* Both amounts ship in the card and the switch is a pure CSS state, so the
   shipped default is correct before any script runs. */
.price-card .amt-yearly { display: none }
[data-billing="yearly"] .price-card .amt-monthly { display: none }
[data-billing="yearly"] .price-card .amt-yearly { display: inline }
[data-socialproof="hide"] .social-proof { display: none }
[data-faq="hide"] .faq-section { display: none }
[data-testimonials="hide"] .testimonials-section { display: none }

.switch { display: inline-flex; padding: 3px; border-radius: var(--r-chip); background: var(--bg); border: 1px solid var(--border) }
.switch button { min-height: 36px; padding: 0 1.2rem; border-radius: var(--r-chip); border: 0; background: transparent; font-size: .84rem; cursor: pointer; color: var(--text3) }
.switch button[aria-pressed="true"] { background: var(--accent); color: var(--on-accent) }

.faq-item { border-bottom: 1px solid var(--border) }
.faq-item summary { display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding: 1.1rem 0; cursor: pointer; list-style: none; font-size: 1.02rem; color: var(--text) }
.faq-item summary::-webkit-details-marker { display: none }
.faq-item summary svg { width: 17px; height: 17px; flex: 0 0 auto; transition: transform var(--dur) var(--ease); color: var(--text3) }
.faq-item[open] summary svg { transform: rotate(180deg) }
.faq-item .faq-body { padding-bottom: 1.2rem; font-size: .92rem; color: var(--text3); max-width: 68ch }

.stat-tile { display: flex; flex-direction: column; gap: .2rem; padding: 1.2rem 0 }
.stat-tile .n { font-family: var(--font-display); font-size: clamp(1.6rem, 3vw, 2.4rem); font-weight: 700; letter-spacing: -.03em; line-height: 1 }
.stat-tile .l { font-size: .78rem; color: var(--text3) }
.stats-bar { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); border-top: 1px solid var(--border); border-bottom: 1px solid var(--border) }
[data-stats="hide"] .stats-bar { display: none }
[data-directory="hide"] .directory-section { display: none }
[data-relatedtags="hide"] .related-tags { display: none }

/* the tag and author hero — banner is the shipped default */
.archive-hero-body { display: flex; gap: 1.6rem; align-items: flex-start; flex-wrap: wrap }
.archive-hero-media { flex: 0 0 clamp(120px, 20vw, 200px); border-radius: var(--r-card); overflow: hidden; background: var(--bg3) }
.archive-hero-media img { width: 100%; height: 100%; object-fit: cover; aspect-ratio: 4 / 3 }
[data-taghero="centered"] .archive-hero-body,
[data-authorhero="centered"] .archive-hero-body { flex-direction: column; align-items: center; text-align: center }
[data-taghero="centered"] .archive-hero-body .lede,
[data-authorhero="centered"] .archive-hero-body .lede { margin-inline: auto }
[data-taghero="compact"] .archive-hero-media,
[data-authorhero="compact"] .archive-hero-media { display: none }
[data-taghero="compact"] .archive-hero h1,
[data-authorhero="compact"] .archive-hero h1 { font-size: clamp(1.6rem, 3vw, 2.6rem) }
[data-taghero="compact"] .archive-hero .lede,
[data-authorhero="compact"] .archive-hero .lede { display: none }

/* Compact previously only reached .archive-hero-media, which is the TAG hero's
   picture — the author hero carries an avatar instead, so on an author page the
   setting shrank the heading and left an 84px portrait sitting next to it. The
   avatar comes down to a byline size rather than disappearing: an author page
   with no face at all reads as a tag archive. */
.archive-hero .author-hero-av { width: 84px; height: 84px }
[data-authorhero="compact"] .archive-hero .author-hero-av { width: 40px; height: 40px }
[data-authorhero="compact"] .archive-hero-body { gap: .9rem; align-items: center }
/* The social row is the other thing that keeps a compact hero from being
   compact; the links stay reachable from the author's own posts. */
[data-authorhero="compact"] .archive-hero .share-btn { width: 32px; height: 32px }

/* Centred needs the avatar to sit above the name rather than beside it, and the
   social row to come back to the middle with everything else. */
[data-authorhero="centered"] .archive-hero-body > div { text-align: center }
[data-authorhero="centered"] .archive-hero-body > div > div { justify-content: center }
[data-taghero="centered"] .archive-hero .sec-head,
[data-authorhero="centered"] .archive-hero .sec-head { justify-content: space-between }

.directory-grid { display: grid; gap: .2rem; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)) }
.directory-grid a { display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding: .75rem 0; border-bottom: 1px solid var(--border) }
.directory-grid a span:first-child { font-weight: 500; font-size: .9rem }

/* --------------------------------------------------------- 19. auth pages */
.auth-shell { min-height: 100dvh; display: flex; flex-direction: column; position: relative }
.auth-card { width: min(430px, 100%); margin-inline: auto; display: flex; flex-direction: column; gap: 1rem }
.auth-split { display: flex; justify-content: center }
.auth-split .auth-media { display: none }
@media (min-width: 860px) {
  .auth-split[data-layout-v="split"] { display: grid; grid-template-columns: 1fr 1fr; gap: 2.5rem; align-items: center; max-width: 940px; margin-inline: auto }
  .auth-split[data-layout-v="split"] .auth-media { display: block; border-radius: var(--r-card); overflow: hidden; aspect-ratio: 4 / 5; background: var(--bg3) }
  .auth-split[data-layout-v="split"] .auth-media img { width: 100%; height: 100%; object-fit: cover }
  .auth-split[data-layout-v="split"] .auth-card { margin-inline: 0 }
}
.auth-topbar { position: absolute; top: 1.2rem; left: 1.2rem; right: 1.2rem; z-index: 2; display: flex; align-items: center; justify-content: space-between; gap: 1rem }
.auth-tabs { display: inline-flex; gap: .2rem; padding: 3px; background: var(--bg2); border: 1px solid var(--border); border-radius: var(--r-chip) }
.auth-tabs a { min-height: 38px; padding: 0 1rem; display: inline-flex; align-items: center; border-radius: var(--r-chip); font-size: .84rem; color: var(--text3) }
.auth-tabs a[aria-current="page"] { background: var(--accent); color: var(--on-accent) }
.account-row { display: flex; justify-content: space-between; gap: 1rem; padding: 1rem 0; border-bottom: 1px solid var(--border) }
.signup-terms { display: flex; gap: .6rem; align-items: flex-start; font-size: .8rem; color: var(--text3); line-height: 1.5 }
.signup-terms input { margin-top: .25rem; accent-color: var(--accent); flex: 0 0 auto }
.signup-terms p { margin: 0 }
.signup-terms a { text-decoration: underline }

/* ------------------------------------------------------------- 20. pages */
.page-layout { display: grid; gap: 2.5rem; grid-template-columns: 1fr; align-items: start }
/* sidebar is the shipped default; the attribute only overrides */
@media (min-width: 1000px) { .page-layout { grid-template-columns: 230px minmax(0, 1fr) } }
body[data-pagelayout="centered"] .page-nav, body[data-pagelayout="wide"] .page-nav { display: none }
@media (min-width: 1000px) {
  body[data-pagelayout="centered"] .page-layout,
  body[data-pagelayout="wide"] .page-layout { grid-template-columns: minmax(0, 1fr) }
}
body[data-pagelayout="centered"] .page-body { max-width: var(--post-w); margin-inline: auto }
body[data-pagelayout="wide"] .page-body { max-width: none }
.page-nav { position: sticky; top: 100px; z-index: 40 }
.page-nav:not(:has(a)) { display: none }
@media (max-width: 999px) { .page-nav { position: static } }

/* --------------------------------------------------------------- 21. error */
.err-wrap { min-height: 62vh; display: grid; place-items: center; text-align: center }
.err-code { font-family: var(--font-display); font-weight: 700; letter-spacing: -.05em; line-height: .85; font-size: clamp(5rem, 20vw, 14rem) }
/* illustrated is the shipped default */
.err-variant { display: none }
.err-illustrated { display: grid }
body[data-errorstyle="minimal"] .err-illustrated,
body[data-errorstyle="search"] .err-illustrated { display: none }
body[data-errorstyle="minimal"] .err-minimal { display: grid }
body[data-errorstyle="search"] .err-search { display: grid }

/* ---------------------------------------------------------------- 22. gdpr */
.gdpr { position: fixed; z-index: 9450; display: none }
.gdpr.is-on { display: block }
.gdpr-inner { background: var(--bg); border: 1px solid var(--border); border-radius: var(--r-card); box-shadow: var(--shadow-3); padding: 1.15rem 1.3rem }
.gdpr-actions { display: flex; gap: .5rem; flex-wrap: wrap; margin-top: .9rem }
/* bottom-left is the shipped default */
.gdpr[data-style="glass"], .gdpr[data-style="corner"] { left: 1rem; bottom: 1rem; right: auto }
body[data-gdprpos="br"] .gdpr[data-style="glass"],
body[data-gdprpos="br"] .gdpr[data-style="corner"] { right: 1rem; bottom: 1rem; left: auto }
.gdpr[data-style="glass"] { width: min(400px, calc(100vw - 2rem)) }
.gdpr[data-style="glass"] .gdpr-inner { background: color-mix(in srgb, var(--bg) 78%, transparent); backdrop-filter: blur(18px) saturate(1.4) }
.gdpr[data-style="corner"] { width: min(330px, calc(100vw - 2rem)) }
.gdpr[data-style="modal"] { inset: 0; display: none; place-items: center; padding: 1rem; background: rgba(10,10,12,.55); backdrop-filter: blur(4px) }
.gdpr[data-style="modal"].is-on { display: grid }
.gdpr[data-style="modal"] .gdpr-inner { width: min(460px, 100%) }
.gdpr[data-style="panel"] { left: 0; right: 0; bottom: 0 }
.gdpr[data-style="panel"] .gdpr-inner { border-radius: var(--r-card) var(--r-card) 0 0; border-bottom: 0; padding-inline: max(var(--gutter), calc((100% - var(--container)) / 2)) }
.gdpr[data-style="strip"] { left: 0; right: 0; bottom: 0 }
.gdpr[data-style="strip"] .gdpr-inner { border-radius: 0; border-inline: 0; border-bottom: 0; display: flex; align-items: center; gap: 1rem; flex-wrap: wrap; padding-inline: max(var(--gutter), calc((100% - var(--container)) / 2)) }
.gdpr[data-style="strip"] .gdpr-actions { margin-top: 0; margin-left: auto }
.gdpr[data-style="creative"] { left: 50%; bottom: 1.25rem; transform: translateX(-50%); width: min(560px, calc(100vw - 2rem)) }
.gdpr[data-style="creative"] .gdpr-inner { border-radius: var(--r-chip); display: flex; align-items: center; gap: 1rem; flex-wrap: wrap; padding: .8rem .85rem .8rem 1.4rem }
.gdpr[data-style="creative"] .gdpr-actions { margin-top: 0; margin-left: auto }

/* ----------------------------------------------------------- 23. preloader */
#preloader { position: fixed; inset: 0; z-index: 9800; display: grid; place-items: center; background: var(--page-bg); transition: opacity .35s ease, visibility .35s ease }
#preloader.is-done { opacity: 0; visibility: hidden; pointer-events: none }
body[data-preloader="off"] #preloader { display: none }
.pl-dots { display: flex; gap: .45rem }
.pl-dots i { width: 9px; height: 9px; border-radius: 100px; background: var(--accent); animation: plPulse 1.1s var(--ease) infinite }
.pl-dots i:nth-child(2) { animation-delay: .16s } .pl-dots i:nth-child(3) { animation-delay: .32s }
@keyframes plPulse { 0%, 100% { opacity: .25; transform: scale(.7) } 45% { opacity: 1; transform: scale(1) } }
.pl-bars { display: flex; gap: .3rem; align-items: flex-end; height: 34px }
/* loader and toast stay ink on purpose — feedback chrome, maximum contrast */
.pl-bars i { width: 5px; height: 100%; background: var(--text); border-radius: 3px; transform-origin: bottom; animation: plBars 1s var(--ease) infinite }
.pl-bars i:nth-child(2) { animation-delay: .12s; background: var(--accent) } .pl-bars i:nth-child(3) { animation-delay: .24s } .pl-bars i:nth-child(4) { animation-delay: .36s }
@keyframes plBars { 0%, 100% { transform: scaleY(.25) } 50% { transform: scaleY(1) } }
.pl-ring { width: 38px; height: 38px; border-radius: 100px; border: 2.5px solid var(--border); border-top-color: var(--accent); animation: plSpin .8s linear infinite }
@keyframes plSpin { to { transform: rotate(360deg) } }
.pl-word { font-family: var(--font-display); font-weight: 700; font-style: italic; text-transform: uppercase; letter-spacing: -.05em; font-size: 1.7rem; animation: plFade 1.3s var(--ease) infinite }
@keyframes plFade { 0%, 100% { opacity: .3 } 50% { opacity: 1 } }
.pl-line { width: min(220px, 50vw); height: 2px; background: var(--border); overflow: hidden; border-radius: 2px }
.pl-line i { display: block; width: 40%; height: 100%; background: var(--accent); animation: plSlide 1.1s var(--ease) infinite }
@keyframes plSlide { 0% { transform: translateX(-100%) } 100% { transform: translateX(350%) } }
.pl-glitch { position: relative; font-family: var(--font-display); font-weight: 700; font-style: italic; text-transform: uppercase; letter-spacing: -.05em; font-size: 1.7rem; color: var(--text) }
.pl-glitch::before, .pl-glitch::after { content: attr(data-t); position: absolute; inset: 0 }
.pl-glitch::before { color: var(--accent); animation: plG1 .7s steps(2) infinite }
.pl-glitch::after { color: var(--accent3); animation: plG2 .7s steps(2) infinite }
@keyframes plG1 { 0%, 100% { transform: translate(0) } 50% { transform: translate(-2px, 1px) } }
@keyframes plG2 { 0%, 100% { transform: translate(0) } 50% { transform: translate(2px, -1px) } }
.pl-custom img { max-width: 160px; max-height: 160px }

/* --------------------------------------------------------------- 24. toast */
.toast {
  position: fixed; left: 50%; bottom: 1.5rem; transform: translate(-50%, 20px);
  z-index: 9600; opacity: 0; pointer-events: none;
  background: var(--text); color: var(--bg);
  padding: .65rem 1.1rem; border-radius: var(--r-chip);
  font-size: .85rem; box-shadow: var(--shadow-3);
  transition: opacity .3s var(--ease), transform .3s var(--ease);
  max-width: calc(100vw - 2rem);
}
.toast.is-on { opacity: 1; transform: translate(-50%, 0) }

/* ------------------------------------------------------- 25. reveal states */
/* Everything animates FROM a visible resting state. These are only ever touched
   by JS after it has confirmed GSAP is present and motion is allowed, so a
   failed timeline leaves readable content behind rather than a blank page. */
[data-reveal] { will-change: auto }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
  .ticker-track { animation: none !important }
  .hero-full .kb img, .hero-full .kb .ph { animation: none !important }
  #preloader { display: none !important }
  [data-reveal], [data-reveal-item] { opacity: 1 !important; filter: none !important; transform: none !important; clip-path: none !important }
}

/* ------------------------------------------------------------- 26. utility */
.hidden { display: none !important }
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0 }
.sr-only:focus { position: fixed; top: 1rem; left: 1rem; width: auto; height: auto; padding: .6rem 1rem; margin: 0; clip: auto; background: var(--bg); border: 1px solid var(--border); border-radius: var(--r-chip); z-index: 9999 }
.divider { border-top: 1px solid var(--border) }
.mono { font-family: var(--font-mono) }
.tnum { font-variant-numeric: tabular-nums }
