/* ============================================================
   Steady Edge Trading, shared site stylesheet
   Introduced in site_v102, July 30, 2026.

   Scope: design tokens, page chrome (nav + footer), and the
   shared atelier card language. Page-specific layout stays in
   each page's own <style> block.

   HARD RULE: the class names below are asserted by the test
   suites (test_legal_pages.js in particular). Restyle the
   rules, never rename the hooks:
     .site-footer  .site-footer-logo  .site-footer-links
     .site-footer-legal  .site-footer-disclaimer  .footer-social
   ============================================================ */

:root {
  --black: #0A0A0A;
  --gold: #EAAA00;
  --white: #FFFFFF;

  --ink: rgba(255,255,255,0.86);
  --ink-2: rgba(255,255,255,0.62);
  --ink-3: rgba(255,255,255,0.40);
  --ink-4: rgba(255,255,255,0.22);

  --plate: rgba(18,18,18,0.72);
  --plate-solid: #121212;
  --hair: rgba(255,255,255,0.10);
  --hair-gold: rgba(234,170,0,0.30);

  --display: 'Bebas Neue', 'Barlow Condensed', sans-serif;
  --body: 'DM Sans', system-ui, -apple-system, sans-serif;

  --wrap: 1120px;
  --nav-h: 64px;

  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
}

/* ---------- reset + base ---------- */

*, *::before, *::after { box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--black);
  color: var(--ink);
  font-family: var(--body);
  font-weight: 300;
  font-size: 16px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

img, video { max-width: 100%; display: block; }

a { color: inherit; }

.wrap { width: 100%; max-width: var(--wrap); margin: 0 auto; padding: 0 24px; }
.center { text-align: center; }

.gold { color: var(--gold); }
.gold-set { color: var(--gold); font-weight: 500; }

.eyebrow {
  display: inline-block;
  font-family: var(--body);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.20em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.display {
  font-family: var(--display);
  font-weight: 400;
  letter-spacing: 0.01em;
  line-height: 1.02;
  color: var(--white);
  margin: 0;
  font-size: clamp(34px, 5vw, 58px);
}

/* ---------- the one gold button ----------
   Exactly one filled-gold button style exists site-wide and it
   always means "buy The Forge". Everything else is outline or
   text. Do not add a second filled-gold treatment. */

.btn-primary,
.btn-outline,
.btn-ghost {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--body);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  text-decoration: none;
  border-radius: 2px;
  padding: 15px 30px;
  transition: transform 0.2s var(--ease), background 0.2s var(--ease),
              border-color 0.2s var(--ease), color 0.2s var(--ease);
  cursor: pointer;
}

.btn-primary {
  background: var(--gold);
  color: var(--black);
  border: 1px solid var(--gold);
  font-weight: 500;
}
.btn-primary:hover { transform: translateY(-1px); background: #F5B916; border-color: #F5B916; }

.btn-outline {
  background: transparent;
  color: var(--white);
  border: 1px solid rgba(255,255,255,0.28);
}
.btn-outline:hover { border-color: var(--gold); color: var(--gold); }

.btn-ghost {
  background: transparent;
  border: none;
  padding: 15px 8px;
  color: var(--ink-2);
  text-transform: none;
  letter-spacing: 0.04em;
  font-size: 14px;
  border-bottom: 1px solid var(--ink-4);
  border-radius: 0;
}
.btn-ghost:hover { color: var(--gold); border-bottom-color: var(--hair-gold); }

/* ---------- nav ---------- */

.site-nav {
  position: sticky;
  top: 0;
  z-index: 60;
  height: var(--nav-h);
  display: flex;
  align-items: center;
  gap: 22px;
  padding: 0 24px;
  background: rgba(10,10,10,0.82);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--hair);
}

.nav-logo {
  font-family: var(--display);
  font-size: 20px;
  letter-spacing: 0.10em;
  color: var(--white);
  text-decoration: none;
  margin-right: auto;
  white-space: nowrap;
}
.nav-logo span { color: var(--gold); }

.nav-link {
  font-size: 13px;
  font-weight: 400;
  letter-spacing: 0.04em;
  color: var(--ink-2);
  text-decoration: none;
  white-space: nowrap;
  transition: color 0.2s var(--ease);
}
.nav-link:hover { color: var(--gold); }

.nav-login {
  font-size: 13px;
  letter-spacing: 0.04em;
  color: var(--ink-3);
  text-decoration: none;
  white-space: nowrap;
  transition: color 0.2s var(--ease);
}
.nav-login:hover { color: var(--white); }

.nav-cta {
  font-family: var(--body);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  background: var(--gold);
  color: var(--black);
  text-decoration: none;
  padding: 10px 18px;
  border-radius: 2px;
  white-space: nowrap;
  transition: background 0.2s var(--ease);
}
.nav-cta:hover { background: #F5B916; }

.nav-menu-btn {
  display: none;
  background: none;
  border: none;
  color: var(--ink-2);
  padding: 8px;
  cursor: pointer;
}

@media (max-width: 720px) {
  .site-nav { gap: 12px; }
  .nav-logo { font-size: 17px; }
  .site-nav .nav-link, .site-nav .nav-login { display: none; }
  .site-nav.open .nav-link, .site-nav.open .nav-login { display: none; }
  .nav-menu-btn { display: inline-flex; order: 3; }
  .nav-cta { font-size: 11px; padding: 9px 13px; order: 2; }
  .nav-drawer.open { display: block; }
}

/* v104. Measured at 390px the nav laid out to 453px wide: logo 200 + CTA 143
   + button 38 + padding and gaps 72. iOS Safari answers horizontal overflow
   by widening the layout viewport, which scales the whole page down and
   leaves a black band under the content. That band was the "massive black
   empty space at the bottom on mobile"; there was never any dead markup. */
@media (max-width: 440px) {
  .site-nav { padding: 0 14px; gap: 10px; }
  .nav-logo { font-size: 15px; }
  .nav-cta { font-size: 10px; padding: 8px 11px; letter-spacing: 0.08em; }
  .nav-menu-btn { padding: 6px; }
}
/* Breakpoints set from measured layout width, not round numbers.
   390px (iPhone 14/15/16) laid out to 400 with the full label, so the
   collapse has to fire above 390, not at 380. 320px still ran 11px over
   with the label already collapsed, so the wordmark shrinks again there. */
@media (max-width: 430px) {
  .nav-cta-rest { display: none; }
}
@media (max-width: 360px) {
  .site-nav { padding: 0 10px; gap: 8px; }
  .nav-logo { font-size: 13px; }
}

/* Belt and braces. Nothing should overflow after the rules above, but a
   single wide element anywhere on the site would reintroduce the same
   letterboxing, and it is invisible on desktop. clip, not hidden: hidden on
   a root element kills position:sticky on the nav. */
html { overflow-x: clip; }
body { overflow-x: clip; }

.nav-drawer {
  display: none;
  position: fixed;
  top: var(--nav-h);
  left: 0;
  right: 0;
  z-index: 59;
  background: rgba(10,10,10,0.97);
  border-bottom: 1px solid var(--hair);
  padding: 10px 24px 20px;
}
.nav-drawer a {
  display: block;
  padding: 13px 0;
  font-size: 15px;
  color: var(--ink-2);
  text-decoration: none;
  border-bottom: 1px solid rgba(255,255,255,0.06);
}
.nav-drawer a:last-child { border-bottom: none; }

/* ---------- atelier card language ---------- */

.plate {
  background: var(--plate);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
  border: 1px solid var(--hair);
  border-radius: 3px;
}

.hairline {
  height: 1px;
  border: none;
  margin: 0;
  background: linear-gradient(90deg,
    transparent, rgba(234,170,0,0.22) 30%, rgba(234,170,0,0.22) 70%, transparent);
}

/* ---------- reveal on scroll ---------- */

/* v149. Content first, animation second. The hidden start state only
   exists when JavaScript is running, so a blocked script, a failed request or
   a non-rendering scraper gets the page rather than blank sections. The .js
   class is set by the first inline script in <head>, before any stylesheet, so
   there is no flash of revealed content. */
.reveal { opacity: 1; transform: none; }
html.js .reveal {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity 0.7s var(--ease), transform 0.7s var(--ease);
}
html.js .reveal.in { opacity: 1; transform: none; }

/* ---------- footer ----------
   Markup and class names carried forward from v101 unchanged. */

.site-footer {
  border-top: 1px solid var(--hair);
  padding: 54px 24px 40px;
  text-align: center;
  background: var(--black);
}

.site-footer-logo {
  font-family: var(--display);
  font-size: 22px;
  letter-spacing: 0.12em;
  color: var(--white);
  margin-bottom: 22px;
}
.site-footer-logo span { color: var(--gold); }

.site-footer-links {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 20px;
  margin: 0 0 20px;
}
.site-footer-links a {
  font-family: var(--body);
  font-size: 12px;
  font-weight: 400;
  letter-spacing: 0.06em;
  color: var(--ink-3);
  text-decoration: none;
  transition: color 0.2s var(--ease);
}
.site-footer-links a:hover { color: var(--gold); }

.site-footer-legal {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 16px;
  margin: 0 0 18px;
}
.site-footer-legal a {
  font-family: var(--body);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  color: var(--ink-4);
  text-decoration: none;
  transition: color 0.2s;
}
.site-footer-legal a:hover { color: var(--gold); }

.footer-social {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 20px;
  margin: 0 0 24px;
}
.footer-social-link {
  color: var(--ink-3);
  transition: color 0.2s var(--ease), transform 0.2s var(--ease);
  display: inline-flex;
}
.footer-social-link:hover { color: var(--gold); transform: translateY(-2px); }

.site-footer-disclaimer {
  max-width: 760px;
  margin: 0 auto 8px;
  font-size: 11px;
  line-height: 1.7;
  color: var(--ink-4);
}

.site-footer-tm {
  max-width: 760px;
  margin: 0 auto 14px;
  font-size: 11px;
  line-height: 1.7;
  color: var(--ink-4);
}

/* ---------- back to top ---------- */

#back-to-top {
  position: fixed;
  bottom: 26px;
  right: 26px;
  z-index: 70;
  width: 42px;
  height: 42px;
  border-radius: 50%;
  border: 1px solid var(--hair);
  background: rgba(18,18,18,0.86);
  color: var(--ink-2);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.3s var(--ease), visibility 0.3s var(--ease);
}
#back-to-top.visible { opacity: 0.72; visibility: visible; }
#back-to-top:hover { opacity: 1; color: var(--gold); }
@media (max-width: 480px) { #back-to-top { bottom: 16px; right: 16px; } }

/* ---------- inner page chrome (used by v103) ---------- */

.page-head { padding: 68px 0 34px; border-bottom: 1px solid var(--hair); }
.page-head .display { margin-top: 10px; }
.page-body { padding: 44px 0 72px; }
.page-body p { color: var(--ink-2); }
.page-body h2 { font-family: var(--display); color: var(--white); font-size: 28px; letter-spacing: 0.02em; margin: 40px 0 12px; }
.page-body h3 { font-family: var(--body); font-weight: 500; color: var(--white); font-size: 17px; margin: 28px 0 8px; }

/* ---------- motion ---------- */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  html.js .reveal { opacity: 1; transform: none; transition: none; }
  * { animation-duration: 0.001ms !important; animation-iteration-count: 1 !important; transition-duration: 0.001ms !important; }
}

/* ============================================================
   INNER PAGE LAYER
   Introduced in site_v135, August 21, 2026.

   Before v135 every public page except the homepage and 404
   carried its own copy of the chrome: its own token block, its
   own nav, its own footer, its own font load. Ten pages, about
   88k of duplicated CSS, and the tokens had drifted (--dark
   #111111 against --plate-solid #121212, a #1E1E1E border
   against --hair, a navy page background on nine of them
   against the standing rule that navy is for PDF documents and
   table header rows only).

   This layer is that chrome, once. A page now carries only what
   is genuinely unique to it.

   The vocabulary is the homepage's: .block, .wrap, .eyebrow,
   .display, .plate, .hairline, .reveal, .btn-*. Anything below
   is an addition to it, not a parallel system.
   ============================================================ */

/* ---------- section rhythm ----------
   Lifted out of the homepage's own <style> block so inner pages
   inherit the same vertical rhythm rather than inventing one.
   The homepage still declares these locally at identical values;
   the duplicate is harmless and keeps that file untouched. */

.block { padding: 92px 0; position: relative; }
.block.tight { padding: 68px 0; }
.block--band { background: var(--plate-solid); border-top: 1px solid var(--hair); border-bottom: 1px solid var(--hair); }
@media (max-width: 720px) {
  .block { padding: 64px 0; }
  .block.tight { padding: 48px 0; }
}

/* ---------- page opener ----------
   The inner-page equivalent of the homepage hero. No media, no
   scrim, no navy: black ground, eyebrow, display headline, one
   lede paragraph, and a hairline that hands off to the body. */

.page-opener { padding: 74px 0 0; }
.page-opener .display { margin-top: 12px; }
.page-opener .hairline { margin-top: 42px; }

.page-lede {
  max-width: 62ch;
  margin: 22px 0 0;
  color: var(--ink-2);
  font-size: 17px;
  line-height: 1.75;
  text-wrap: balance;
}
.page-lede.center { margin-left: auto; margin-right: auto; }

.page-meta {
  margin: 18px 0 0;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-4);
}

@media (max-width: 720px) {
  .page-opener { padding-top: 52px; }
  .page-opener .hairline { margin-top: 34px; }
  /* 15px, not 16. balance only engages while a paragraph fits inside Chrome's
     six-line cap; at 16px the longer ledes spill to seven lines on a 390px
     screen, balance switches off, and the last line strands. One step down
     keeps every lede inside the cap. Measured, not guessed: check_widows.py
     flags .page-lede at 390px and 15px is the only value clean on all twelve
     public pages. */
  .page-lede { font-size: 15px; text-wrap: balance; }
}

/* ---------- long-form document layer ----------
   Terms, Privacy, Refund, Copyright, Disclaimer. Measure is
   capped at 68ch because policy text is read, not scanned, and
   a 1120px line of 15px type is unreadable.

   .disclaimer-section is the pre-v135 name for .doc-section and
   is kept as an alias so the five policy pages did not need
   every section div rewritten. Prefer .doc-section in new work. */

/* A policy page is one column, not a headline over a narrower body. The
   .doc-page class on <body> narrows the shared .wrap so the opener and the
   sections share a left edge; without it the 1120px opener and the 760px
   document read as two unrelated blocks. */
.doc-page .wrap { max-width: 808px; }
.doc-page .page-body { padding: 0 0 64px; }
.doc-page .site-footer { border-top-color: var(--hair); }

.doc { padding: 0; }

.doc-section,
.disclaimer-section { padding: 38px 0; border-bottom: 1px solid var(--hair); }
.doc-section:first-child,
.disclaimer-section:first-child { padding-top: 30px; }
.doc-section:last-child,
.disclaimer-section:last-child { border-bottom: none; }

.section-label {
  display: block;
  font-family: var(--body);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-bottom: 10px;
}

.section-heading {
  font-family: var(--display);
  font-weight: 400;
  font-size: 27px;
  letter-spacing: 0.03em;
  line-height: 1.1;
  color: var(--white);
  margin: 0 0 18px;
}

.section-body { font-size: 15px; line-height: 1.85; color: var(--ink-2); }
.section-body p { margin: 0 0 16px; text-wrap: pretty; }
.section-body p:last-child { margin-bottom: 0; }
.section-body strong { color: var(--ink); font-weight: 500; }
.section-body a { color: var(--gold); text-decoration: underline; text-underline-offset: 2px; }
.section-body a:hover { text-decoration-color: var(--hair-gold); }
.section-body ul, .section-body ol { margin: 12px 0 16px; padding-left: 22px; }
.section-body li { margin-bottom: 9px; text-wrap: pretty; }

/* Two emphasis plates. Both are the atelier plate with one gold
   edge, which is the only place a gold rule is allowed to sit
   flush against a block of text. */

.highlight-box {
  background: var(--plate);
  border: 1px solid var(--hair);
  border-left: 2px solid var(--gold);
  border-radius: 0 3px 3px 0;
  padding: 20px 24px;
  margin: 26px 0;
}
.highlight-box p { font-size: 15px; line-height: 1.8; color: var(--ink); margin: 0 0 12px; }
.highlight-box p:last-child { margin-bottom: 0; }
.highlight-box strong { color: var(--white); font-weight: 500; }

.risk-band {
  background: var(--plate);
  border: 1px solid var(--hair);
  border-top: 2px solid var(--gold);
  border-radius: 0 0 3px 3px;
  padding: 26px 30px;
  margin: 0 0 12px;
}
.risk-band-title {
  font-family: var(--display);
  font-weight: 400;
  font-size: 19px;
  letter-spacing: 0.09em;
  color: var(--gold);
  margin: 0 0 10px;
}
.risk-band p { font-size: 14px; line-height: 1.8; color: var(--ink-2); margin: 0; text-wrap: pretty; }

@media (max-width: 720px) {
  .doc-section, .disclaimer-section { padding: 32px 0; }
  .section-heading { font-size: 24px; }
  .risk-band { padding: 22px 20px; }
  .highlight-box { padding: 18px 18px; }
}

/* ---------- closing CTA band ----------
   The last thing on every marketing page. Before v135 these
   pages had no exit at all: the only outbound link was "back to
   home", on pages that are the ones search actually lands on. */

.closing-band { border-top: 1px solid var(--hair); background: var(--plate-solid); }
.closing-band .wrap { text-align: center; }
.closing-band .display { font-size: clamp(30px, 4.2vw, 46px); }
.closing-band .page-lede { margin: 16px auto 0; max-width: 54ch; }
.closing-band-actions {
  display: flex; flex-wrap: wrap; align-items: center;
  justify-content: center; gap: 14px; margin-top: 30px;
}
.closing-band-alt {
  margin: 24px auto 0; max-width: 56ch;
  font-size: 14px; line-height: 1.7; color: var(--ink-3);
  text-wrap: balance;
}
.closing-band-alt a { color: var(--ink); text-decoration: underline;
  text-decoration-color: var(--hair); text-underline-offset: 3px; }
.closing-band-alt a:hover { color: var(--gold); text-decoration-color: var(--hair-gold); }

.closing-band-fine {
  margin: 18px auto 0; max-width: 56ch;
  font-size: 12px; line-height: 1.7; color: var(--ink-4);
  text-wrap: balance;
}

/* ---------- prose defaults for inner bodies ---------- */

.prose { max-width: 68ch; }
.prose p { color: var(--ink-2); font-size: 16px; line-height: 1.85; margin: 0 0 18px; text-wrap: pretty; }
.prose p:last-child { margin-bottom: 0; }
.prose a { color: var(--gold); text-decoration: underline; text-underline-offset: 2px; }
.prose strong { color: var(--ink); font-weight: 500; }

/* ---------- tables and sub-headings inside the document layer ----------
   The privacy page carried a 31-cell data table styled entirely with
   inline attributes on hard-coded hexes (#1E1E1E, #2A2A2A). Classed
   here so it moves with the tokens. Navy is the header colour in PDF
   documents only and deliberately does not appear on any web surface. */

.doc-table-scroll { overflow-x: auto; margin: 20px 0; }
.doc-table { width: 100%; border-collapse: collapse; font-size: 14px; line-height: 1.6; }
.doc-table th {
  text-align: left; padding: 10px 12px;
  border-bottom: 1px solid var(--hair-gold);
  font-family: var(--body); font-weight: 500;
  font-size: 11px; letter-spacing: 0.10em; text-transform: uppercase;
  color: var(--ink);
}
.doc-table td { padding: 10px 12px; border-bottom: 1px solid var(--hair); vertical-align: top; color: var(--ink-2); }
.doc-table tr:last-child td { border-bottom: none; }

.doc-h4 {
  font-family: var(--display); font-weight: 400;
  font-size: 18px; letter-spacing: 0.08em;
  color: var(--white); margin: 26px 0 10px;
}

/* ---------- display size steps ----------
   .display is the page headline. .display.sm is a section headline inside
   an inner page, which needs to sit below the h1 without competing with it. */

.display.sm { font-size: clamp(26px, 3.4vw, 38px); }
.display.xs { font-size: clamp(22px, 2.6vw, 30px); }

/* ---------- pull quote ----------
   One line, centred, held between two hairlines. Used where a page needs to
   stop and say the thing. Pre-v135 this was a pair of solid gold rules at
   0.4 alpha, which shouted; the gradient hairline is the atelier version. */

.pull-quote {
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(24px, 3.2vw, 33px);
  letter-spacing: 0.03em;
  line-height: 1.22;
  color: var(--white);
  text-align: center;
  /* v139: 24ch stranded the last word of any quote short enough to break at
     all ("Prop firms are one path."). Widened until both short quotes sit on
     one line, with balance as the backstop for longer ones. */
  max-width: 28ch;
  text-wrap: balance;
  margin: 46px auto;
  padding: 28px 20px;
  border-top: 1px solid var(--hair);
  border-bottom: 1px solid var(--hair);
  position: relative;
}
.pull-quote::before,
.pull-quote::after {
  content: ''; position: absolute; left: 50%; transform: translateX(-50%);
  width: 84px; height: 1px; background: rgba(234,170,0,0.42);
}
.pull-quote::before { top: -1px; }
.pull-quote::after { bottom: -1px; }
@media (max-width: 720px) { .pull-quote { margin: 34px auto; padding: 22px 12px; } }

/* ---------- numbered list rows ----------
   Principles and myths: a gold ordinal, a title, a paragraph, separated by
   hairlines rather than boxed. Long-form reasoning reads badly inside a card. */

/* ---------- roles table (license-the-forge) ----------
   Four columns at desktop. Collapses to stacked cards below 720px rather
   than scrolling sideways, because the site never scrolls horizontally.
   Each cell carries data-label, which becomes its heading in card mode. */

.roles-table-wrap { margin-top: 34px; }
.roles-table { width: 100%; border-collapse: collapse; font-size: 14px; line-height: 1.7;
  table-layout: fixed; }
.roles-table col.rt-role { width: 19%; }
.roles-table col.rt-hold { width: 23%; }
.roles-table col.rt-do   { width: 27%; }
.roles-table col.rt-get  { width: 31%; }
.roles-table th {
  text-align: left; padding: 12px 14px;
  border-bottom: 1px solid var(--hair-gold);
  font-family: var(--body); font-weight: 500;
  font-size: 11px; letter-spacing: 0.10em; text-transform: uppercase;
  color: var(--ink); white-space: nowrap;
}
.roles-table td {
  padding: 18px 14px; border-bottom: 1px solid var(--hair);
  vertical-align: top; color: var(--ink-2); text-wrap: balance;
}
.roles-table tr:last-child td { border-bottom: none; }
.roles-table th:first-child, .roles-table td:first-child { padding-left: 0; }
.roles-table th:last-child, .roles-table td:last-child { padding-right: 0; }

.role-name {
  display: block; font-family: var(--display); font-weight: 400;
  font-size: 20px; letter-spacing: 0.06em; color: var(--white);
}
.role-tag {
  display: inline-block; margin-top: 9px; white-space: nowrap;
  font-family: var(--body); font-size: 10px; font-weight: 500;
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--ink-4);
  border: 1px solid var(--hair); border-radius: 2px; padding: 3px 8px;
}
.role-tag--open { color: var(--gold); border-color: var(--hair-gold); }

@media (max-width: 720px) {
  .roles-table { table-layout: auto; }
  .roles-table, .roles-table tbody, .roles-table tr, .roles-table td { display: block; width: 100%; }
  .roles-table thead, .roles-table colgroup { display: none; }
  .roles-table tr {
    background: var(--plate); border: 1px solid var(--hair); border-radius: 3px;
    padding: 22px 20px; margin-bottom: 14px;
  }
  .roles-table tr:last-child { margin-bottom: 0; }
  .roles-table td, .roles-table td:first-child, .roles-table td:last-child {
    border-bottom: none; padding: 0 0 16px;
  }
  .roles-table td:last-child { padding-bottom: 0; }
  .roles-table td[data-label]:not(:first-child)::before {
    content: attr(data-label);
    display: block; font-family: var(--body); font-size: 10px; font-weight: 500;
    letter-spacing: 0.16em; text-transform: uppercase; color: var(--ink-4);
    margin-bottom: 6px;
  }
}

/* ---------- spec grid (license-the-forge) ----------
   Short labelled inventory items, two columns at desktop. A card is the wrong
   container for reasoning but the right one for a spec line, so these are
   hairline separated rather than boxed, matching the numbered rows below.
   Collapses to one column under 720px; the second cell has to take its top
   border back when it does, or the stack opens with two borderless rows. */

.spec-grid { margin-top: 34px; display: grid; grid-template-columns: 1fr 1fr; gap: 0 44px; }
.spec-cell { padding: 22px 0; border-top: 1px solid var(--hair); }
.spec-cell:nth-child(1), .spec-cell:nth-child(2) { border-top: none; padding-top: 6px; }
.spec-label {
  display: block; font-family: var(--body); font-size: 10px; font-weight: 500;
  letter-spacing: 0.18em; text-transform: uppercase; color: var(--gold); margin-bottom: 9px;
}
.spec-cell p { margin: 0; font-size: 15px; line-height: 1.75; color: var(--ink-2); text-wrap: pretty; }
@media (max-width: 720px) {
  .spec-grid { grid-template-columns: 1fr; gap: 0; }
  .spec-cell { padding: 20px 0; }
  .spec-cell:nth-child(2) { border-top: 1px solid var(--hair); padding-top: 20px; }
}

.rowlist { margin-top: 34px; max-width: 820px; }
.rowitem { padding: 30px 0; border-top: 1px solid var(--hair); }
.rowitem:first-child { border-top: none; padding-top: 6px; }
.rowitem-n {
  display: block; font-family: var(--display); font-weight: 400;
  font-size: 15px; letter-spacing: 0.18em; color: var(--gold); margin-bottom: 10px;
}
.rowitem-t {
  font-family: var(--body); font-weight: 500; font-size: 19px;
  line-height: 1.4; color: var(--white); margin: 0 0 12px; text-wrap: pretty;
}
.rowitem p { color: var(--ink-2); font-size: 16px; line-height: 1.8; margin: 0 0 14px; text-wrap: pretty; }
.rowitem p:last-child { margin-bottom: 0; }
@media (max-width: 720px) { .rowitem { padding: 24px 0; } .rowitem-t { font-size: 17px; } }

/* ---------- inner-page section spacing and rule collisions ----------
   A section headline needs air under it; .display carries margin:0 because
   the homepage always follows it with a grid that supplies its own gap.
   The two rules below stop a hairline and a band border stacking into a
   double line where an opener or a band meets the next block. */

.block .display.sm,
.block .display.xs { margin-bottom: 24px; }
.page-opener + .block--band,
.block--band + .closing-band,
.block--band + .block--band { border-top: none; }
.closing-band + .site-footer { border-top: none; }

/* ---------- measure inside inner-page sections ----------
   A paragraph sitting directly in a 1120px wrap runs to about 150 characters,
   which is roughly twice a comfortable measure. Cards, grids and the centred
   closing band set their own and are excluded. */

section.block > .wrap > p { max-width: 68ch; }
section.block > .wrap > p.page-lede { max-width: 62ch; }
.closing-band > .wrap > p { max-width: 54ch; margin-left: auto; margin-right: auto; }

/* ============================================================
   MACRO BRIEF PAGE LAYER
   Added in site_v136, August 21, 2026.

   A brief page is the email body under the site chrome. The body
   itself keeps its own stylesheet, inline and table-based, because
   the same markup has to survive Gmail; nothing below touches it.
   What this layer does is give the page the site's nav, footer and
   masthead, and narrow .wrap to the email column so the two line up.

   Before v136 these 21 pages had a THIRD nav (wordmark stacked over
   a tagline, "Archive" and "Subscribe Free"), no <h1>, no headings
   of any kind, and a dead email footer carrying href="#" unsubscribe
   links on a public web page.
   ============================================================ */

.brief-page .wrap { max-width: none; padding: 0 48px; }
@media (max-width: 600px) { .brief-page .wrap { padding: 0 24px; } }

.brief-opener { padding: 40px 0 0; }
.brief-opener .display { font-size: clamp(28px, 4.4vw, 44px); line-height: 1.04; }
.brief-opener .hairline { margin-top: 30px; }
.brief-opener .page-meta { margin-top: 14px; }

/* the crumb back to the archive */
.brief-back-bar { max-width: 640px; margin: 0 auto; padding: 26px 48px 0; }
.brief-back-bar a {
  font-family: var(--body); font-size: 11px; font-weight: 500;
  letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--ink-3); text-decoration: none;
  transition: color 0.2s var(--ease);
}
.brief-back-bar a:hover { color: var(--gold); }
.brief-back-bar a::before { content: '\2190  '; }
@media (max-width: 600px) { .brief-back-bar { padding: 20px 24px 0; } }

/* The brief body sets its own type, so the closing band has to be
   pulled back out to the site's measure rather than the email column. */
.brief-page .closing-band .wrap { max-width: var(--wrap); padding: 0 24px; margin: 0 auto; }

/* ---------------------------------------------------------------------------
   Shared components, moved out of index.html page-scope in v144 because
   /license-the-forge/ and /before-you-pay/ now use them too. Rules are
   unchanged from the homepage originals. v137 rule: a reusable component lives
   here, not in a page's own <style>.
   --------------------------------------------------------------------------- */
.lead { max-width: 640px; margin: 16px auto 0; color: var(--ink-2); font-size: 17px; }
.lead.left { margin-left: 0; }
.stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; margin-top: 44px; }
.stat { padding: 28px 18px; text-align: center; }
.stat .v { font-family: var(--display); font-size: 42px; line-height: 1; color: var(--gold); letter-spacing: 0.02em; }
.stat .k { margin-top: 10px; font-size: 12.5px; color: var(--ink-3); line-height: 1.5; }
@media (max-width: 880px) { .stats { grid-template-columns: repeat(2, 1fr); } }
.faqrow { max-width: 780px; margin: 0 auto; text-align: left; }
.faqrow details { border-bottom: 1px solid rgba(255,255,255,0.10); }
.faqrow details:first-of-type { border-top: 1px solid rgba(255,255,255,0.10); }
.faqrow summary { list-style: none; cursor: pointer; padding: 20px 34px 20px 0; position: relative;
  font-family: 'DM Sans', sans-serif; font-size: 17px; font-weight: 500; color: #FFFFFF;
  line-height: 1.45; text-wrap: pretty; }
.faqrow summary::-webkit-details-marker { display: none; }
.faqrow summary::after { content: '+'; position: absolute; right: 4px; top: 18px; font-size: 22px;
  color: #EAAA00; line-height: 1; transition: transform 0.18s; }
.faqrow details[open] summary::after { content: '\2212'; }
.faqrow summary:hover { color: #EAAA00; }
.faqrow .faq-a { padding: 0 34px 22px 0; font-size: 15px; line-height: 1.75;
  color: rgba(255,255,255,0.66); text-wrap: pretty; }
.faqrow .faq-lead { color: #FFFFFF; margin: 0 0 10px; }
.faqrow .faq-lead-ul { margin: 0; padding-left: 20px; }
.faqrow .faq-lead-ul li { margin: 0 0 8px; text-wrap: pretty; }
.faqrow .faq-lead-ul li:last-child { margin-bottom: 0; }
.faqrow .faq-lead-ul li b { color: rgba(255,255,255,0.92); font-weight: 500; }
.faqrow .faq-more { text-align: center; margin-top: 30px; }
.faqrow .faq-more a { color: #EAAA00; text-decoration: none; font-size: 14px; letter-spacing: 0.5px; }
.faqrow .faq-more a:hover { text-decoration: underline; }

/* ---------- S1 hero ---------- */

.hero {
  position: relative;
  min-height: calc(100vh - var(--nav-h)); min-height: calc(100dvh - var(--nav-h));
  display: flex;
  align-items: center;
  overflow: hidden;
  padding: 80px 0;
}
.hero-bg { position: absolute; inset: 0; z-index: 0; }
.hero-video,
.hero-poster {
  width: 100%; height: 100%;
  object-fit: cover;
  /* The source was re-cropped in v104 to drop a dead left quarter that read
     as a loading failure on any viewport wider in aspect than the clip.
     What remains is all subject, so this centres rather than biasing right. */
  object-position: center;
}
/* The scrim exists to protect headline legibility, not to hide the room.
   Left edge holds enough density for white type at AAA contrast; the right
   two thirds now let the hearth and the wall chart actually read. */
.hero-overlay {
  position: absolute; inset: 0; z-index: 1;
  /* v149. THE DESKTOP SCRIM IS ANCHORED TO THE COPY COLUMN, NOT TO A FRACTION
     OF THE VIEWPORT. Same rule v148 wrote for the mobile scrim, and it was
     failing here for the same reason. .hero-sub is a fixed 624px column
     (54ch at 17px), so its right edge is at 648px on any viewport up to the
     1120 wrap and then tracks the centred wrap outward. Percentage stops slid
     out from under it as the viewport narrowed: measured 2.65:1 at 901px on
     the licensing page. These two landmarks are the copy column's own
     geometry, and 100% resolves against the overlay box, so a visible
     scrollbar does not shift them. Re-measure them if .hero-sub's max-width
     changes; do not nudge them by eye. check_contrast.py is the guard. */
  --copy-l: max(24px, (100% - 1120px) / 2);
  --copy-r: calc(var(--copy-l) + 624px);
  background:
    linear-gradient(90deg,
      rgba(10,10,10,0.90) 0px,
      rgba(10,10,10,0.78) calc(var(--copy-r) - 200px),
      rgba(10,10,10,0.48) calc(var(--copy-r) + 100px),
      rgba(10,10,10,0.14) 84%,
      rgba(10,10,10,0.05) 100%),
    radial-gradient(115% 85% at 16% 50%, rgba(10,10,10,0.34), transparent 68%);
}
.hero .wrap { position: relative; z-index: 2; }
/* The sub-copy and tagline are the palest type on the page and they sit
   closest to the lit part of the frame. A wide, very soft shadow buys
   contrast without reading as a drop shadow. */
.hero .wrap > * { text-shadow: 0 1px 26px rgba(10,10,10,0.78); }

.hero-brandline {
  font-size: 12px; font-weight: 500; letter-spacing: 0.20em;
  text-transform: uppercase; color: var(--gold); margin-bottom: 20px;
  max-width: 640px; line-height: 1.7;
}
.hero-brandline .nb { white-space: nowrap; }
.hero h1 {
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(40px, 6.4vw, 76px);
  line-height: 0.98;
  letter-spacing: 0.01em;
  color: var(--white);
  margin: 0;
  max-width: 15ch;
}
.hero-sub { max-width: 54ch; margin: 22px 0 0; color: var(--ink-2); font-size: 17px; line-height: 1.7; }
/* Brightening the hero cost the tagline contrast it used to get for free
   from a near-black backdrop. Measured 3.49:1 at ink-3, which only clears
   AA-large; ink-2 puts it at roughly 5.5:1. It is a required above-the-fold
   brand element, so it should not sit at the floor. */
.hero-tagline {
  margin-top: 20px; font-family: var(--display); font-size: 19px;
  letter-spacing: 0.14em; color: var(--ink-2);
}
.hero-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 14px; margin-top: 34px; }

/* v148. The image used to sit alone above the copy at phone widths, which
   read as an oddly placed picture at the top of the page rather than as a
   hero. It is now layered behind the copy the way desktop does it: the top
   third of the screen shows the room through a light scrim, the copy sits on
   the darkened lower two thirds, and the text-shadow already on
   .hero .wrap > * carries the rest. object-position pushes the lit part of
   each frame up and to the right, above the first line of the headline. */
@media (max-width: 900px) {
  .hero {
    display: flex; align-items: flex-end;
    min-height: calc(100vh - var(--nav-h));
    min-height: calc(100svh - var(--nav-h));
    padding: 140px 0 56px;
  }
  .hero-bg { position: absolute; inset: 0; height: auto; aspect-ratio: auto; }
  .hero-video, .hero-poster { object-position: 68% 28%; }
  /* THE SCRIM IS ANCHORED TO THE COPY BLOCK, NOT TO THE VIEWPORT.
     The v148 spec wrote this in percentages, assuming the copy fills the lower
     two thirds. It does not: measured at 390px the kicker starts 17 percent
     down on the homepage and on /license-the-forge/, both of which carry a
     three-line kicker and a four-line headline. Against a percentage scrim the
     gold kicker measured 2.78:1 and 4.01:1 there and 1.82:1 on the Five
     Questions, all below the 4.5:1 that 12px text needs.

     Two reasons the stops are absolute pixels from the BOTTOM instead. The
     copy block is bottom-anchored by align-items: flex-end, so pixels from the
     bottom move with it and percentages do not. And .hero is sized in 100svh:
     when a mobile address bar collapses the viewport GROWS, so a percentage
     scrim slides out from under bottom-anchored copy at exactly the moment the
     page is being read.

     The three stops below are the copy block's own landmarks, measured
     September 11, 2026 at 390 and 430 across all four pages that share this
     component. Re-measure them if the hero copy changes materially; do not
     nudge them by eye. check_contrast.py is the guard that catches it. */
  .hero {
    --hero-copy-base: 56px;       /* .hero padding-bottom: where the copy ends */
    --hero-copy-top-short: 435px; /* top of the shortest copy block, /principles/ at 390 */
    --hero-copy-top-tall: 679px;  /* top of the tallest, the homepage at 390 */
  }
  .hero-overlay {
    inset: 0; height: auto;
    background:
      linear-gradient(to top,
        rgba(10,10,10,0.97) 0px,
        rgba(10,10,10,0.94) var(--hero-copy-base),
        rgba(10,10,10,0.87) var(--hero-copy-top-short),
        rgba(10,10,10,0.74) var(--hero-copy-top-tall),
        rgba(10,10,10,0.20) 100%);
  }
  .hero .wrap { padding-top: 0; }
  .hero h1 { max-width: none; font-size: clamp(38px, 11vw, 54px); }
}

/* ---- the guided-rep window ----
   A real TREPP session: uptrend, pullback into the 21 EMA, entry at the
   resumption, stop under the pullback low, target at twice the risk. The
   candles and both EMAs are computed, not drawn by eye. Built by
   build_rep_chart.py; regenerate there, never hand-edit the SVG. */
.rep-frame {
  position: relative; overflow: hidden;
  background: #0E0E0E; display: flex; flex-direction: column;
}
.rep-frame img { width: 100%; height: 100%; object-fit: cover; }

.rep-bar {
  display: flex; align-items: center; gap: 8px;
  padding: 13px 18px; border-bottom: 1px solid var(--hair);
}
.rep-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--ink-4); flex: none; }
.rep-dot.live { background: var(--gold); }
.rep-bar-title {
  margin-left: 6px; font-size: 10.5px; letter-spacing: 0.15em;
  text-transform: uppercase; color: var(--ink-3);
}
.rep-bar-n {
  margin-left: auto; font-size: 10.5px; letter-spacing: 0.13em;
  text-transform: uppercase; color: var(--ink-4); white-space: nowrap;
}

/* v118: the .rep-score / .rep-rule scorecard rules were deleted with the
   generated SVG chart they styled. The walkthrough carries that story now. */
@media (max-width: 460px) { .rep-bar-n { display: none; } }

/* ---- v118: the walkthrough player -------------------------------------
   Click to play, audio as authored, nothing downloaded until pressed. */
.rep-video { position: relative; background: #000; line-height: 0; }
.rep-video video {
  display: block; width: 100%; height: auto; aspect-ratio: 16 / 9;
  background: #000; outline: none;
}
/* the poster layer: only present until first play */
.rep-play {
  position: absolute; inset: 0; width: 100%; height: 100%;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 16px; margin: 0; padding: 0; border: 0; cursor: pointer;
  background: linear-gradient(180deg, rgba(10,10,10,0.30) 0%, rgba(10,10,10,0.52) 100%);
  -webkit-tap-highlight-color: transparent;
  transition: background 0.25s ease;
}
.rep-play[hidden] { display: none; }
.rep-play:hover, .rep-play:focus-visible {
  background: linear-gradient(180deg, rgba(10,10,10,0.20) 0%, rgba(10,10,10,0.44) 100%);
}
.rep-play:focus-visible { outline: 2px solid var(--gold); outline-offset: -4px; }
.rep-play-ring {
  position: relative;
  width: 84px; height: 84px; border-radius: 50%;
  background: var(--gold);
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 10px 34px rgba(0,0,0,0.55);
  transition: transform 0.22s cubic-bezier(0.2,0.7,0.3,1);
}
/* the halo that says "press me" */
.rep-play-ring::after {
  content: ''; position: absolute; inset: -10px; border-radius: 50%;
  border: 2px solid rgba(234,170,0,0.55);
  animation: repPulse 2.4s ease-out infinite;
}
.rep-play:hover .rep-play-ring, .rep-play:focus-visible .rep-play-ring { transform: scale(1.07); }
.rep-play:active .rep-play-ring { transform: scale(0.97); }
.rep-play-ring svg { width: 30px; height: 30px; margin-left: 5px; fill: #0A0A0A; }
@keyframes repPulse {
  0%   { transform: scale(1);    opacity: 0.85; }
  70%  { transform: scale(1.28); opacity: 0; }
  100% { transform: scale(1.28); opacity: 0; }
}
.rep-play-label {
  font-family: var(--display); font-size: 20px; letter-spacing: 0.08em;
  text-transform: uppercase; color: #FFFFFF; line-height: 1;
  text-shadow: 0 2px 14px rgba(0,0,0,0.75);
}
@media (prefers-reduced-motion: reduce) {
  .rep-play-ring::after { animation: none; }
  .rep-play-ring, .rep-play { transition: none; }
}

@media (max-width: 560px) {
  .rep-play-ring { width: 64px; height: 64px; }
  .rep-play-ring svg { width: 23px; height: 23px; }
  .rep-play-label { font-size: 16px; }
}

/* ---------- S4 steps ---------- */

.steps { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; margin-top: 44px; text-align: left; }
.step { padding: 28px 22px; }
.step-ic { width: 34px; height: 34px; color: var(--gold); margin-bottom: 18px; }
.step-ic svg { width: 100%; height: 100%; }
.step-k { font-size: 11px; letter-spacing: 0.18em; text-transform: uppercase; color: var(--ink-4); }
.step h3 { font-family: var(--display); font-size: 24px; letter-spacing: 0.03em; color: var(--white); margin: 8px 0 10px; font-weight: 400; }
.step p { margin: 0; font-size: 15px; color: var(--ink-2); line-height: 1.6; }
.steps-note { margin: 30px auto 0; max-width: 660px; font-size: 15px; color: var(--ink-2); line-height: 1.7; }
@media (max-width: 1040px) { .steps { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 700px) { .steps { grid-template-columns: 1fr; } }

.atelier { overflow: hidden; }
.atelier-bg { position: absolute; inset: 0; z-index: 0; }
.atelier-bg img { width: 100%; height: 100%; object-fit: cover; opacity: 0.80; }
.atelier-scrim {
  position: absolute; inset: 0; z-index: 1;
  background: radial-gradient(96% 78% at 50% 50%, rgba(10,10,10,0.26), rgba(10,10,10,0.78) 86%);
}
/* Lighter pairing for the path section: the badges carry that block, so the
   room sits further back than it does behind the price cards. */
.atelier-bg.soft img { opacity: 0.78; }
.atelier-scrim.soft {
  background:
    radial-gradient(92% 76% at 50% 46%, rgba(10,10,10,0.24), rgba(10,10,10,0.72) 88%),
    linear-gradient(180deg, var(--black) 0%, transparent 8%, transparent 92%, var(--black) 100%);
}
.atelier .wrap { position: relative; z-index: 2; }
/* The backdrop was raised hard in v105, which is exactly what was asked for, but
   a brighter room shows through a 0.72 plate and softens card text sitting over
   the fire. Opacity is lifted on atelier plates ONLY. The global --plate token in
   set.css is shared by 31 pages and is deliberately not touched. */
.atelier .plate { background: rgba(13,13,13,0.88); }

/* ---------------------------------------------------------------------------
   v147. Everything above this line up to the v144 banner moved here from
   index.html page-scope, verbatim, because /license-the-forge/ now reuses
   the hero, the walkthrough player, the step cards and the atelier band. v137
   rule: a reusable component lives here, not in a page's own <style>.
   --------------------------------------------------------------------------- */

/* The text-wrap half of the stranded-word rule for the classes that just moved.
   The homepage states these same values in its own <style>; they are identical,
   so the two cannot disagree, and without them here the moved classes would be
   unprotected on any page that is not the homepage. */
.hero-sub, .steps-note { text-wrap: balance; }
.step p { text-wrap: pretty; }

/* v144 moved .lead into set.css but left its text-wrap declaration behind in
   index.html page-scope, so .lead was balanced on the homepage and unbalanced
   on the eleven other pages that use it. At true font metrics that stranded
   "actually buying." on /before-you-pay/ at 390px. This completes that move.
   The rule a component needs travels with the component or the class is
   protected on exactly one page. */
.lead { text-wrap: balance; }

/* ---------- three-card row (v147) ----------
   The one new component in this slice. It carries The Gap, where the middle
   card is deliberately unfilled and dashed so the void between two solid cards
   IS the argument, and How the money works, where all three are filled. The
   word GAP is the middle card's heading, standing in for the small-caps label
   the other two carry.

   These are narrow columns, roughly 300px at the 1120px wrap and narrower at
   1024. .tri-card p goes in NARROW in check_widows.py, not WIDE. */
.tri-row {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px;
  margin-top: 38px; text-align: left; align-items: stretch;
}
.tri-card { padding: 30px 24px; display: flex; flex-direction: column; }
/* The label slot is one fixed, bottom-aligned height across all three cards,
   because the middle card's heading is the word GAP at display size and the
   other two carry an 11px label. Without this the middle card's body copy
   starts 20px below its neighbours and the row reads as a mistake rather than
   as a deliberate void. */
.tri-k, .tri-word { display: flex; align-items: flex-end; min-height: 42px; margin: 0 0 14px; }
.tri-k {
  font-family: var(--body); font-size: 11px; font-weight: 500;
  letter-spacing: 0.18em; text-transform: uppercase; color: var(--gold);
}
.tri-card p { margin: 0; font-size: 15px; line-height: 1.7; color: var(--ink-2); text-wrap: pretty; }
.tri-card--empty { background: transparent; border: 1px dashed var(--hair-gold); border-radius: 3px; }
.tri-word {
  font-family: var(--display); font-size: 38px; line-height: 0.86;
  letter-spacing: 0.08em; color: var(--gold);
}
/* Stacked, the gap card stays in the middle because it is in the middle of the
   DOM. That ordering is the point of the section and must not be reflowed. */
@media (max-width: 900px) { .tri-row { grid-template-columns: 1fr; } }


/* ---------- five-card step row (v148) ----------
   The homepage step card carries four across. Principles has five, and five in
   a four-column grid strands one card alone on the second row. A six-column
   track gives 2 then 3: the first two cards span three columns each, the last
   three span two each. Below 1040 it collapses to two and then to one, which
   is exactly what the four-card grid does, so the two never diverge on a phone.
   .step-n is the gold ordinal standing where .step-ic puts the icon. It holds
   the same 34px slot so a numbered card and an iconed card line up if they are
   ever placed in the same row. */
.steps.steps--five { grid-template-columns: repeat(6, 1fr); }
.steps.steps--five > .step:nth-child(-n+2) { grid-column: span 3; }
.steps.steps--five > .step:nth-child(n+3) { grid-column: span 2; }
.step-n {
  display: block; height: 34px; margin-bottom: 18px;
  font-family: var(--display); font-weight: 400;
  font-size: 34px; line-height: 34px; letter-spacing: 0.06em; color: var(--gold);
}
@media (max-width: 1040px) {
  .steps.steps--five { grid-template-columns: repeat(2, 1fr); }
  .steps.steps--five > .step:nth-child(-n+2),
  .steps.steps--five > .step:nth-child(n+3) { grid-column: auto; }
}
@media (max-width: 700px) { .steps.steps--five { grid-template-columns: 1fr; } }

/* ---------- the page callout (v148) ----------
   A short passage the page needs to stop on. Running copy at body size, which
   is what separates it from .pull-quote, display type at 28ch for a single line.

   It is NOT named .callout, and that is deliberate. Thirteen Macro Brief pages
   carry 108 elements with class="callout" and each declares its own page-scoped
   rules. Those rules are declared after set.css so they win on every property
   they set, but they do not set max-width or text-align, so a shared .callout
   leaked exactly those two into all 108 of them. The v148 pixel diff caught it
   reflowing brief bodies on nine published pages before the zip was cut. The
   shared component takes a name of its own until the brief layer is unified,
   which is its own job. */
.page-callout {
  max-width: 720px; margin: 38px auto 0; padding: 24px 28px;
  background: var(--plate); border: 1px solid var(--hair);
  border-top: 2px solid var(--gold); border-radius: 3px; text-align: left;
}
.page-callout-label {
  display: block; font-family: var(--body); font-size: 10px; font-weight: 500;
  letter-spacing: 0.20em; text-transform: uppercase; color: var(--gold); margin: 0 0 10px;
}
.page-callout p { margin: 0 0 12px; font-size: 16px; line-height: 1.8; color: var(--ink-2); text-wrap: pretty; }
.page-callout p:last-child { margin-bottom: 0; }
@media (max-width: 720px) { .page-callout { padding: 20px; margin-top: 30px; } }

/* ---------- split block (v148) ----------
   A heading and its paragraph on the left, one card on the right. Used where a
   section makes an argument and then hands over a single next step. A
   full-measure paragraph with a link trailing off the end of it does not read
   as a next step, it reads as a footnote. Stacks under 900. */
.split { display: grid; grid-template-columns: 1.35fr 1fr; gap: 44px; align-items: start; margin-top: 32px; text-align: left; }
.split-body p { color: var(--ink-2); font-size: 16px; line-height: 1.8; margin: 0 0 16px; text-wrap: pretty; }
.split-body p:last-child { margin-bottom: 0; }
.split-card { padding: 30px 26px; }
.split-card p { margin: 0 0 22px; font-size: 15px; line-height: 1.7; color: var(--ink-2); text-wrap: pretty; }
@media (max-width: 900px) { .split { grid-template-columns: 1fr; gap: 28px; } }

/* ---------- spec grid, card chrome (v148) ----------
   The Five Questions runs five spec cells as its answer to its own checklist.
   Hairline separation reads there as one list of claims; boxed, they read as
   five discrete answers, which is the point of the section. Six-column track
   gives 3 then 2, so no cell is ever left alone on a row. */
.spec-grid.spec-grid--cards { grid-template-columns: repeat(6, 1fr); gap: 16px; margin-top: 38px; }
.spec-grid.spec-grid--cards > .spec-cell { padding: 26px 24px; border-top: none; grid-column: span 2; }
.spec-grid.spec-grid--cards > .spec-cell:nth-child(n+4) { grid-column: span 3; }
@media (max-width: 900px) {
  .spec-grid.spec-grid--cards { grid-template-columns: repeat(2, 1fr); }
  .spec-grid.spec-grid--cards > .spec-cell,
  .spec-grid.spec-grid--cards > .spec-cell:nth-child(n+4) { grid-column: auto; }
}
@media (max-width: 720px) {
  .spec-grid.spec-grid--cards { grid-template-columns: 1fr; gap: 14px; }
  .spec-grid.spec-grid--cards > .spec-cell { padding: 24px 22px; border-top: none; padding-top: 24px; }
}
/* ---------- wide hero headline (v148) ----------
   .hero h1 holds a 15ch measure, tuned for the homepage and the partner page
   where the headline is long enough to want a hard ceiling. "What Steady Edge
   Trading stands for" is 24 characters of Bebas and strands "for" on a third
   line at 15ch, which is the exact defect the widow check exists to catch on
   body copy. The measure is the problem, not the copy, so the page that needs
   a wider one asks for it here rather than with an inline style. */
.hero h1.h1-wide { max-width: 24ch; }

/* ---------- dense hero scrim (v148) ----------
   The shared .hero-overlay desktop gradient is tuned for a hero image that
   carries its own shadow on the left: the homepage loop, the candle-wall bench
   on /license-the-forge/, the lamp-lit anvil on /principles/ all do, and all
   three put the 12px gold kicker between 6.3:1 and 8.5:1 at 1440.

   atelier-room.jpg on /before-you-pay/ does not. It is the full workshop, lit
   evenly corner to corner, and against the shared scrim its kicker measured
   3.60:1 at 1440 and 3.88:1 at 1280, both under the 4.5:1 that 12px text
   needs. object-position gives no leverage here, because a 1.79 image in a
   1.73 box is barely cropped horizontally, so there is no darker region to
   pull across.

   So the page whose image has no shadow asks for a denser scrim rather than
   all four pages getting darker. Desktop only: below 901px the layered mobile
   scrim owns .hero-overlay outright, and this selector would otherwise beat it
   on specificity no matter where it sits in the file.
   The stops run darker and further right than the shared scrim because the
   copy column sits proportionally further into the lit half as the viewport
   narrows: 1024 failed at 3.92:1 on the first attempt at these values while
   1440 and 1280 passed. Every hero width this site is checked at now clears.
   Found by check_contrast.py, which is the whole reason that guard exists. */
@media (min-width: 901px) {
  .hero--lit .hero-overlay {
    background:
      linear-gradient(90deg, rgba(10,10,10,0.95) 0%, rgba(10,10,10,0.91) 46%, rgba(10,10,10,0.74) 64%, rgba(10,10,10,0.24) 86%, rgba(10,10,10,0.08) 100%),
      radial-gradient(115% 85% at 16% 50%, rgba(10,10,10,0.40), transparent 68%);
  }
}

/* ---------- the tier gap, v149 ----------
   Replaces the three-card row that carried this section from v146 to v148.

   One render function sets six custom properties and every geometry decision
   is made here, which is what lets the same function drive the desktop rail
   and the mobile ladder without knowing which one is on screen.

     --tg-a     beat A, the rail arrives and the lowest tier rises
     --tg-b     beat B, the highest tier rises at the far end
     --tg-c     beat C, leaders drop, the dimension line draws, the figure counts
     --tg-d     beat D, The Forge lands and the dimension line turns gold
     --tg-e     beat E, the resolve line settles
     --tg-rail  the rail draw, which deliberately spans beats A and B

   --tg-rail is the sixth variable rather than a calc over the first two,
   because easing beat A and beat B separately and concatenating them puts a
   visible stutter at the seam where the rail should be drawing at one speed.

   EVERY DEFAULT IS 1, WHICH IS THE FINISHED STATE. With no JavaScript at all
   the section renders complete and readable. The animation is the enhancement,
   never the content. */
.tiergap {
  --tg-a: 1; --tg-b: 1; --tg-c: 1; --tg-d: 1; --tg-e: 1; --tg-rail: 1;
  --tg-inset: clamp(58px, 11%, 130px);
  --tg-dim: #8A6600;
  margin: 34px 0 0;
}
/* The muted gold is the whole point of beat D: there is no gold anywhere in
   the sequence until the product lands, so the eye has exactly one place to
   go when it does. color-mix does the handover; the flat value above is the
   fallback and is the muted end, never the lit one. */
@supports (color: color-mix(in srgb, #000 50%, #fff)) {
  .tiergap { --tg-dim: color-mix(in srgb, #EAAA00 calc(var(--tg-d) * 100%), #8A6600); }
}

/* THE VALUE ON THE GRAPHIC IS THE INPUT.
   The spec put two number fields in a row above the graphic. Built that way it
   printed "Your lowest tier" twice sixty pixels apart, once on the field and
   once on the stop it feeds, and the reader had to look in two places to see
   one number. Editing the figure where it is drawn is the same interaction
   with half the furniture, and it is the thing that makes the section a
   realisation instead of a claim. The gold hairline under each value is the
   affordance; the line under the graphic says so in words. */
/* v150. THE AFFORDANCE. A dashed gold rule reads as a blank to be filled in
   the way a solid hairline does not, and it is the difference between a
   figure a reader looks at and a figure a reader edits. It goes solid on
   focus so the field says it is live while it is being typed in. */
.tiergap-v {
  display: inline-flex; align-items: baseline; gap: 2px; margin-top: 6px;
  padding-bottom: 4px; border-bottom: 2px dashed var(--gold);
  cursor: text;
}
.tiergap-v:focus-within { border-bottom-style: solid; }

.tiergap-cur {
  font-family: var(--display); font-size: 26px; line-height: 1.05;
  color: var(--ink-3);
}
.tiergap-input {
  width: 4.4ch; max-width: 100%; background: transparent; padding: 0;
  border: none;
  font-family: var(--display); font-size: 38px; line-height: 1.05;
  letter-spacing: 0.02em; color: var(--white); -moz-appearance: textfield;
  cursor: text;
}
/* The field is as wide as the number in it, so "$50" and "$500" both sit
   tight against the dollar sign instead of leaving a hole where the unused
   characters would be. */
@supports (field-sizing: content) {
  .tiergap-input { field-sizing: content; width: auto; min-width: 1.6ch; }
}
.tiergap-input::-webkit-outer-spin-button,
.tiergap-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.tiergap-input:focus-visible { outline: 2px solid var(--gold); outline-offset: 3px; }

/* The hint under each figure. It says what the dashed rule implies, because
   an affordance nobody has seen before is worth naming once. The wording
   follows the pointer rather than the user agent string: a hover-capable fine
   pointer gets "click", everything else keeps "tap", which is the honest
   default for a phone and for a touch laptop. */
.tiergap-edit {
  display: flex; align-items: center; gap: 5px; margin-top: 8px;
  font-size: 10px; font-weight: 500; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--gold);
}
.tiergap-stop--high .tiergap-edit { justify-content: flex-end; }
.tiergap-edit svg { width: 11px; height: 11px; flex: none; fill: currentColor; }
.tiergap-edit i { font-style: normal; }
.tiergap-edit .tg-point { display: none; }
@media (hover: hover) and (pointer: fine) {
  .tiergap-edit .tg-touch { display: none; }
  .tiergap-edit .tg-point { display: inline; }
}

/* ---- the stage ----
   The rail is the price axis and the two tiers sit on it. Extension lines drop
   from each tier past the dimension line, which measures the distance between
   them. The figure labels that distance and the product lands in it. That is
   how a drafting dimension is drawn, and the section is calling out a
   distance, so it is the one piece of visual language here that is not
   decoration. */
.tiergap-stage { position: relative; height: 372px; margin-top: 30px; }

.tiergap-rail {
  position: absolute; left: 0; right: 0; top: 136px; height: 1px;
  background: var(--hair);
  transform: scaleX(var(--tg-rail)); transform-origin: left center;
}

.tiergap-stop {
  position: absolute; top: 0; width: clamp(206px, 27%, 278px);
  display: flex; flex-direction: column;
}
.tiergap-stop--low { left: 0; align-items: flex-start; text-align: left;
  opacity: var(--tg-a); transform: translateY(calc((1 - var(--tg-a)) * 26px)); }
.tiergap-stop--high { right: 0; align-items: flex-end; text-align: right;
  opacity: var(--tg-b); transform: translateY(calc((1 - var(--tg-b)) * 26px)); }

.tiergap-k {
  display: block; font-size: 11px; font-weight: 500; letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--ink-3);
}
.tiergap-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 12px; width: 100%; }
.tiergap-stop--high .tiergap-chips { justify-content: flex-end; }
.tiergap-chips i {
  font-style: normal; font-size: 11px; line-height: 1;
  padding: 6px 8px; border: 1px solid var(--hair); border-radius: 2px;
  color: var(--ink-2); white-space: nowrap;
}

/* Extension lines. They start under each tier stop, cross the rail, and run to
   the dimension line, which is what says WHICH two points are being measured. */
.tiergap-lead {
  position: absolute; top: 112px; bottom: 50px; width: 1px;
  background: var(--hair);
  transform: scaleY(var(--tg-c)); transform-origin: top center;
}
.tiergap-lead--low { left: var(--tg-inset); }
.tiergap-lead--high { right: var(--tg-inset); }

/* The dimension line: a rule across the empty gap with a tick at each end. */
.tiergap-dim {
  position: absolute; left: var(--tg-inset); right: var(--tg-inset); bottom: 50px;
  height: 1px; color: var(--tg-dim);
}
.tiergap-dim-line {
  position: absolute; inset: 0; background: currentColor;
  transform: scaleX(var(--tg-c)); transform-origin: left center;
}
.tiergap-tick {
  position: absolute; top: -6px; width: 1px; height: 13px;
  background: currentColor; opacity: var(--tg-c);
}
.tiergap-tick--l { left: 0; }
.tiergap-tick--r { right: 0; }

/* The figure sits centred above the dimension line and counts up on beat C.
   The caption sits under it, on the other side of the line. */
.tiergap-fig {
  position: absolute; left: var(--tg-inset); right: var(--tg-inset); top: 262px;
  margin: 0; text-align: center; color: var(--tg-dim);
  opacity: var(--tg-c); transform: translateY(calc((1 - var(--tg-c)) * 10px));
}
.tiergap-fig-n {
  display: block; font-family: var(--display); font-size: 46px;
  line-height: 1; letter-spacing: 0.02em; color: currentColor;
  font-variant-numeric: tabular-nums;
}
.tiergap-fig-c {
  position: absolute; left: var(--tg-inset); right: var(--tg-inset); bottom: 16px;
  margin: 0; text-align: center; font-size: 13px; line-height: 1.6;
  color: var(--ink-3); text-wrap: pretty;
  opacity: var(--tg-c); transform: translateY(calc((1 - var(--tg-c)) * 10px));
}

/* The product lands in the measured space. */
.tiergap-forge {
  position: absolute; left: 50%; top: 156px; width: min(300px, 44%);
  padding: 18px 20px; text-align: center;
  background: var(--plate); border: 1px solid var(--hair-gold); border-radius: 3px;
  opacity: var(--tg-d);
  transform: translateX(-50%) translateY(calc((1 - var(--tg-d)) * -38px));
}
.tiergap-forge-k {
  display: block; font-size: 10px; font-weight: 500; letter-spacing: 0.2em;
  text-transform: uppercase; color: var(--ink-3);
}
.tiergap-forge-n {
  display: block; margin-top: 7px; font-family: var(--display);
  font-size: 30px; line-height: 1; letter-spacing: 0.03em; color: var(--gold);
}

/* v150. The instruction moved ABOVE the rail, because a reader who meets the
   figures first has already decided they are a claim. It also moved off beat
   E onto beat A: an instruction that arrives last, at the top, after the
   answer it was supposed to frame, is worse than no instruction. */
.tiergap-note {
  margin: 4px 0 0; text-align: center; font-size: 12px; line-height: 1.7;
  color: var(--ink-2);
  opacity: var(--tg-a); transform: translateY(calc((1 - var(--tg-a)) * 8px));
}
/* The resolve line settles under the graphic on beat E. It lives inside
   .tiergap so it inherits the beat variables; it keeps the .criteria-body
   treatment it has carried since v146 and its copy is unchanged. */
.tiergap-resolve {
  margin-top: 26px;
  opacity: var(--tg-e); transform: translateY(calc((1 - var(--tg-e)) * 10px));
}

/* ---- below 760 the rail rotates to a ladder down the left edge ----
   Same five beats, same variables, same render function. The layout
   difference lives entirely here, which is the contract that lets JOB 2 stay
   layout agnostic. */
@media (max-width: 759px) {
  .tiergap-stage {
    height: auto;
    display: grid;
    grid-template-columns: 50px minmax(0, 1fr);
    row-gap: 22px;
  }
  .tiergap-rail {
    top: 6px; bottom: 6px; left: 16px; right: auto; width: 1px; height: auto;
    transform: scaleY(var(--tg-rail)); transform-origin: top center;
  }
  /* .tiergap-dim STAYS positioned. Making it static hands its absolutely
     positioned line to .tiergap-stage instead, and inset: 0 then paints a
     gold rectangle over the whole component. */
  .tiergap-dim { position: relative; }
  .tiergap-stop, .tiergap-forge, .tiergap-fig, .tiergap-fig-c,
  .tiergap-lead { position: static; }

  .tiergap-stop { width: auto; grid-column: 2; text-align: left; }
  .tiergap-stop--low { grid-row: 1; }
  .tiergap-stop--high { grid-row: 5; }
  .tiergap-stop--high { align-items: flex-start; text-align: left; }
  .tiergap-stop--high .tiergap-chips { justify-content: flex-start; }

  /* the extension lines become horizontal stubs off the rail */
  .tiergap-lead {
    grid-column: 1; width: auto; height: 1px; margin: 16px 6px 0 17px;
    align-self: start;
    transform: scaleX(var(--tg-c)); transform-origin: left center;
  }
  .tiergap-lead--low { grid-row: 1; }
  .tiergap-lead--high { grid-row: 5; }

  /* and the dimension line runs vertically beside the gap band */
  .tiergap-dim {
    grid-column: 1; grid-row: 2 / 5;
    left: auto; right: auto; bottom: auto;
    width: 1px; height: auto; margin-left: 16px; justify-self: start;
  }
  .tiergap-dim-line { transform: scaleY(var(--tg-c)); transform-origin: top center; }
  .tiergap-tick { top: auto; left: -6px; right: auto; width: 13px; height: 1px; }
  .tiergap-tick--l { top: 0; }
  .tiergap-tick--r { bottom: 0; }

  .tiergap-forge {
    grid-column: 2; grid-row: 2; width: auto; left: auto; top: auto;
    transform: translateY(calc((1 - var(--tg-d)) * -22px));
    text-align: left;
  }
  .tiergap-fig {
    grid-column: 2; grid-row: 3; left: auto; right: auto; top: auto;
    text-align: left; transform: translateY(calc((1 - var(--tg-c)) * 8px));
  }
  .tiergap-fig-n { font-size: 40px; }
  .tiergap-fig-c {
    grid-column: 2; grid-row: 4; left: auto; right: auto; bottom: auto;
    text-align: left; transform: translateY(calc((1 - var(--tg-c)) * 8px));
  }
  .tiergap-note { text-align: left; }
}
