
/* ---------------------------------------------------------------------------
   BRAND PALETTE -- from Brand_Colors_Chart.pdf, Darby + designer, 2026-09.
   Same colors as the Fraternal Youth cover.

   Weight, most to least:
     Azure Blue 7, Magenta 6, Cosmic Periwinkle 5, Teal 4,
     Light Periwinkle Blue 3, Golden Hour 2, Yellow 1.

   Azure and Magenta are too light for small text on off-white (3.4:1 and
   3.8:1; readable body text needs 4.5:1). So small text uses the -deep shades,
   and the true brand colors go on fills, borders and large display type, where
   3:1 is enough. Cosmic Periwinkle is the only brand color dark enough to be
   text as-is, which is why it carries the headings and the masthead.

   DERIVED, not on the chart: --azure-deep, --magenta-deep, --ink-soft,
   --ink-faint, and the dark-mode surfaces. Each was computed to pass 4.5:1 on
   every background it sits on. Worth the designer's sign-off.
   --------------------------------------------------------------------------- */
:root{
  /* base colors */
  --azure:#1D91C2;  --magenta:#D64A97;  --cosmic:#564786;  --golden:#F6D86B;
  --teal:#2BB6B2;   --peri:#8F9EF9;     --yellow:#F8E18F;
  /* supporting colors */
  --mint:#66DDAA;   --peri-light:#C5D1FA;
  /* DERIVED. Mint taken from 63% lightness / 64% saturation down to 50 / 55,
     and turned toward Teal (hue 154 -> 166). Mint glows against a saturated
     fill; Teal vanishes into one. This is the last stop between them: at
     2.46:1 on the magenta it is the dimmest edge that still reads. Anything
     darker measures at or below Teal's 2.12:1 and stops being a border. */
  --mint-deep:#39C6A5;
  --yellow-light:#FAEBB4;  --yellow-lighter:#FCF1D6;
  /* neutrals */
  --offwhite:#FAF9F6;  --charcoal:#2E2E2E;
  /* derived for readable text */
  --azure-deep:#17759C;  --magenta-deep:#C32C7F;

  /* roles -- rules below use these, never the raw colors */
  --ink:var(--charcoal); --ink-soft:#55525E; --ink-faint:#6B6778;
  --paper:var(--offwhite); --paper-2:var(--yellow-lighter); --line:var(--peri-light);
  --link:var(--azure-deep); --link-hover:var(--magenta-deep);
  --accent:var(--azure-deep); --accent-hover:var(--magenta-deep); --on-accent:#fff;
  --heading:var(--cosmic); --display-accent:var(--magenta); --label:var(--magenta-deep);
  --band:var(--cosmic); --band-ink:var(--offwhite); --band-soft:var(--peri-light);
  --band-accent:var(--golden);
  --rule:var(--magenta); --gold:var(--golden); --hover-border:var(--teal);
  /* The price tiers fill on hover, and must not be confused with the azure
     CTA buttons next to them -- a tier is a different kind of thing. Magenta
     is the second brand weight and carries white at 5.27:1. A tier with no
     link yet fills too, but with the soft neutral, never the action colour. */
  --tier-fill:var(--magenta-deep); --tier-ink:#fff;
  /* The edge on a hovered live tier. Against the magenta fill: Mint 3.13:1 but
     it glows, Teal 2.12:1 and you cannot see it, Mint Deep 2.46:1 and calm.
     This is the bottom of the useful range -- if it still reads too hot, the
     fix is a lighter edge or no edge, not a darker one. */
  --tier-edge:var(--mint-deep);
  --tier-off-fill:var(--line); --tier-off-ink:var(--ink);
  --max:44rem;
  --serif:'Iowan Old Style','Palatino Linotype',Palatino,'Book Antiqua',Georgia,serif;
  --sans:'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;

  /* ---- SPACING SCALE -------------------------------------------------------
     Nine steps on a 4px base. Full reasoning in docs/brand/layout-spacing.md.

     No rule below this line uses a raw length for margin, padding or gap. If a
     gap needs a value that is not on this scale, the scale is wrong -- fix it
     here, once, rather than inventing a fortieth number in one component.

     The scale before this existed: 42 different values, so the space between
     any two things was whatever three unrelated rules happened to add up to. */
  --space-3xs:.25rem;  /*  4px  hairline: label to the thing it labels        */
  --space-2xs:.5rem;   /*  8px  inside a control                             */
  --space-xs:.75rem;   /* 12px  tight pair                                   */
  --space-s:1rem;      /* 16px  heading to its own paragraph                 */
  --space-m:1.5rem;    /* 24px  DEFAULT. paragraph to paragraph              */
  --space-l:2rem;      /* 32px  block to block down a page                   */
  --space-xl:3rem;     /* 48px  one section to the next                      */
  --space-2xl:4rem;    /* 64px  page top, and away from the footer           */
  --space-3xl:6rem;    /* 96px  reserved for the home hero                   */

  --gutter:var(--space-m);      /* the page's left and right breathing room  */
  --flow-space:var(--space-m);  /* the default gap the flow engine applies   */
}
@media (prefers-color-scheme:dark){
  :root{ --ink:var(--offwhite); --ink-soft:#D9D5E2; --ink-faint:#ABA6BA;
         --paper:var(--charcoal); --paper-2:#38344A; --line:#4A4560;
         --link:var(--peri); --link-hover:var(--golden);
         --accent:var(--peri); --accent-hover:var(--golden); --on-accent:var(--charcoal);
         --heading:var(--peri-light); --label:var(--teal); }
}
*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{margin:0;background:var(--paper);color:var(--ink);
  font-family:var(--serif);font-size:1.1875rem;line-height:1.7;
  font-synthesis-weight:none;-webkit-font-smoothing:antialiased}
.wrap{max-width:var(--max);margin:0 auto;padding-inline:var(--gutter)}
.wide{max-width:64rem}
a{color:var(--link);text-underline-offset:.18em;text-decoration-thickness:.06em}
a:hover{color:var(--link-hover)}
img{max-width:100%;height:auto;display:block;border-radius:4px}
hr{border:0;border-top:1px solid var(--line);--flow-space:var(--space-xl)}
::selection{background:var(--golden);color:var(--charcoal)}

/* Browser default margins inside imported Substack markup. Those wrappers nest
   -- a div holding a figure, an li holding a paragraph -- and a nested child's
   UA margin collapses up out of its wrapper and lands as a gap the scale never
   authorised. :where() scores zero specificity, so this reset loses to the
   flow rules right below it for anything that IS a direct child, and wins for
   everything nested, which is exactly the split we want. It also clears the
   40px side margin a browser puts on <figure>. */
.prose :where(p,ul,ol,li,figure,blockquote,pre,h1,h2,h3,h4,h5,h6){margin:0}

/* ---------------------------------------------------------------------------
   FLOW -- the one thing that puts space between two stacked elements.

   Heydon Pickering's owl selector carrying Andy Bell's --flow-space custom
   property. Inside a flow container nothing owns a bottom margin, so the gap
   between any two siblings is exactly one number and can never accumulate.
   Change the gap for one element by setting --flow-space ON THAT ELEMENT;
   custom properties cascade, so that element's own margin picks it up.

   Components below set margin:0 and keep only their internal padding. A
   component does not decide how much room it has around it. That is the
   page's decision, and the page makes it here.
   --------------------------------------------------------------------------- */
.flow,main,.article,.article header,.hero,.hero .wrap,.prose,
.efoot,.efoot>section,.book>div,footer.site .wrap{
  --flow-space:var(--space-m)}
.flow>*,main>*,.article>*,.article header>*,.hero>*,.hero .wrap>*,.prose>*,
.efoot>*,.efoot>section>*,.book>div>*,footer.site .wrap>*{
  margin-block:0}
/* A component that is a flow child must never declare its own margin. A class
   selector scores (0,1,0) against the flow rule's (0,0,1), so a stray
   margin:0 on .note or .cards silently wins and collapses the gap to nothing.
   The reset above is the only margin a flow child gets. */
.flow>*+*,main>*+*,.article>*+*,.article header>*+*,.hero>*+*,.hero .wrap>*+*,
.prose>*+*,.efoot>*+*,.efoot>section>*+*,.book>div>*+*,footer.site .wrap>*+*{
  margin-block-start:var(--flow-space)}

/* Page-level blocks sit further apart than paragraphs do. */
main,.article{--flow-space:var(--space-l)}
/* A title stays close to its own words. */
.article header{--flow-space:var(--space-2xs)}

/* header */
.masthead{border-bottom:1px solid var(--band);background:var(--band);
  position:sticky;top:0;z-index:20;backdrop-filter:saturate(180%) blur(8px)}
.masthead .wrap{display:flex;align-items:center;gap:var(--space-m);
  padding-block:var(--space-xs)}
.brand{font-family:var(--sans);font-weight:800;font-size:1.05rem;letter-spacing:-.02em;
  color:var(--band-ink);text-decoration:none;white-space:nowrap}
.brand span{color:var(--band-accent)}
.nav{margin-left:auto;display:flex;gap:var(--space-s);flex-wrap:wrap}
.nav a{font-family:var(--sans);font-size:.86rem;font-weight:500;color:var(--band-soft);
  text-decoration:none;letter-spacing:.01em}
.nav a:hover,.nav a[aria-current]{color:var(--band-accent)}

/* hero. .plain is the section-page variant: no rule under it and no bottom
   padding, because the flow gap below already spaces it from what follows.
   Every section page used to carry that as an inline style. */
.hero{padding-block:var(--space-3xl) var(--space-xl);
  border-bottom:1px solid var(--line);--flow-space:var(--space-s)}
.hero.plain{border-bottom:0;padding-block:var(--space-2xl) 0}
.hero h1{font-family:var(--sans);font-weight:800;letter-spacing:-.035em;color:var(--heading);
  font-size:clamp(2.6rem,8vw,4.5rem);line-height:1.02;--flow-space:var(--space-xs)}
.hero h1 em{font-style:normal;color:var(--display-accent)}
.hero p{font-size:1.25rem;color:var(--ink-soft);max-width:34rem}
.hero .btn-row{--flow-space:var(--space-m)}
.kicker{font-family:var(--sans);font-size:.75rem;font-weight:700;letter-spacing:.16em;
  text-transform:uppercase;color:var(--label)}
/* "All writing ->" and friends: a quiet link trailing its list. */
.more-link{font-size:.95rem;--flow-space:var(--space-m)}
/* The SoundCloud iframe on /music. display:block matters: an iframe is inline
   by default, so it sits on a text baseline and carries ~9px of descender
   space under it that no margin accounts for. That was the one gap on the
   whole site the scale could not explain. */
.sc-player{display:block;border-radius:8px}

/* signup */
.signup{background:var(--paper-2);border:1px solid var(--gold);border-radius:10px;
  padding:var(--space-m)}
.signup h3{font-family:var(--sans);font-size:1.02rem;font-weight:700;
  margin:0 0 var(--space-3xs)}
.signup p{font-family:var(--sans);font-size:.87rem;color:var(--ink-faint);
  margin:0 0 var(--space-xs)}
.signup form{display:flex;gap:var(--space-2xs);flex-wrap:wrap}
.signup input[type=email]{flex:1 1 15rem;min-width:0;font:inherit;font-family:var(--sans);
  font-size:.95rem;padding:var(--space-2xs) var(--space-xs);border:1px solid var(--line);
  border-radius:7px;background:var(--paper);color:var(--ink)}
.signup input[type=email]:focus{outline:2px solid var(--accent);outline-offset:-1px;
  border-color:var(--accent)}
.btn{font-family:var(--sans);font-size:.92rem;font-weight:650;cursor:pointer;
  padding:var(--space-2xs) var(--space-m);border:1px solid var(--accent);border-radius:7px;
  background:var(--accent);color:var(--on-accent);text-decoration:none;display:inline-block;
  line-height:1.5;transition:background .15s}
.btn:hover{background:var(--accent-hover);border-color:var(--accent-hover);color:var(--on-accent)}
.btn.ghost{background:transparent;color:var(--accent)}
.btn.ghost:hover{background:var(--accent);color:var(--on-accent)}

/* essay list */
.section-title{font-family:var(--sans);font-size:.75rem;font-weight:700;
  letter-spacing:.16em;text-transform:uppercase;color:var(--heading);
  padding-bottom:var(--space-2xs);border-bottom:1px solid var(--line);
  --flow-space:var(--space-xl)}
.section-title+*{--flow-space:var(--space-2xs)}
.postlist{list-style:none;padding:0}
.postlist li{border-bottom:1px solid var(--line)}
.postlist a{display:block;padding-block:var(--space-m);text-decoration:none;color:inherit}
/* The gap above a list is the flow gap. The first row must not add to it. */
.postlist li:first-child a{padding-block-start:0}
.postlist a:hover h3{color:var(--link)}
.postlist h3{font-family:var(--sans);font-weight:700;font-size:1.28rem;
  letter-spacing:-.02em;line-height:1.25;margin:0 0 var(--space-3xs);transition:color .12s}
.postlist p{margin:0;color:var(--ink-soft);font-size:1rem}
.postlist time{font-family:var(--sans);font-size:.76rem;font-weight:600;
  letter-spacing:.08em;text-transform:uppercase;color:var(--ink-faint);
  display:block;margin-bottom:var(--space-3xs)}

/* /top-10. The rank comes from CSS counters, so reordering TOP10 in build.py
   renumbers the page and nothing in the markup has to agree with itself. */
.top10-hero{width:100%;height:auto;border-radius:8px}
.ranklist{list-style:none;padding:0;counter-reset:rank}
/* The grid sits on the li, not on an anchor, so only the title is clickable.
   Exactly two grid children: the ::before counter, and one div holding the
   title and the hook. Put the h3 and the p in the grid directly and the hook
   drops onto a second row inside the number column. */
.ranklist li{border-bottom:1px solid var(--line);counter-increment:rank;
  display:grid;grid-template-columns:2.4rem minmax(0,1fr);gap:var(--space-s);
  padding-block:var(--space-m)}
.ranklist li:first-child{padding-block-start:0}
.ranklist li::before{content:counter(rank);font-family:var(--sans);font-weight:800;
  font-size:1.65rem;line-height:1.15;letter-spacing:-.04em;color:var(--display-accent)}
.ranklist h3{font-family:var(--sans);font-weight:700;font-size:1.28rem;
  letter-spacing:-.02em;line-height:1.25;margin:0 0 var(--space-3xs)}
.ranklist h3 a{color:var(--link);text-decoration:none}
.ranklist h3 a:hover{color:var(--link-hover);text-decoration:underline}
.ranklist p{margin:0;color:var(--ink-soft);font-size:1rem}
@media(max-width:34rem){.ranklist li{grid-template-columns:1.9rem minmax(0,1fr);
    gap:var(--space-xs)}
  .ranklist li::before{font-size:1.3rem}}

/* global essay furniture -- see ESSAY_HEADER / SUPPORT in build.py */
.ehead{font-family:var(--sans);font-size:.94rem;line-height:1.55;color:var(--ink-soft);
  background:var(--paper-2);border-left:3px solid var(--rule);border-radius:0 8px 8px 0;
  padding:var(--space-s) var(--space-m)}
.ehead a{color:var(--link);font-weight:650}
/* A divided block spends the flow gap above its rule and its own padding
   below it. Two numbers, both deliberate, neither one an accident. */
.efoot{padding-block-start:var(--space-xl);border-top:1px solid var(--line);
  --flow-space:var(--space-xl)}
.efoot>section+section{padding-block-start:var(--space-xl);
  border-top:1px solid var(--line)}
.efoot h2{font-family:var(--sans);font-weight:800;letter-spacing:-.02em;
  font-size:1.35rem}
.efoot h2+*{--flow-space:var(--space-s)}
.efoot h2 a{color:inherit;text-decoration:none}
.efoot h2 a:hover{color:var(--link)}
.efoot p{color:var(--ink-soft);--flow-space:var(--space-s)}
.efoot img{border-radius:8px;--flow-space:var(--space-m)}
.scale-label{font-family:var(--sans);font-size:.85rem;font-weight:650;
  letter-spacing:.02em;--flow-space:var(--space-m)}
.scale-label+*{--flow-space:var(--space-2xs)}
.tiers{display:flex;flex-wrap:wrap;gap:var(--space-2xs)}
.tier{font-family:var(--sans);font-weight:700;font-size:1rem;
  padding:var(--space-2xs) var(--space-xs);
  border:1px solid var(--line);border-radius:8px;text-decoration:none;color:var(--link);
  transition:background .15s,border-color .15s,color .15s,transform .15s,box-shadow .15s}
/* A live tier fills magenta, turns white, lifts 2px and takes a mint edge.
   Not the azure of the Buy Me a Coffee button beside it: same gesture,
   different colour, because it is a different thing.

   The edge is 1px, the border the tier already carries at rest, recoloured.
   No ring: 2px of turquoise on magenta read as heat however far the colour
   was dimmed, and the thinner line was what actually fixed it. Nothing here
   changes the box size either, so nothing shifts under the pointer. */
.tier:hover{border-color:var(--tier-edge);background:var(--tier-fill);
  color:var(--tier-ink);transform:translateY(-2px);
  box-shadow:0 5px 14px rgba(0,0,0,.2)}
.tier:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.tier:active{transform:translateY(0);box-shadow:none}
/* No payment link yet. Rendered flat so it never looks clickable -- and that
   has to include hover. .tier.off and .tier:hover score the same specificity
   (0,2,0), so .tier.off wins on source order and keeps its grey text, but
   nothing was cancelling .tier:hover's accent background. Grey on azure is
   1.06:1 in light mode and 1.06:1 in dark: the amount is invisible, on the
   exact element somebody is pointing at. A dead tier takes no hover at all. */
.tier.off{color:var(--ink-faint);cursor:default}
/* A tier with no link yet fills as well, so the gesture matches, but with the
   soft neutral instead of the brand colour and with no shadow and half the
   lift. Side by side the difference is obvious: one is saturated and floating,
   the other is flat and quiet. Text stays 8.97:1 light, 8.63:1 dark. */
.tier.off:hover{background:var(--tier-off-fill);border-color:var(--tier-off-fill);
  color:var(--tier-off-ink);transform:translateY(-1px);box-shadow:none}
/* A dead tier gets no edge and no ring. That is the tell: a live price wears a
   mint outline and floats, a price you cannot pay yet is flat and edgeless. */
@media(prefers-reduced-motion:reduce){
  .tier{transition:background .15s,border-color .15s,color .15s}
  .tier:hover,.tier.off:hover{transform:none}}

/* article */
.article{padding-block:var(--space-2xl) var(--space-s)}
.article h1{font-family:var(--sans);font-weight:800;letter-spacing:-.035em;color:var(--heading);
  font-size:clamp(2.1rem,5.5vw,3.15rem);line-height:1.06}
.article .sub{font-size:1.2rem;color:var(--ink-soft);line-height:1.45}
.meta{font-family:var(--sans);font-size:.78rem;font-weight:600;letter-spacing:.09em;
  text-transform:uppercase;color:var(--ink-faint)}
.prose h2{font-family:var(--sans);font-weight:800;letter-spacing:-.025em;color:var(--heading);
  font-size:1.85rem;line-height:1.15;--flow-space:var(--space-xl)}
.prose h3{font-family:var(--sans);font-weight:750;letter-spacing:-.02em;
  font-size:1.4rem;line-height:1.2;--flow-space:var(--space-l)}
.prose h4{font-family:var(--sans);font-weight:700;font-size:1.12rem;
  line-height:1.3;color:var(--ink);--flow-space:var(--space-m)}
/* Whatever follows a heading belongs to it, so it sits closer. */
.prose :is(h2,h3,h4)+*{--flow-space:var(--space-s)}
.prose ul,.prose ol{padding-left:var(--space-m)}
.prose li+li{margin-block-start:var(--space-2xs)}
/* Substack wraps every list item's text in a paragraph. The reset above
   flattens it; this is the gap between two of them in one item. */
.prose li>p+p{margin-block-start:var(--space-2xs)}
.prose blockquote{padding-left:var(--space-m);
  border-left:3px solid var(--rule);color:var(--ink-soft);font-style:italic;
  --flow-space:var(--space-l)}
.prose figure{--flow-space:var(--space-l)}
.prose figcaption{font-family:var(--sans);font-size:.83rem;color:var(--ink-faint);
  margin-top:var(--space-2xs);line-height:1.45}
.prose img{margin-inline:auto}

/* headlines of hope */
.hoh-toc{background:var(--paper-2);border:1px solid var(--line);border-radius:10px;
  padding:var(--space-m)}
.hoh-toc h2{font-family:var(--sans);font-size:.75rem;font-weight:700;letter-spacing:.16em;
  text-transform:uppercase;color:var(--heading);margin:0 0 var(--space-xs)}
.hoh-toc ul{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;
  gap:var(--space-2xs)}
.hoh-toc a{font-family:var(--sans);font-size:.86rem;font-weight:650;text-decoration:none;
  padding:var(--space-3xs) var(--space-xs);border:1px solid var(--line);border-radius:99px;
  background:var(--paper);color:var(--ink-soft)}
.hoh-toc a:hover{border-color:var(--hover-border);color:var(--link)}
.vol{scroll-margin-top:var(--space-xl)}
.prose h3.vol{border-top:1px solid var(--line);padding-block-start:var(--space-xl);
  --flow-space:var(--space-xl)}

/* video embeds -- see youtube_embed() in build.py */
.prose .embed{position:relative;aspect-ratio:16/9;border-radius:8px;
  overflow:hidden;background:var(--paper-2);border:1px solid var(--line);
  --flow-space:var(--space-l)}
.prose .embed iframe{position:absolute;inset:0;width:100%;height:100%;border:0}
/* Only feed readers see this. They strip iframes, and a silent gap in the RSS
   is worse than a link. On the site the player is right there. */
.prose .embed-fallback{display:none}

/* cards */
.cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(15rem,1fr));
  gap:var(--space-s)}
.card{border:1px solid var(--line);border-radius:10px;padding:var(--space-m);
  background:var(--paper-2);text-decoration:none;color:inherit;display:block}
.card:hover{border-color:var(--hover-border)}
.card h3{font-family:var(--sans);font-size:1.08rem;font-weight:700;
  margin:0 0 var(--space-3xs);letter-spacing:-.015em}
.card p{font-family:var(--sans);font-size:.88rem;color:var(--ink-soft);margin:0;line-height:1.5}
.card .tag{font-family:var(--sans);font-size:.68rem;font-weight:700;letter-spacing:.13em;
  text-transform:uppercase;color:var(--label);display:block;margin-bottom:var(--space-2xs)}
/* The featured card on /top-10: square animation left, words right. The image
   is square already, but object-fit keeps it square if it is ever swapped for
   something that is not. */
.card.feature{display:grid;grid-template-columns:9.5rem minmax(0,1fr);
  gap:var(--space-m);align-items:center}
.card.feature img{display:block;width:100%;aspect-ratio:1;object-fit:cover;
  border-radius:8px;background:var(--paper-2)}
.card.feature h3{font-size:1.22rem;line-height:1.25;margin:0 0 var(--space-3xs)}
.card.feature .more{display:inline-block;margin-top:var(--space-2xs);font-family:var(--sans);
  font-size:.85rem;font-weight:700;color:var(--link);transition:color .12s}
.card.feature:hover .more{color:var(--link-hover)}
@media(max-width:34rem){.card.feature{grid-template-columns:1fr;gap:var(--space-s)}
  .card.feature img{max-width:10rem}}

.book{display:grid;grid-template-columns:minmax(0,14rem) minmax(0,1fr);
  gap:var(--space-xl);align-items:start;
  padding-block:var(--space-2xl) var(--space-s)}
.book h1{font-family:var(--sans);font-weight:800;letter-spacing:-.035em;color:var(--heading);
  font-size:clamp(1.9rem,5vw,2.8rem);line-height:1.05}
.book p{font-size:1.05rem;color:var(--ink-soft);max-width:34rem;--flow-space:var(--space-s)}
.book img{border-radius:6px;box-shadow:0 8px 30px rgba(0,0,0,.16)}
.book .btn{margin-right:var(--space-2xs)}
.book h2{font-family:var(--sans);font-weight:800;letter-spacing:-.03em;color:var(--heading);
  font-size:clamp(1.6rem,4vw,2.2rem);line-height:1.08}
.book.ebook{border-top:1px solid var(--line);padding-block-start:var(--space-xl);
  --flow-space:var(--space-xl)}
/* The ebook cover's own title band: Golden Hour on Cosmic Periwinkle, 5.7:1. */
.soon{display:inline-block;font-family:var(--sans);font-size:.72rem;font-weight:700;
  letter-spacing:.14em;text-transform:uppercase;background:var(--cosmic);
  color:var(--golden)!important;padding:var(--space-3xs) var(--space-xs);border-radius:99px}
/* Affiliate disclosure. Secondary, never faint -- the FTC wants it clear and
   conspicuous, so no opacity tricks and no shrinking this below .85rem. */
.fine{font-size:.85rem;color:var(--ink-soft);max-width:30rem;--flow-space:var(--space-l)}
@media(max-width:40rem){.book{grid-template-columns:1fr;gap:var(--space-m);
    padding-block-start:var(--space-xl)}
  .book>div:first-child{max-width:13rem}}
.note{background:var(--paper-2);border-left:3px solid var(--gold);border-radius:0 8px 8px 0;
  padding:var(--space-s) var(--space-m);font-family:var(--sans);font-size:.93rem;
  color:var(--ink-soft);line-height:1.6}
.note strong{color:var(--ink)}

footer.site{border-top:1px solid var(--line);margin-top:var(--space-2xl);
  padding-block:var(--space-xl) var(--space-2xl);
  font-family:var(--sans);font-size:.86rem;color:var(--ink-faint);
  --flow-space:var(--space-s)}
footer.site a{color:var(--ink-soft);text-decoration:none;margin-right:var(--space-s)}
footer.site a:hover{color:var(--link)}
footer.site .fine{font-size:.78rem;--flow-space:var(--space-s)}
footer.site .disclosure{font-size:.85rem;color:var(--ink-faint);--flow-space:var(--space-2xs)}
.sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0)}
@media(max-width:760px){
  body{font-size:1.12rem}
  .hero{padding-block:var(--space-xl) var(--space-l)}
  .hero.plain{padding-block:var(--space-xl) 0}
  .masthead{position:static}
  .masthead .wrap{flex-direction:column;align-items:flex-start;gap:var(--space-2xs);
    padding-block:var(--space-2xs)}
  .nav{margin-left:0;gap:var(--space-xs);width:100%;overflow-x:auto;
    -webkit-overflow-scrolling:touch;scrollbar-width:none;padding-bottom:var(--space-3xs)}
  .nav::-webkit-scrollbar{display:none}
  .vol{scroll-margin-top:var(--space-s)}
  .signup form{flex-direction:column;align-items:stretch}
  .signup input[type=email]{flex:0 0 auto;width:100%}
  .signup .btn{width:100%}
}
