/* Mobile-first. The 375px column is the design; every media query widens it.
   Tokens match the PDF design system so the page and the artefact are the same
   product. */

:root {
  /* ---- OptimizedMale base palette (DESIGN_SYSTEM_SPEC.md §2) -------------
     Blues sampled from the brand banner; --om-blue-600 is the exact banner
     ground. Cream and ink sampled from the 7-Day Plan PDF.
     THERE IS NO NAVY. #14263F was used early and is retired brand-wide. */
  --om-blue-900: #0A2A4A;
  --om-blue-800: #0B3D6C;
  --om-blue-700: #0C4780;
  --om-blue-600: #0D508C;   /* PRIMARY - banner ground */
  --om-blue-500: #0F85C5;   /* GATE-3: rules and borders ONLY. 2.04:1 on the
                               blue ground, 3.79:1 on the page ground. It is
                               never a text ground and never a button fill. */
  --om-blue-300: #6F8BB0;
  --om-blue-200: #B9C8DD;
  --om-blue-100: #DBE4EF;
  --om-blue-050: #E6EAF0;

  --om-cream-050: #FAF7F1;  /* page ground */
  --om-cream-100: #F4EFE6;  /* panel / alternating band */
  --om-cream-200: #E9E4DB;
  --om-cream-300: #E1DBCF;
  --om-cream-400: #D8D1C4;
  --om-cream-500: #B0A795;

  --om-ink-900: #23262B;
  --om-ink-700: #4A5058;
  --om-ink-500: #666C74;
  --om-ink-400: #878F98;    /* 3.06:1 on the page ground - AA-large only.
                               NOT for running text. See the note below. */
  --om-white: #FFFFFF;

  --om-caution-700: #8A5A16;
  --om-caution-050: #F6EEDF;
  --om-positive-700: #2C6046;
  --om-positive-050: #E7EFE9;

  /* ---- semantic aliases -------------------------------------------------- */
  --ground-page: var(--om-cream-050);
  --ground-panel: var(--om-cream-100);
  --ground-deep: var(--om-blue-600);
  --ground-callout: var(--om-blue-050);
  --surface-card: var(--om-white);

  --text-body: var(--om-ink-900);
  --text-muted: var(--om-ink-500);
  --text-heading: var(--om-blue-800);
  --text-link: var(--om-blue-600);
  --text-on-deep: var(--om-cream-050);
  --text-on-deep-muted: var(--om-blue-200);

  --border-hairline: var(--om-cream-300);
  --border-on-deep: rgba(255, 255, 255, 0.22);
  --border-strong: var(--om-blue-600);
  --accent-rule: var(--om-blue-500);

  /* ---- geometry (spec §4) ------------------------------------------------ */
  /* No radius tokens. Square corners everywhere, decided 4 September 2026:
     one value (3px) on seven pages and absent on nine is a leftover, not a
     system, and 3px rounding under a 3px coloured edge - six of those on this
     page - is a dated pattern where the curve fights the rule. Removed rather
     than spread. Full reasoning in site/styles.css; DESIGN_SYSTEM_SPEC 4. */
  --border-width-hairline: 1px;
  --border-width-rule: 2px;
  --border-width-marker: 3px;

  /* ---- lockup: one constant, N consumers (spec §5, GATE-6) --------------- */
  --lockup-tagline: 0.97;
  --lockup-rule-width: 0.24;
  --lockup-rule-thickness: 0.0106;

  /* ---- motion (spec §7) -------------------------------------------------- */
  --duration-fast: 120ms;
  --duration-base: 180ms;
  --ease-standard: cubic-bezier(0.4, 0, 0.2, 1);

  /* ---- page-level names used throughout this stylesheet ------------------
     Retargeted onto the palette above. Every contrast ratio re-measured
     against the new page ground #FAF7F1, which is LIGHTER than the #f4efe6 it
     replaces, so every foreground gained contrast rather than losing it:
       --ink        14.19:1 (was 13.25)     --ink-muted  5.76:1 (was 5.38)
       --field      7.72:1  (was 7.21)      --signal     5.43:1 (was 5.07)
     On the deep ground #0D508C: #fff 8.26:1, --field-ink 7.72:1,
     --field-muted 4.86:1. */
  --field: var(--om-blue-600);
  --field-ink: var(--om-cream-050);
  --field-muted: var(--om-blue-200);
  --accent: var(--om-blue-500);
  --paper: var(--om-cream-050);
  --panel: var(--om-cream-100);
  --ink: var(--om-ink-900);
  --ink-muted: #5b626c;       /* 5.76:1. Kept over --om-ink-500 (4.96:1)
                                 because it already clears AA with margin. */
  --rule: var(--om-cream-400);
  --signal: #35705a;
  /* SALES_PAGE_SPEC §2: sections are full-bleed, the container inside them is
     --container-wide. 34rem (544px) made a 1440 screen read as a stretched
     phone rather than a designed page - the same defect as the site's prose
     column, flagged by the brand owner on both surfaces.
     The readable line is held by --measure-body on the prose itself, so the
     wider container never widens a line of text. */
  --measure: 67.5rem;             /* 1080px container */
  /* 42rem (672px), NOT 68ch. `ch` is the width of the "0" glyph in the CURRENT
     font, so a ch-based measure is a different number of pixels before and
     after the webfont swaps - the column itself resizes, and the sub-headline
     reflowed 31px at 1440. A metric-matched fallback cannot help with that,
     because the mismatch is in the container, not the type. Fixed length. */
  /* NARROWED 42rem -> 37rem, 4 September 2026, on a measurement rather than a
     unit. Method, so nobody re-derives the old wrong number: render the page,
     take every real body run over 120 characters, measure its advance width
     with the SAME computed font via canvas measureText, and divide the
     container width by the average per-character advance. 32 samples of live
     prose at 18px Source Serif 4 give an average advance of 8.49px, so 42rem
     (672px) was setting 79 characters a line (77-83 across samples), not the
     68 the spec claimed.
     `ch` is what produced that claim and `ch` is the wrong tool: it is the
     advance of the "0" glyph, which in this face is materially wider than the
     average letter, so "68ch" was only ever 68 zeros.
     37rem is 592px = 70 characters at the measured advance, 67-73 across the
     same samples - inside the 66-75 target at both ends. It stays in rem, not
     ch, because a ch measure resizes the container itself when the webfont
     swaps.
     GUARDED, from 4 September 2026. This number is no longer held by this
     comment. render_check.mjs measures it on every run - the same method,
     performed rather than asserted - and fails the build unless the 18px
     column leaves 66-75 characters, and again if any smaller type sharing
     that column sets MORE characters than the body does. The comment that
     used to stand here claimed 68ch and was wrong for months, precisely
     because a comment is a claim nobody can check from where it is written. If you change this token,
     the check will tell you what you actually did.
     */
  --measure-body: 37rem;
  /* Small type gets its own measure, in em. See site/styles.css for the full
     reasoning: --measure-body is right for the 18px run and much too wide for
     the 15px FAQ answers (measured 91-99 characters a line at 1440px) and the
     13px legal line (116). em scales with font-size and, unlike ch, is
     independent of glyph metrics, so it holds identically with the webfont and
     without. 30em is 64-68 characters at the sizes it is used at here - at or
     under the body, never over it, which is the relation render_check.mjs
     asserts on every run. */
  --measure-small: 30em;

  /* Fallback metrics matched to the webfonts, so the swap does not reflow the
     first screen. The hero must be correctly laid out with zero webfonts. */
  --serif: "OM Serif", "Source Serif 4 Fallback", Georgia, "Times New Roman", serif;
  --sans: "OM Sans", "Outfit Fallback", system-ui, -apple-system, "Segoe UI", sans-serif;
}

/* OM Sans is Outfit, a VARIABLE face. The `font-weight: 300 800` range below is
   not the bug that was fixed here previously: that was three static Inter files
   where ONE declared `400 700` and the browser drew 700 from the 400 outline.
   This file carries a real `wght` axis (verified: fvar wght 100-900), so every
   weight in the declared range is drawn, not synthesised. Confirm with
   `fonttools` before ever widening it again - a static file claiming a range is
   the failure mode, a variable file stating its true axis is not.
   Outfit and Source Serif 4 are both SIL OFL 1.1. */
@font-face {
  font-family: "OM Sans"; src: url("fonts/outfit-latin-wght-normal.woff2") format("woff2");
  font-weight: 300 800; font-display: swap;
}
@font-face {
  font-family: "OM Serif"; src: url("fonts/source-serif-4-latin-400-normal.woff2") format("woff2");
  font-weight: 400; font-display: swap;
}
@font-face {
  font-family: "OM Serif"; src: url("fonts/source-serif-4-latin-600-normal.woff2") format("woff2");
  font-weight: 600; font-display: swap;
}
@font-face {
  font-family: "OM Serif"; src: url("fonts/source-serif-4-latin-400-italic.woff2") format("woff2");
  font-weight: 400; font-style: italic; font-display: swap;
}
/* Metric-matched fallbacks: same line box before and after the swap. */
@font-face {
  font-family: "Source Serif 4 Fallback"; src: local("Georgia"), local("Times New Roman");
  /* RE-MEASURED 4 September 2026, when headings moved to the serif.
     98% was never width-matched - measured in Chromium, it rendered the hero
     string at 89.7% of the real face's advance width. At 18px body that never
     flipped a line so nothing caught it; at the 52px display step it dropped the
     hero from three lines to two and reflowed the first screen by 55px, which
     render_check is built to fail.
     109.2% is the measured width match (98 x 1395.7 / 1252.3). The vertical
     overrides are scaled by the inverse (x 98/109.2) so the LINE BOX is
     unchanged and only the glyph width moves: 92 -> 82.6, 26 -> 23.3. */
  size-adjust: 109.2%; ascent-override: 82.6%; descent-override: 23.3%; line-gap-override: 0%;
}
@font-face {
  font-family: "Outfit Fallback"; src: local("Helvetica Neue"), local("Arial");
  /* 100%, not the 108% Inter needed. Measured two ways that agree: Outfit@700
     sets 102.9% of Arial's advance width directly, and Outfit is 92.8% of
     Inter's width, which scales Inter's empirically-verified 108% to 100.2%.
     Wrap parity with the webfont is asserted by the render check, which is the
     criterion that actually matters - these numbers only pick the candidate. */
  size-adjust: 100%; ascent-override: 90%; descent-override: 22%; line-gap-override: 0%;
}

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  font: 400 18px/1.62 var(--serif);
  color: var(--ink);
  background: var(--paper);
}

.skip {
  position: absolute; left: -9999px;
  background: var(--paper); color: var(--ink); padding: .75rem 1rem;
}
.skip:focus { left: 1rem; top: 1rem; z-index: 10; }

section, footer {
  padding-block: 2rem;
}
/* The container is centred ONCE, by PADDING, and children are left-aligned
   within it.
   Two failure modes, both seen on this page:
     - centring every child individually (`margin-inline: auto` on each) only
       looks right while they are all the same width. The moment a heading and
       a paragraph have different max-widths it staggers them.
     - making children flush-left without centring the container leaves the
       text hugging the viewport edge: at 1440 the column started at x=32 with
       736px of dead space to its right, which is a worse version of the
       stretched-phone problem the wide container was meant to fix.
   Symmetric padding sized to centre a --measure content box does both: the
   container is centred, and everything inside it shares one left edge. */
section, footer {
  padding-inline: max(20px, calc((100% - var(--measure)) / 2));
}
section > *, footer > * { max-width: var(--measure-body); margin-inline: 0; }
section > .om-2up, section > .module-grid, section > .table-scroll,
/* The FAQ container may be wide, but the TEXT inside it may not. At
   --measure (1080px) the answers ran ~144 characters per line at 15px - about
   2.5x a readable measure, and on the smallest type on the page, answering the
   two most anxious questions a buyer brings. The question and the answer are
   both capped to the body measure; the row's rule still spans the container. */
section > .faq, section > .close-2up { max-width: var(--measure); }
.faq-q { max-width: var(--measure-body); }
/* The answers run at 15px, so they take the small measure, not the body one. */
.faq-a > * { max-width: var(--measure-small); }
/* The technique block is the thing the reader is asked to DO. It was the widest
   prose on the page at 113 chars; it reads at the body measure like everything
   else. */
.technique > * { max-width: var(--measure-body); }
section > p, section > ul, section > ol, footer > p { max-width: var(--measure-body); }
/* Element rules below MUST use margin-block, never the margin shorthand: the
   shorthand resets margin-inline to 0 and un-centres the column. */

.field { background: var(--field); color: var(--field-ink); }
.field h1, .field h2, .field h3 { color: #fff; }
.field a { color: #cddbec; }
.paper { background: var(--paper); color: var(--ink); }

h1 {
  /* SERIF DISPLAY. Changed 4 September 2026 - DESIGN_SYSTEM_SPEC §3.
     This is still the DISPLAY role, the largest thing on the page, but it is
     now Source Serif 4. The old value was Outfit 800 at 64px, and a serif
     cannot simply take that number: at 64px a serif 600 is optically larger and
     considerably heavier than a geometric sans 800, and the hero is two lines
     of a personal sentence, not a slogan. 52px desktop / 33px mobile at 600,
     with tracking pulled from -0.022em to -0.012em because tight tracking on a
     serif at display size collides the serifs. */
  font: 600 33px/1.12 var(--serif);
  letter-spacing: -0.012em;
  margin-block: 0 1rem;
}
h2 {
  font: 600 24px/1.26 var(--serif);
  letter-spacing: -0.005em;
  margin-block: 2.4rem .6rem;
}
h3 {
  font: 600 20px/1.34 var(--serif);
  letter-spacing: 0;
  margin-block: 2rem .6rem;
}
p { margin-block: 0 1.1rem; }
/* Spec §3: emphasis is 600, never 700. Undeclared here until now, so it took the
   user-agent default of `bold` (700) and Source Serif 4 had no 600 face shipped
   at all - the 600 woff2 is added in this pass. */
strong { font-weight: 600; }
.hero .sub { font-size: 21px; line-height: 1.52; }
/* THE HERO CLOSES ON ITS OWN COPY. On a phone the blue ran 49px past the
   sub-headline's last line against 32px above the headline - the section's
   2rem bottom padding plus the sub's own trailing margin, which is doing
   nothing because the sub is the last child. Bottom-heavy by half a line, and
   worse than the number looks because that last line is short ("half of it.")
   so the eye reads the whole right side of it as empty too. It stopped reading
   as breathing room and started reading as an unfinished block.
   Trailing margin dropped, bottom padding brought under the top: the ground
   now changes shortly after the copy it contains, which is what a ground
   change is for. */
.hero > :last-child { margin-block-end: 0; }
.hero { padding-block: 2rem 1.6rem; }
.field p { color: var(--field-ink); }
.cta-note, .field .cta-note { font: 400 14px/1.5 var(--sans); color: var(--ink-muted); }
.field .cta-note { color: var(--field-muted); }

ul, ol { margin-block: 0 1.2rem; padding-left: 1.2rem; }
li { margin-block: 0 .5rem; }

/* ------------------------------------------------------------- header */
/* The page opened directly onto the <h1>: no mark, no name, nothing telling a
   reader arriving from a bio link that he was in the right place. */
.site-header { padding: 1.25rem 20px; }
.site-header .brand {
  display: flex; align-items: center; gap: .625rem;
  max-width: var(--measure); margin-inline: auto; margin-block: 0;
  color: #fff;
  font: 700 19px/1 var(--sans); letter-spacing: -.01em;
}
.site-header img { display: block; height: 27px; width: auto; }
@media (min-width: 768px) { .site-header { padding: 1.5rem 2rem; } }

/* ---------------------------------------------------------------- CTA */
/* Left-aligned with everything else, not centred. `margin-inline: auto` was
   correct while the column was 544px and effectively the whole page; inside a
   centred 1080 container it puts the button on a different vertical from the
   text above and below it. The button is also capped so it does not stretch
   the full container width on desktop - a 1080px-wide button is a banner. */
/* The cap is on the BUTTON, not the block. .cta wraps the button AND its trust
   line, so capping the block squeezed the note to 22rem and broke a two-line
   sentence into four cramped ones. The button needs the cap - a 1080px-wide
   button is a banner - and the note needs the readable measure. */
.cta { margin-block: 2rem 0; margin-inline: 0; }
.cta .btn { max-width: 22rem; }
/* The note sat hard against the button's underside. 12px of air, and the
   readable measure so a two-line sentence stays two lines. */
.cta .cta-note { max-width: var(--measure-body); margin-block: .75rem 0; }
.btn {
  display: block;
  width: 100%;
  padding: 1rem 1.25rem;
  background: var(--ink);
  color: var(--paper);
  font: 700 17px/1.3 var(--sans);
  text-align: center;
  text-decoration: none;
  /* LOAD-BEARING, not a defensive default. This is what actually holds every
     button on the page above the 44px tap floor - the paddings above and on
     .sticky-btn do not, and a mutation shrinking .sticky-btn's padding to 2px
     could not move the rendered height at all. Removing this line drops the
     sticky button to ~44.5px on its own, and below the floor in combination
     with any padding reduction. See the note at .sticky-btn. */
  min-height: 48px;
}
.paper .btn { background: var(--field); color: var(--paper); }
.field .btn { background: var(--paper); color: var(--field); }
.btn:hover { opacity: .92; }
/* The focus ring was --signal on both grounds, which measures 2.62:1 against
   the navy field - a keyboard user could not see where they were. Each ground
   gets the ring that contrasts with it. */
.btn:focus-visible { outline: 3px solid var(--field); outline-offset: 3px; }
.field .btn:focus-visible { outline-color: #ffffff; }
.paper .btn:focus-visible { outline-color: var(--field); }
a:focus-visible { outline: 3px solid currentColor; outline-offset: 2px; }

/* ------------------------------------------------------------ callout */
/* SALES_PAGE_SPEC §4.8: the guarantee sits on the blue ground. This panel used
   to be a cream box on a cream page; once the section became blue, the cream
   fill stayed and `.field p` painted --field-ink (cream) on top of it - 1.01:1,
   invisible, and caught by the contrast check rather than by eye. The panel is
   now a hairline on the blue ground and carries no fill of its own. */
.callout {
  border: 1px solid var(--border-on-deep, rgba(255, 255, 255, 0.22));
  padding: 1.5rem 1.25rem;
  background: transparent;
}
.callout > :last-child { margin-bottom: 0; }

/* -------------------------------------------------------------- table */
.table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
table { border-collapse: collapse; width: 100%; font: 400 15px/1.45 var(--sans); }
th, td { padding: .7rem .75rem; text-align: left; border-bottom: 1px solid var(--rule); vertical-align: top; }
thead th { font-weight: 700; white-space: nowrap; }
tbody th { font-weight: 600; }
tbody td:first-of-type { background: rgba(20, 38, 63, .05); }

/* ------------------------------------- signature: the half-the-picture split
   SALES_PAGE_DESIGN_PLAN §4. REBUILT 4 September 2026, second attempt.

   ONE BAR, SPLIT IN HALF - not two bars. The first build stacked two
   full-length bars, one filled and one outlined, and two identical bars where
   one is ticked and one is not reads as a checklist: have this, do not have
   that. The plan calls this "the half-the-picture split", and a split is one
   thing divided rather than two things compared. So: a single bar the width of
   the measure, left half solid, right half hollow, sharing an edge. Blur the
   words and the claim is still there - half of it is present and half of it is
   not.

   The halves are equal, and the alternative was built and looked at rather than
   argued about. With the second half materially shorter it reads "a lot of
   that, very little of this", which says the missing half is SMALL - the
   opposite of the argument, since the missing half is the product - and it
   reads as a bar chart with the axis cropped, implying a measurement that does
   not exist. 50/50 is the only ratio this page can state honestly, and the copy
   already states it: every app teaches half of it.

   THE BAR IS THE OBJECT. The first build was 70% type - small bars beside loud
   tracked uppercase - so a screenshot of it shared a caption, not an image. The
   bar now carries the section on its own and the labels annotate it.

   No animation. §4 makes motion optional and requires it to degrade to a static
   two-state figure; a static figure IS that figure, needs no reduced-motion
   branch, and is what survives a screenshot. */
.signature {
  margin-block: 0 2.25rem;
  max-width: var(--measure-body);
  border-top: 1px solid var(--rule);
  padding-top: 1.5rem;
}
/* The two halves share an edge. No gap: a gap turns one divided object back
   into two adjacent ones, which is the reading this rebuild exists to lose. */
.signature-bars { display: flex; }
.signature-bar { flex: 1 1 50%; height: 56px; display: block; }
.signature-bar-full { background: var(--field); }
.signature-bar-empty { background: transparent; border: 2px solid var(--field); }
/* Each label sits under its own half, so the caption pair maps onto the picture
   without a leader line or a key. */
.signature-caption { display: flex; margin-block: .6rem 0; }
.signature-label {
  flex: 1 1 50%;
  margin: 0;
  padding-right: 1.25rem;
  /* SMALL, QUIET, SUBORDINATE. Was 12/13px at 0.1em in the brighter ink and
     competing with the bars it was supposed to annotate. The tracking comes
     down because tracking is what made it shout; 0.04em still separates
     uppercase letterforms without spacing them out like a headline. It stays
     12px at every width - it does not grow on desktop, the bar does. */
  font: 600 12px/1.35 var(--sans);
  letter-spacing: 0.04em;
  /* NOT text-transform. The copy walk reads RENDERED text, so a CSS transform
     makes the rendered string differ from anything the build can declare - the
     same trap already recorded for the module eyebrow. The label is uppercased
     in build.mjs and STRUCTURAL_TEXT is built from the same constant. */
  color: var(--ink-muted);
}
.signature-label:last-child { padding-right: 0; }
.signature-label-key { color: var(--field); }
@media (min-width: 768px) { .signature-bar { height: 72px; } }
/* ON THE DEEP GROUND. Caught by screenshotting the element on its own rather
   than trusting the page shot: --field IS the ground of a .field section, so
   the bars were being painted in the ground colour and the whole figure
   rendered as an empty blue band with labels floating beside nothing. The
   signature was designed against paper and then placed on blue.
   On blue the fill inverts to the paper colour (--field-ink, 7.72:1 on
   #0D508C) and the hollow half keeps a paper outline, so "filled" still reads
   as filled and "empty" still reads as empty. The second label takes the
   brighter of the two inks, because that half is the one carrying the
   argument. */
.field .signature { border-top-color: var(--border-on-deep); }
.field .signature-bar-full { background: var(--field-ink); }
.field .signature-bar-empty { border-color: var(--field-ink); }
.field .signature-label { color: var(--field-muted); }
.field .signature-label-key { color: var(--field-ink); }

/* -------------------------------------------------------- breakpoints */
@media (min-width: 768px) {
  /* 4.5rem left a 194px dead band at every one of the nine section boundaries
     on desktop (88 padding each side plus the last child's own margin), and
     114px on mobile. Measured, not eyeballed. 3rem brings desktop to ~114 and
     mobile to ~82 - still a clear register change, ~720px less dead scroll. */
  /* padding-BLOCK only: the `padding` shorthand resets padding-inline and
     would undo the centred container above. */
  section, footer { padding-block: 3rem; }
  h1 { font-size: 52px; line-height: 1.06; }   /* serif display, spec §3 */
  h2 { font-size: 28px; line-height: 1.22; }
  h3 { font-size: 21px; line-height: 1.32; }
  h2, h3 { font-size: 26px; }    /* spec §3 h2 */
  .btn { display: inline-block; width: auto; min-width: 20rem; }
}
@media (min-width: 1440px) {
  /* Was 5.5rem. THIS is the rule that produced the 194px band at 1440 - the
     768 breakpoint never applied there, so changing that one alone moved
     nothing on the width the page is mostly read at. Measured after: 130px.
     Kept slightly above the 768 value because a wider column earns a little
     more air, but nowhere near double. */
  section, footer { padding-block: 3.5rem; }
}

/* ------------------------------------------------- cold / warm variants */
/* One class on <html>, set from ?s=1 before first paint. The cold page is the
   default, which is the safe state for a shared or forwarded link. */
[data-variant="warm"] { display: none; }
.warm [data-variant="warm"] { display: block; }
.warm [data-variant="cold"] { display: none; }

/* `.field p` is (0,1,1) and beats `.ps` at (0,1,0), so the muted colour never
   applied and the P.S. rendered identical to the FTC line above it. The file
   already handles this for .cta-note; .ps needed the same. */
.ps { font: 400 14px/1.55 var(--sans); margin-block: 1.5rem 0; }
.field .ps { color: var(--field-muted); }

/* ------------------------------------------------------- legal footer */
/* Stripe requires these four reachable from the page taking payment. Muted and
   small, below the FTC line: legal furniture, not navigation. */
.legal ul { list-style: none; padding-left: 0; margin-block: 1.75rem .75rem;
            display: flex; flex-wrap: wrap; gap: 0 1.25rem; }
.legal li { margin-block: 0; }
/* 44px touch target. These are standalone links, not links inside a sentence,
   so the WCAG 2.2 inline exception does not apply to them. */
/* min-WIDTH too, not only height: "Terms" measures 41px at 14px/Inter and the
   target-size check caught it. A 3px miss is still a miss. */
.legal a { display: inline-block; min-height: 44px; min-width: 44px; text-align: center;
           padding-block: .65rem; font: 400 14px/1.55 var(--sans); }
/* Ground-aware. `--field-muted` is a colour for the BLUE ground only; when the
   footer moved to cream this rule put --om-blue-200 on --om-cream-050 at
   1.59:1. The base rule now carries the cream-ground colour and `.field`
   overrides it, which is the same shape .cta-note and .ps already use. */
.entity { font: 400 13px/1.5 var(--sans); color: var(--ink-muted); margin-block: 0; }
.field .entity { color: var(--field-muted); }

/* ===================================================================
   DESIGN SYSTEM — SALES_PAGE_SPEC
   =================================================================== */

/* §2 ground sequence. Three grounds exist; never more than two in one
   viewport (spec §9 hard rule 5, and "view" = a viewport at the widths under
   test). cream-050 / cream-100 is the quiet step, blue is the loud one. */
.panel { background: var(--panel); color: var(--ink); }

/* -------------------------------------------------- §3 BannerMasthead */
/* Same ground as the hero, separated by a hairline rather than by a second
   blue. GATE-6: --lockup-w is the ONLY dimension set here. */
.masthead {
  background: transparent;
  border-bottom: var(--border-width-hairline, 1px) solid var(--rule);
  padding: 1.15rem 24px .85rem;
  text-align: left;
  --lockup-w: 132px;
}
/* margin 0, not "0 auto". The head is left aligned but the image was still
   centring itself inside it, so the sales page shipped a centred running head
   while the site shipped a left-aligned one. */
.lockup-wordmark {
  display: block; margin: 0;
  width: 100%; max-width: var(--lockup-w); height: auto;
}
.lockup-rule {
  display: block; margin: 1rem auto 0;
  background: var(--accent);
  width: calc(var(--lockup-w) * var(--lockup-rule-width));
  /* max(): 0.0106W is 3.07px at W=290 and the spec sets a 3px FLOOR, so the
     floor is expressed rather than the value hard-coded per breakpoint. */
  height: max(3px, calc(var(--lockup-w) * var(--lockup-rule-thickness)));
}
.lockup-tagline {
  display: block; margin: 1rem auto 0;
  width: 100%; max-width: calc(var(--lockup-w) * var(--lockup-tagline));
  height: auto;
}

/* -------------------------------------------------- §5 StickyCta */
/* The only fixed element the brand permits. Reserve its height at the foot of
   the page so it can never cover the footer's last line. */
body { padding-bottom: 70px; }
.sticky {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 40;
  background: var(--field);
  /* The CONTAINER carries the colour, not only the spans inside it. Setting it
     on .sticky-price/.sticky-name alone left the <p> itself inheriting --ink
     from body, which is #23262B on #0D508C - 1.84:1, unreadable. The contrast
     check measures the block element, which is the <p>. */
  color: #fff;
  border-top: var(--border-width-rule) solid var(--accent);
  transform: translateY(102%);
  transition: transform 280ms var(--ease-out);
}
.sticky.is-in { transform: translateY(0); }
.sticky-inner {
  max-width: var(--measure); margin-inline: auto;
  padding: 12px 20px;
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
}
.sticky-facts {
  margin: 0; display: flex; align-items: baseline; gap: .75rem;
  min-width: 0;                            /* lets the ellipsis below engage */
}
.sticky-price {
  font: 800 26px/1 var(--sans); letter-spacing: -0.02em; color: #fff;
}
.sticky-name {
  font: 600 14px/1.2 var(--sans); color: #fff;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* §7 decision 3 answered by measurement, not preference: at 390px the left
   cluster cannot hold price + name + note + button above a 44px tap target.
   The NOTE drops, not the name - the guarantee is repeated in the guarantee
   block and the comparison table, the product name is what tells the reader
   what the $49 buys. */
.sticky-note { font: 400 12px/1.2 var(--sans); color: var(--field-muted); white-space: nowrap; }
@media (max-width: 619px) { .sticky-note { display: none; } }
/* The 44px tap floor on this button is held by `min-height: 48px` on .btn, NOT
   by the padding below. Established by mutation: shrinking this padding to 2px
   does not move the rendered height at all, and dropping min-height alone
   still leaves the button at ~44.5px. Only both together breach the floor.
   Consequence for whoever tunes this next, in both directions: this padding
   has more slack than it looks (the floor is elsewhere), and min-height is
   load-bearing despite reading like a defensive default. Do not remove it. */
.sticky-btn {
  flex: none; margin: 0; width: auto; min-width: 0; padding: .7rem 1.1rem;
  /* §5: the bar's button is the onDeep variant. Without this it inherited
     .btn's base fill (--ink, near-black) - .paper .btn and .field .btn both
     scope to a section class, and the bar is inside neither. A near-black
     button on the brand blue is off-system and reads as a third colour. */
  background: var(--paper); color: var(--field);
}
.sticky-btn:focus-visible { outline-color: #fff; }

/* -------------------------------------------------- §7 motion + focus */
/* Colour only. No scale, no shrink, no linear timing (doctrine WEB-013). */
a, .btn { transition: var(--duration-fast) var(--ease-standard); transition-property: color, background-color, border-color; }
:focus-visible { outline: var(--border-width-rule) solid var(--accent); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) {
  /* BLANKET, matching site/styles.css. This rule used to enumerate .sticky and
     `a, .btn`, and .module was not on the list - so two border-colour
     transitions survived a reduced-motion preference. An enumerated list is a
     list somebody has to remember to extend; the universal selector cannot be
     forgotten. */
  *, *::before, *::after {
    transition: none !important;
    animation: none !important;
    scroll-behavior: auto !important;
  }
}
}

/* -------------------------------------------------- §3/§6 lockup ramp */
/* THE RUNNING HEAD STAYS A RUNNING HEAD ON DESKTOP. These two rules used to
   read 420px/3rem and 560px/4rem, which is the billboard the phone lost: at
   1440 the head was 270px tall with a wordmark wider than the prose column
   under it. A masthead that shrinks on the small screen and grows on the large
   one is sized for the designer's monitor, not the reader.
   It grows a little, because a 132px mark on a 1440px canvas reads as an
   oversight rather than a decision, and the gutter widens to match the page's
   own. Nothing else changes: same rule, same alignment, same 44px target. */
@media (min-width: 768px) { .masthead { --lockup-w: 152px; padding: 1.35rem 32px 1rem; } }

/* -------------------------------------------------- §4.4 ModuleCard */
.module-grid { display: grid; gap: 16px; margin-block: 2rem 0; }
.module {
  position: relative;                      /* the ghost is absolute to this */
  overflow: hidden;                        /* and is clipped by it */
  background: var(--surface-card);
  border: var(--border-width-hairline) solid var(--om-cream-300);
  border-top: var(--border-width-marker) solid var(--om-blue-600);
  padding: 2rem 1.5rem;
  transition: border-color var(--duration-fast) var(--ease-standard);
}
/* §7: hover is colour only. Nothing moves. */
.module:hover { border-color: var(--accent); }
.module-ghost {
  position: absolute; top: 6px; right: 14px;
  font: 800 78px/1 var(--sans); letter-spacing: -0.04em;
  color: var(--om-blue-050);
  pointer-events: none;
  /* aria-hidden in the markup as well: this is the card's own number rendered
     large, and a screen reader announcing "2" before "Module 2" is noise. */
}
.module-body {
  position: relative;                      /* sits above the ghost */
  /* §4.4 calls `meta` a FOOTER slot. Without this the metric row follows the
     body copy wherever it ends, so in a 3-up grid of unequal card lengths the
     rows sit at three different heights with dead space beneath the shortest.
     Pinning meta to the bottom makes the figures line up ACROSS the row, which
     is the whole reason the section is data rather than prose. */
  display: flex; flex-direction: column;
  height: 100%;
}
.module { display: flex; }                 /* so .module-body can fill it */
/* Cards size to their own content instead of stretching to the tallest in the
   row. Stretching left Module 1 - whose copy is short and which the source
   supports only ONE figure for - as a mostly empty box with its metric marooned
   at the bottom. The alternative was inventing a second figure for it, which is
   inventing content. A ragged bottom edge across a row of hairline cards is
   ordinary editorial layout; a hollow card is a defect. */
.module-grid { align-items: start; }
/* One heading block, three visual parts. The spans give §4.4's hierarchy while
   the h3's text content stays exactly the source line, so copy fidelity grades
   the sentence the document actually contains. */
.module-head { margin-block: .25rem .75rem; }
.module-eyebrow {
  display: block;
  font: 600 12px/1 var(--sans); letter-spacing: 0.18em;
  color: var(--field);
  margin-block: 0 .5rem;
  /* NO text-transform. Uppercasing rewrites rendered copy, and this eyebrow is
     part of a sentence the page reproduces verbatim. Weight, tracking, size
     and colour carry the eyebrow role without touching the words. */
}
/* The em dash is structural in the source and meaningless once the parts are
   stacked, so it is hidden from sight but left in the text for the checker. */
.module-dash { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
.module-title { display: block; font: 600 21px/1.26 var(--serif); letter-spacing: -0.004em; }
.module-sub {
  display: block; margin-top: .35rem;
  font: 600 13px/1.4 var(--sans); color: var(--ink-muted); letter-spacing: 0;
}
.module-meta {
  display: flex; flex-wrap: wrap; gap: 24px;
  border-top: var(--border-width-hairline) solid var(--om-cream-300);
  margin-block: 1.25rem 0; padding-block: 1rem 0;
  margin-top: auto;                        /* the footer slot */
}

/* -------------------------------------------------- §6 Metric */
/* Numerals are tabular everywhere (spec §9 hard rule 10) - the subset ships
   `tnum` and this is where it is switched on. */
.metric { margin: 0; font-variant-numeric: tabular-nums; }
.metric-value {
  font: 800 40px/0.9 var(--sans); letter-spacing: -0.03em;
  color: var(--field);
}
.metric-unit { font: 600 11px/1 var(--sans); color: var(--ink-muted); margin-left: .2rem; }
.metric-label {
  display: block; margin-top: 8px;
  /* NO text-transform: the build emits the label already uppercased, so the
     rendered string is one this file can also construct for the allowlist. */
  font: 600 11px/1.2 var(--sans); letter-spacing: 0.12em;
  color: var(--ink-muted);
}
/* tone="deep" - on the blue ground. */
.metric-deep .metric-value { color: #fff; }
.metric-deep .metric-unit,
.metric-deep .metric-label { color: var(--field-muted); }

@media (min-width: 620px) {
  .module-grid { grid-template-columns: repeat(2, 1fr); gap: 20px; }
}
@media (min-width: 900px) {
  .module-grid { grid-template-columns: repeat(3, 1fr); }
}

/* -------------------------------------------------- §4.5 Fit panels */
.om-2up { display: grid; gap: 16px; margin-block: 1.5rem 0; }
.fit {
  border: var(--border-width-hairline) solid var(--om-cream-300);
  padding: 1.5rem 1.25rem;
}
/* No ticks, no crosses, no green, no red (§4.5). The fill, the border weight
   and the marker weight do the ranking. */
.fit-yes { background: var(--surface-card); border-top: var(--border-width-marker) solid var(--om-blue-600); }
.fit-no  { background: transparent;         border-top: var(--border-width-marker) solid var(--om-cream-400); }
.fit p:first-child { font: 700 19px/1.3 var(--sans); margin-block: 0 .9rem; }
.fit-yes p:first-child { color: var(--text-heading); }
.fit-no  p:first-child { color: var(--ink-muted); }
.fit ul { list-style: none; padding-left: 0; margin-block: 0; }
.fit li {
  display: grid; grid-template-columns: 18px 1fr; gap: 12px;
  font-size: 15px; line-height: 1.6; margin-block: 0 16px;
}
.fit li::before { content: ""; display: block; margin-top: 11px; }
.fit-yes li::before { border-top: 2px solid var(--om-blue-600); }
.fit-no  li::before { border-top: 1px solid var(--om-cream-500); }

/* -------------------------------------------------- §4.7 ComparisonTable */
/* Column 2 is ours and is highlighted. Cells carry WORDS, not symbols. Below
   620px the table scrolls horizontally rather than restructuring into stacked
   cards: stacked cards read more easily and lose the side-by-side comparison,
   which is the entire point of the section. Explicit brand-owner decision,
   made knowing most traffic is mobile. */
[data-section="comparison"] table { min-width: 620px; }
[data-section="comparison"] thead th { border-bottom: var(--border-width-rule) solid var(--om-cream-300); }
[data-section="comparison"] thead th:nth-child(2) {
  background: var(--om-blue-600); color: #fff;
  border-bottom-color: var(--om-blue-600);
}
[data-section="comparison"] tbody td:nth-child(2) {
  background: var(--om-blue-050); color: var(--om-blue-800); font-weight: 600;
  border-bottom-color: var(--om-blue-100);
}
[data-section="comparison"] tbody th { font-size: 13px; color: var(--ink-muted); vertical-align: top; }
[data-section="comparison"] td { vertical-align: top; }

/* -------------------------------------------------- §4.9 FaqItem */
.faq { margin-block: 1.5rem 0; }
.faq-row { border-bottom: var(--border-width-hairline) solid var(--om-cream-300); }
/* DO NOT put `display: flex` on <summary>. Chrome stops treating it as the
   details' summary and the disclosure silently dies: every row reports
   open=false while its content renders at full height, so the accordion looks
   built, behaves as a plain list, and nothing about the page looks wrong. That
   shipped here once and was found only by measuring an answer's height in both
   states. The flex layout goes on an inner wrapper instead. */
.faq-row summary {
  padding-block: 24px; cursor: pointer;
  font: 700 17px/1.35 var(--sans); color: var(--text-heading);
  list-style: none;                        /* kill the default triangle */
}
.faq-head { display: flex; justify-content: space-between; align-items: baseline; gap: 1rem; }
.faq-row summary::-webkit-details-marker { display: none; }
/* The marker is the CHARACTERS + and -, per §4.9. No chevron, no icon, no
   rotation - a rotating chevron is a transform, and §7 permits none.
   Drawn into a REAL element rather than with ::after content. render_check
   rejects generated content on a non-block element, and rightly: text painted
   in by CSS belongs to no block, so no copy or contrast check can read it.
   The span is aria-hidden - <summary> already announces its own expanded
   state, and a screen reader reading "plus" after the question is noise. */
/* BOTH characters ship in the markup and CSS chooses between them. A ::before
   with `content` is generated content, which render_check rejects for every
   element - text painted in by CSS belongs to no block, so nothing can read it
   for copy or grade it for contrast. Swapping one character on [open] without
   JavaScript means having both present and hiding one. */
.faq-marker { flex: none; font: 400 20px/1 var(--sans); color: var(--field); }
.faq-row .faq-minus { display: none; }
.faq-row[open] .faq-plus { display: none; }
.faq-row[open] .faq-minus { display: inline; }
.faq-row summary:focus-visible { outline: var(--border-width-rule) solid var(--accent); outline-offset: 2px; }
.faq-a { padding-block: 0 24px; max-width: var(--measure); }
.faq-a p { font-size: 15px; line-height: 1.6; }

@media (min-width: 620px) {
  .om-2up { grid-template-columns: 1fr 1fr; gap: 32px; }
}

/* -------------------------------------------------- §4.6 Proof panel */
/* A callout with a 3px left marker, square on the marker side. The two clinical
   figures are NOT restructured into StatFigure components: the value, the label
   and the source caveat are one sentence each in the copy, and pulling the
   numeral out to display scale would reorder the words. GATE-2 is already
   satisfied by the copy itself - each figure states its caveat in the same
   breath - so the styling emphasises the figure and sets the citation apart
   without touching the sentence. */
[data-section="clinical"] > ul {
  background: var(--ground-callout);
  border-left: var(--border-width-marker) solid var(--om-blue-600);
  list-style: none;
  padding: 1.5rem 1.25rem;
  margin-block: 1.5rem;
}
[data-section="clinical"] > ul > li { margin-block: 0 1.25rem; }
[data-section="clinical"] > ul > li:last-child { margin-block: 0; }
/* The bolded claim is the figure. Larger and in the brand blue, so the number
   carries display weight while staying inside its sentence. */
[data-section="clinical"] > ul > li strong {
  font-size: 19px; line-height: 1.35; color: var(--text-heading);
  font-variant-numeric: tabular-nums;
}
/* The citation. `em` is the *(Dorey et al., 2004)* the copy already carries. */
[data-section="clinical"] > ul > li em {
  font-size: 13px; color: var(--ink-muted);
}

/* -------------------------------------------------- §4.10 Close cards */
.close-card {
  padding: 1.5rem 1.25rem;
}
/* Option 1 is not styled to lose - see the note in build.mjs. */
.close-1 { background: transparent; border-top: var(--border-width-marker) solid var(--om-cream-400); }
.close-1 p { color: var(--ink-muted); font-size: 15px; }
.close-2 { background: var(--field); border-top: var(--border-width-marker) solid var(--accent); }
.close-2 p { color: var(--field-ink); font-size: 15px; }
.close-2 strong { color: #fff; }

/* ===================================================================
   TWO NEW BLOCK TYPES — added for copy v2
   Nothing else in this file changed. Both are structural: v2 introduces
   two kinds of block v1 had no equivalent for, and neither could be
   drawn with an existing class without reading as the selling copy it
   has to be told apart from.
   =================================================================== */

/* "Try This Now" — a technique the reader PERFORMS while reading, sitting
   between two sections that are selling to him. If it looks like another
   pitch he skips it, and it is the strongest thing on the page, so it is
   given the paper ground on a panel band plus a marker rule: an inset
   card, visibly a different kind of thing from the prose above and below.
   The marker is --om-blue-600, not --om-blue-500: GATE-3 permits the
   accent as a rule, and this rule is heavy enough to read as a fill at a
   glance, so the darker token is the safer of the two. */
.technique {
  background: var(--paper);
  border-left: var(--border-width-marker, 3px) solid var(--om-blue-600);
  padding: 1.75rem 1.5rem;
  margin-inline: auto;
  max-width: var(--measure);
}
.technique > :last-child { margin-bottom: 0; }
@media (min-width: 768px) { .technique { padding: 2.25rem 2rem; } }

/* The three forum quotes in "What Nobody Teaches". Real public posts,
   quoted verbatim, spelling and grammar as posted — which is the whole
   point of quoting them, so nothing here corrects or tidies anything.
   Set in the serif at body size, indented behind a rule, so they read as
   somebody else's voice rather than as the page's own.
   The attribution is a span INSIDE the paragraph, not a <cite>: the copy
   walk grades leaf blocks, and a sibling <cite> would belong to no block
   and go ungraded. It is told apart by weight and face, never by colour —
   a dimmer colour on a run nested inside the graded leaf would be a
   contrast hole the checker cannot see. */
.forum-quote {
  margin: 1.25rem 0;
  padding-left: 1.25rem;
  border-left: 2px solid var(--om-blue-500);
}
.forum-quote p { font-style: italic; }
.quote-source { font: 600 14px/1.5 var(--sans); font-style: normal; white-space: nowrap; }

/* The legal links moved from a <ul> to one inline sentence, because the
   copy now writes them as one — "Terms · Privacy · Refunds · Contact —
   OptimizedMale is a brand of…". The 44px target rule above still
   applies to each anchor; this only stops the inline-block anchors from
   pulling the line apart. */
p.legal { font: 400 13px/1.5 var(--sans); color: var(--ink-muted); margin-block: 1.5rem 0;
           max-width: var(--measure-small); }
p.legal a { min-width: 0; padding-inline: .25rem; }
.field p.legal { color: var(--field-muted); }

/* The exit-intent section's button. A SECONDARY action: it offers the free
   plan, not the product, and it sits on the blue field ground where the buy
   button is a solid cream slab. Drawn as an outline instead — same size and
   the same 44px floor, deliberately less weight — so it cannot be mistaken
   for the buy button by a reader skimming the modal. White on --om-blue-600
   is 6.7:1, and the border carries the shape at the same contrast rather
   than relying on the accent, which GATE-3 keeps off text grounds. */
.btn-secondary,
.field .btn-secondary {
  background: transparent;
  color: #fff;
  border: 2px solid rgba(255, 255, 255, .72);
  font-weight: 600;
}
.btn-secondary:hover { background: rgba(255, 255, 255, .10); border-color: #fff; }
.field .btn-secondary:focus-visible { outline-color: #ffffff; }

/* ------------------------------------------------ the exit-intent modal
   It ships with the `hidden` attribute and the inline script removes it.
   `.modal` sets `display: flex`, which BEATS the browser's own
   `[hidden] { display: none }` — so the attribute would have stopped hiding
   anything and the modal would have been on screen from first paint, over
   the hero, for every reader. The `[hidden]` rule below is load-bearing, not
   defensive tidying: it is what makes `hidden` mean hidden once this element
   has a display of its own. */
.modal[hidden] { display: none !important; }
.modal {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.25rem;
  /* Deep blue at 72%, not black: the scrim is the brand's own ground dimmed,
     and the panel sits on the same blue so the two read as one surface. */
  background: rgba(10, 42, 74, .72);
}
.modal-panel {
  position: relative;
  width: 100%;
  max-width: 34rem;
  max-height: 90vh;
  overflow-y: auto;
  padding: 2.25rem 1.5rem 1.75rem;
  background: var(--field);
  border: 1px solid rgba(255, 255, 255, .22);
}
.modal-panel > :last-child { margin-bottom: 0; }
/* 44px on both axes. It is the only way out for a reader who does not know
   about Escape, and a close control under the tap floor is a trap. */
.modal-close {
  position: absolute;
  top: 0;
  right: 0;
  min-width: 44px;
  min-height: 44px;
  padding: 0;
  background: transparent;
  border: 0;
  color: #fff;
  font: 400 26px/1 var(--sans);
  cursor: pointer;
}
.modal-close:hover { color: var(--om-blue-100); }
.modal-close:focus-visible { outline: 2px solid #fff; outline-offset: -4px; }
