/* The Business Growth Pro — one stylesheet, whole site. Carried over unchanged from
   ontheclock.show 2026-10-21, minus the countdown and premiere-form rules.
   Design language set by Matt 2026-09-02 from mockup D2:
     paper ground, NO black sections anywhere, prose over lists, no numerals,
     one centred serif hero, and the accent only ever on a number or a date. */

/* ---------- fonts ---------- */
/* Headline face: Newsreader. Instrument Serif was the launch face and Matt ruled
   against it 2026-09-03 ("I don't like the serif fonts for the headlines"). Newsreader
   is editorial by design, sturdier on paper, and has a real italic -- which this design
   leans on hard (the deck, the statement, and the <em> in the inner-page h1s; the
   homepage h1 is set roman throughout [Matt 2026-09-03]). The Instrument
   woff2 files stay on disk: the eight /preview/ mockups still reference them. */
@font-face{font-family:'Newsreader';font-style:normal;font-weight:400;font-display:swap;
  src:url(/assets/fonts/newsreader-latin.woff2) format('woff2');
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;}
@font-face{font-family:'Newsreader';font-style:italic;font-weight:400;font-display:swap;
  src:url(/assets/fonts/newsreader-latin-italic.woff2) format('woff2');
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;}

/* ---------- hidden ----------
   ⛔ `el.hidden = true` DOES NOTHING to an element this stylesheet gives a
   `display` to. The `hidden` attribute is only a UA rule (`[hidden]{display:none}`),
   and ANY author rule setting display beats a UA rule outright -- specificity never
   enters into it. That is not theoretical: on 2026-09-05 Matt submitted the contact
   form and the button sat on "Sending..." forever with the field labels still under
   it, because `.btn{display:inline-flex}` and `.field label{display:block}` silently
   won. The inputs vanished correctly, which is what made it look like a JS bug.
   This rule makes the attribute mean what every reader assumes it means. */
[hidden]{display:none!important}

/* On success the form collapses to its confirmation. Doing it in CSS rather than by
   walking the DOM in JS means a field type nobody thought of cannot survive the
   collapse -- the old handler enumerated input/select/textarea/label and missed the
   button entirely. */
form[data-form].sent>*:not(.form-ok){display:none!important}

/* ---------- tokens ---------- */
:root{
  --paper:#FAF8F5;          /* warm paper, never #FFF */
  --paper-raised:#F2EEE8;   /* the site's ONE fill: priced panels, and the /work-with-matt/ jump bar */
  --ink:#0E0D0C;
  --text:#2B2825;           /* 13.8:1 */
  --dim:#6B655E;            /*  5.4:1 */
  --faint:#736C64;          /*  4.9:1 */
  --accent:#9A5F0F;         /*  4.9:1 on paper, 4.52 on --paper-raised — bronze.
                                 NUMBERS AND DATES, plus the "Ideal for" label. */
  --caution:#9E2B20;        /*  7.0:1 on paper, 6.4:1 on --paper-raised — the ONE red.
                                 Only the "Not for" label. Jay uses a bright red on
                                 near-black; this is its paper-ground equivalent, deep
                                 enough to sit beside the bronze without shouting. */
  --rule:rgba(14,13,12,.11);
  --rule-strong:rgba(14,13,12,.26);
  --on-ink:#DCD7D0;        /* 11.8:1 on ink */
  --on-ink-dim:#B3ACA4;    /*  7.5:1 */
  --on-ink-faint:#8D867F;  /*  5.4:1 */
  --rule-ink:rgba(243,240,234,.13);
  --rule-ink-strong:rgba(243,240,234,.34);

  --serif:'Newsreader',"Iowan Old Style","Palatino Linotype",Palatino,Georgia,serif;
  --sans:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;

  /* fluid scale — preferred value is always rem + vw so browser zoom still works */
  --s--1:clamp(.8125rem,.79rem + .11vw,.875rem);
  --s-0: clamp(1.0625rem,1.02rem + .22vw,1.1875rem);
  --s-1: clamp(1.1875rem,1.11rem + .38vw,1.4375rem);
  --s-2: clamp(1.4375rem,1.28rem + .78vw,1.9375rem);
  --s-3: clamp(1.75rem,1.44rem + 1.55vw,2.625rem);
  --s-4: clamp(2.125rem,1.6rem + 2.6vw,3.25rem);
  --s-5: clamp(2.375rem,1.75rem + 3.1vw,4rem);
  --s-7: clamp(3rem,1.8rem + 6vw,7rem);

  --space-xs:clamp(.5rem,.47rem + .15vw,.625rem);
  --space-s: clamp(.875rem,.8rem + .37vw,1.125rem);
  --space-m: clamp(1.5rem,1.35rem + .75vw,2.125rem);
  --space-l: clamp(2.5rem,2.1rem + 2vw,4rem);
  --space-xl:clamp(4rem,3.1rem + 4.5vw,7rem);

  --shell:72rem;            /* masthead, footer, rules, wide sections */
  --read:46ch;              /* prose measure — D2's paragraph width */
  --gutter:clamp(1.25rem,.95rem + 1.5vw,2.5rem);
}

/* ---------- reset ---------- */
*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{
  margin:0;background:var(--paper);color:var(--text);
  font-family:var(--sans);font-size:var(--s-0);line-height:1.65;
  -webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;overflow-wrap:break-word;
}
img{max-width:100%;height:auto;display:block}
h1,h2,h3{font-family:var(--serif);font-weight:400;line-height:1.05;letter-spacing:-.014em;margin:0}
p,ul,ol,dl{margin:0}
a{color:inherit}

/* ---------- layout ---------- */
.wrap{width:100%;max-width:var(--shell);margin-inline:auto;padding-inline:var(--gutter)}
section{padding-block:var(--space-l)}
/* A hero already pays a generous bottom padding, so the section after it must not pay
   a full top padding as well -- stacked they make ~134px of dead space, which reads as
   a doubled gap wherever that section opens on PROSE instead of a landmark. Matt flagged
   it on /about/, /work-with-matt/ and /contact/ [2026-09-05: "there's too much spacing
   below the headline/subhead. it's like the spacing got doubled"].
   /apply/ and the report page had already been given this by hand with inline styles at
   ~75px; this makes it the rule instead of a thing you have to remember to type.
   :has() scopes it to sections with NO kicker -- where a kicker leads (the homepage), it
   is its own landmark and the wider gap is correct. Browsers without :has() drop the
   rule and get today's spacing, so it degrades safely.
   NOTE the adjacency is load-bearing too: /privacy/, /terms/ and the report thanks page
   carry a rulebar.thin between hero and section, which breaks `+` and leaves them at the
   wider gap. That is CORRECT -- the rule is a landmark sitting in the space, same as a
   kicker -- so do NOT 'fix' it by adding `.hero + .rulebar + section`. */
.hero + section:not(:has(.kicker)){padding-top:0}
/* The drop from the hero to the first body copy should equal the gap from the headline
   to the deck [Matt 2026-09-05: "ideally, it's the same space as between the headline
   and this section"]. That whole gap is the hero's own padding-bottom (72px at 1440,
   the next section already sits at padding-top:0), so it is the only thing to change.
   Scoped with :has() to heroes actually followed by prose -- the report page's
   hero->form gap is set inline and must stay tight. */
.hero:has(+ section .prose){padding-bottom:var(--space-m)}
.stack-s>*+*{margin-top:var(--space-s)}
.stack-m>*+*{margin-top:var(--space-m)}
/* prose column: centred, D2's measure, left-aligned text */
.prose{max-width:var(--read);margin-inline:auto}
.prose>*+*{margin-top:var(--space-m)}
/* Body copy sits exactly ONE LINE of text apart [Matt 2026-09-05: "change spacing
   between all this body copy to only be the height of one line of text... it applies
   to all sections where there's multiple body copy sections stacked"].
   ⚠️ The MARGIN is not the gap the eye sees. line-height:1.65 puts half-leading above
   AND below every line, so a margin equal to the line-height (31.35px at 1440) renders
   about 1.4 lines of white -- which is why it read as "more than one line" while
   measuring as one. `1em` on a paragraph equals its own font-size, and font-size plus
   the two half-leadings equals exactly one line. Headings deliberately keep --space-m:
   a heading needs more air above it than a paragraph does. */
.prose>p+p,.prose>p+ul,.prose>ul+p,.prose>ul+ul{margin-top:1em}
.prose p{font-size:var(--s-0)}
.prose .serif{font-family:var(--serif);font-size:var(--s-2);line-height:1.36;letter-spacing:-.008em}

/* ---------- masthead ---------- */
.masthead{border-bottom:1px solid var(--rule);background:var(--paper)}
@media (min-width:60em){.masthead{position:sticky;top:0;z-index:10}}
/* Phone: the header still scrolls away with the page exactly as before, but ANY
   upward scroll brings it straight back [Matt 2026-09-05]. Scroll DIRECTION cannot
   be expressed in CSS, so `.pinned`/`.reveal` are driven by the inline script at the
   bottom of shell.html; with JS off the header simply behaves as it always has.
   Breakpoint is the exact complement of the desktop sticky rule above, and matches
   the width at which the nav collapses into the hamburger -- one definition of
   "phone header", not a second one. */
@media (max-width:59.99em){
  .masthead.pinned{
    position:fixed;top:0;left:0;right:0;z-index:20;
    transform:translateY(-100%);transition:transform .2s ease;
    will-change:transform;
  }
  .masthead.pinned.reveal{transform:translateY(0)}
  /* The revealed header is position:fixed at z-index 20 and was landing ON TOP of the
     sticky jump bar [Matt 2026-09-08: "on mobile when I pull down, the top nav bar that
     apperas covers the 1-4 nav bar"]. The bar drops by the header's own height for
     exactly as long as the header is showing -- the same relationship the two have on
     desktop, where the masthead is sticky and .enav sits at top:var(--mast-h).
     ⚠️ The earlier note that "the revealed header passes over it" was a decision, and
     this overrides it; don't restore it.
     The transition matches the header's .2s so the two move together -- without it the
     bar jumps to its new offset while the header is still sliding, opening a 200ms
     window of page content between them. It lives on .enav, not on the revealed rule,
     so the return trip animates too (the rule is gone by then). */
  .enav{transition:top .2s ease}
  .masthead.pinned.reveal ~ main .enav{top:var(--mast-pinned-h,var(--mast-h))}
}
@media (prefers-reduced-motion:reduce){.enav{transition:none}}
@media (prefers-reduced-motion:reduce){.masthead.pinned{transition:none}}
.masthead .bar{
  width:100%;max-width:var(--shell);margin-inline:auto;padding:var(--space-s) var(--gutter);
  display:flex;align-items:center;justify-content:space-between;gap:var(--space-m);flex-wrap:wrap;
}
.brand{display:flex;flex-direction:row;align-items:center;gap:.6rem;text-decoration:none;color:var(--ink)}
.brand .brandtext{display:flex;flex-direction:column;gap:.15rem;min-width:0}
/* the mark spans the WHOLE wordmark block: wordmark + gap + tagline. Height is
   derived from those three tokens so it stays locked to the type as it scales. */
.brand .brandmark{display:block;width:auto;height:calc(var(--s-1) + .15rem + .6875rem);flex:0 0 auto}
.brand .wordmark{font-family:var(--serif);font-size:var(--s-1);line-height:1;letter-spacing:.004em}
.brand .tag{font-size:.6875rem;letter-spacing:.155em;text-transform:uppercase;color:var(--faint);line-height:1;white-space:nowrap}
.mainnav ul{display:flex;gap:clamp(1rem,.5rem + 1.6vw,2.25rem);list-style:none;margin:0;padding:0}
.mainnav a{
  display:inline-flex;align-items:center;min-height:44px;text-decoration:none;color:var(--text);
  font-size:var(--s--1);letter-spacing:.13em;text-transform:uppercase;
  border-bottom:1px solid transparent;transition:border-color .18s ease;
}
.mainnav a:hover,.mainnav a[aria-current="page"]{border-bottom-color:var(--ink)}
.nav-cta{
  display:inline-flex;align-items:center;justify-content:center;min-height:44px;padding:.6rem 1.35rem;
  background:var(--ink);color:var(--paper);text-decoration:none;white-space:nowrap;
  font-size:var(--s--1);letter-spacing:.13em;text-transform:uppercase;
  border:1px solid var(--ink);transition:background .18s ease,color .18s ease;
}
.nav-cta:hover{background:transparent;color:var(--ink)}
/* the hamburger. <details> so it needs no JavaScript and stays keyboard-usable. */
.menu{display:none}
.menu summary{
  list-style:none;cursor:pointer;width:44px;height:44px;
  display:inline-flex;align-items:center;justify-content:center;-webkit-tap-highlight-color:transparent;
}
.menu summary::-webkit-details-marker{display:none}
.menu summary::marker{content:""}
.burger,.burger::before,.burger::after{
  display:block;width:22px;height:2px;background:var(--ink);
  transition:transform .18s ease,top .18s ease,background .12s ease;
}
.burger{position:relative}
.burger::before,.burger::after{content:"";position:absolute;left:0}
.burger::before{top:-7px}
.burger::after{top:7px}
.menu[open] .burger{background:transparent}
.menu[open] .burger::before{top:0;transform:rotate(45deg)}
.menu[open] .burger::after{top:0;transform:rotate(-45deg)}
.menu-panel{
  position:absolute;right:0;top:calc(100% + var(--space-xs));z-index:20;min-width:15rem;
  background:var(--paper);border:1px solid var(--rule-strong);
}
.menu-panel ul{list-style:none;margin:0;padding:0}
.menu-panel li+li{border-top:1px solid var(--rule)}
.menu-panel a{
  display:flex;align-items:center;min-height:54px;padding:0 var(--space-m);text-decoration:none;
  color:var(--text);font-size:var(--s--1);letter-spacing:.13em;text-transform:uppercase;
}
.menu-panel a:hover,.menu-panel a[aria-current="page"]{background:var(--paper-raised)}

/* phone: the three nav links live behind the hamburger, never on the bar */
@media (max-width:59.99em){
  .masthead .bar{flex-wrap:nowrap;gap:var(--space-s)}
  .mainnav{display:none}
  .menu{display:block;position:relative;flex:0 0 auto}
  .brand{flex:1 1 auto;min-width:0}
  .nav-cta{padding:.6rem .8rem;letter-spacing:.08em;flex:0 0 auto}
}
@media (max-width:22em){.brand .tag{display:none}}

/* ---------- the hero pattern ---------- */
.hero{padding-block:clamp(2.25rem,1.7rem + 2.4vw,4rem) clamp(2.5rem,1.9rem + 3vw,4.5rem);text-align:center}
.kicker{
  display:flex;align-items:center;gap:var(--space-s);
  font-size:var(--s--1);letter-spacing:.24em;text-transform:uppercase;color:var(--faint);white-space:nowrap;
}
.kicker::before,.kicker::after{content:"";height:1px;background:var(--rule-strong);flex:1 1 auto;min-width:1rem}
/* A SECTION kicker sits further above its content than a HERO kicker does above its h1
   (62px vs 32px at 1440). That was six copies of an inline style="margin-bottom:var(--space-l)"
   until 2026-09-05 -- the split was clean, but the next section kicker anyone added would have
   silently got the hero gap with nothing erroring. Made a real rule at Matt's instruction.
   The hero keeps its smaller gap because .hero h1 supplies its own top margin. */
section:not(.hero) .kicker{margin-bottom:var(--space-l)}
/* On a phone the kicker's own tracking is what overflows the page: nowrap keeps the
   rules flanking one line, and "Thirty minutes. Maximum profit." needed 330px against a
   288px budget at .24em -- 22px of sideways scroll the day that copy was written.
   (That copy is now "Thirty minutes on the clock" [Matt 2026-09-04] and is shorter, but
   the fix stays: the longest kicker on the site is still wider than a 390px phone.)
   Measured at 390px: pulling the tracking to .14em and tightening the gap and the rule
   minimum yields 305px of budget against 290px of text. The line stays unbroken and the
   rules stay long enough to read as rules rather than as stubs. */
@media (max-width:560px){
  .kicker{letter-spacing:.14em;gap:.5rem}
  .kicker::before,.kicker::after{min-width:.375rem}
}
.hero h1{font-size:var(--s-7);line-height:.98;letter-spacing:-.026em;max-width:19ch;margin:var(--space-m) auto 0}
.hero h1 em{font-style:italic}
.hero.sm h1{font-size:var(--s-5);max-width:22ch}
/* a headline of two sentences breaks BETWEEN them, never mid-sentence, at any width.
   The report hero's coda is three sentences and takes the same treatment. */
.hero h1 .sent,.hero .coda .sent{display:inline-block}
/* `.brk` forces a line break at a chosen word, but ONLY where it helps. Matt asked for
   the break after "one-on-one" for the headline's shape [2026-09-05] and said not to
   push anything onto three lines on mobile. ⚠️ Measured before building it: that
   headline ALREADY wraps to three lines at every phone width, with or without the
   break -- it is simply too long for a phone -- and forcing it adds a FOURTH line at
   320px. Matt then ruled three lines on mobile acceptable, so the break stays ON at every
   real phone width and is disabled only below 360px, which is the measured point
   where it would spill to a fourth line. 22.5em is measured, not guessed. */
@media (max-width:22.5em){.hero h1 .sent.brk{display:inline}}
.hero.xs h1{font-size:var(--s-4);max-width:24ch}
.deck{
  font-family:var(--serif);font-style:italic;font-size:var(--s-2);line-height:1.3;color:var(--dim);
  max-width:36ch;margin:var(--space-m) auto 0;
}
.hero.sm .deck,.hero.xs .deck{font-size:var(--s-1);max-width:44ch}
/* The homepage deck is Matt's own description of the show, and he asked for it in
   the BODY face rather than the serif italic [Matt 2026-09-03] -- it is a paragraph
   doing explaining work now, not a one-line flourish, so it also takes a wider
   measure. The show's name keeps the italic, at his instruction. */
.hero .deck.plain{
  font-family:var(--sans);font-style:normal;font-size:var(--s-1);
  line-height:1.5;max-width:52ch;
}
.hero .deck.plain em{font-style:italic}
.byline{margin-top:var(--space-m);font-size:var(--s--1);letter-spacing:.18em;text-transform:uppercase;color:var(--faint)}
/* the homepage premiere line is a headline in its own right, not a caption --
   scoped to the full hero so "Last updated ..." on the legal pages stays small. */
.hero:not(.sm):not(.xs) .byline{font-size:var(--s-1);letter-spacing:.11em;color:var(--dim)}
.byline .num{letter-spacing:.06em}
.hero .actions{margin-top:var(--space-l);justify-content:center}

/* ---------- rules (furniture, never separators between list items) ---------- */
.rulebar{max-width:var(--shell);margin-inline:auto;padding-inline:var(--gutter)}
/* .dbl is UNUSED as of 2026-09-05 -- the heavy hero/body band was removed from all five
   pages that carried it. Kept so the change is a one-line revert if Matt wants it back. */
.rulebar .dbl{height:4px;border-top:2px solid var(--ink);border-bottom:1px solid var(--ink)}
.rulebar .thin{border-top:1px solid var(--rule-strong)}
/* [Matt 2026-09-05] "Remove this line" on the homepage divider, scoped by his own
   composer to MOBILE ONLY -- the review tool stores `views` only when he deliberately
   restricts a note, so mobile-only is a choice, not a default. 40em == the composer's
   own 640px mobile ceiling (review.js), which is why this breakpoint is not one of the
   site's usual ones. Applied via a modifier on that one element rather than to
   `.rulebar` globally: report-thanks and work-with-matt also carry a rulebar and he
   has not looked at them at this width. */
@media (max-width:40em){.rulebar.hide-m{display:none}}

/* ---------- type helpers ---------- */
.eyebrow{font-size:var(--s--1);letter-spacing:.19em;text-transform:uppercase;color:var(--faint)}
.h2{font-size:var(--s-3)}
.h3{font-size:var(--s-2)}
.tc{text-align:center}
/* `.tc` is text-align, which does nothing to a flex container's items --
   `.actions` is a flex row from 30em up, so centring it needs this too. */
.actions.tc{justify-content:center}
.lede{font-size:var(--s-1);line-height:1.45;color:var(--text)}
.dim{color:var(--dim)}
.faint{color:var(--faint)}
.statement{font-family:var(--serif);font-style:italic;font-size:var(--s-3);text-align:center;
  margin:var(--space-xl) auto 0}
/* the accent, and its rule: numbers and dates only */
.num{color:var(--accent);font-variant-numeric:tabular-nums lining-nums}
/* ⛔ There is deliberately NO "number without the accent" class. Matt asked for two
   bare counts in prose to lose the accent [2026-09-05], I gave them a .num.ink
   modifier, and he corrected it: "I wanted it the same color, font, and size as the
   text that surrounds it." A class can only ever approximate that -- it has to
   re-state colour, family, size and numeric variant, and drifts the moment any of
   them changes. Plain text IS the treatment: just don't wrap the number.
   So .num means one thing only -- this number carries the accent. */

/* ---------- the principles block ---------- */
/* Eight named things, so it stays a list -- but set as an inscription: no
   bullets, no numerals, no rules between items. Each opens to Matt's own
   sub-notes; <details name> makes them mutually exclusive natively, and a
   6-line script on the page guarantees it on browsers that lack it.
   Source: Matt's own "My life principles - core values.md". */
.principles{list-style:none;margin:var(--space-l) 0 0;padding:0}
.principles li+li{margin-top:var(--space-xs)}
.principles summary{
  list-style:none;cursor:pointer;display:flex;align-items:baseline;gap:.55em;
  font-family:var(--serif);font-size:var(--s-2);line-height:1.3;letter-spacing:-.01em;
  color:var(--text);padding-block:.3rem;min-height:44px;
}
.principles .sub{margin-left:.95em}
.principles summary::-webkit-details-marker{display:none}
.principles summary::marker{content:""}
/* caret leads on the left: points right when closed, down when open */
.principles summary::before{
  content:"";width:.4em;height:.4em;flex:0 0 auto;order:-1;
  border-right:1.5px solid var(--faint);border-bottom:1.5px solid var(--faint);
  transform:translateY(-.06em) rotate(-45deg);transition:transform .18s ease;
}
@media (hover:hover) and (pointer:fine){
  .principles summary:hover{color:var(--accent)}
  .principles summary:hover::before{border-color:var(--accent)}
}
.principles details[open] summary{color:var(--accent)}
.principles details[open] summary::before{border-color:var(--accent);transform:translateY(-.18em) rotate(45deg)}
.principles .sub{
  margin:.1rem 0 var(--space-s);max-width:44ch;
  font-size:var(--s-0);line-height:1.6;color:var(--dim);
}

/* ---------- run-in list inside .prose ----------
   The site is prose-over-lists by design [Matt 2026-09-02] and carried NO list
   styling at all, so his three items first shipped as plain paragraphs. Asked for
   a real bullet on 2026-09-05 I built four candidates at /preview/bullets/ -- solid
   dot, en dash, hollow ring, and this one -- and he picked this one: no marker at
   all, the opening phrase set in the site's own italic serif. It is the only
   candidate that uses a treatment the site already owns (the deck, the coda, the
   <em> in the inner-page headlines) instead of introducing a new mark.
   margin-top is NOT 0: `.prose>*+*` supplies the rhythm at the same specificity and
   this rule sits later in the file, so a blanket margin:0 silently wins and welds
   the list to the paragraph above it. State the gap, don't zero it. */
.runin{list-style:none;margin:1em 0 0;padding:0}
.runin li+li{margin-top:1em}
.runin .lead{font-family:var(--serif);font-style:italic;font-size:1.08em;color:var(--ink)}

/* ---------- two columns with a single vertical rule ---------- */
.cols{display:grid;grid-template-columns:1fr;gap:var(--space-l)}
@media (min-width:56em){
  .cols{grid-template-columns:1fr 1fr;gap:0}
  .cols>*{padding-inline:var(--space-l)}
  .cols>*:first-child{padding-left:0}
  .cols>*:last-child{padding-right:0;border-left:1px solid var(--rule)}
}
.cols>*>*+*{margin-top:var(--space-m)}
/* A subhead belongs to the headline above it, so it does not take the full
   between-blocks gap [Matt 2026-09-04, review: the report column is now
   "Free profit report:" with the seven-places line dropped under it]. */
.cols>*>.subhead,.cols>*>.coda{margin-top:var(--space-xs)}
/* "Any business. Any size. Any industry." belongs to the title it sits under, not
   to the paragraph beneath it [Matt 2026-09-04, review: "it should go at the end of
   this line, but I don't know how to make it look good"]. Tacking it onto the h3
   itself would leave a smaller, dimmer fragment dangling off a headline that wraps
   to three lines on a phone -- so it takes its own line instead, tight against the
   subhead, and the REGISTER does the separating: serif italic, one size step down,
   dim. Same voice the deleted centred .statement had, quieter and left-aligned. */
.coda{font-family:var(--serif);font-style:italic;font-size:var(--s-1);line-height:1.3;color:var(--dim)}
/* Under a hero H1 the coda takes the size step Matt asked for -- "if the headline is
   H1, this should be H2" [Matt 2026-09-04, review] -- in the same italic serif dim
   voice it has on the homepage, so the one sentence reads the same way sitewide and
   only its scale follows what it sits under. It belongs to the headline, so it sits
   tighter to it than the deck below does. */
.hero .coda{font-size:var(--s-3);max-width:26ch;margin:var(--space-s) auto 0}

/* ---------- buttons ---------- */
.btn{
  display:inline-flex;align-items:center;justify-content:center;min-height:52px;padding:.85rem 1.75rem;
  font-family:var(--sans);font-size:var(--s-0);font-weight:500;letter-spacing:.005em;text-decoration:none;
  background:var(--ink);color:var(--paper);border:1px solid var(--ink);border-radius:0;cursor:pointer;
  transition:background .18s ease,color .18s ease,border-color .18s ease;
}
.btn:hover{background:transparent;color:var(--ink)}
.btn-ghost{background:transparent;color:var(--ink);border-color:var(--rule-strong)}
.btn-ghost:hover{background:transparent;color:var(--ink);border-color:var(--ink)}
.actions{display:flex;flex-direction:column;gap:var(--space-s);align-items:stretch}
.actions .btn{width:100%}
@media (min-width:30em){.actions{flex-direction:row;flex-wrap:wrap;align-items:center}.actions .btn{width:auto}}
.textlink{
  display:inline-flex;align-items:center;min-height:44px;color:var(--ink);text-decoration:none;
  border-bottom:1px solid var(--rule-strong);transition:border-color .18s ease;
}
.textlink:hover{border-bottom-color:var(--ink)}

/* ---------- priced panels (structure after abraham.com/consulting, on paper) ---------- */
.offers{display:grid;grid-template-columns:1fr;gap:var(--space-m)}
@media (min-width:48em){.offers{grid-template-columns:repeat(2,1fr);gap:var(--space-l)}}
.offer{
  border:1px solid var(--rule-strong);background:var(--paper-raised);
  padding:var(--space-m);display:flex;flex-direction:column;
}
.offer .oh{
  font-size:var(--s--1);letter-spacing:.19em;text-transform:uppercase;color:var(--accent);
  padding-bottom:var(--space-s);border-bottom:1px solid var(--rule-strong);margin-bottom:var(--space-m);
}
/* The panel's only h3 is now the "Expected outcome" .slab, and this rule outranked it
   (.offer h3 is 0,0,1,1 against .slab's 0,0,1,0) -- the label shipped at 23px instead of
   11px. The old card TITLE this styled no longer exists; the panel is .oh + dl + outcome.
   Second override of this kind in one build: append a rule and check the RENDERED value,
   never the stylesheet. */
.offer h3:not(.slab){font-size:var(--s-2);margin-bottom:var(--space-m)}
.offer dl{margin:0}
/* --dim, NOT --faint. --faint's documented 4.9:1 is against --paper; on --paper-raised,
   which is this panel's fill, it measures 4.48 and fails the 4.5 floor -- all 20 labels.
   PRE-EXISTING since the panels shipped 2026-09-02 and audit.py does not catch it
   (BUGS #68); found by measuring the ratio directly. */
.offer dt{font-size:.6875rem;letter-spacing:.16em;text-transform:uppercase;color:var(--dim);margin-bottom:.2rem}
.offer dd{margin:0 0 var(--space-s)}
/* Panel copy is a reference table beside the argument, not the argument -- it reads a step
   down from body size [Matt 2026-09-06: "the text in the boxes is way too big"]. Jay's
   equivalent runs ~14px against 17px body. */
.offer dd{font-size:var(--s--1);line-height:1.5}
.offer .investment{
  font-family:var(--serif);font-size:var(--s-1);line-height:1.15;color:var(--accent);
  font-variant-numeric:tabular-nums lining-nums;
}
.offer .outcome{border-top:1px solid var(--rule-strong);padding-top:var(--space-m);margin-top:var(--space-xs)}
.offer .outcome p+p{margin-top:var(--space-s)}
.offer .outcome p{color:var(--dim);font-size:var(--s--1);line-height:1.5}
.offer .btn{width:100%;margin-top:var(--space-m)}
/* ⛔ ORDER IS LOAD-BEARING HERE, and getting it wrong shipped a real defect.
   .offer is a flex column, and `margin-top:auto` bottom-aligns the CTA across the
   equal-height cards of `.offers`. NO PAGE USES .offers any more, and .egrid sets
   align-items:start, so nothing on this site stretches a panel -- which means the auto
   resolved to 0 AND beat the rule above it on a specificity tie (both 0,0,2,0, and it
   came later). Desktop escaped only because `.ecol .offer .btn` (0,0,3,0) overrides it
   further down. So on tablet and phone the CTA sat flush against the copy above it
   [Matt 2026-09-12: "all four of these buttons on mobile and tablet touch the text above
   them. they need spacing."] The push is kept for a genuinely stretched panel; the
   button now restates its own gap AFTER it, so it can never be the thing that loses. */
.offer>*:last-child{margin-top:auto}
.offer>.btn{margin-top:var(--space-m)}

/* ---------- forms ---------- */
.form{margin-top:var(--space-l);max-width:38rem;margin-inline:auto}
.form>.btn{width:100%}
@media (min-width:30em){.form>.btn{width:auto;min-width:14rem}}
.field{margin-bottom:var(--space-s)}
.field label{
  display:block;margin-bottom:.4rem;
  font-size:var(--s--1);letter-spacing:.1em;text-transform:uppercase;color:var(--faint);
}
/* Required-field marker [Matt 2026-09-04, review note]: every form on the site EXCEPT
   the two name-and-email opt-ins marks its required labels with an asterisk. It is
   deliberately NOT in the accent -- the accent only ever touches a number or a date --
   so it sits one step darker than the label instead. aria-hidden because the control
   already carries `required`, which is what a screen reader announces. */
.field label .req{margin-left:.25em;color:var(--dim)}
.field input,.field select,.field textarea{
  width:100%;min-height:52px;padding:.75rem .9rem;
  font-family:var(--sans);font-size:var(--s-0);line-height:1.4;
  color:var(--text);background:#fff;
  border:1px solid var(--rule-strong);border-radius:0;appearance:none;
}
.field textarea{min-height:7.5rem;resize:vertical}
.field select{
  background-image:linear-gradient(45deg,transparent 50%,var(--dim) 50%),linear-gradient(135deg,var(--dim) 50%,transparent 50%);
  background-position:calc(100% - 1.15rem) 55%,calc(100% - .8rem) 55%;
  background-size:6px 6px,6px 6px;background-repeat:no-repeat;padding-right:2.5rem;
}
.field input:focus,.field select:focus,.field textarea:focus{
  outline:2px solid var(--accent);outline-offset:1px;border-color:transparent;
}
.field .hint{margin-top:.35rem;font-size:var(--s--1);color:var(--faint);letter-spacing:0;text-transform:none}
.form-note{
  margin-top:var(--space-s);padding:var(--space-s);
  border:1px dashed var(--rule-strong);font-size:var(--s--1);color:var(--faint);
}
@media (min-width:38em){.row2{display:grid;grid-template-columns:1fr 1fr;gap:0 var(--space-s)}}

/* ---------- footer ---------- */
/* Black is deliberate here [Matt 2026-09-02] and is the ONE exception to the
   no-dark-sections rule -- it closes the page rather than interrupting it. */
.foot{
  background:var(--ink);color:var(--on-ink-dim);
  padding-block:var(--space-l) var(--space-m);margin-top:var(--space-xl);
}
.foot a{color:var(--on-ink);text-decoration:none;border-bottom:1px solid transparent}
.foot a:hover{color:#fff;border-bottom-color:var(--rule-ink-strong)}
.foot-nav{
  display:flex;flex-wrap:wrap;justify-content:center;gap:var(--space-xs) var(--space-m);
  list-style:none;padding:0;margin:0;
  font-size:var(--s--1);letter-spacing:.13em;text-transform:uppercase;
}
.foot-nav a{display:inline-flex;align-items:center;min-height:44px}
/* [Matt 2026-09-03, review] "mobile only: reduce spacing between the stacking of
   the TOS / privacy policy and the contact link." MEASURED: below 480px the three
   links break to two rows at a 52px pitch (44px tap target + an 8px row gap)
   against ~18px of text, which is the gap he is seeing. Dropping the row gap and
   the target to 36px takes the pitch to 36 -- still well clear of the 24px tap
   minimum the audit enforces. Scoped to the site's 560px phone band; between 480
   and 560 the row does not stack, so this only shortens the bar there. */
@media (max-width:560px){
  .foot-nav{row-gap:0}
  .foot-nav a{min-height:36px}
}
.foot .fine{
  margin-top:var(--space-s);padding-top:var(--space-s);border-top:1px solid var(--rule-ink);
  font-size:var(--s--1);color:var(--on-ink-faint);
  display:flex;flex-wrap:wrap;gap:var(--space-xs) var(--space-m);justify-content:center;text-align:center;
}

/* ---------- misc ---------- */
.skip{position:absolute;left:-9999px}
.skip:focus{left:var(--gutter);top:var(--space-s);z-index:20;background:var(--ink);color:var(--paper);padding:.75rem 1rem}
:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
@media (prefers-reduced-motion:reduce){*{transition:none!important;animation:none!important}}

/* Honeypot. Off-screen rather than display:none -- some bots skip hidden
   fields, and a real person never reaches it (tabindex -1, aria-hidden). */
.hp{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}

/* ---------- consulting engagements ----------
   Page STRUCTURE follows abraham.com/consulting [Matt 2026-09-06: "I want the scrolling
   and general layout to be the same as jay's consulting page"], which lifted his earlier
   "ONLY the boxes, not the rest of that page's design" from 2026-09-02.
   What was taken: a sticky jump nav under the header, one anchored section per
   engagement, and a details panel that STICKS beside the copy on desktop while the long
   column scrolls past it, stacking below on tablet and phone.
   What was deliberately NOT taken, because each breaks a standing rule of Matt's:
   the giant ghosted numerals (no numerals as ornament), the alternating black bands
   (no dark sections), the numbered step circles (same, plus prose over lists), and the
   boxes around Ideal-for / Not-for (boxes only around a priced offer). */

/* Derived from the masthead's own tokens rather than a measured constant, so it tracks
   if the type scale moves: nav links are min-height:44px inside .bar's vertical padding,
   plus the 1px bottom border. */
:root{
  --mast-h:calc(44px + (2 * var(--space-s)) + 1px);
  /* One link tall, plus .enav-in's bottom padding, plus the bar's bottom border.
     MEASURED, not assumed: an early value here was derived from a padding that did not
     exist and overshot by 20px -- so if the padding below changes, change this too.
     The padding is --space-s [Matt 2026-09-07: "I see a horizontal line that goes across
     the lines under each link and it just makes things look weird ... just move the links
     up a bit so there's some space between the lines under each link and the line that
     spans the page"]. Each link carries a standing 1px underline and the bar carries a
     1px bottom rule; with no padding the two sat ~2px apart and read as one broken line.
     --space-s is the masthead's own vertical padding, so the two bars now match. */
  --enav-h:calc(44px + (2 * var(--space-s)) + 2px);
}
/* Below 44em the links are 36px, and below ~35em they wrap to two rows. This value is
   used for anchor clearance only (the sticky panel exists solely above 64em, where the
   bar is always one 44px row), so the two-row figure is used across the whole phone band:
   over-clearing an anchor jump costs a little extra gap, under-clearing hides the
   headline behind the bar. ⚠️ The wrap point moves if an engagement is renamed -- re-run
   test_sticky.py, which asserts every headline lands BELOW the bar. */
@media (max-width:44em){
  :root{--enav-h:calc((2 * 36px) + (2 * var(--space-s)) + 2px)}
}

/* The bar carries its OWN GROUND -- a raised fill with a hairline on both edges
   [Matt 2026-09-08: "the numbered intra-page sections look like they're part of the
   headline complex. it doesn't look right"]. On paper, with the hero's white space
   above it and a boundary only BELOW it, the eye grouped the row upward with the
   headline; the fill breaks that grouping by material rather than by spacing.
   He chose it from four treatments deployed at /preview/nav-a|b|c|d/ (still live,
   noindex, the record of what was rejected: a rule closing the hero, an editorial
   contents block, and reveal-on-scroll).
   ⚠️ This is the site's SECOND use of --paper-raised, which until now meant "priced
   panel" and nothing else. Deliberate, and his call. */
.enav{
  position:sticky;top:0;z-index:9;
  background:var(--paper-raised);
  border-top:1px solid var(--rule);border-bottom:1px solid var(--rule);
}
/* Desktop: the masthead is sticky at top:0, so this sits directly under it. On a phone
   the masthead is NOT sticky -- it pins only on an upward scroll, at z-index 20 -- so
   this sits at the top on its own until the header comes back.
   ⛔ This comment used to end "and the revealed header passes over it", which was a
   decision and is OVERRIDDEN as of 2026-09-08: the header covering the bar is exactly
   what Matt reported. The bar now yields to it -- see the .masthead.pinned.reveal rule
   in the masthead block above. */
@media (min-width:60em){.enav{top:var(--mast-h)}}
/* Padding on BOTH sides since 2026-09-08. It used to be bottom-only, on the reasoning
   that the links already sat clear of whatever was above them -- true while the bar was
   transparent, false the moment it took a fill, because the band now has a top edge of
   its own for the links to crowd. The bottom value is unchanged and still Matt's
   [2026-09-07: "just move the links up a bit so there's some space between the lines
   under each link and the line that spans the page"] -- though the per-link underline
   that complaint was about is now gone (see .enav a below), so what it buys today is
   simply that the band is not tighter under the links than over them.
   ⚠️ This value is baked into --enav-h above -- change both or anchor jumps and the
   sticky panel offset go wrong. */
.enav-in{
  width:100%;max-width:var(--shell);margin-inline:auto;
  padding-inline:var(--gutter);padding-block:var(--space-s);
}
/* WRAPS -- it does not scroll sideways [Matt 2026-09-06: "on mobile, those links slide
   left and right and the rightmost one starts off the page. i want them all on the page"].
   The first build used overflow-x:auto, copying Jay's, which pushes PARTNERSHIP off the
   right edge of a 390px screen with no affordance that anything is there. */
/* CENTRED above 44em, LEFT-ALIGNED below it [Matt 2026-09-08: "actually, just
   left-alighn them on mobile. it looks weird on desktop"]. The split is real, not a
   preference: MEASURED by sweeping the viewport, the four links sit on one row from
   592px up and wrap to two below it, and a centred two-row block leaves a short ragged
   second line under a full first one. 44em is reused rather than 37em because it is
   already this component's phone boundary (the 36px targets and --enav-h both turn
   there) -- one number to move if an engagement is ever renamed, not two. The cost is
   that 592-704px gets a left-aligned single row, which is a tablet, not the desktop he
   was looking at. ⚠️ Re-run the sweep if a nav label changes: the wrap point moves. */
.enav ul{
  display:flex;flex-wrap:wrap;justify-content:center;
  column-gap:clamp(1rem,.4rem + 1.9vw,2.25rem);row-gap:0;
  list-style:none;margin:0;padding:0;
}
/* These read as plain words without a persistent underline [Matt 2026-09-06: "the
   intra-page links aren't visually clear enough that they're links"]. The treatment is
   the site's existing one -- .textlink: ink, a standing 1px rule underneath, darkening
   to full ink on hover -- rather than a second link convention invented for this page. */
/* The standing underline is TRANSPARENT, not removed -- the box still reserves its
   1px so nothing shifts on hover. Once the bar has a fill it reads as navigation on
   its own, and keeping the underlines put a rule under every link between two rules
   spanning the page: three line families stacked, which is the pile Matt objected to
   on 2026-09-07. His 2026-09-06 ask that these read as links is answered by the band. */
.enav a{
  display:inline-flex;align-items:center;min-height:44px;white-space:nowrap;
  text-decoration:none;color:var(--ink);
  font-size:var(--s--1);letter-spacing:.16em;text-transform:uppercase;
  border-bottom:1px solid transparent;transition:border-color .18s ease;
}
.enav a:hover,.enav a:focus-visible{border-bottom-color:var(--ink)}
/* Two rows on a phone, so the bar does not eat the screen: 36px targets on a 36px pitch,
   the same trade the footer nav already makes below 480px, and still well clear of the
   24px minimum audit.py enforces. */
@media (max-width:44em){
  .enav a{min-height:36px}
  .enav ul{justify-content:flex-start}
}

/* An anchored jump must clear both sticky bars, or the headline lands underneath them. */
.engagement{scroll-margin-top:calc(var(--enav-h) + var(--space-m))}
@media (min-width:60em){
  .engagement{scroll-margin-top:calc(var(--mast-h) + var(--enav-h) + var(--space-m))}
}

.egrid{display:grid;grid-template-columns:1fr;gap:var(--space-l)}
/* The left column is exactly the site's reading measure -- widening it would introduce a
   SECOND measure, and leaving it inside a 1fr column left 330px of white beside every
   paragraph. So the pair is sized to its content and centred, which is what the rest of
   the site does with a measure on a wide screen. */
@media (min-width:64em){
  .egrid{
    grid-template-columns:minmax(0,var(--read)) 21rem;
    gap:var(--space-xl);align-items:start;justify-content:center;
  }
}
/* The reading measure is unchanged -- --read, the site's one measure -- it simply sits
   at the left of its column here instead of centred in the page.
   ⚠️ SCOPED to >=64em since 2026-09-08. Unscoped, it also fired in the 40-64em band,
   where .egrid is a SINGLE full-width column -- so the copy was pinned left at 463px
   inside a 765px column and left 329px of dead white down the right of every paragraph
   on an iPad [Matt 2026-09-08: "it looks terrible on the ipad air view"]. That is the
   exact defect the two-column desktop rule above was written to cure; the tablet band
   was simply never looked at. Below 64em .prose's own margin-inline:auto now stands,
   which is what every other page on the site does with a measure on a wide screen. */
@media (min-width:64em){.eflow{margin-inline:0}}

/* Same band, same cause: with .egrid at one full-width column the details panel had
   nothing capping it, so a box that is 336px wide on a desktop rendered 765px wide on
   an iPad. Capped at the reading measure and centred, so its edges line up with the
   copy above it rather than running out to the gutters. Inert at >=64em, where the
   grid column is already 21rem. */
@media (max-width:63.99em){
  .ecol{max-width:var(--read);margin-inline:auto}
}
/* ⛔ The engagement subheads are GONE [Matt 2026-09-06: "remove all the subheads under
   the option headings, like 'The conversation you can't have on camera.' -- get rid of
   those"]. Jay carries a promise line above each headline; Matt does not want one. */

/* Small-caps label in the flow of the copy. Same treatment as .offer dt and .field
   label already use -- faint, never the accent, which only ever touches a number. */
/* --dim, NOT --faint. --faint is documented at 4.9:1 and that is against --paper; on
   --paper-raised (the fitbox and panel fill) it measures 4.48 and fails the 4.5 floor.
   audit.py caught it; the eye never would. --dim is 5.4:1 on paper, ~5.0 on raised. */
.slab{
  font-size:.6875rem;letter-spacing:.16em;text-transform:uppercase;color:var(--dim);
  font-weight:400;
}
.eflow>.slab+p{margin-top:var(--space-xs)}

/* Ideal-for / Not-for are VISUAL BLOCKS [Matt 2026-09-06: "change the 'ideal for' and
   'not for' text into visual blocks like on Jay's site"]. ⚠️ This deliberately overrides
   his own 2026-09-02 rule that boxes are only ever allowed around a priced offer -- he
   asked for it directly, against Jay's page, with both in front of him.
   ⛔ These are ONE COLUMN at every width since 2026-09-08. There used to be a two-up
   rule for 40-64em, justified in this very comment on the grounds that the copy "runs
   the full page width" there -- and it never did. MEASURED: the copy runs at --read in
   that band too, so the split gave each box 213-218px, four or five words a line, which
   is the outcome the same comment rejected for the desktop case at 175px. The comment
   even names the trap it then fell into: the media query is a viewport width and the
   column is not. The correct test was the COLUMN's width, and nothing on this page ever
   gives it enough. Tablet now matches desktop, which is what Matt has actually seen. */
.fit{display:grid;grid-template-columns:1fr;gap:var(--space-m)}
.fitbox{border:1px solid var(--rule-strong);background:var(--paper-raised);padding:var(--space-m)}
.fitbox p{margin-top:var(--space-xs);color:var(--dim);font-size:var(--s--1);line-height:1.55}
/* ⛔ SIDE BY SIDE ON DESKTOP, INSIDE THE LEFT COLUMN. Both halves are Matt's, and the
   second half is a correction of how the first was built.
   [Matt 2026-09-12 #1: "make all the 'ideal for' and 'not for' boxes side by side on
   desktop like they are on Jay's site."]
   [Matt 2026-09-12 #2: "The boxes overlap on desktop when I scroll. they should be in
   the left column like they are on jay's site."]
   The first build satisfied #1 by making .fit a direct child of .egrid spanning BOTH
   columns, which bought each box 451px against the 226px the reading measure allows.
   It also shipped a defect: the sticky panel in column 2 travels down its own grid
   area, and with the boxes on a full-width row BENEATH that area the panel rode over
   them mid-scroll. Nothing static could see it -- the page renders clean at scroll 0,
   and the sticky test only asked whether the panel held at its offset, never what it
   held on top of. test_sticky.py now sweeps for exactly this collision.
   ⚠️ So the two-up split the 2026-09-08 note measured and rejected is now back, on
   Matt's explicit instruction, at 226px a box. It cannot be widened from here: at 1440
   the content area is 934px and the columns already consume all of it (486 + 112 gap +
   336 panel). Jay's boxes are 372px because his PROSE column is 768px and his
   paragraphs fill it -- he has no separate reading measure. Matching his box width
   would mean widening --read for this page, which puts a second measure on the site, or
   widening the column alone, which puts dead white beside every paragraph. Flagged to
   him with those numbers; do not quietly pick one. */
@media (min-width:64em){
  /* --space-s, not --space-m: at this width every pixel of the gap is a pixel off the
     box, and the boxes are already at the narrow end. */
  .fit{grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--space-s)}
  .fit .fitbox{padding:var(--space-s)}
}
/* The box labels take colour [Matt 2026-09-12: "change the color of the headings of the
   boxes like they are on jay's site, but use our color scheme"]. Jay's are gold #c9a84c
   and red #f87171 on near-black; ours are the bronze accent and --caution on paper.
   ⚠️ This is the THIRD documented override of "the accent only ever touches a number or
   a date" on this page, after the engagement numerals and the boxes themselves -- he
   asked for each one directly, with Jay's page in front of him. Still not a licence to
   colour a heading anywhere else on the site.
   Contrast is against --paper-raised (the fitbox fill), NOT --paper: that is the trap
   that shipped 20 failing labels for four days. Measured 4.52 and 6.44. */
.fitbox .slab{color:var(--accent)}
.fitbox.fit-no .slab{color:var(--caution)}

/* Desktop only: the panel follows the copy down its own section. Below 64em the grid is
   one column and the panel is an ordinary block under the prose. */
/* Desktop only: the panel follows the copy down its own section. Below 64em the grid is
   one column and the panel is an ordinary block under the prose.
   ⚠️ A sticky item can only travel as far as its column is TALLER than the item, so the
   panel's height and this offset together decide whether the effect is visible at all.
   Measured against abraham.com/consulting at 1440: his panels are 501-553px with a 144px
   offset (travel 248-438). The first build here was 633-728px with a 178px offset (travel
   177-307) and the panel ran out of column before it ever reached the offset -- it read as
   sticky in the CSS and did not stick on screen. The clearance below is --space-s, not
   --space-m, and the panel's internal rhythm is tightened, for exactly that reason. */
@media (min-width:64em){
  .ecol{position:sticky;top:calc(var(--mast-h) + var(--enav-h) + var(--space-s))}
  .ecol .offer .oh{margin-bottom:var(--space-s)}
  .ecol .offer dd{margin-bottom:var(--space-xs)}
  .ecol .offer .outcome{padding-top:var(--space-s);margin-top:var(--space-s)}
  .ecol .offer .btn{margin-top:var(--space-s)}
}

/* A compound price ("Half day $8,000 · Full day $12,000") wraps to three lines at --s-3
   and swamps the panel. build.py tags anything over 22 characters so the step down is
   mechanical rather than a judgement call per engagement. */
.offer .investment.long{font-size:var(--s-0);line-height:1.3}

/* The engagement number sits to the LEFT of its title [Matt 2026-09-06: "number the four
   intra-page links and also put the number to the left of the title of each of the four
   options"], and the jump links are numbered to match.
   ⚠️ This REVERSES his 2026-09-02 ruling -- "I really don't like the numbering", and the
   no-numerals-as-ornament rule that came out of it. He asked for it directly against
   Jay's page. It is NOT a licence to bring numerals back anywhere else on the site.
   Faint, not the accent: he ruled the accent off the new figures on this page the same
   day, and a numeral that is pure navigation is not a figure that means anything. */
.ehead{display:flex;align-items:baseline;gap:var(--space-s)}
.enum{
  font-family:var(--serif);font-size:var(--s-3);line-height:1;color:var(--faint);
  font-variant-numeric:lining-nums tabular-nums;flex:0 0 auto;
}
/* --dim, NOT --faint, and the reason is the fill above: --faint is documented at 4.9:1
   against --paper and measures 4.48 against --paper-raised, so these four numbers failed
   the 4.5 floor at all three viewports the moment the bar took a fill. audit.py caught
   it on the preview; the eye never would. Same trap as .slab, one element along. */
.enav .enum-n{
  font-variant-numeric:lining-nums tabular-nums;color:var(--dim);margin-right:.15em;
}
/* "What happens" is a numbered sequence [Matt 2026-09-12: "I want all the 'what happens'
   sections on this page to have 1-2-3 numbering like they do on Jay's consulting page"].
   Jay sets each numeral in a filled circle; this is the same information in this site's
   skin -- a serif figure in the margin, no circle, no rule between steps (his standing
   2026-09-02 rule against hairlines separating list items is untouched by the numbering
   instruction). Counter rather than list-style so the numeral can take its own face.
   --dim, not --faint and not the accent: these sit on --paper, but --faint measures 4.9
   there and a numeral that is pure sequence is not a figure that means anything. */
.steps{list-style:none;margin:var(--space-s) 0 0;padding:0;counter-reset:step}
/* ⛔ The numeral is BASELINE-ALIGNED with the step title, and it has to be done by the
   layout rather than by an offset. The first version absolutely positioned the ::before
   at `top:-.1em` -- an em of the NUMERAL's own font-size, which is a step larger than the
   title's and set in the serif, so the two never shared a baseline at any width and the
   figure rode high [Matt 2026-09-12: "all the numbers for all the 'what happens' section
   look too high; they're not on the same horizontal plane as the heading like they
   should be."] Nudging that offset is the wrong repair: it is a magic number that only
   holds at one font size, and this scale is fluid. A two-column grid with
   align-items:baseline hands the arithmetic to the browser, so it stays true as the
   clamp() sizes move between 390px and 1879px.
   The numeral takes row 1 explicitly; everything else auto-places down column 2, so a
   step with no title (build.py still accepts a bare string) simply puts its paragraph
   in row 1 and aligns to that instead. */
.steps>li{
  counter-increment:step;display:grid;grid-template-columns:auto minmax(0,1fr);
  column-gap:.9rem;align-items:baseline;
}
.steps>li+li{margin-top:var(--space-m)}
.steps>li>*{grid-column:2}
.steps>li::before{
  content:counter(step);grid-column:1;grid-row:1;
  font-family:var(--serif);font-size:var(--s-1);line-height:inherit;color:var(--dim);
  font-variant-numeric:lining-nums tabular-nums;
}
.steps .stept{font-size:var(--s-0);color:var(--text)}
.steps .stept+p{margin-top:.15rem;color:var(--dim);font-size:var(--s--1);line-height:1.55}
/* An introduction above the jump nav [Matt 2026-09-12]. It reads as part of the hero's
   thought, so it loses the hero's bottom padding rather than adding a full section gap. */
.eintro{padding-top:0}

/* Jay puts the expected outcome inside the panel under its own label; the label is the
   same small-caps treatment the rest of the page uses. */
.offer .outcome .slab{margin-bottom:var(--space-xs)}
