/* ===========================================================================
   supermodelsurvival.com — the shared reader system
   ===========================================================================
   ONE stylesheet for the five PUBLIC pages:
     home.html  chapter-one.html  book-two.html  chris-white.html  thank-you.html

   It is deliberately NOT used by index.html. index.html is the GATED literary
   agent pitch at caseybobby.buzzboxmedia.com/book/ and it keeps its own inline
   <style>. Two audiences, two templates, one set of source text. Chris's prose
   is never duplicated: every public page draws it from synopsis.json and
   chapter1.json and the deploy inlines the SAME anchored trims into the markup.
   What is duplicated here is layout, not text.

   TYPE. Playfair Display 400/500 and Inter 400/500/600. Nothing heavier, ever.
   Inter is NEVER set in italic: the variable file has no true italic and the
   @font-face for it points back at the upright, so an italic request renders
   upright. Every editorial italic on this property is Playfair Display Italic.

   GROUND. Cream is Oyster Bay and the novel; the page goes dark only where the
   story does. Three dark surfaces exist on this site and no others: the storm
   hero, the two full-bleed Register B plates, and the cover inset in the two
   books section. Never harmonize a dark plate into the cream. The break is the
   point.

   FORBIDDEN, and these are hard: no pill, chip or badge shapes (corners stay
   square, emphasis comes from tracking and a gold hairline). No decorative
   horizontal rules; the only two rules in this file are the structural
   hairlines that close the masthead and open the footer, and they are the same
   token. No em dashes, no en dashes, no arrows, no emoji. No "we", "us", "our".
   No single word alone on a line at any width, in any element, nav items and
   buttons included.
   ========================================================================= */

:root{
  --cream:#f5f0e5; --cream2:#ede4d2; --paper:#fbf7ec;
  --ink:#1a1712; --ink-soft:#332d22;
  --gold:#b0863a; --gold-lt:#c9a84c;
  /* #88672d, not --gold. Measured on the cream ground --gold is 2.93:1 and
     every use below is small uppercase, which needs 4.5:1 for text and 3:1 for
     a focus ring. #88672d is 4.59:1 in the same hue family. */
  --gold-ink:#88672d;
  --hair:rgba(176,134,58,.28);
  --crimson:#8f2d3b; --charcoal:#14161c;
  /* ONE secondary ink, and --muted is gone rather than merely unused. It was
     #8a8272, carved out as "a CAPTION colour only" on the reasoning that an
     editorial italic at 16px was decorative enough to sit below the bar. It is
     not: a plate caption is the sentence that says who the two women are, it
     measured 3.35:1 on the cream, and WCAG 2.2 AA asks 4.5:1 of any text under
     18.66px. --dim measures 5.21:1 and every other piece of secondary text on
     this property (.cfnote, .cutlink, .tag, .copy, the kickers) already used
     it, so the fix is the palette losing an exception, not gaining a colour.
     --ash-dim #7a7469 was considered and rejected: 4.08:1 still fails. */
  --dim:#6b6357;
  /* MEASURED from web-cover-mockup.jpg's own 8px border, not picked by eye. The
     mockup carries its dark field baked into the file, so any ground behind it
     that differs in lightness OR hue draws a visible rectangle where the image
     ends. Re-measure if the mockup is ever re-exported. */
  --mockup-field:#060809;
  --display:'Playfair Display',Georgia,'Times New Roman',serif;
  --serif:'Playfair Display',Georgia,'Times New Roman',serif;
  --sans:'Inter',-apple-system,BlinkMacSystemFont,sans-serif;
}

*{ margin:0; padding:0; box-sizing:border-box; }
html{ scroll-behavior:smooth; -webkit-text-size-adjust:100%; }
@media (prefers-reduced-motion:reduce){ html{ scroll-behavior:auto; } }
body{ background:var(--cream); color:var(--ink); font-family:var(--sans);
  font-weight:400; -webkit-font-smoothing:antialiased; }
img{ display:block; }

/* ── THE MASTHEAD ────────────────────────────────────────────────────────────
   A slim cream bar, not a chrome bar. No background fill, no shadow, no pill
   around the current page, one hairline beneath. Sticky nowhere, on any width:
   a fixed bar would float over the storm and over the two plates, and nothing
   on this property is allowed to sit on a figure. */
.nav{ display:flex; align-items:baseline; justify-content:space-between;
  gap:clamp(16px,3vw,40px); padding:20px clamp(20px,6vw,64px) 15px;
  border-bottom:1px solid var(--hair); }
.nav .mark{ font-family:var(--display); font-weight:500;
  font-size:clamp(17px,1.5vw,20px); letter-spacing:.03em; color:var(--ink);
  text-decoration:none; white-space:nowrap; }
.nav .mark:hover{ color:var(--gold-ink); }
.navlinks{ display:flex; gap:clamp(15px,2.2vw,30px); }
/* white-space:nowrap is not styling here, it is the no-single-word-on-a-line
   rule: "Chapter One" and "Chris White" are two words each and either would
   strand its second word the moment the row got tight. */
.navlinks a{ font-family:var(--sans); font-weight:500; font-size:12px;
  letter-spacing:.2em; text-transform:uppercase; color:var(--dim);
  text-decoration:none; white-space:nowrap; transition:color .18s ease; }
.navlinks a:hover{ color:var(--ink); }
/* ── TOUCH TARGETS ──────────────────────────────────────────────────────────
   WCAG 2.2 SC 2.5.8 wants 24 x 24 CSS px. Every text link on this property is
   set at 11 to 13px, so the hit area WAS the height of the type: 15px in the
   masthead, 16px in the footer, 17px on a .cutlink. On a phone that is a
   coin-flip tap, and this audience is overwhelmingly phones.
   PADDING GROWS THE TARGET, AN EQUAL NEGATIVE MARGIN GIVES THE SPACE BACK, so
   the margin box stays exactly the box it was and nothing on any page moves.
   That is the whole trick and it is why this is safe to apply to five different
   layouts at once; the snapshot diff over five pages at five widths is the
   proof, not the reasoning.
   TWO CONSEQUENCES WERE REAL AND ARE HANDLED BELOW rather than left to be found
   later. First, a grown target is 39px tall inside a 15px margin box, so
   anywhere these STACK the two hit areas overlap unless the row gap clears
   24px: the footer nav wraps to two rows under about 420px and the thank-you
   onward list is a column, and both ran a 14px row gap. Second, four rules set
   an explicit margin-top on a .cutlink (five, counting .bio .hfa); each is
   re-expressed 12px lower so the
   visible gap is unchanged. Change one of those numbers and you move the page. */
.navlinks a, .foot .fnav a, .cutlink, .nav .mark{ padding:12px 4px; margin:-12px -4px; }
/* The wordmark is in the list for the same reason and with one extra note: the
   masthead is baseline aligned, and equal padding with an equal negative margin
   leaves the distance from the margin box's top edge to the first baseline
   exactly where it was, so baseline alignment is preserved rather than merely
   survived. It was 128 x 22 and it is the link every reader taps to get home. */

.navlinks a[aria-current="page"]{ color:var(--gold-ink); }
.nav a:focus-visible, .foot a:focus-visible{ outline:2px solid var(--gold-ink);
  outline-offset:3px; }

/* Under 640 the bar stacks: wordmark on its own line, then the three links on
   ONE row, all three still visible. No hamburger. Three items do not earn a
   menu, and a menu on a four page site is chrome pretending to be structure.
   The size floor tracks the viewport below 390 so the row cannot wrap and
   strand a word; at 390, the tested phone width, it holds the specified 13px. */
@media (max-width:640px){
  .nav{ flex-direction:column; align-items:center; gap:11px; padding:16px 5vw 13px; }
  .navlinks{ gap:min(18px,4.2vw); }
  .navlinks a{ font-size:min(13px,3.33vw); letter-spacing:.16em; }
}

/* ── THE FOOTER ──────────────────────────────────────────────────────────── */
/* Cream, like the rest of the page. The old charcoal band was a deck close,
   and a reader page does not end by going dark; it ends by running out of
   paper. The hairline above is the same token as the masthead's, so the page is
   opened and closed by the same line rather than by a decorative rule. */
.foot{ border-top:1px solid var(--hair); margin-top:clamp(64px,9vh,110px);
  padding:clamp(46px,7vh,72px) clamp(20px,6vw,64px) clamp(44px,6vh,60px);
  text-align:center; }
.foot .tag{ font-family:var(--serif); font-style:italic; font-weight:400;
  font-size:clamp(17px,1.7vw,19px); line-height:1.5; letter-spacing:.02em;
  color:var(--dim); }
/* ROW GAP 26, NOT 14. Four links do not fit on one row under about 420px, and
   two 39px hit areas 14px apart overlap by 10px, which is a mis-tap rather than
   a violation. 26 clears the 24px target height with 2px to spare. Above 420
   the row never wraps and this value is never used. */
.foot .fnav{ display:flex; flex-wrap:wrap; justify-content:center;
  gap:26px clamp(16px,2.4vw,30px); margin-top:clamp(26px,3.4vh,34px); }
.foot .fnav a{ font-family:var(--sans); font-weight:500; font-size:12px;
  letter-spacing:.2em; text-transform:uppercase; color:var(--dim);
  text-decoration:none; white-space:nowrap; transition:color .18s ease; }
.foot .fnav a:hover{ color:var(--ink); }
.foot .copy{ margin-top:clamp(24px,3vh,32px); font-family:var(--sans);
  font-weight:500; font-size:11px; letter-spacing:.3em; text-transform:uppercase;
  color:var(--dim); }

/* ── PAGE FURNITURE ──────────────────────────────────────────────────────── */
.sec{ padding:clamp(64px,10vh,124px) clamp(20px,7vw,64px); }
.sec.tight{ padding-top:clamp(44px,6vh,72px); padding-bottom:clamp(44px,6vh,72px); }
.mid{ max-width:1120px; margin:0 auto; }
.kicker{ font-family:var(--sans); font-weight:600; font-size:12px;
  letter-spacing:.34em; text-transform:uppercase; color:var(--gold-ink); }
h1,h2,h3{ font-family:var(--display); font-weight:500; letter-spacing:.012em;
  color:var(--ink); }
.h-lg{ font-size:clamp(30px,4.1vw,46px); line-height:1.14; }
.h-md{ font-size:clamp(25px,2.8vw,34px); line-height:1.2; }
/* the block is CENTRED and the text inside it is not. Left-aligned inside a
   1120px container the synopsis hung against the far edge with an empty right
   half, under a plate that is centred, and the page read as two different
   layouts stacked. Centring the measure fixes it without touching the measure
   itself, which the guide caps at reading width for a reason. */
/* 52ch, NOT 64ch, and the two numbers describe the same measure. `ch` is the
   advance width of a ZERO, and Inter's zero is tabular and wider than its
   average lowercase letter, so a 64ch box renders about 79 characters: measured
   79 on the home synopsis and 81 on the bio, against the BRAND-GUIDE 1.4 cap of
   52 for body prose. 52ch lands at roughly 64 rendered characters, which is the
   measure the guide is actually asking for. Do not "restore" 64: the unit lies. */
.prose{ font-family:var(--sans); font-weight:400; font-size:17px; line-height:1.75;
  color:var(--ink-soft); max-width:52ch; margin-left:auto; margin-right:auto;
  text-wrap:pretty; }
.prose p + p{ margin-top:18px; }
.center{ text-align:center; }
.center .prose{ margin-left:auto; margin-right:auto; }

/* the display statement. Capped at 24ch per the guide's 20 to 26ch band, with
   the last two words of each sentence bound in the markup so neither line can
   ever end on a word by itself. */
.stmt{ font-family:var(--display); font-weight:500;
  font-size:clamp(24px,3.1vw,38px); line-height:1.26; letter-spacing:.012em;
  color:var(--ink); max-width:24ch; margin:0 auto; }

/* THE DOOR ONE SWAP TARGET. Nothing uses this today and that is deliberate.
   THE SWAP, IN PROSE, AND IT IS WRITTEN IN PROSE ON PURPOSE. When the Book One
   download URL exists, delete the <form> in the two books section of home.html
   and put in its place a single anchor carrying the class dgo, the real
   download URL as its href, and the words Read It Free as its text. No CSS
   moves and nothing else on the page moves.
   IT IS NOT WRITTEN OUT AS MARKUP, HERE OR ANYWHERE. The previous version of
   this comment spelled the anchor out with a placeholder https URL in it, and
   so did home.html, while this same comment asserted that no such thing existed
   in the shipped markup. Both files went out with it and the assertion was
   simply false. A placeholder URL inside a comment is one careless uncomment
   from being a live link to nowhere, so the deploy now aborts if any staged
   file carries an href pointing at an ellipsis placeholder. That check is why
   this paragraph describes the swap instead of showing it. Do not write the
   anchor out here to save yourself typing it later.
   Deliberately not gold filled: one door submits and one navigates, and
   flattening that difference would leave the section with no primary action at
   all. */
.dgo{ display:block; text-align:center; text-decoration:none;
  font-family:var(--sans); font-weight:600; font-size:12px; letter-spacing:.2em;
  text-transform:uppercase; white-space:nowrap; margin-top:16px;
  padding:13px 18px; border:1px solid rgba(176,134,58,.75);
  background:rgba(176,134,58,.10); color:var(--ink);
  transition:background-color .18s ease, color .18s ease; }
.dgo:hover, .dgo:focus-visible{ background:var(--gold); color:#141109; }

/* the quiet text link idiom used everywhere on this property instead of a
   secondary button. text-decoration, NOT border-bottom: a border on a
   blockified flex item spans the whole column and reads as the decorative
   horizontal rule the house rules ban, while an underline is drawn on the words
   themselves and stops where they stop, at any width. */
.cutlink{ display:inline-block; font-family:var(--sans); font-weight:500;
  font-size:12.5px; letter-spacing:.06em; color:var(--dim);
  text-decoration:underline; text-decoration-color:rgba(176,134,58,.75);
  text-decoration-thickness:1px; text-underline-offset:4px;
  transition:color .18s ease; }
.cutlink:hover{ color:var(--ink); }
.cutlink:focus-visible{ outline:2px solid var(--gold-ink); outline-offset:3px; }

/* ── THE STORM HERO ──────────────────────────────────────────────────────────
   Register B, and the only place on this site where the page opens dark. The
   masthead and the hero share one flex column so the pair fills exactly one
   screen: the hero takes whatever the bar does not, which is the same guarantee
   as 100svh without a magic number for the bar's height.

   svh, not vh. On iOS Safari, vh is the viewport WITHOUT its chrome, so at
   first paint the browser bars overlay the bottom of a 100vh box and eat the
   action link. svh is the small viewport, which is the one that is actually on
   screen while the chrome is showing.

   COVER-CROP IS CORRECT HERE and the letterbox rule for narrow screens does not
   apply. That rule exists to stop a lead being sliced out of frame by a hard
   sideways crop, and this image contains no people at all. At 390 the centre
   crop keeps the lightning and loses the dock, which is the right thing to
   lose. */
/* 100svh MINUS a sliver, and the sliver is the point. At exactly one screen
   the hero terminated on the fold with not one pixel of the next section
   showing, so the page had a false bottom: measured, the first cream pixel
   landed at y=664 at 664, y=844 at 390 and y=900 at 1440, dead on the fold at
   all three. 52px hands the top of the promise section to the first screen,
   which is the only signal a reader gets that there is a page under the storm.
   It costs the hero nothing: its bottom 320px is open water with no type in it.
   No arrow, no chevron, no scroll cue, no copy. The next section peeking IS the
   cue, and it is the only one this property is allowed. */
.top{ min-height:calc(100svh - 52px); display:flex; flex-direction:column; }
.hero{ position:relative; flex:1 1 auto; display:flex; align-items:flex-start;
  min-height:min(560px,72svh); background:var(--mockup-field); overflow:hidden; }
.hero .heroimg{ position:absolute; inset:0; width:100%; height:100%;
  object-fit:cover; object-position:50% 42%; }
/* the type sits on OPEN SKY at upper left and nowhere else. Measured on the
   source: that region runs mean luminance 17 and peaks at 43 of 255, so bone
   type clears 12:1 there and needs no scrim of any kind. The lightning glow
   sits at roughly 50 to 67 percent across and 50 to 67 percent down, which is
   why the block is capped in width and never reaches the lower middle.
   No gradient under the type: the composition already provides its own
   contrast, and every scrim is a chance to darken something that must not be
   darkened. */
/* anchored to the TOP of the frame, not centred in it. Centred, the block lands
   around the halfway mark, which is exactly where the lightning glow sits. */
.hero .htype{ position:relative; z-index:2; width:100%;
  padding:clamp(28px,9svh,96px) clamp(20px,7vw,80px) clamp(32px,5svh,64px);
  max-width:min(900px,100%); }
/* SIZED SO THE LONGER LINE CANNOT WRAP, at any width this site is read at.
   "SUPERMODEL SURVIVAL" is 19 uppercase glyphs; Playfair caps average about
   .62em of advance and the lockup adds .045em of tracking per glyph, so the
   line measures roughly 12.6 x the font size. Against the block's own available
   width that gives a ceiling of about 26px at 390, 52px at 768 and 59px at
   1440, and the clamp below sits under all three. That matters more than it
   looks: a wrap here strands "SURVIVAL" alone on a line, which is the one
   typographic rule this property enforces at every width. The QA pass measures
   scrollWidth against clientWidth rather than trusting the arithmetic. */
.hero .htitle{ font-family:var(--display); font-weight:500; text-transform:uppercase;
  font-size:clamp(21px,6.05vw,53px); line-height:1.06; letter-spacing:.045em;
  color:#f4efe4; }
.hero .htitle .l1, .hero .htitle .l2{ display:block; white-space:nowrap; }
.hero .hcredit{ font-family:var(--sans); font-weight:400;
  font-size:clamp(12.5px,1.05vw,14.5px); letter-spacing:.2em; text-transform:uppercase;
  color:#c8c0ad; margin-top:clamp(16px,2.2vh,24px); }
.hero .htag{ font-family:var(--serif); font-style:italic; font-weight:400;
  font-size:clamp(16px,1.55vw,22px); line-height:1.45; letter-spacing:.01em;
  color:#e3dbc8; margin-top:clamp(14px,2vh,22px); max-width:26ch; }
/* THE HERO'S ONE ACTION GETS THE SAME TOUCH TARGET AS EVERY OTHER LINK, and it
   is the one that most needed it: 12.5px type gave it a 15px hit area, on the
   single most important control on the property, on the first screen of a phone.
   The margin is written out longhand rather than inherited from the shared
   TOUCH TARGETS rule because .hero .hgo out-specifies it: the top value is the
   original clamp less the 12px of new padding, so the gap above the link is
   unchanged to the pixel. */
.hero .hgo{ display:inline-block; padding:12px 4px;
  margin:calc(clamp(22px,3.4vh,38px) - 12px) -4px -12px;
  font-family:var(--sans); font-weight:500; font-size:12.5px; letter-spacing:.24em;
  text-transform:uppercase; color:var(--gold-lt); text-decoration:underline;
  text-decoration-color:rgba(201,168,76,.7); text-decoration-thickness:1px;
  text-underline-offset:6px; white-space:nowrap; transition:color .18s ease; }
.hero .hgo:hover{ color:#f0e2b6; }
.hero .hgo:focus-visible{ outline:2px solid var(--gold-lt); outline-offset:4px; }
@media (max-width:760px){
  /* the crop narrows to the middle of the frame on a phone, so the type block
     takes the full width rather than sitting in a 58% column that would put its
     right edge over the lightning */
  .hero .htype{ max-width:100%; }
  .hero .htag{ max-width:24ch; }
}

/* ── REGISTER A: a plate tipped into a book ──────────────────────────────────
   Contained, never full bleed. The warm grade (sepia .16 / sat .92 /
   contrast 1.02 / bright 1.02) and the shared grain are BAKED INTO the JPEGs,
   not applied here: a CSS filter on an <img> makes Chrome rasterize the whole
   page when it is written to PDF, which took the pitch PDF from 2.4 MB to
   17.7 MB. Bake script: tasks/pitch-deck/bake-photos.py */
.figsec{ padding:clamp(56px,8vh,96px) clamp(20px,7vw,64px);
  display:flex; flex-direction:column; align-items:center; }
.figure-warm{ position:relative; width:fit-content; max-width:min(760px,92vw);
  margin:0 auto; isolation:isolate; }
.figure-warm .fw-img{ position:relative; display:block; }
.figure-warm img{ max-width:100%; max-height:64vh; width:auto; height:auto;
  box-shadow:0 24px 60px rgba(60,40,15,.22); }
/* a paper edge, not a photo border: the gold hairline is held 10px OFF the
   image so it reads as the edge of a tipped-in plate */
.figure-warm::after{ content:""; position:absolute; inset:-10px;
  pointer-events:none; border:1px solid rgba(176,134,58,.42); }
/* feather TOP ONLY, on both placements. The fence figures run to the bottom
   edge and the Oyster Bay grass bottoms out near luminance 40, so a bottom
   feather fogs into mud. Never left or right. Never over a face. */
.figure-warm .feather{ position:absolute; inset:0; z-index:2; pointer-events:none;
  background:linear-gradient(to bottom, rgba(245,240,229,.55) 0%, rgba(245,240,229,0) 14%); }
/* --dim, not the old --muted. Two live instances, "Casey and Bobbie." on / and
   the Oyster Bay caption on /chapter-one/, both of which failed AA at 3.35:1.
   The italic is unchanged; only the ink moved. */
.figsec .caption{ font-family:var(--serif); font-style:italic; font-weight:400;
  font-size:16px; line-height:1.45; color:var(--dim); margin-top:30px;
  text-align:center; max-width:54ch; }
/* landscape source (1.83): cap by height so the whole section, caption
   included, stays inside one screen */
.figsec.wide .figure-warm{ max-width:min(1040px,92vw); }
.figsec.wide .figure-warm img{ max-height:70vh; }

/* ── /chapter-one/ ABOVE THE FOLD ───────────────────────────────────────────
   Measured at 664 before this block: plate 143 to 318, caption 354 to 412,
   "Chapter One" 524 to 552, and the drop cap's first ink at 661, three pixels
   above the fold. The page whose only job is to be read opened with no prose on
   it at all, and the two gaps carrying that were 112px and 109px, both of them
   the sum of one section's bottom padding and the next one's top padding.
   Halve both, below 760 only. Nothing above 760 moves: the desktop first screen
   already reaches the reading block. Target is the drop cap plus three or four
   lines, which is the point at which a stranger is reading rather than
   deciding. */
@media (max-width:760px){
  .figsec{ padding-bottom:clamp(28px,4vh,48px); }
  .sec.tight{ padding-top:clamp(22px,3vh,36px); padding-bottom:clamp(22px,3vh,36px); }
  .reading{ padding-top:clamp(28px,4vh,48px); }
}
/* and a ceiling on the plate for the SHORT viewports, where the gaps alone are
   not the whole story. It does not bind on an upright phone (the 1.83 source
   renders about 195px tall at 390, well under the cap) and it is there for the
   landscape phone and the short dragged window, where 70vh of a 1.83 landscape
   would otherwise eat the screen the words are supposed to be on. */
@media (max-width:760px) and (max-height:700px){
  .figsec.wide .figure-warm img{ max-height:46svh; }
}

/* ── REGISTER B: full bleed ─────────────────────────────────────────────────
   The warm-up (sepia .08 / sat .95) and the grain are baked into web-rise.jpg
   and web-cost.jpg for the same reason as above. */
.plate{ min-height:100svh; position:relative; display:flex; justify-content:center;
  background-size:cover; background-position:center; background-color:#07090e; }
.plate .veil{ position:absolute; inset:0; }
.plate .cap{ position:relative; z-index:2; color:#fbf7ea; }
/* NO KICKER ON A PLATE, and .plate .cap .k is gone rather than merely unused.
   "The Rise" was the last deck kicker left on the property: every other kicker
   on this site is .kicker and names an object a reader can act on (Book One,
   Book Two, Keep Reading), while that one named a section of a pitch document
   and told a stranger they were being walked through one. The <h2> under it
   already names the cities, so nothing was lost with it.
   The h2's margin-top went with it: it was spacing the h2 off the kicker, and
   there is no longer anything above it to be spaced from.
   deliberately NOT text-wrap:balance: with the hard <br> in this caption,
   balance evens the two halves and strands "Dreamed." alone on a line */
.plate .cap h2{ color:#fbf7ea; font-weight:500;
  font-size:clamp(24px,4.1vw,46px); line-height:1.14; }

/* caption LEFT, for web-rise, whose left third measures luminance 20 to 27.
   Text lands in the dark and never on a figure; the lit runway floor stays
   clean. */
.plate.capleft{ align-items:center; justify-content:flex-start; }
.plate.capleft .cap{ text-align:left; padding:0 0 0 7vw; max-width:42%; }
/* the left caption lives in a column, not across the page, so it takes its own
   smaller scale or "Dreamed." ends up stranded */
.plate.capleft .cap h2{ font-size:clamp(22px,2.35vw,34px); }
.plate.capleft .veil{ background:linear-gradient(to right, rgba(8,10,16,.55) 0%, rgba(8,10,16,0) 42%); }
/* mid widths: the crowd rides higher in the left third, so lift the caption
   into the clean dark wall above it rather than onto silhouettes */
@media (min-width:761px) and (max-width:1100px){
  .plate.capleft{ align-items:flex-start; }
  .plate.capleft .cap{ padding-top:19vh; max-width:50%; }
}
/* a wordless plate. No caption, no veil, no kicker: the page ends on the story
   rather than terminating on a form, and there is nothing to keep off a
   figure. */
.plate.bare .veil{ background:none; }

/* The two Register B sources are 0.73 portraits. These positions are chosen so
   the crowns of both heads clear the caption at every width.
   THE STILL IS ATTACHED BY .lit, NOT HERE. A CSS background-image is fetched as
   soon as its element is in the document and there is no lazy equivalent, so
   declaring the url unconditionally pulled 805 KB of below-the-fold photograph
   before the first screen had finished painting. Three readers want it and each
   gets it a different way: reduced motion and a failed clip both add .lit from
   site.js, no JavaScript at all gets it from the page's own <noscript> block,
   and everyone else gets the clip, whose last frame IS this plate. Keep all
   three routes: dropping any one silently breaks that reader. */
#rise{ background-position:50% 4%; }
#cost{ background-position:50% 8%; }
#rise.lit{ background-image:url('/web-rise.jpg'); }
#cost.lit{ background-image:url('/web-cost.jpg'); }
@media (max-width:760px){
  #rise, #cost{ background-position:center bottom; }
}

/* ── LETTERBOX, AND IT IS AN ASPECT RULE RATHER THAN A WIDTH RULE ───────────
   web-rise.jpg and web-cost.jpg are both 1440 x 1973, a 0.73 portrait, and both
   are full-length runway SCENES: two figures inside a machine, a crowd at the
   left, the runway running away underneath. Neither is a portrait of anybody.
   A hard cover-crop is what turns one into a portrait of somebody, and how hard
   it crops is a function of the VIEWPORT'S ASPECT, not of its width:

     visible fraction of the source = (height / width) x 0.7299

   which is 46% at 1440x900, 55% at 1024x768, 97% at 768x1024 and 100% below.
   This block was written as a phone rule because that was the case somebody
   looked at, and the two widest desktop cases are worse than the phone case it
   was written for. At 1440 the crop kept only the top 46% and rendered both
   leads' heads at about 195 CSS px, larger than the fence plate's, both looking
   to camera: a second full-scale instance of the two faces, which BRAND-GUIDE
   3.7 allows exactly once and spends on the fence plate.

   So it is one treatment in two regimes, split on where the letterbox band
   falls rather than on how wide the screen is:

     TALLER than the source (<=760, and any narrow window)  band top and bottom,
       picture anchored bottom, caption centred in the band above it.
     WIDER  than the source (>=761 and aspect >= 5/4)       band left and right,
       and #rise anchors its picture RIGHT so the whole band is one column on
       the left, which is where .capleft's caption already lives.

   BETWEEN THEM, aspect under 5/4 at 761 and up, the plate keeps cover-crop ON
   PURPOSE. That zone is 768x1024 and its neighbours, where the source and the
   viewport are nearly the same shape: cover shows 97% of the picture, so there
   is no defect to fix, and contain would leave a 10px band that no caption can
   live in. Letterboxing there would be the cure inventing the disease. */
@media (max-width:760px){
  .plate{ background-size:contain; background-repeat:no-repeat;
    background-color:#07090e; justify-content:center; }
  .plate{ background-position:center bottom; }
  /* .plate.capleft, NOT .plate. This is the whole fix and it is a specificity
     bug rather than a layout decision. `.plate{align-items:flex-start}` is
     (0,1,0) and it loses to `.plate.capleft{align-items:center}` at (0,2,0)
     further up the file: a media query adds no specificity of its own, so the
     narrow rule never applied and the caption stayed vertically CENTRED in the
     plate, which put it on the figures at 664 and at 390. Measured before the
     fix: the letterboxed still leaves a dead black band of 129px at 664 and
     310px at 390 across the top, and the caption sat 129px and 34px BELOW the
     bottom of that band, i.e. on the photograph, while the band above it was
     empty. BRAND-GUIDE 5.1.3 is HARD: text never touches a figure.
     The 761 to 1100 branch above already writes the selector this way, which is
     why that band has always been correct. */
  .plate.capleft{ align-items:flex-start; }
  .plate.capleft .cap{ text-align:center; padding:6vh 7vw 0; max-width:100%; }
  /* "the caption lands in the black band above" only holds while the
     letterboxed still is short enough to leave one. The band is
     (100svh - imageHeight) and contain makes imageHeight = width / 0.73, so it
     collapses on any viewport wider than about 0.73 of its height: a phone in
     landscape, a short window dragged narrow, an iPhone SE at 320x568. There
     the caption would land on the runway lights, which is exactly what must
     never happen. Restore the guarantee with a top scrim rather than by moving
     the caption or shrinking the still: where the band already exists this
     paints black on black and is invisible, and where it does not it creates
     the dark zone the caption is specified to sit in. */
  .plate.capleft .veil{ background:linear-gradient(to bottom,
    rgba(7,9,14,.92) 0%, rgba(7,9,14,.88) 22%, rgba(7,9,14,.58) 33%, transparent 46%); }
}

/* WIDER THAN THE SOURCE: the band is a column on each side, not a band above.
   Same treatment, the other axis. */
@media (min-width:761px) and (min-aspect-ratio:5/4){
  .plate{ background-size:contain; background-repeat:no-repeat;
    background-color:#07090e; }
  /* THE TWO PLATES ANCHOR DIFFERENTLY AND THE REASON IS THE CAPTION, not taste.
     #cost is wordless, so it centres and takes a band on each side. #rise
     carries the only type on any plate, and centring it would halve the band
     the caption has to live in: 391px at 1440 and 232px at 1024, and 232px
     cannot hold "Cairo. Queensland." at the caption's own size, because those
     two words are bound with a NO-BREAK SPACE and the pair is one unbreakable
     token about 9em wide. Shrinking the type to fit re-breaks the line and
     strands "Milan." alone, which is the widow rule. Anchor the picture right
     instead and the band is ONE column of 783px at 1440 and 463px at 1024, the
     caption keeps the size, position and line breaks it already had, and the
     composition gains: the crowd and the runway come back on the left, under
     the words. */
  #rise{ background-position:right center; }
  #cost{ background-position:center; }
  /* undo the 761-1100 lift: that rule pushed the caption to 19vh because the
     crowd rode high in a cover-cropped left third. There is no cropped left
     third here, there is flat panel, so the caption comes back to centre. */
  .plate.capleft{ align-items:center; }
  /* Cap the caption at the band. contain fits the 0.7299 portrait to the
     plate's HEIGHT, so the picture is height x 0.7299 wide and everything left
     of it is panel; 0.75 rather than 0.7299 is a deliberate 2.7% of slack, so
     the box still clears the picture if the plate ever runs taller than 100svh.
     The 42% is the base rule's own number and binds first at 1440, which is why
     the caption there is pixel-for-pixel what it was. */
  .plate.capleft .cap{ padding:0 0 0 7vw;
    max-width:min(42%, calc(100% - min(100%, 100svh * .75))); }
}

/* ── MOTION PLATES ──────────────────────────────────────────────────────────
   Clips are mounted by site.js from data- attributes, and only for a reader who
   has not asked for reduced motion. Nothing here changes the stills: the no-JS
   page and the reduced-motion page are the page as it would have shipped
   without any of this, not a fallback.

   Stacking on a full-bleed plate: the clip is inserted as the FIRST child and
   .veil is the second, so the veil still paints over the picture and the
   caption (z-index 2) still paints over both. That ordering is the whole reason
   the clip is z-index 0 and inserted rather than appended. Appended, it would
   cover the veil and a caption would sit on a lit figure.

   Every clip is encoded at its plate's own native ratio (1440x1972 against the
   still's 1440x1973), so object-fit has nothing to crop and the tuned
   background-position values carry straight over as object-position.

   WHERE THE PLATE LETTERBOXES, THE CLIP MUST LETTERBOX WITH IT, and in the same
   place. site.js writes data-fit onto the video as an INLINE object-position,
   which no ordinary rule can reach past, so the two letterbox regimes below
   take it back with !important. That is the whole reason those declarations are
   marked and it is the only place on this property that they are. data-fit
   keeps its job in the cover-crop regime, where it is tuned so the crowns clear
   the caption; in a letterbox regime the geometry is decided by the band and
   the value it carries is simply the wrong one. Left as it was, a motion reader
   at 1440 would have seen a centred clip beside a right-anchored still, and a
   motion reader at 390 was already seeing a clip pinned 12px from the TOP while
   the still sat on the bottom, which put the picture directly under the caption
   the narrow branch had just been fixed to clear. */
.mv{ opacity:0; transition:opacity .4s ease; }
.mv.on{ opacity:1; }
.plate .mv{ position:absolute; inset:0; z-index:0; width:100%; height:100%;
  object-fit:cover; pointer-events:none; background:#07090e; }
.fw-img .mv{ position:absolute; inset:0; z-index:1; width:100%; height:100%;
  object-fit:cover; pointer-events:none; }
@media (max-width:760px){
  .plate .mv{ object-fit:contain; object-position:center bottom !important; }
}
@media (min-width:761px) and (min-aspect-ratio:5/4){
  .plate .mv{ object-fit:contain; }
  #rise .mv{ object-position:right center !important; }
  #cost .mv{ object-position:center !important; }
}
@media (prefers-reduced-motion:reduce){ .mv{ display:none !important; } }

/* ── THE READING BLOCK ──────────────────────────────────────────────────────
   Chapter One, 143 paragraphs, and the only genuinely long-form block on the
   property. Set on paper rather than in the cream so the reading surface is
   distinguishable from the page around it, but with no border and no shadow:
   the boxed "paper" card was right for a pitch document being flipped through
   and wrong for a page whose only job is to be read.

   Ragged right, not justified. The pitch version was justified and hyphenated,
   which is how a book is set and not how a browser sets one: with no proper
   h&j the result is rivers and short measure, which is the same failure the
   BRAND-GUIDE names when it bans images inside this block. */
/* ASYMMETRIC, top to bottom, on purpose. The opening air and the closing air
   were the same value, which reads as a box. A chapter that stops mid-scene
   wants a beat of silence before the ask that follows it, so the bottom alone
   runs to about 140px at 1440 while the top stays where it was. */
.reading{ background:var(--paper);
  padding:clamp(56px,8vh,96px) clamp(20px,7vw,56px) clamp(84px,16vh,140px); }
.reading .col{ max-width:34em; margin:0 auto; font-family:var(--serif);
  font-weight:400; font-size:clamp(17px,1.35vw,19px); line-height:1.85;
  letter-spacing:.004em; color:var(--ink); }
/* text-wrap:pretty, and it is doing real work here rather than being a nicety.
   Ragged right over 143 paragraphs produces last lines holding a single word,
   and the house rule against a word alone on a line does not carve out body
   copy. Justifying would have hidden it and bought rivers instead. pretty asks
   the engine to avoid the short last line, which is the same fix a typesetter
   would make and the only one that scales to a whole chapter. */
.reading .col p{ text-indent:1.6em; text-wrap:pretty; }
.reading .col p:first-of-type{ text-indent:0; }
/* Hyphenation ON only on a narrow measure, and off on a wide one. At 390 the
   column is about 336px, roughly 42 characters, and a long word at the end of a
   paragraph ("Massachusetts.") cannot be moved anywhere: text-wrap:pretty has
   nothing to trade and leaves it alone on the last line. Breaking it is the
   only fix that does not touch Chris's words. On the desktop measure the
   column is wide enough that pretty handles it and hyphens would only add
   breaks nobody needs, which is why this is scoped rather than global.
   Justifying the column would hide the same problem behind rivers. */
@media (max-width:760px){
  .reading .col{ hyphens:auto; -webkit-hyphens:auto;
    /* WORD 6, BEFORE 3, AFTER 3. hyphens:auto with no limits gave five
       hyphenated line ends in the first 24 lines at 664, one of them "af-" on
       the very first line beside the drop cap, which is a two-letter fragment
       and reads as a typo rather than as typesetting. Six characters minimum in
       the word and three either side of the break keeps the long breaks that
       are doing real work and kills the short ones that are not.
       The -webkit- pair is not decoration: hyphenate-limit-chars only landed in
       Safari 17, and this audience is overwhelmingly iOS Safari, so an older
       iPhone reads the WebKit properties or reads no limit at all. */
    -webkit-hyphenate-limit-before:3; -webkit-hyphenate-limit-after:3;
    -webkit-hyphenate-limit-chars:6 3 3; hyphenate-limit-chars:6 3 3; }
}
.reading .col p:first-of-type::first-letter{ font-family:var(--display);
  font-weight:500; font-size:3.4em; float:left; line-height:.8;
  padding:.06em .1em 0 0; color:var(--crimson); }

/* ── THE TWO BOOKS ──────────────────────────────────────────────────────────
   The duology, made legible, and the two are NOT symmetric. Equal boxes tell a
   stranger the two things cost the same amount of attention. They do not: Book
   One is free and available in a form today, Book Two is a thing to be told
   about later.

   Book One keeps its frame and its gold control and is the only framed object
   in the section. Book Two loses its border and its vertical padding entirely
   and its control becomes the .cutlink text idiom, so it reads as the reason
   the free book exists rather than as a competing offer, with its own page one
   tap away. */
/* TOP aligned, not centre aligned. Book One is about 900px tall once the cover
   inset is in it, and centring floated Book Two in the middle of a tall empty
   column where it read as an accident rather than as a second beat. Aligned to
   the top, the eye lands on the cover and then finds Book Two beside it, which
   is the order the section is arguing for. */
.books{ display:grid; grid-template-columns:minmax(0,2fr) minmax(0,1fr);
  gap:clamp(34px,4.4vw,64px); align-items:start; }
/* BOTTOM ALIGNED, NOT TOP ALIGNED, and this reverses an earlier decision that
   was right about the reasoning and wrong about the direction.
   Top aligned, Book Two's kicker sat one card padding down from the top of the
   grid row, which at 1440 put the words BOOK TWO at y4022 and Book One's own
   name at y4697. The first label a reader met in the section arguing that Book
   One is the loud one was the name of the other book, 675px above it, and Book
   Two's content stopped at y4145 in a column that ran to y4858: 713px of empty
   cream in the middle of the page.
   Aligned to the bottom, held up by one card padding so it lands on the same
   inset edge Book One's own type does, the two labels come to rest near each
   other, the emptiness moves ABOVE Book Two where the cover is doing the
   talking, and the eye still lands on the cover first.
   Nothing changes at 760 and below, where the two stack and already read
   correctly. */
@media (min-width:761px){
  .booktwo{ align-self:end; padding-bottom:clamp(26px,3vw,34px); }
}
.bookone{ border:1px solid rgba(176,134,58,.45);
  padding:clamp(22px,2.4vw,30px) clamp(18px,2vw,28px) clamp(26px,3vw,34px); }
/* the cover inset. A Register B panel, not a workaround: at this point in the
   page the object being shown really is the product.

   THE FIELD COLOUR IS MEASURED, NOT CHOSEN. The mockup is a dark-field
   composite and the book inside it is a perspective quad, so no rectangular
   crop is clean (the four corners of a tight crop measure 9, 9, 3 and 5 of
   255) and the image can only ever sit on a dark ground. The panel therefore
   has to match the file's own field or its edge draws a rectangle. Do not crop
   this image and do not re-run retitle-mockup.py; both are documented traps. */
.coverinset{ background:var(--mockup-field); display:flex; justify-content:center;
  align-items:center; padding:0; }
/* THE PANEL IS THE IMAGE'S WIDTH, not the column's. At 1440 the inset measured
   647 x 649, a near square with the book at about 26 percent of its area and
   roughly 72px of flat #060809 beyond the picture on each side, so the object
   on the page read as a black box that happened to contain a book.
   This is safe only because of the mask above: the ellipse holds full opacity
   out past the book and is fully transparent by the time it reaches the file's
   own left and right edges, so the panel's new edge lands where the image is
   already showing nothing but panel. No new seam is created, which is the thing
   that would otherwise stop this. Narrow only: under 760 the inset is
   deliberately full bleed so the book can still hit its floor on a phone.
   A CENTRED PLATE OVER LEFT ALIGNED TYPE IS THIS PROPERTY'S OWN IDIOM, not a
   new one: .figure-warm is width:fit-content with auto side margins for exactly
   the same reason, on both Register A plates. At 1024 the panel comes within
   25px of the card and the two edges effectively agree; at 1440 the column is
   wider than the picture and about 72px of cream falls either side, which reads
   as a plate tipped into the card rather than as a misalignment. Making the
   panel fill the card at 1440 instead would mean moving the two thirds / one
   third grid the whole section argues with, which BUILD-SPEC 5 pins. */
@media (min-width:761px){
  .coverinset{ width:fit-content; margin-left:auto; margin-right:auto; }
}
/* SIZED BY THE BOOK, NOT BY THE SLOT. The book occupies 64.7% of the file's
   height, so a 420px book needs a 649px image and a 300px book needs a 464px
   one. Assert the BOOK dimension in QA, never the <img> dimension. The three
   accreted #cover img rules that produced a 326px book on desktop and a 175px
   book on a phone are gone; this replaces them and there is exactly one. */
.coverinset img{ height:649px; width:auto; max-width:100%;
  /* THE FIELD IS FEATHERED INTO THE PANEL, not merely placed on a matching one.
     Measured on the file: its corners run rgb(6,7,9), which the panel colour
     matches almost exactly, but the mid-edges run rgb(5,10,16), a bluish
     ambient glow around the book. Against any flat ground that glow draws a
     readable rectangle where the image ends, which is the exact artefact the
     measured panel colour exists to prevent and which the colour alone cannot.
     An elliptical mask holds full opacity out past the book itself (the book
     occupies 25 to 79 percent of the file across and 13 to 78 percent down) and
     then fades the surrounding field out. NOTE the radii are percentages of the
     box's FULL width and height, not of its half dimensions, which is a factor
     of two that is easy to lose.
     A MASK, NOT A FILTER. The BRAND-GUIDE bans CSS filters on <img> because
     they make Chrome rasterize a whole page when writing a PDF; nothing on this
     host is ever printed, and a mask does not carry that cost anyway. */
  -webkit-mask-image:radial-gradient(ellipse 42% 49% at 50% 50%, #000 0 70%, transparent 100%);
  mask-image:radial-gradient(ellipse 42% 49% at 50% 50%, #000 0 70%, transparent 100%); }
.bookone .kicker{ display:block; margin-top:clamp(24px,3vh,32px); }
.bookone .btitle{ font-family:var(--display); font-weight:500;
  font-size:clamp(24px,2.5vw,32px); line-height:1.2; letter-spacing:.014em;
  margin-top:11px; }
.booktwo .btitle{ font-family:var(--display); font-weight:500;
  font-size:clamp(21px,2vw,26px); line-height:1.24; letter-spacing:.014em;
  margin-top:11px; }
.booktwo .cutlink{ margin-top:8px; }   /* 20 - 12, see TOUCH TARGETS */
/* 64vw, NOT 46vw, and this is the same "size by the book, not by the slot"
   rule as everywhere else. 46vw was a guess with a lot of slack in it, and the
   slack was coming straight off the book: it rendered a 305px book at 1024 and
   a 229px book at 768 against a 420px desktop floor, which is a 45 percent miss
   at 768, and neither width had ever been rendered.
   The real ceiling is the Book One column, which holds steady at about 49 to 51
   percent of the viewport across this whole band (two thirds of the grid, less
   the page padding, the grid gap and the card padding). An image is 0.7725 of
   its own height wide, so the tallest image the column can take is about 63.4vw
   and 64vw sits on it. max-width:100% is still the backstop underneath, and the
   QA pass measures the BOOK and flags the overflow if this is ever wrong.
   At 1024 this puts the book on 420 exactly. AT 768 IT CANNOT REACH 420 AND
   NOTHING HERE WILL: two thirds of 768, less the padding, is a 381px column,
   which caps the book at about 319 however the image is sized. Raising it
   further means moving the grid ratio in this band, which is a design decision
   and not a number. It is flagged, not quietly papered over. */
@media (max-width:1180px){
  .coverinset img{ height:min(649px,64vw); }
}
@media (max-width:760px){
  /* stacked, Book One first, 64px of air between them, and no boxes at all.
     The dark inset stays: it is a plate, not a box. It goes edge to edge so the
     book can still render at its 300px floor on a 390 screen, which a padded
     column cannot give it. */
  .books{ grid-template-columns:1fr; gap:64px; }
  .bookone{ border:0; padding:0; }
  .books .coverinset{ margin-left:calc(clamp(20px,7vw,64px) * -1);
    margin-right:calc(clamp(20px,7vw,64px) * -1); }
  /* DRIVEN BY THE WIDTH, NOT A FIXED HEIGHT. The book is 64.7% of the file's
     height and the file is 0.7725 of its own height wide, so a 300px book needs
     a 464px image and a 464px image is 358px across. On a 390 viewport the full
     bleed panel has exactly 390px to give it, so the old fixed 464 sat ON the
     floor with 32px of slack and NO slack at all below a 349px viewport, where
     max-width:100% quietly re-clamped the height and took the book under 300
     with every measurement still passing. Sizing from the panel instead means
     the clamp can never fire and the floor degrades smoothly instead of
     breaking: 390 gives a 325px book, 360 gives 300, and the cap holds it at
     520 on the wider phones. */
  .coverinset img{ height:min(520px,129vw); }
  /* THE SECTION'S OWN TOP PADDING IS THE ONLY CREAM between the Register B
     plate above and the dark cover inset below, and the clamp resolved it to
     66px at 664 and 84px at 390. That is not a register break, it is a sliver:
     two dark blocks with a bright line between them, flickering the one ground
     that is this site's identity. Give the return to paper enough room to read
     as a return. */
  #books{ padding-top:clamp(120px,15vh,132px); }
  .bookone .kicker, .booktwo .kicker{ text-align:center; display:block; }
  .bookone .btitle, .booktwo .btitle, .booktwo .cutlink{ text-align:center; }
  .booktwo{ text-align:center; }
  .bookone .capform{ margin-left:auto; margin-right:auto; }
}

/* ── BOOK TWO ───────────────────────────────────────────────────────────── */
/* One centred column while the cover art is missing. The two column rule below
   is written and unused on purpose: when the art lands, adding `haspic` to the
   .b2 div and a figure before the column is the whole change. */
.b2{ max-width:560px; margin:0 auto; }
.b2 .kicker{ display:block; }
.b2 h1{ margin-top:14px; }
.b2 .prose{ margin:22px auto 0; max-width:46ch; }
.b2 .capform{ max-width:460px; margin:30px auto 0; }
.b2 .b2back{ margin-top:16px; }        /* 28 - 12, see TOUCH TARGETS */
.b2.haspic{ max-width:1000px; display:grid;
  grid-template-columns:minmax(0,300px) minmax(0,1fr);
  gap:clamp(34px,5.5vw,80px); align-items:center; text-align:left; }
@media (max-width:820px){
  .b2.haspic{ grid-template-columns:1fr; text-align:center; }
}

/* ── THE AUTHOR ─────────────────────────────────────────────────────────── */
.bio{ display:grid; grid-template-columns:minmax(0,300px) minmax(0,1fr);
  gap:clamp(34px,5vw,72px); align-items:center; }
.bio .biopic{ max-width:100%; }
.bio .biopic img{ width:100%; max-width:300px; max-height:none; }
.bio .biotext .prose{ margin-top:22px; }
.bio .hfa{ margin-top:14px; }          /* 26 - 12, see TOUCH TARGETS */
@media (max-width:760px){
  .bio{ grid-template-columns:1fr; gap:38px; justify-items:center; text-align:center; }
  .bio .biotext .prose{ margin-left:auto; margin-right:auto; }
  /* THE HEADING STAYS CENTRED, THE PARAGRAPH DOES NOT. Centring is a treatment
     for one or two lines. This paragraph runs to ten lines on a phone, and ten
     centred lines give the eye a new left edge to find on every one of them,
     which is the slowest possible way to read a bio that is trying to establish
     that the man can write. The block itself stays centred in the column; the
     text inside it is set ragged right like every other paragraph on the site. */
  .bio .biotext .prose{ text-align:left; }
  .bio .biopic img{ max-width:230px; }
}

/* ── THE CUT ────────────────────────────────────────────────────────────────
   Chapter One stops mid-story and this is the highest intent moment on the
   site: the reader has just spent four thousand words and wants the rest. It
   repeats the Book One ask rather than introducing a second offer. */
.cut{ text-align:center; display:flex; flex-direction:column; align-items:center; }
.cut h2{ margin-top:18px; }
.cut .capform{ max-width:460px; width:100%; margin-top:30px; }
.cut .cutlink{ margin-top:14px; }      /* 26 - 12, see TOUCH TARGETS */

/* ── THE CAPTURE FORM ───────────────────────────────────────────────────────
   One component, two grounds. The colours are variables rather than a second
   rule set, so the copy on the cream and the copy on a dark ground cannot drift
   apart the way two hand maintained blocks would. */
.capform{ --cf-ink:var(--ink); --cf-line:rgba(176,134,58,.62); --cf-dim:var(--dim);
  --cf-field:rgba(255,255,255,.55); --cf-ring:var(--gold-ink); width:100%; }
.cfrow{ display:flex; flex-wrap:wrap; gap:9px; }
.cfl{ position:absolute; width:1px; height:1px; overflow:hidden;
  clip:rect(0 0 0 0); clip-path:inset(50%); white-space:nowrap; }
.cfi{ flex:1 1 170px; min-width:0; font-family:var(--sans); font-weight:400;
  font-size:15px; color:var(--cf-ink); background:var(--cf-field);
  border:1px solid var(--cf-line); padding:12px 13px; border-radius:0;
  -webkit-appearance:none; appearance:none; }
.cfi::placeholder{ color:var(--cf-dim); opacity:.75; }
/* a focus ring is a non-text indicator and needs 3:1; --gold on cream is
   2.93:1, so the ring uses the AA gold */
.cfi:focus-visible{ outline:2px solid var(--cf-ring); outline-offset:1px; }
/* the honeypot. Off screen rather than display:none, because a bot that reads
   the stylesheet skips a hidden field and fills a visible one. */
.cfhp{ position:absolute; left:-9999px; width:1px; height:1px; opacity:0; }
.cfb{ flex:0 0 auto; font-family:var(--sans); font-weight:600; font-size:12px;
  letter-spacing:.2em; text-transform:uppercase; white-space:nowrap;
  color:#141109; background:var(--gold); border:1px solid var(--gold);
  padding:13px 20px; cursor:pointer; border-radius:0;
  transition:background-color .18s ease; }
.cfb:hover{ background:var(--gold-lt); }
.cfb:focus-visible{ outline:2px solid var(--ink); outline-offset:2px; }
.cfb[disabled]{ opacity:.55; cursor:default; }
.cfnote{ font-family:var(--sans); font-weight:400; font-size:11.5px;
  line-height:1.5; color:var(--cf-dim); margin-top:10px; text-wrap:pretty; }
.cfmsg{ font-family:var(--sans); font-weight:500; font-size:13px; line-height:1.5;
  margin-top:10px; color:var(--cf-ink); text-wrap:pretty; }
.cfmsg:empty{ display:none; }
.cfmsg.bad{ color:var(--crimson); }
/* The onward link for a reader who has just handed over an address.
   ON THE HOME PAGE IT IS NOT HIDDEN. The same element is the free-chapter link
   that makes Door One's "Free to Read" heading true, so it carries no hidden
   attribute there and site.js's reveal is a no-op on it. It sits after .cfmsg,
   which is display:none while empty, so it reads directly under the note before
   submit and under the confirmation afterwards. */
.cfon{ margin-top:2px; }               /* 14 - 12, see TOUCH TARGETS */
/* Kept for any .cfon that DOES ship hidden. [hidden] is a UA rule and
   .cutlink's display:inline-block out-specifies it, so without this an element
   carrying the attribute would ship visible anyway. */
.cfon[hidden]{ display:none; }

@media (max-width:520px){
  /* flex-basis follows the MAIN AXIS, and the main axis just became vertical.
     `flex:1 1 170px` on a column reads as "start 170px TALL and grow", which
     rendered the email field about 330px deep as a giant empty box with the
     placeholder floating in the middle of it. Every measurement passed while
     that was on screen. Reset the basis on the axis it now belongs to. */
  .cfrow{ flex-direction:column; }
  .cfi{ flex:0 0 auto; width:100%; }
  .cfb{ width:100%; }
}
/* Side by side but narrow: between 641 and 900 a two column layout leaves the
   form about 300 to 380px, where a 15px field plus a tracked button cannot hold
   one line. The button wrapped under the field and came out narrower than it.
   The stacked form is the right layout for that band too. */
@media (min-width:641px) and (max-width:900px){
  .books .cfrow{ flex-direction:column; }
  .books .cfi{ flex:0 0 auto; width:100%; }
  .books .cfb{ width:100%; }
}

/* ── PAPER GRAIN ────────────────────────────────────────────────────────────
   One tiled PNG at .06, held between .05 and .07. Above .08 it stops looking
   like paper and starts looking like noise. No mix-blend-mode and no full page
   SVG filter: both exploded the print PDF on this property. Layered gradients
   and a tiled PNG only.

   It sits at z-index -1, BEHIND every section rather than over the top of them.
   That is the whole trick: the cream sections are transparent so the grain
   reads through them as paper, and the hero, the two plates and the cover inset
   all carry opaque dark backgrounds of their own, so the grain never reaches a
   dark surface. Grain on a near-black wash reads as dirt, and a fixed overlay
   above everything would have put it on all three. */
body::before{ content:""; position:fixed; inset:0; z-index:-1;
  pointer-events:none; background:url('grain.png') repeat;
  background-size:300px 300px; opacity:.06; }
/* the reading block paints its own paper tone, which would hide the page grain
   underneath it, so it carries its own at the same value */
.reading{ position:relative; }
.reading::before{ content:""; position:absolute; inset:0; z-index:0;
  pointer-events:none; background:url('grain.png') repeat;
  background-size:300px 300px; opacity:.06; }
.reading .col{ position:relative; z-index:1; }
