/* =====================================================================
   ANTAEUS — site layer. Depends on tokens-10.css.
   The page is one page of the ledger the app keeps: a continuous spine,
   a mono margin, ruled entries. Doctrine:
   docs/design-reference/LEDGER_SPEC.md.
   ===================================================================== */

main {
  position: relative;
  z-index: 1;
}

/* =====================================================================
   THE CHASSIS
   The spine is ONE absolutely-positioned pseudo-element on the page
   wrapper, not a per-section border. That is what makes it continuous
   by construction: no section boundary can interrupt a rule drawn on a
   single element, so no future section can accidentally break it.
   ===================================================================== */
.ledger-page {
  position: relative;
  padding-left: calc(var(--mgn) + var(--mgn-pad));
}
.ledger-page::before {
  content: '';
  position: absolute;
  left: var(--mgn);
  top: 0;
  bottom: 0;
  width: 1px;
  background: var(--border);
}

/* A margin mark: mono, right-aligned against the spine.
   SPARSE BY LAW. A mark must survive "why is that there?" — if the
   answer is "the column looked empty", delete it. A mark on everything
   is a mark on nothing, the same way accent on every row is accent on
   none. */
.mark {
  position: absolute;
  left: calc(-1 * (var(--mgn) + var(--mgn-pad)));
  width: var(--mgn);
  padding-right: var(--s-sm);
  text-align: right;
  font-family: var(--f-mono);
  font-weight: 500;
  font-size: 11px;
  line-height: 16px;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--t3);
  font-variant-numeric: tabular-nums;
}
/* Accent is EARNED — a PR, a shipped release. Never a category tag. */
.mark.earned {
  color: var(--accent);
}

/* Rule head: 2px is reserved for section starts (LEDGER_SPEC §4). The
   1px .rule in tokens-10.css stays the ROW weight, and the two are
   never adjacent. */
.rulehead {
  display: flex;
  align-items: flex-end;
  gap: var(--s-sm);
  padding-bottom: var(--s-sm);
  border-bottom: 2px solid var(--border);
  margin: 0 0 var(--s-lg);
}
.rulehead > .mono:first-child {
  color: var(--t2);
}
/* A rule head that IS the section's heading (the tools pages' Questions
   and More free tools) must stay a real <h2> for the document outline
   while reading as a head, not as a 32px display line. All of its text
   lives in the .mono span, so the element's own type only sets the flex
   line box. */
h2.rulehead,
h3.rulehead {
  font-size: inherit;
  font-weight: inherit;
}
.rulehead .rulehead-cap {
  margin-left: auto;
  text-align: right;
  font-size: 13px;
  line-height: 18px;
  color: var(--t3);
  flex-shrink: 1;
}

/* ⚠️ THE WRAP FIX HAS TO COME WITH THE 2px WEIGHT. `.rulehead` was
   copied from `.rule` (tokens-10.css) but not `.rule`'s 760px rule, so
   between 561 and 760px a head had neither: the label wrapped mid-phrase
   while the cap hugged the right edge.

   The answer below 560px used to be `display: none` on the cap, with the
   reason "every cap on this site restates the section's own first
   sentence, so dropping it here costs nothing". That is false for the
   pages it hit hardest: build-tools-pages.py replaced an always-visible
   `FREE TOOL · NO SIGNUP` line with a rulehead whose cap is "No signup,
   nothing stored", and no tool lede restates it. Phones are the bulk of
   organic search traffic to /tools/*, so the one promise those pages
   exist to make was deleted for most of their readers. A cap that drops
   to its own line and reads left costs a line and keeps the claim. */
@media (max-width: 760px) {
  .rulehead {
    flex-wrap: wrap;
  }
  .rulehead .rulehead-cap {
    margin-left: 0;
    text-align: left;
    flex-basis: 100%;
  }
}

/* The band: value vs personal baseline, centre tick (LEDGER_SPEC §7).
   A BAND is never a TRACK — a track measures progress toward a target
   and puts its tick at the END. One band on this site, in the coach
   entry, carrying the number its own sentence names. */
.band {
  position: relative;
  display: block;
  height: 14px;
  width: 100%;
  max-width: 180px;
  margin-top: var(--s-sm);
}
.band i {
  position: absolute;
  display: block;
}
.band .band-line {
  top: 50%;
  left: 0;
  right: 0;
  height: 1px;
  background: var(--tick);
}
.band .band-centre {
  top: 3px;
  bottom: 3px;
  left: 50%;
  width: 1px;
  background: var(--ghost-outline);
}
.band .band-now {
  top: 50%;
  left: var(--band-pos, 50%);
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--t1);
  transform: translate(-50%, -50%);
}

/* Marks fade in as their entry arrives — opacity only, nothing moves,
   and the whole effect is absent under reduced motion (where the marks
   are simply always visible, and the observer is never created).

   ⚠️ GATED ON `.marks-anim`, WHICH marks-1.js SETS ON <html>. Without
   that gate the default state was `opacity: 0` and only the script could
   reveal it — so a blocked, failed or slow script left every margin mark
   INVISIBLE. The marks carry information (privacy §4 is cited by number
   from CLAUDE.md and SITE_README), so they must never depend on
   JavaScript to be seen. Hiding is now something the script opts INTO
   after it has proven it can undo it. */
@media (prefers-reduced-motion: no-preference) {
  .marks-anim .mark {
    opacity: 0;
    transition: opacity 150ms ease;
  }
  .marks-anim .mark.in {
    opacity: 1;
  }
}

/* =====================================================================
   PHONE — a hairline bezel. LEDGER_SPEC §5 exempts HARDWARE from the
   chamfer scale, which is why 42px is allowed here and nowhere else.
   The fill and the drop shadow are gone: they were card chrome, and
   the screenshot is meant to be the only surface on the page.
   The screen is a CSS background so only ONE theme's image is ever
   downloaded, and the swap is instant with no flash.
   ===================================================================== */
.phone {
  width: 100%;
  max-width: 320px;
  border-radius: 42px;
  border: 2px solid var(--border);
  padding: 6px;
}
.shot {
  display: block;
  width: 100%;
  aspect-ratio: 860 / 1870;
  border-radius: 34px;
  background-size: cover;
  background-position: top center;
  background-repeat: no-repeat;
  background-color: var(--bg);
}
.phone.tall .shot {
  aspect-ratio: 860 / 1180;
  background-position: top center;
}

/* One rule per screen, twice (light default + dark override).
   Versioned in the FILENAME, never with a ?v= token — this zone's
   cache does not treat the query string as part of the cache key, and
   a reused name served a four-month-old screenshot for exactly that
   reason. siteIntegrity.test.mjs now fails on either mistake. */
.shot.today { background-image: url('screens/today-light-4.webp'); }
.shot.muscles { background-image: url('screens/muscles-light-4.webp'); }
.shot.fuel { background-image: url('screens/fuel-light-4.webp'); }
.shot.coach { background-image: url('screens/coach-light-4.webp'); }
.shot.records { background-image: url('screens/records-light-4.webp'); }
.shot.logger { background-image: url('screens/logger-light-4.webp'); }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) .shot.today { background-image: url('screens/today-dark-4.webp'); }
  :root:not([data-theme='light']) .shot.muscles { background-image: url('screens/muscles-dark-4.webp'); }
  :root:not([data-theme='light']) .shot.fuel { background-image: url('screens/fuel-dark-4.webp'); }
  :root:not([data-theme='light']) .shot.coach { background-image: url('screens/coach-dark-4.webp'); }
  :root:not([data-theme='light']) .shot.records { background-image: url('screens/records-dark-4.webp'); }
  :root:not([data-theme='light']) .shot.logger { background-image: url('screens/logger-dark-4.webp'); }
}
:root[data-theme='dark'] .shot.today { background-image: url('screens/today-dark-4.webp'); }
:root[data-theme='dark'] .shot.muscles { background-image: url('screens/muscles-dark-4.webp'); }
:root[data-theme='dark'] .shot.fuel { background-image: url('screens/fuel-dark-4.webp'); }
:root[data-theme='dark'] .shot.coach { background-image: url('screens/coach-dark-4.webp'); }
:root[data-theme='dark'] .shot.records { background-image: url('screens/records-dark-4.webp'); }
:root[data-theme='dark'] .shot.logger { background-image: url('screens/logger-dark-4.webp'); }

/* =====================================================================
   HERO — the page opens the way an app screen does: rule head, the one
   interpreted state, then evidence in layers (LEDGER_SPEC §5).
   Its margin is deliberately EMPTY. There is no honest datum for it —
   a date stamp would be invented and a build number would go stale on
   a static page — so the first mark a reader meets scrolling this page
   is the coach's tick, several entries down.
   ===================================================================== */
.hero {
  display: grid;
  grid-template-columns: 1.1fr 0.9fr;
  gap: var(--s-huge);
  align-items: center;
  /* ⚠️ NO TOP PADDING. The hero used to be the page's first element and
     owned its own opening space; it now sits inside `<section
     id="product">`, which already pays `--s-huge` at the top, and a rule
     head sits between the two. Keeping both stacked them — the landing
     page opened on roughly 128px of empty column between "iOS · Private
     beta" and the headline. The section owns the space above, the hero
     owns the space below it. */
  padding: 0 0 var(--s-xxxl);
}
.hero h1 {
  font-family: var(--f-display);
  font-weight: 600;
  /* 62px until 2026-09-09. The BRAND.md §4 h1 is two full sentences
     ("It changes the plan. / It shows the number."), and at 62px the
     second one overflowed the hero column and broke into an orphaned
     "number." — `text-wrap: balance` re-breaks a <br> segment that does
     not fit. 54px holds both sentences on one line each at every width
     down to the 760px collapse. Check this if the h1 copy changes. */
  font-size: clamp(36px, 5.2vw, 54px);
  line-height: 1.04;
  letter-spacing: -0.5px;
  color: var(--t1);
  margin: var(--s-lg) 0 var(--s-lg);
  text-wrap: balance;
}
.hero .lede {
  max-width: 46ch;
}
.hero-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-lg);
  margin-top: var(--s-xxl);
  align-items: center;
}
.hero-note {
  margin-top: var(--s-md);
  font-family: var(--f-mono);
  font-size: 11px;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--t3);
}
.hero-phone {
  display: flex;
  justify-content: center;
}
/* The hero's phone is the TALL crop: the morning block — adjusted line,
   three readings, the coach's sentence — is what the receipt below
   reads back, so that is the part that must be above the fold. A whole
   1870px-tall screen at 320 wide put the fold halfway down the week
   dots and the headline beside empty bezel. */
.hero .phone {
  max-width: 300px;
}

/* =====================================================================
   THE RECEIPT — the page's signature. Evidence left (three readings in
   the measurement face, ruled), decision right (the change, then the
   reason behind a native disclosure). Both columns carry the ledger's
   own anatomy — mono label, figure, hairline — at display scale, so the
   block reads as the app's Today screen enlarged, not as a web card.
   The amber tick appears exactly where the app puts it: on ADJUSTED and
   on the coach's sentence. Nowhere else on this section.
   ===================================================================== */
.receipt {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
  gap: var(--s-huge);
  align-items: start;
}
.receipt-evidence .rule {
  margin-bottom: 0;
}
/* A reading: label in the fixed mono column, the figure in Barlow at a
   size the app reserves for its hero numbers, the delta beside it in
   the caption register. Baseline-aligned so the three figures read as
   one column of numbers. */
.rrow {
  display: grid;
  grid-template-columns: 104px auto minmax(0, 1fr);
  align-items: baseline;
  gap: var(--s-md);
  padding: var(--s-md) 0;
  border-bottom: 1px solid var(--border-sub);
}
.rfig {
  font-family: var(--f-display);
  font-weight: 600;
  font-size: 40px;
  line-height: 44px;
  letter-spacing: -0.4px;
  font-variant-numeric: tabular-nums;
  color: var(--t1);
}
.rdelta {
  font-size: 13px;
  line-height: 18px;
  color: var(--t3);
}
/* The arrow is the app's own glyph beside a reading — amber for below
   your normal (the app's warn tone, "vs your normal" is monitoring
   language, never danger), ink for above. */
.rarrow {
  font-family: var(--f-mono);
  color: var(--warn);
  margin-right: var(--s-xxs);
}
.rarrow.up {
  color: var(--t2);
}

/* The decision column hosts two callouts, so it carries the same tick
   lane the tool results do (see `.tool-out` above): the tick sits at the
   column's own left edge, and there is no second spine on the page. */
.receipt-change > .callout,
.receipt-change .why > .callout {
  padding-left: calc(var(--tick-w) + 5px + var(--mgn-pad));
}
.receipt-change > .callout::before,
.receipt-change .why > .callout::before {
  left: 0;
}
.rchange {
  font-family: var(--f-display);
  font-weight: 600;
  font-size: clamp(44px, 5vw, 64px);
  line-height: 1;
  letter-spacing: -0.8px;
  font-variant-numeric: tabular-nums;
  color: var(--t1);
  margin: var(--s-xs) 0 0;
}
.receipt-change .callout .rchange-sub {
  margin: var(--s-sm) 0 0;
  font-family: var(--f-display);
  font-weight: 500;
  font-size: 20px;
  line-height: 24px;
  font-variant-numeric: tabular-nums;
  color: var(--t2);
}
/* The WHY disclosure. A <details> whose summary is the mono label the
   app shows under the adjusted line, with the same small chevron. The
   chevron is drawn with a border, not a glyph font, so it turns without
   a second character. */
.why {
  margin-top: var(--s-xl);
  padding-top: var(--s-md);
  border-top: 1px solid var(--border-sub);
}
.why > summary {
  list-style: none;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: var(--s-sm);
  min-height: 32px;
  padding-left: calc(var(--tick-w) + 5px + var(--mgn-pad));
}
.why > summary::-webkit-details-marker { display: none; }
.why > summary::marker { content: ''; }
.why > summary .mono { color: var(--t2); }
.why > summary::after {
  content: '';
  width: 6px;
  height: 6px;
  border-right: 1.5px solid var(--t3);
  border-bottom: 1.5px solid var(--t3);
  transform: translateY(-2px) rotate(45deg);
  transition: transform 150ms ease;
}
.why[open] > summary::after {
  transform: translateY(1px) rotate(-135deg);
}
.why > summary:hover .mono { color: var(--t1); }
.why > summary:focus-visible { outline: 2px solid var(--t1); outline-offset: 2px; border-radius: var(--r-xs); }
.why > .callout {
  margin-top: var(--s-md);
}
.why > .callout p {
  font-weight: 400;
  color: var(--t1);
  max-width: 40ch;
}
.receipt-cap,
.section-cap {
  margin: var(--s-xl) 0 0;
  color: var(--t3);
  max-width: 60ch;
}

/* The receipt writes itself as it arrives: each row fades in, in order,
   opacity only. Same gate as the margin marks — `.marks-anim`, set only
   by marks-1.js after it has proven it can reveal — so a blocked script
   leaves every figure visible. The stagger is nth-child, so no inline
   style is needed. Absent under reduced motion. */
@media (prefers-reduced-motion: no-preference) {
  .marks-anim .writes > * {
    opacity: 0;
    transition: opacity 260ms ease;
  }
  .marks-anim .writes > .in {
    opacity: 1;
  }
  .marks-anim .writes > :nth-child(2) {
    transition-delay: 180ms;
  }
}

/* =====================================================================
   THE LOOP — five steps across one line. The ordinals are inline mono
   because the strip reads left to right, not down the margin.
   ===================================================================== */
.loop-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: var(--s-xl);
}
.step {
  border-top: 1px solid var(--border);
  padding-top: var(--s-md);
}
.step-n {
  display: block;
  color: var(--t3);
  margin-bottom: var(--s-lg);
}
.step h3 {
  margin: 0 0 var(--s-xs);
  font-size: 15px;
  font-weight: 600;
  color: var(--t1);
}
.step p {
  margin: 0;
  font-size: 14px;
  line-height: 20px;
  color: var(--t2);
}

/* =====================================================================
   THREE SCREENS, ONE ROW — the last three features share a line rather
   than each taking a full alternation. Each phone is the tall crop.
   ===================================================================== */
.trio {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--s-xxl);
  margin-top: var(--s-xxxl);
  padding-top: var(--s-xxxl);
  border-top: 1px solid var(--border-sub);
}
.trio-item {
  min-width: 0;
}
.trio-item .phone {
  max-width: 260px;
  margin: 0 0 var(--s-xl);
}
.trio-item .rulehead {
  margin-bottom: var(--s-md);
}
.trio-item h3 {
  font-family: var(--f-display);
  font-weight: 600;
  font-size: 22px;
  line-height: 1.15;
  color: var(--t1);
  margin: 0 0 var(--s-sm);
  text-wrap: balance;
}
.trio-item p {
  margin: 0;
  font-size: 14px;
  line-height: 20px;
  color: var(--t2);
}
/* The one accent on the features section: the records entry's PR cap.
   Same rule as `.mark.earned` — accent is spent on the earned event. */
.rulehead .earned {
  color: var(--accent);
  font-size: 11px;
  line-height: 14px;
  letter-spacing: 1.2px;
}
/* A two-letter mark never needs the phone-width wrap the caption rule
   below gives sentence-length caps; it stays on the head's line. */
@media (max-width: 760px) {
  .rulehead .rulehead-cap.earned {
    flex-basis: auto;
    margin-left: auto;
    text-align: right;
  }
}

/* =====================================================================
   SECTIONS
   ===================================================================== */
section {
  padding: var(--s-huge) 0;
}
.section-head {
  margin-bottom: var(--s-xxl);
}
.section-head h2 {
  font-family: var(--f-display);
  font-weight: 600;
  font-size: clamp(26px, 3.4vw, 34px);
  line-height: 1.1;
  letter-spacing: -0.2px;
  color: var(--t1);
  margin: 0;
  text-wrap: balance;
}
.section-head p {
  margin: var(--s-sm) 0 0;
  max-width: 58ch;
}

/* --- ruled entries: the five "instead of" rows and the loop --------- */
.entries {
  margin: 0;
}
.erow {
  position: relative;
  display: grid;
  grid-template-columns: 200px minmax(0, 1fr);
  gap: var(--s-lg);
  align-items: baseline;
  padding: var(--s-lg) 0;
  border-top: 1px solid var(--border-sub);
}
.erow:first-child {
  border-top: 0;
}
.erow p {
  margin: 0;
  font-size: 14px;
  line-height: 20px;
  color: var(--t2);
}
.erow h3 {
  margin: 0 0 var(--s-xs);
  font-size: 15px;
  font-weight: 600;
  color: var(--t1);
}
/* The loop steps carry their number in the MARGIN, so their content is
   a single column. This is the one place on the page where numbering is
   earned: goal → plan → log → adjust → prove is genuinely ordered. */
.erow.step {
  grid-template-columns: minmax(0, 1fr);
}

/* --- FEATURE ROWS: alternating, real screens ----------------------- */
.feat {
  display: grid;
  /* Explicit columns + explicit placement. An `auto` column gave the
     phone no intrinsic width, so `width:100%` resolved against zero and
     the whole visual collapsed on alternating rows. */
  grid-template-columns: minmax(0, 1fr) minmax(0, 340px);
  gap: var(--s-huge);
  /* START, not center. A rule head marks where a section BEGINS; centred
     against a 700px-tall screenshot it floated to the middle of the row
     and read as a caption on the phone instead of the head of the entry. */
  align-items: start;
  padding: var(--s-xxxl) 0;
}
.feat-body {
  grid-column: 1;
  grid-row: 1;
}
.feat-visual {
  grid-column: 2;
  grid-row: 1;
  display: flex;
  justify-content: center;
}
.feat:nth-of-type(even) .feat-body {
  grid-column: 2;
}
.feat:nth-of-type(even) .feat-visual {
  grid-column: 1;
}
.feat h3 {
  font-family: var(--f-display);
  font-weight: 600;
  font-size: clamp(23px, 2.6vw, 30px);
  line-height: 1.12;
  color: var(--t1);
  margin: 0 0 var(--s-md);
  text-wrap: balance;
}
.feat p {
  margin: 0 0 var(--s-lg);
  max-width: 50ch;
}
.feat-points {
  list-style: none;
  margin: 0;
  padding: 0;
}
.feat-points li {
  position: relative;
  padding: var(--s-sm) 0 var(--s-sm) var(--s-xl);
  border-top: 1px solid var(--border-sub);
  font-size: 14px;
  line-height: 20px;
  color: var(--t2);
}
.feat-points li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 15px;
  width: 10px;
  height: 1px;
  background: var(--t3);
}

/* --- the coach's own entries: the product thesis, as ruled lines ----
   No box. The amber tick in the margin (tokens-10.css .callout) is what
   says the coach is speaking — position, never prose, and never a bulb. */

/* ⚠️ A CALLOUT NEEDS A MARGIN TO HANG ITS TICK IN, AND ONLY SOME
   ANCESTORS HAVE ONE. `.callout::before` is offset from the callout's
   own left edge, so the tick reads correctly only where that edge is a
   ledger's content edge — true inside `.ledger-page`, false inside
   these two, which are grid COLUMN 2 and sit hundreds of pixels right
   of the page spine. The homepage's flagship "the coach" feature and
   every calculator result were painting detached amber bars in the
   column gutter, saying nothing: position is the whole claim of
   LEDGER_SPEC §8, and a tick in open space has no position.

   `.ledger` therefore carries a local margin with the same geometry as
   the page: spine at X, content at X + --mgn-pad, so the tick lands in
   [0, --tick-w] and clears the spine by 5px, exactly as it does against
   `.ledger-page::before`. It earns a spine of its own because it is a
   DEPICTION of the app's ledger, sitting in its own grid column. */
.ledger {
  position: relative;
  padding-left: calc(var(--tick-w) + 5px + var(--mgn-pad));
  max-width: 460px;
}
.ledger::before {
  content: '';
  position: absolute;
  left: calc(var(--tick-w) + 5px);
  top: 0;
  bottom: 0;
  width: 1px;
  background: var(--border);
}

/* ⚠️ THE TOOL RESULTS GET A TICK LANE, NOT A SPINE. `.tool-out` is page
   content inside a `.ledger-page` that already draws one continuous left
   edge; a second rule down the results column would give the page two
   left edges at different x — the precise failure `ledgerChassis.test.ts`
   opens by describing. Only the coach lines are indented, and their tick
   sits at their own left edge. */
.tool-out > .callout {
  padding-left: calc(var(--tick-w) + 5px + var(--mgn-pad));
}
.tool-out > .callout::before {
  left: 0;
}
.ledger .callout + .callout {
  margin-top: var(--s-lg);
  padding-top: var(--s-lg);
  border-top: 1px solid var(--border-sub);
}
.ledger .callout p em {
  font-style: normal;
  font-weight: 400;
  color: var(--t3);
}

/* --- privacy: the label/value ledger grid --------------------------- */
.spec {
  max-width: 640px;
}
.spec .lrow {
  border-top: 1px solid var(--border-sub);
  padding: var(--s-md) 0;
}
.spec .lrow:first-child {
  border-top: 0;
}
.spec .lrow > .mono:first-child {
  width: 148px;
}
.spec .lrow p {
  margin: 0;
  font-size: 14px;
  line-height: 20px;
  color: var(--t1);
}

/* --- beta signup ---------------------------------------------------- */
.join {
  padding-top: var(--s-xxxl);
}
.signup {
  display: flex;
  gap: var(--s-md);
  max-width: 520px;
  margin-top: var(--s-lg);
  flex-wrap: wrap;
}
.signup .field {
  flex: 1 1 260px;
}
.hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}
.note {
  margin-top: var(--s-md);
  font-size: 13px;
  line-height: 18px;
  color: var(--t3);
}
.note.err {
  color: var(--danger);
}
/* Being on a waitlist is not an EARNED event, so the confirmation is
   ink. Accent on this line would spend the page's one earned colour on
   a form submission. */
.note.ok {
  color: var(--t1);
}
#success {
  display: none;
}
#success.on {
  display: block;
}

/* --- doc pages (privacy/terms/support/404) --------------------------
   A doc section is an entry: the number lives in the margin, the title
   sits on a 2px rule head. Those numbers are REAL — privacy §4 and
   terms §5 are cited by number from CLAUDE.md and SITE_README.md. */
.doc {
  max-width: 720px;
  padding: var(--s-huge) 0;
}
.doc h1 {
  font-family: var(--f-display);
  font-weight: 600;
  font-size: clamp(30px, 5vw, 44px);
  line-height: 1.05;
  color: var(--t1);
  margin: var(--s-sm) 0 var(--s-sm);
}
.doc h2 {
  position: relative;
  font-family: var(--f-display);
  font-weight: 600;
  font-size: 20px;
  letter-spacing: 0.2px;
  color: var(--t1);
  margin: var(--s-xxxl) 0 var(--s-md);
  padding-bottom: var(--s-sm);
  border-bottom: 2px solid var(--border);
}
.doc h2 .mark {
  top: 4px;
}
.doc p,
.doc li {
  color: var(--t2);
  font-size: 15px;
  line-height: 25px;
}
.doc ul {
  margin: var(--s-md) 0;
  padding-left: var(--s-xl);
}
.doc li {
  margin: var(--s-sm) 0;
}
.doc strong {
  color: var(--t1);
}
.doc table {
  width: 100%;
  border-collapse: collapse;
  margin: var(--s-lg) 0;
  font-size: 14px;
}
.doc th,
.doc td {
  text-align: left;
  padding: var(--s-sm) var(--s-md) var(--s-sm) 0;
  border-bottom: 1px solid var(--border-sub);
  color: var(--t2);
  vertical-align: top;
  line-height: 20px;
}
.doc th {
  font-family: var(--f-mono);
  font-size: 11px;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--t3);
}
/* --- changelog: a record, so its tags are margin marks --------------- */
.release {
  position: relative;
  padding: var(--s-xxl) 0;
  border-top: 1px solid var(--border-sub);
}
.release-head {
  display: flex;
  align-items: baseline;
  gap: var(--s-md);
  margin-bottom: var(--s-md);
}
.release-head h2 {
  font-family: var(--f-display);
  font-weight: 600;
  font-size: 26px;
  color: var(--t1);
  margin: 0;
}
.change {
  position: relative;
  padding: var(--s-sm) 0;
}
.change p {
  margin: 0;
  font-size: 14px;
  line-height: 20px;
  color: var(--t1);
}
.change .from {
  display: inline-block;
  margin-top: var(--s-xxs);
  font-family: var(--f-mono);
  font-size: 11px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--t3);
  text-decoration: none;
  border-bottom: 1px solid var(--border);
}
.change .from:hover {
  color: var(--t1);
}

/* --- a quiet, non-intrusive feedback line --------------------------- */
.nudge {
  margin-top: var(--s-huge);
  padding-top: var(--s-lg);
  border-top: 1px solid var(--border-sub);
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-md);
  align-items: baseline;
}
.nudge a {
  font-family: var(--f-mono);
  font-size: 11px;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--t3);
  text-decoration: none;
}
.nudge a:hover {
  color: var(--t1);
}

/* =====================================================================
   RESPONSIVE
   The margin narrows (tokens-10.css) but never collapses. Nothing here
   may remove it: the chassis holding at 320px is the claim.
   ===================================================================== */
@media (max-width: 900px) {
  .hero {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--s-xxl);
    padding-top: var(--s-xxl);
  }
  /* The headline leads on a phone. `order: -1` on the screenshot put
     the h1 a full screenshot below the fold on a 390px viewport, so the
     first thing a reader met was a picture of a different phone. */
  .hero .phone {
    max-width: 280px;
  }
  .phone {
    max-width: 260px;
  }
  .receipt {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--s-xxl);
  }
  .loop-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  /* Three phones down a 390px page is the column this row exists to
     avoid, so it scrolls sideways instead: one screen at a time, snapped. */
  .trio {
    display: flex;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    gap: var(--s-lg);
    /* Bleed to the viewport edge so the next screen peeks in. */
    margin-right: calc(-1 * var(--gutter));
    padding-right: var(--gutter);
  }
  .trio::-webkit-scrollbar { display: none; }
  .trio-item {
    flex: 0 0 min(78%, 300px);
    scroll-snap-align: start;
  }
  .trio-item .phone {
    max-width: 220px;
  }
  .feat {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--s-xxl);
  }
  .feat-body,
  .feat:nth-of-type(even) .feat-body {
    grid-column: 1;
    grid-row: 1;
  }
  .feat-visual,
  .feat:nth-of-type(even) .feat-visual {
    grid-column: 1;
    grid-row: 2;
  }
  .feat .phone,
  .feat .ledger {
    margin: 0 auto;
  }
  .erow {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--s-xs);
  }
}
@media (max-width: 560px) {
  section {
    padding: var(--s-xxxl) 0;
  }
  .signup {
    flex-direction: column;
  }
  /* `flex: 1 1 260px` measures along the MAIN axis, so the moment this
     column stacks, 260px stopped being the field's minimum width and
     became its height — a quarter-screen-tall email box on every phone.
     Down here the field just wants full width and its own height. */
  .signup .field {
    flex: 0 0 auto;
    width: 100%;
  }
  .signup .btn {
    width: 100%;
  }
  .lrow > .mono:first-child,
  .spec .lrow > .mono:first-child {
    width: 104px;
  }
  .rrow {
    grid-template-columns: 84px auto minmax(0, 1fr);
  }
  .rfig {
    font-size: 32px;
    line-height: 36px;
  }
  .loop-grid {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--s-lg);
  }
}
/* Below 400px the margin is 40px and a 4-character mark no longer fits
   beside the spine. Marks shorten rather than the chassis collapsing. */
@media (max-width: 400px) {
  .mark {
    font-size: 10px;
    letter-spacing: 0.8px;
    padding-right: var(--s-xs);
  }
}
