/* ═══ SELF-HOSTED FACES ═════════════════════════════════════════════════════
   Served from our own origin — NOT fonts.googleapis.com. Required by
   V1_landing_page_build_spec.md §5.2: a Google-hosted <link> transmits every
   visitor's IP to Google on page load, before any interaction and with no
   lawful basis to rely on. See V1_data_flow_inventory.md §2.7.

   All three are VARIABLE fonts — one file spans the whole weight range, so
   `font-weight` here is a range, not a single value. Do not split these into
   per-weight faces; there is only one file per family per subset.

   Two subsets each, with the same unicode-range Google itself served, so
   latin-ext downloads only when a glyph actually needs it (accented names).
   Regenerate by fetching the css2 API with a modern UA and taking the
   latin / latin-ext blocks.
   ═════════════════════════════════════════════════════════════════════════ */
@font-face{
  font-family:'Space Grotesk'; font-style:normal; font-weight:300 700; font-display:swap;
  src:url('/assets/fonts/space-grotesk-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face{
  font-family:'Space Grotesk'; font-style:normal; font-weight:300 700; font-display:swap;
  src:url('/assets/fonts/space-grotesk-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}
@font-face{
  font-family:'Inter'; font-style:normal; font-weight:100 900; font-display:swap;
  src:url('/assets/fonts/inter-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face{
  font-family:'Inter'; font-style:normal; font-weight:100 900; font-display:swap;
  src:url('/assets/fonts/inter-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}
@font-face{
  font-family:'Caveat'; font-style:normal; font-weight:400 700; font-display:swap;
  src:url('/assets/fonts/caveat-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face{
  font-family:'Caveat'; font-style:normal; font-weight:400 700; font-display:swap;
  src:url('/assets/fonts/caveat-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}

/* ═══ TOKENS — every hex lifted from apps/frontend/src/styles/tokens.css ═══ */
:root{
  --ink:#080e18;          /* page ground        (app --bg)          */
  --raised:#0f1a28;       /* surfaces that lift (app --card)        */
  --line:#1a2d44;         /* the floor          (app --border)      */
  --jade:#0EA47D;         /* above the line     (--brand-jade)      */
  --gold:#CBA54C;         /* the one thing      (--brand-gold)      */
  --breach:#ff3d5a;       /* below the line     (app --red)         */
  --tx:#ddeeff;           /* primary text       (app --text)        */
  --tx2:#8ba3bf;          /* secondary text     (app --text-secondary) */

  --display:'Space Grotesk',system-ui,sans-serif;
  --body:'Inter',system-ui,sans-serif;
  --hand:'Caveat',cursive;   /* hero illustration ONLY — nowhere else */

  /* 1.25 modular scale off 17px */
  --t0:17px; --t1:21px; --t2:27px; --t3:34px; --t4:43px; --t5:54px; --t6:68px;

  --gut:clamp(20px,5vw,64px);
  --maxw:1320px;
  /* CTA gradient. Deliberately GOLD, not the app's sky --primary: the
     app's amber-is-signal-only rule (Q-AK4) exists because amber competes
     with P&L colour on a data surface, and there is no P&L here for it to
     collide with. Marketing gets the freedom; the dashboard does not.
     The construction is borrowed from the app's --primary-grad — an
     off-centre radial at 35%/30% rather than a flat linear ramp, which is
     what makes it read as a lit object instead of a painted rectangle.
     Stops LIFTED ACC (was #F2DC98 / #CBA54C 52% / #96722C): once the ground
     went jade, the old shadow stop read olive-brown where the button meets
     it. Same hue, lighter shadow; --cta-solid stays the brand gold. */
  --cta-grad:  radial-gradient(circle at 35% 30%, #F6E3A6 0%, #D4AE55 55%, #AC8738 100%);
  --cta-solid: #CBA54C;
  --on-cta:    #170F02;   /* 9.0:1 on the mid tone, 5.7:1 at the shadow stop */

  /* Ground effect intensities — the two dials. Raise to taste; the test is
     that you should feel the page is lit, not notice a gradient. */
  /* Operator-calibrated on a real monitor 2026-09-07: the warm backlight only
     becomes perceptible above ~.50, so anything below that is a paint cost
     with no visible result. Set just clear of that threshold — a value tuned
     to be BARELY visible on a good display disappears entirely on a dim one. */
  /* WHY THAT CALIBRATION KEPT FAILING (and why the numbers below changed):
     the dial was alpha on a MEDIUM TAN source, and normal compositing can
     only interpolate toward the source — it can never exceed it. The hottest
     pixel the old glow could physically produce was
       0.496 x rgb(214,178,102) over rgb(16,28,46) = #72664A
     — lightness 37%, saturation 21%. Olive mud. No value of --lamp fixed
     that, because the ceiling was the source colour, not the dial: pushing
     alpha to 1.0 just yields a solid tan rectangle. So the source stops are
     now CREAM and the hot core is small and high-alpha, which is what lets
     the composite reach ~#C6B38B (lightness 66%) and read as a light instead
     of a stain.

     RE-CALIBRATED ON THE OPERATOR'S MONITOR 2026-09-15 (ABW): .80 -> 1.30.
     .80 was never a judgement about this light — it was left over from the
     regime above, where the dial could not change anything, so it carried a
     number chosen for a system that no longer exists. Q-ABU-lamp CLOSED.

     WHAT THE DIAL IS: a multiplier on the alpha of every stop in both
     gradients of `.diary::before`, not a single opacity. At 1.30 the two
     cores resolve to .715 (spill) and .676 (source); 1.00 renders the stops
     at their authored values, so anything below that is attenuation.

     THE REAL CEILING IS 1.82, NOT ~1.67 as Q-ABU-lamp recorded — the first
     stop to clamp is the spill core at 1/0.55. Nothing clamps at 1.67
     (0.55 x 1.67 = 0.92). Above the ceiling the falloff flattens and the
     glow reads as a lit disc with a hard border rather than as light. */
  --lamp:1.30;   /* warm source behind the diary — operator-set ABW */
  --depth:.90;   /* vertical darkening down the page */

  /* ── SURFACE LIFT ────────────────────────────────────────────────────────
     On a dark ground a drop shadow is nearly invisible (black on near-black),
     so panels were separating from the page by 4.5 points of lightness alone
     (--ink 6.3% vs --raised 10.8%) and read as flat rectangles. What actually
     separates a surface in a dark room is the SPECULAR TOP EDGE — the lit lip
     where the object faces the light — plus weight underneath it. --raised
     itself is deliberately NOT changed: it is the app's real --card hex and
     the hero panel mirrors a real product surface (Rule 86), so the lift is
     carried by light and shadow rather than by repainting the fill. */
  --edge:rgba(255,255,255,.07);            /* lit top lip */
  --lift:0 18px 40px -20px rgba(0,0,0,.9); /* weight underneath */

  /* ── THE GROUND, AS ONE DEFINITION ───────────────────────────────────────
     Both `body` and the sticky `.topbar` paint this. It has to be shared, not
     duplicated: the nav must be opaque so scrolled content does not show
     through it, and while it was a flat `--ink` fill it read as a darker strip
     across the top of the page — measured, 13 points of lightness below the
     page behind it (nav rgb(8,14,24) vs page rgb(26,46,74)). That gap opened
     when the ambient was added, because the ambient is centred at 50% 0% — the
     top of the viewport — so the nav was the one band of the page getting none
     of it. With `background-attachment:fixed` on both, each resolves against
     the VIEWPORT rather than its own box, so the nav's copy lands pixel-for-
     pixel on the body's and the bar disappears while staying opaque. */
  /* JADE, NOT NAVY — operator-calibrated 2026-09-15 (ABW). Hue 216 -> 164,
     each stop's own saturation and lightness kept, +2 points of lift.
     164 is --jade's own hue (#0EA47D measures 164), landed on by eye.

     WHY: the lamp is warm (~38) and the old ground was ~216 — within 2 of
     complementary, which is maximum hue opposition, so the glow read as a
     foreign object rather than as light in the room. Moving the ground
     toward the lamp lets them share a space.

     WHY ONLY +2 OF LIFT, when +8 looked better on the dial: --tx2 carries
     nearly all body copy AND renders inside the mock assessment panel, so it
     cannot be lightened to compensate without breaking the product mirror
     (see SURFACE LIFT above, Rule 86). That caps the ramp. Measured against
     the TRUE composite — the gradient is alpha var(--depth) over --ink, not
     over black, which is worth 0.13 of contrast:
         0%   #163e34   tx 10.01   tx2 4.56   <- worst case
         40%  #0e2923   tx 13.05   tx2 5.95
         72%  #0b221d   tx 14.08   tx2 6.42
         100% #081c17   tx 14.93   tx2 6.80
     +4 puts the top stop at 4.27 and fails AA. Do not raise this without
     re-measuring tx2 at the 0% stop.

     DELIBERATELY NOT CHANGED: --raised, --line, --tx, --tx2. They are the
     app's real hexes and all four render inside the hero panel, which mirrors
     a real product surface. The ground is page chrome; the panel is product.
     Operator caught this when a draft moved them together. */
  --ground:
    radial-gradient(ellipse 64% 40% at 50% 0%,
        rgba(60,164,137,.17) 0%, rgba(36,109,89,.07) 45%, rgba(0,0,0,0) 74%),
    linear-gradient(178deg,
      rgba(24,67,55,var(--depth)) 0%,
      rgba(15,44,36,var(--depth)) 40%,
      rgba(11,36,29,var(--depth)) 72%,
      rgba(8,29,23,var(--depth)) 100%);

  --tape:51px;   /* fixed bottom tape — body reserves this so the footer clears it */
  --bar:72px;    /* sticky header */
}

*{box-sizing:border-box;margin:0;padding:0}
html{scroll-behavior:smooth}
/* ═══ GROUND ══════════════════════════════════════════════════════════════
   Not a flat fill, and deliberately not the decorative mesh-gradient this
   category defaults to. Two motivated effects only:

   1. DEPTH — the page darkens as it descends, which is the floor idea the
      whole layout is built on, expressed in the ground itself. Fixed to the
      viewport so it does not band across an 8,000px document.
   2. LIGHT — see .diary::before. The diary is the one lit object on the page;
      a warm source behind it explains why, and turns the book's feathered
      edge into light falloff instead of a mask.

   Both stay under the threshold where they read as "a gradient". If you can
   name the effect, it is too strong. */
body{
  background:var(--ink);
  /* Chroma matters more than lightness here. The old ramp ran #142238 to
     #03060B — four near-identical desaturated navies, the last of which is
     effectively black. Fixed to the viewport, that means five screens below
     the fold sat on a flat dead field with no light in them at all, which is
     most of what read as "stiff". Same descent, same fixed attachment, but
     the top now carries real colour and the bottom stops short of black so
     the ground still has a hue at the footer. */
  /* Lives in --ground (see :root) because the sticky nav paints the same thing.
     The ambient there is ONE light for the whole document, fixed to the
     viewport so every section scrolls THROUGH the same pool rather than each
     getting its own effect — scattered per-section glows are the tell we are
     avoiding. Cool on purpose: warm belongs to the lamp, gold to the CTA. It
     exists so the five screens below the fold are lit at all; they were a flat
     field with no light in them. */
  background-image:var(--ground);
  background-attachment:fixed;
  color:var(--tx);
  font-family:var(--body); font-size:var(--t0); line-height:1.65;
  -webkit-font-smoothing:antialiased;
}
/* Only the home page carries the tape; scoping this stops the legal pages
   ending in 51px of empty space below the footer. */
body:has(.tape){padding-bottom:var(--tape)}
h1,h2,h3,.num{font-family:var(--display); line-height:1.08; letter-spacing:-.02em}
a{color:inherit}
p{max-width:68ch}          /* measure cap, per spec §5.2 */

.shell{max-width:var(--maxw); margin:0 auto; padding:0 var(--gut)}

/* ═══ THE FLOOR ═══════════════════════════════════════════════════════════
   The site's one structural device: a hairline that MEANS the daily loss
   limit, used as the section divider throughout. Never used decoratively.
   Spec §5.3.

   `.floor--live` REMOVED (ABW). It tinted the hero's instance 55% toward
   --breach, on the reasoning quoted here until now: "emphasised in the hero
   where it carries that meaning literally; quiet everywhere else — SAME LINE,
   SO THE EYE LEARNS IT."

   The eye could not learn it. Measured at rest, the hero's floor sits flush
   under the fixed tape at every desktop size — 859 vs tape 858 at 1920x910,
   689/688 at 1585x740, 649/648 at 1366x700 — and below the fold entirely on
   mobile (1273 vs a 812 viewport). **It was never visible on load at any
   size.** The only time it appeared was mid-scroll, where it reads as an
   unexplained coloured seam rather than as a device: the lamp lights the
   region above it and nothing lights the region below, so there is a genuine
   tonal step there, and a red hairline pointed straight at it. The operator
   saw it while scrolling and called it a broken look.

   So the teaching instance was the one nobody saw, and what shipped was the
   inverse of the intent. The floor survives everywhere it actually works;
   only the invisible red copy is gone. --breach stays reserved for what it
   means — below the line — which is the same argument the file already makes
   for gold (CTA only) and that ABW made for jade. */
.floor{border:0; border-top:1px solid var(--line); margin:0}

section{padding:clamp(56px,8vw,104px) 0}
/* Anchor jumps must clear the sticky header, or the heading you jumped to
   lands underneath it. Affects every nav link (#how, #features, #pricing,
   #faq), not just the newest one. */
section[id]{scroll-margin-top:calc(var(--bar) + 20px)}

/* ═══ NAV — sticky ════════════════════════════════════════════════════════ */
/* The bar is chrome, not content: it runs the full width with only the page
   gutter holding it off the edges, so the logo sits far left and the actions
   far right. Constraining it to the reading column made it read as a floating
   strip rather than a header. */
.topbar{
  position:sticky; top:0; z-index:40;
  /* Paints the page's own ground rather than a flat fill — see --ground. Both
     are background-attachment:fixed, so this resolves against the viewport and
     lands exactly on the body's, making the bar opaque but invisible. */
  background-color:var(--ink);
  background-image:var(--ground);
  background-attachment:fixed;
  border-bottom:1px solid transparent;
}
.topbar .shell{max-width:none}
.topbar.stuck{border-bottom-color:var(--line)}   /* rule appears only once scrolled */
.nav{display:flex; align-items:center; gap:32px; padding:22px 0; height:var(--bar)}
.mark{display:flex; align-items:center; gap:10px; text-decoration:none; margin-right:auto}
.mark svg{width:28px; height:28px; color:var(--tx)}
.wordmark{font-family:var(--display); font-weight:600; font-size:19px; letter-spacing:-.01em}
.wordmark i{font-style:normal; color:var(--jade)}
.nav a.lnk{color:var(--tx2); text-decoration:none; font-size:15px}
.nav a.lnk:hover{color:var(--tx)}
/* Log in is a quiet text link, not a second button: one action gets button
   weight per surface, and the returning user already knows where they are
   going. It sits next to the CTA rather than among the section anchors
   because it is a destination, not a jump. */
.login{
  color:var(--tx); text-decoration:none; font-size:15px; font-weight:500;
  padding:8px 4px; white-space:nowrap;
}
.login:hover{color:var(--cta-solid)}

.btn{
  display:inline-flex; align-items:center; justify-content:center;
  font-family:var(--display); font-weight:600;
  font-size:15px; letter-spacing:-.01em; text-decoration:none; white-space:nowrap;
  padding:11px 21px; min-height:44px; border-radius:7px; border:0; cursor:pointer;
  color:var(--on-cta); background:var(--cta-grad);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.5),        /* lit top edge */
    inset 0 -1px 0 rgba(0,0,0,.22),            /* grounded bottom edge */
    0 1px 2px rgba(0,0,0,.45),
    0 6px 18px -8px rgba(203,165,76,.45);      /* warm cast, not a grey blur */
  transition:box-shadow .18s ease, transform .18s ease, filter .18s ease;
}
.btn:hover{filter:brightness(1.07); transform:translateY(-1px)}
.btn:active{transform:translateY(0); filter:brightness(.96)}

/* The hero and pricing CTA. Same object, more presence — a wider glow does
   the work rather than a second colour, so hierarchy costs nothing. */
/* Sized DOWN from --t1/16-32 (206x67) when the hero went to zoom:.80. The CTA
   is a sibling of .split, not a child, so the scale did not reach it and it
   went from 25.6% of the panel's width to 30.8% without anything being edited
   — it grew by standing still. Two further reasons not to put it back:
   the gold gradient already makes this the most salient object on the page,
   so size was spending emphasis that colour had already bought; and at 21px
   against a 56px headline the ratio was .375, roughly double the .16-.21 of
   the two reference heroes this design was measured against. */
.btn--lg{
  /* 19px is deliberately BETWEEN --t0 (17) and --t1 (21) and off the 1.25
     scale. --t1 restored the pre-zoom oversizing; --t0 left it only 24px
     wider than the nav button, which made the page's primary action read as
     a peer of its chrome. A button is a target, not prose, so it is the one
     element allowed off the text scale. */
  font-size:19px; padding:14px 29px; border-radius:8px;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.55),
    inset 0 -1px 0 rgba(0,0,0,.24),
    0 2px 4px rgba(0,0,0,.45),
    0 16px 40px -12px rgba(203,165,76,.62);
}
.btn--lg:hover{
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.6),
    inset 0 -1px 0 rgba(0,0,0,.24),
    0 3px 6px rgba(0,0,0,.45),
    0 22px 52px -12px rgba(203,165,76,.75);
}

/* Motion here answers a click rather than announcing itself, so it stays —
   but the preference is still honoured. */
@media (prefers-reduced-motion:reduce){
  .btn{transition:none}
  .btn:hover,.btn:active{transform:none}
}

/* ═══ HERO ════════════════════════════════════════════════════════════════ */
/* ═══ THE FOLD ════════════════════════════════════════════════════════════
   Everything through the CTA must be visible without scrolling: headline,
   quote, both panels, the button. The tape is fixed to the bottom edge so it
   is always visible and costs the fold nothing but its own height.
   svh (not vh) so mobile browser chrome does not push the CTA under the fold.
   Below 880px wide the hero stacks and returns to natural height; there is no
   fold to protect there.

   NOTE: .topbar must stay OUTSIDE .fold. A sticky element only sticks while
   its own parent is in view, so nesting it here would unstick the header the
   moment the hero scrolled past.

   THE HEIGHT GATE WAS REMOVED (it was min-height:760px) and that is not a
   loosening — it was never doing the job its comment claimed. The operator's
   laptop reports a 1585x740 VIEWPORT (a 1600x900 screen, less ~160px of tab
   strip, address bar, bookmarks bar and taskbar — Rule 89), which is 20px
   under the gate, so none of this block applied: the hero fell back to its
   natural 513px, ended at y=586, and left a 103px dead band of ground between
   the red floor and the fixed tape.

   The gate read as protection against "crushing the panels", but min-height
   cannot crush anything — it is a FLOOR. When the content is taller than
   `100svh - bar - tape` the content wins and the page scrolls, which is what
   already happens below ~640. Crushing is the job of the max-height:900 tier
   further down, and that is untouched. At 740 the natural hero fits the 615px
   band with 102px to spare, so the only thing the gate bought was the gap. */
@media (min-width:881px){
  .fold{
    min-height:calc(100svh - var(--bar) - var(--tape));
    display:flex; flex-direction:column;
  }
  .heroShell{flex:1; display:flex; flex-direction:column; justify-content:center}
}
/* Contains the lamp's horizontal bleed. The glow box extends 30% of the book's
   width past it on each side — free on desktop, where the book ends near
   mid-container, but 81px of horizontal overflow on a phone where the book is
   full width.
   THREE choices here and only one is correct:
   - `overflow-x:hidden` on body would work and silently break the sticky
     header: hidden establishes a scroll container, and position:sticky stops
     working inside one.
   - putting it on `body` at all does nothing anyway — when html is `visible`,
     body's overflow PROPAGATES to the viewport and body computes back to
     visible. Measured: body reported `clip` while the 81px overflow remained.
   - `clip` on .fold works because .fold is a normal element (no viewport
     propagation), it establishes no scroll container, and the sticky .topbar
     is a SIBLING of .fold rather than a descendant, so stickiness is
     untouched. It also lets overflow-y stay visible, which hidden cannot. */
.fold{overflow-x:clip}
.hero{padding:clamp(28px,4vw,52px) 0 clamp(24px,3vw,44px)}
/* 21ch breaks the headline to two lines, not three — the third line was
   costing ~74px of fold for no extra meaning. */
/* Cap raised 56 -> 68 (--t6, the top of the existing scale, not an arbitrary
   number) when the headline became a single line. One 56px line could not hold
   the top of a composition this heavy — the hero read top-light against the
   book and card below. The single line also freed 61px of fold, which is what
   pays for this. */
.hero h1{font-size:clamp(38px,5.2vw,68px); font-weight:700; max-width:22ch}

/* Headline and quote sit side by side above 1000px. Stacked, they left a dead
   top-right quadrant on wide screens and pushed the split too far down. The
   quote hangs from the headline's last baseline rather than the top. */
/* The quote sits on its OWN line under the headline. Pairing it beside the
   headline was a fix for a dead top-right quadrant, not a compositional
   intent, and it made the quote compete with the headline at the same eye
   level. On its own line it reads as what it is: a second, quieter voice
   before the object. */
.heroTop{display:block}
.quote{
  /* Narrow enough that the quote's BOX ends clear of the raised panel, not
     just its glyphs. At 590px the boxes overlapped 83px and the text only
     escaped because the panel's top edge fell below the first line — one copy
     change or a different font metric and it would have collided.
     468px ALONE was not enough: it is a fixed width while the panel's left
     edge tracks the viewport, so below ~1150 the panel arrives under a quote
     that has not narrowed to meet it. At 1024 that hid 36px of text — the
     word "underlying" was amputated mid-word and the attribution line ran
     behind the book. The 40vw term is what makes the quote yield as the space
     closes; min() keeps 468px binding on everything wide, so nothing above
     ~1170 changes at all. */
  margin-top:clamp(18px,2vw,26px); max-width:min(468px,40vw,100%); font-size:var(--t1);
  color:var(--tx2); font-weight:400; line-height:1.5;
}
.quote cite{
  display:block; margin-top:10px; font-size:15px; font-style:normal;
  /* Was #5a7a99. That reads at 3.9:1 on the page ground but only 2.53:1 where
     this line crosses the book's leather — and since the z-index below makes
     it sit ON the leather rather than be clipped by it, the dim half became
     the visible problem. --tx2 gives 4.37:1 there. Intermediate tones do not
     reach it: #7590ad, halfway between, still only manages 3.43:1.
     The cost is that the attribution now shares the quote's colour, so the
     hierarchy between them is carried by size alone. For an attribution line
     that is ordinary typography, not a compromise. */
  color:var(--tx2);
  /* ABOVE the book, not clear of it. The book's -5deg tilt raises its right
     edge 52px, and that raised corner climbs into this line at every desktop
     width — measured 12px at 1920, 28px at 1440 and 1200, 23px at 1024. The
     geometric fix (pushing the book down) costs ~32px of fold, which the hero
     does not have to spare. Z-order costs nothing: .diary is z-index 1 and
     .split .read is z-index 2, so 3 puts the attribution over both and it
     cannot be covered at any width. The part of the book it lands on is the
     plain leather top edge, which carries no content to compete with. */
  position:relative; z-index:3;
}

/* the split: journal → signal. Not a card grid — two unlike things. */
/* stretch, not center: a journal page is a PAGE. Centering a short leaf inside
   a taller row left it floating with ~50px of hole above it. */
/* OVERLAPPING CLUSTER, not two aligned columns. Equal rectangles with matched
   tops and bottoms and a gap between them read as a diagram: every edge rhymed
   with another edge. The panel now sits ON the book, dropped low and pushed
   left over it, so neither is a peer of the other and the transition is
   carried by depth rather than by an arrow. The 12-column track is what makes
   that overlap expressible. */
.split{
  position:relative;
  display:grid; grid-template-columns:repeat(12,1fr);
  margin:clamp(24px,3vw,36px) 0 0;
}
/* ═══ HERO SCALE ══════════════════════════════════════════════════════════
   The book and the panel are the two most expensive objects in the fold, and
   they cost the SAME: the panel is 485px tall but carries a -104px pull-up,
   so its net contribution is 381px against the book's 382px. They are matched
   by construction, which is why scaling only one buys nothing — the row is
   max(book, panel).

   MEASURED at 1920x910 (a maximised browser on a 1080p monitor: tab strip,
   address bar, bookmarks bar and taskbar take ~170px, so 1080 is never the
   real viewport height and was the wrong number to verify against):
     CTA bottom 917 vs fixed-tape top 858  ->  the CTA sat 59px UNDER the tape.

   `zoom`, NOT `transform:scale`. Verified in the page, both ways:
     transform:scale(.8) -> CTA bottom 917  (unchanged — it scales the painted
                            pixels but keeps the original layout box, so it
                            reclaims exactly nothing and only looks smaller)
     zoom:.8             -> CTA bottom 835, fold 889->807, 23px clear of tape
   The lamp is sized in percentages of .split, so it scales with the scene and
   keeps its relationship to the book rather than needing a re-tune.

   Scoped above the stacking breakpoint: below 880px the hero is a single
   column and there is no fold to protect. */
@media (min-width:881px){
  .split{zoom:.80}
}
/* The lamp. Warm because the object it lights is cream paper and cognac
   leather; weak because a light source you notice is a light source that has
   become decoration. Sits behind both panels and is inert to pointers. */
/* ═══ THE LAMP ════════════════════════════════════════════════════════════
   ANCHORED TO THE BOOK, not to .split. That is the point of this rule.

   It used to hang off .split::before as percentages of a box derived from the
   split, and that silently mis-registers: the book's position INSIDE the split
   is not constant. .diary switches aspect-ratio from 640/430 to 640/330 at
   >=1420 wide and >=900 tall, and the short-viewport block changes the split's
   margin and the panel's padding, both of which move the row height. So a
   placement tuned at one size drifts at every other. Measured with the same
   probe both ways: the spill core sat 11px below the book's bottom edge at
   1920x910 (correct) and 88px below at 1030x780 — 166% of its own radius, so
   the light did not reach the book at all. What showed was a warm blob with a
   dark gap under it.

   Hanging it off .diary makes every percentage below relative to the BOOK, so
   registration holds at every width by construction and cannot be broken again
   by someone changing an aspect-ratio.

   THE BOX: inset -55% vertical / -30% horizontal = 210% of the book's height
   and 160% of its width, with the book itself occupying 26.2%..73.8% and
   18.75%..81.25% of it. Every coordinate below is in THOSE units. Change the
   insets and you must recompute all of them — do not nudge.

   COUNTER-ROTATION: .diary carries rotate(-5deg) and a child inherits it. The
   spill must stay LEVEL — it is the widest, flattest shape at the base of the
   composition, so the eye reads it as a horizon, and tilting a horizon does
   not tilt the light, it tilts the world. rotate(5deg) cancels the parent so
   the glow travels with the book while staying square to the page. The mobile
   block resets both, since .diary is unrotated there.

   z-index:-1 keeps it behind the book's SVG while staying inside .diary's
   stacking context, so it paints above the page ground and below the paper.

   KEPT FROM THE OLD RULE, both paid for once already:
   - explicit ellipse radii, never farthest-corner. A gradient still opaque
     where its box ends reads as a lit RECTANGLE with a hard border — invisible
     at low --lamp, obvious the moment it is turned up.
   - every falloff reaches zero inside the box on all four sides. */
.diary::before{
  content:''; position:absolute; inset:-55% -30%;
  z-index:-1; pointer-events:none;
  transform:rotate(5deg);
  background:
    /* SPILL — the pool the book sits in. Centre 48%/76% is just below the
       book's bottom edge and slightly left of its middle, because the card
       covers the book's right end and only the VISIBLE part of that edge is
       worth lighting. The wide falloff is load-bearing: the edge slopes at
       -5deg and a level ellipse can only touch a tilted edge at one point, so
       width is what buys contact along the whole run instead of one spot. */
    radial-gradient(ellipse 46% 11% at 48% 76%,
        rgba(255,226,168,calc(var(--lamp) * .55)) 0%,
        rgba(233,186,110,calc(var(--lamp) * .26)) 30%,
        rgba(176,132,68,calc(var(--lamp) * .10)) 58%,
        rgba(203,165,76,0) 100%),
    /* SOURCE — ON the book's top edge (y 26% IS the edge), not inside it. A
       rim needs its falloff to cross the silhouette steeply, so the core
       straddles the boundary and its upper half escapes into the empty band
       between book and quote — the only place in this composition where a
       backlight can actually be seen. An earlier version buried the core deep
       inside the book, so all that ever showed was the weak outer halo, which
       read as haze rather than as light. */
    radial-gradient(ellipse 19% 24% at 65% 26%,
        rgba(255,232,182,calc(var(--lamp) * .52)) 0%,
        rgba(236,190,116,calc(var(--lamp) * .25)) 30%,
        rgba(180,136,70,calc(var(--lamp) * .09)) 58%,
        rgba(203,165,76,0) 100%);
}
.diary{position:relative; z-index:1}
/* SCOPED TO .split DELIBERATELY — do not unscope.
   `.read` is the shared panel SKIN (rule further down) and is reused by the
   #features assessment panel, which lays out in `.two`, a 2-track grid. While
   the placement below was unscoped it followed the class into that grid: the
   panel asked for line 6→13, grid manufactured ten implicit columns to honour
   it, `.two`'s 72px gap got paid eleven times, and the prose column collapsed
   to 142px (heading wrapped one word per line). Placement belongs to the hero
   grid; only the skin is shared. The mobile reset near the bottom of this file
   is scoped the same way and must stay in step. */
.split .diary{grid-area:1/1/2/7}
.split .read{
  /* RAISED into the quote band. The quote is capped at 54ch and left-aligned,
     so the space to its right is empty — the panel fills it instead of sitting
     below, which turns a side-by-side pair into a layered diagonal AND costs
     the hero less height than stacking did. Anchored to the top of the row and
     pulled up, rather than hung from the bottom. */
  grid-area:1/6/2/13; align-self:start; z-index:2;
  margin-top:clamp(-104px,-6.5vw,-48px);
  /* One grid column of overlap was landing ON the handwriting. The lap is
     eased right so it covers the book's blank fore-edge instead — the depth
     cue survives, the writing stays fully legible. */
  margin-left:clamp(20px,2vw,30px);

  /* EXPERIMENT (composition) — clockwise tilt against the book's -1deg so the
     two objects read as a wedge rather than two parallel slabs.
     ORIGIN IS THE POINT. Rotating about the default centre swung the card's
     bottom-left corner down and left, straight over the book (and 46px into
     the CTA) — the book stopped reading. Pivoting at the bottom-right corner
     instead lifts the card's LEFT side away from the book and drops almost
     nothing, because the corner nearest the CTA is the one held still.
     ANGLE: 15deg fitted, but it rotated 8.8px calendar type off the pixel
     grid and left the top-left corner with zero headline clearance. 7deg
     keeps the diagonal, keeps the numerals legible, and clears both. */
  transform:rotate(7deg); transform-origin:100% 100%;

  /* box-shadow does not merge across rules, so this replaces the shared
     .read shadow entirely — the specular lip has to be repeated here or the
     hero panel is the one panel on the page without it. */
  box-shadow:inset 0 1px 0 var(--edge),
             0 24px 60px -12px rgba(0,0,0,.85),
             0 0 0 1px var(--line);
}
/* (The old 1.2fr/auto/1fr override is gone — column ratios are expressed by
   the grid-area spans above now.) */
/* .arrow REMOVED. Two boxes with an arrow between them IS a flowchart, and it
   was the main thing making this read as technical. Position, overlap and the
   caption carry the transition; animating it would also have spent a second
   continuous-motion budget when the tape already holds the only one. */

/* ── LEFT: the diary ──────────────────────────────────────────────────────
   An OPEN spread, cropped at the left edge. A closed book shows no content
   and would kill the whole journal→signal idea; the crop keeps the binding,
   gutter and page-stack — the features that actually say "bound book" —
   while giving the right page enough width for the hand to breathe.

   The paper is CREAM on purpose. It is the one warm, lit, physical object on
   a cold near-black page, which is the concept doing visual work rather than
   being captioned: human artifact left, machine reading right. It is also the
   single boldest element on the site — everything else stays disciplined.

   The leather is derived from --brand-gold (cognac is dark desaturated gold),
   so no new hue enters the palette. Kept very dark so bright gold stays
   reserved for the CTA.                                                      */
/* -5deg, not the old -1deg: the book is the other side of the wedge. Pivoting
   at the TOP-LEFT corner rather than the centre does two things a centre pivot
   cannot — the book's left edge stays aligned with the headline and quote
   above it, and the bottom cannot swing down into the CTA (a centre pivot at
   this angle left only 3px of CTA clearance). The right side lifts toward the
   card, which is what makes the two objects converge instead of diverge. */
.diary{position:relative; aspect-ratio:640/430; transform:rotate(-5deg); transform-origin:0 0}
/* THE LIT LIP. The lamp sits BEHIND .diary, so the cover occludes it — and the
   cover's leather runs 11px above the cream page (measured). The result was
   glow, then a band of dead-black leather, then paper: light that stops short
   of the object it is lighting, which is the one thing a backlight must never
   do. A real source above catches the top edge FIRST. This paints that catch,
   as a child of .diary so it rotates with the book and stays on its edge.
   Centred at 70% because that is where the lamp is in the book's own width
   (lamp x=798 within a book spanning 358..977). Scaled by --lamp so it tracks
   the dial instead of becoming a fixed highlight that survives turning the
   lamp down. Only 3.2% tall, so it cannot reach .entry at top:10%. */
.diary::after{
  content:''; position:absolute; left:0; right:0; top:0; height:3.2%;
  pointer-events:none; z-index:2;
  background:radial-gradient(ellipse 55% 100% at 70% 0%,
      rgba(255,228,172,calc(var(--lamp) * .60)) 0%,
      rgba(214,172,104,calc(var(--lamp) * .22)) 45%,
      rgba(0,0,0,0) 100%);
}
/* Masked on the SVG ONLY — the handwriting is a sibling layer and must stay
   fully opaque. The book loses its hard rectangle and dissolves into the page
   ground, which is what stops it rhyming with the panel. A hard circular crop
   would have cut the cover corners and stitching, the cues that say "bound
   book"; feathering keeps them and still removes the edge. */
.diary svg{
  position:absolute; inset:0; width:100%; height:100%; display:block;
  -webkit-mask-image:radial-gradient(ellipse 70% 78% at 46% 50%, #000 66%, rgba(0,0,0,.6) 86%, transparent 100%);
          mask-image:radial-gradient(ellipse 70% 78% at 46% 50%, #000 66%, rgba(0,0,0,.6) 86%, transparent 100%);
}

/* Handwriting is real HTML over the right page — SVG <text> does not wrap. */
.entry{
  /* ONE pitch drives the ruled lines AND every line of writing, so the hand
     always sits on a rule. Both clamps track vw, so they stay in proportion. */
  --rule:clamp(23px,2.5vw,37px);
  /* The writing has to start AFTER the margin rule, not through it.
     Derivation, so this survives edits to either side: the rule is drawn in
     the SVG at x=180 of a 640-wide viewBox with preserveAspectRatio="none",
     so it renders at a fixed 28.125% of .diary's width. .entry's box starts
     at 25%, which put the first glyph 3.125% to the LEFT of the rule.
     PADDING, not a larger `left`. Percentage padding on an absolutely
     positioned box resolves against the containing block (.diary), so 5% here
     is 5% of the book's width — and because background-origin is padding-box,
     the ruled lines still span the whole element. Moving `left` instead would
     have dragged the rules right with the text and left a bare strip between
     the margin rule and the first rule, which no notebook has.
     Text now starts at 25 + 5 = 30%, clearing the rule by 1.875% of the book
     (~12px at this size) — a real notebook's margin gap.
     `right` comes in from 18% to 14% to pay the 5% back: the leaf runs to
     96.6%, so there was unused page on that side anyway, and the measure ends
     up 56% against the previous 57% — the hand keeps its line breaks. */
  position:absolute; left:25%; right:14%; top:10%; bottom:9%; overflow:hidden;
  padding-left:5%;
  font-family:var(--hand); color:#243444;
  background-image:repeating-linear-gradient(
    to bottom, transparent 0 calc(var(--rule) - 1px),
    rgba(140,126,96,.55) calc(var(--rule) - 1px) var(--rule));
}
.entry .date{font-size:clamp(15px,1.7vw,23px); color:#8a7f66; line-height:var(--rule); margin:0}
.entry .hand{font-size:clamp(15px,1.9vw,27px); line-height:var(--rule); max-width:none}
/* Its own line at every width. Inline, the crossed-out phrase ran across a
   wrap and merged with what followed, so the self-correction — the point of
   the entry — stopped reading. */
.entry .struck{display:block; text-decoration:line-through; color:#8c8471}
/* "finished red." must not split across a line. It did once, when the measure
   was widened to pay for the margin-rule padding: "finished" was pulled up to
   the previous line and "red." orphaned onto the next, breaking a two-word
   clause in the middle of the entry's punchline. Pinning the pair states the
   intent and holds at every width — retuning the measure would only have
   fixed it at one. */
.entry .keep{white-space:nowrap}
.entry .hand b{font-weight:600}

/* right — the same day, read by EdgeKeeper */
/* Shared panel skin. The inset top line is a specular lip, not a border — it
   is what makes a dark surface read as an object in a dark room, where an
   ordinary drop shadow is black on near-black and does nothing on its own. */
.read{
  background:var(--raised); border:1px solid var(--line); border-radius:3px;
  padding:22px 24px;
  box-shadow:inset 0 1px 0 var(--edge), var(--lift);
}
.read .hd{
  display:flex; justify-content:space-between; align-items:baseline;
  padding-bottom:13px; border-bottom:1px solid var(--line); margin-bottom:15px;
}
.read .hd b{font-family:var(--display); font-weight:600; font-size:var(--t0)}
.read .hd span{font-size:14px; color:var(--tx2)}
.row{display:flex; justify-content:space-between; align-items:baseline; padding:7px 0; gap:20px}
.row .k{font-size:15px; color:var(--tx2)}
.row .v{font-family:var(--display); font-weight:600; font-size:var(--t0); letter-spacing:-.01em}
.v--bad{color:var(--breach)}
.v--ok{color:var(--jade)}
.netRow{display:flex; justify-content:space-between; align-items:baseline; gap:16px; padding:2px 0 10px}
.net{font-family:var(--display); font-weight:700; font-size:clamp(24px,2.4vw,32px); letter-spacing:-.02em; line-height:1.1}
.statGrid{
  display:grid; grid-template-columns:repeat(4,1fr); gap:10px 14px;
  padding:12px 0; border-top:1px solid var(--line); border-bottom:1px solid var(--line);
}
.statGrid div{display:flex; flex-direction:column; gap:2px; min-width:0}
.sk{font-size:13px; color:var(--tx2); white-space:nowrap}
.sv{font-family:var(--display); font-weight:600; font-size:var(--t0); letter-spacing:-.01em}
.dirBlock{padding-top:10px}
.dirLabel{font-size:13px; color:var(--tx2); margin-bottom:2px}

/* ── Daily P&L calendar ────────────────────────────────────────────────────
   The visual anchor the panel lacked: a month of coloured cells is a shape,
   where four rows of numbers were only ever a list. Colour carries the same
   meaning it does everywhere else on the page — jade above the line, red
   below — so this adds no new vocabulary. */
.calWrap{padding-top:11px}
.cal{
  display:grid; grid-template-columns:repeat(7,1fr); gap:3px; margin-top:6px;
}
.calHead{
  font-size:11px; color:#5a7a99; text-align:center; padding-bottom:2px;
  font-family:var(--body);
}
.cel{
  display:flex; align-items:center; justify-content:center;
  height:26px; border-radius:3px; font-style:normal;
  font-family:var(--display); font-weight:600; font-size:11px;
  letter-spacing:-.01em; background:rgba(255,255,255,.02);
}
.cel--win {background:rgba(14,164,125,.17);  color:#5fd3ab}
.cel--loss{background:rgba(255,61,90,.15);   color:#ff8497}
.cel--off {background:rgba(255,255,255,.018)}          /* weekend, no trades */
.cel--adj {background:none; opacity:.3}                /* adjacent month */
/* Selected day wears a ring — the app's own affordance (Session AAK). */
.cel--sel{box-shadow:0 0 0 2px var(--cta-solid); position:relative; z-index:1}
.verdict{
  margin-top:12px; padding-top:12px; border-top:1px solid var(--line);
  display:flex; align-items:center; gap:9px; flex-wrap:wrap;
  font-family:var(--display); font-weight:600; font-size:var(--t0); color:var(--breach);
}
/* The pattern name is real, but it comes from the 90-day assessment, not from
   this day. Saying so is the difference between a claim and a fabrication. */
.vsrc{font-family:var(--body); font-weight:400; font-size:13px; color:var(--tx2); margin-left:auto}
.dot{width:7px; height:7px; border-radius:50%; background:var(--breach); flex:none}

.cap{margin-top:11px; font-size:14px; color:#5a7a99}
.cta{display:flex; align-items:center; gap:18px; flex-wrap:wrap; margin-top:clamp(22px,2.8vw,34px)}
.cta small{font-size:15px; color:var(--tx2)}

/* ═══ TICKER — the site's ONLY continuous motion (spec §5.4) ══════════════ */
.tape{
  position:fixed; bottom:0; left:0; right:0; z-index:45;
  background:var(--ink); border-top:1px solid var(--line);
  overflow:hidden; padding:13px 0;
}
.tape ul{display:flex; gap:0; list-style:none; width:max-content; animation:run 52s linear infinite}
.tape li{
  display:flex; align-items:center; gap:36px; padding-right:36px;
  font-size:15px; color:var(--tx2); white-space:nowrap;
}
.tape li::after{content:''; width:4px; height:4px; border-radius:50%; background:var(--line)}
.tape .seat{color:var(--gold)}
@keyframes run{from{transform:translateX(0)} to{transform:translateX(-50%)}}
.tape:hover ul{animation-play-state:paused}
@media (prefers-reduced-motion:reduce){
  .tape ul{animation:none; width:auto; flex-wrap:wrap}
}

/* ═══ GENERIC SECTION TYPE ════════════════════════════════════════════════ */
h2{font-size:clamp(27px,3.8vw,43px); font-weight:700; max-width:19ch}
.lede{margin-top:18px; font-size:var(--t1); color:var(--tx2); line-height:1.55}
.body{margin-top:16px; color:var(--tx2)}


/* steps — the ONLY numbered markers on the site, because this IS a sequence */
.steps{display:grid; grid-template-columns:repeat(3,1fr); gap:clamp(24px,3.5vw,48px); margin-top:44px; counter-reset:s}
.step{counter-increment:s; padding-top:18px; border-top:1px solid var(--line)}
.step::before{
  content:counter(s,decimal-leading-zero); display:block; margin-bottom:12px;
  font-family:var(--display); font-weight:600; font-size:15px; color:var(--gold);
}
.step h3{font-size:var(--t1); font-weight:600; margin-bottom:9px}
.step p{font-size:15px; color:var(--tx2); line-height:1.6}

/* two-column asymmetric block — deliberately NOT equal cards */
.two{display:grid; grid-template-columns:1.05fr .95fr; gap:clamp(32px,5vw,72px); align-items:start}
/* Q-ABU-officer's merged section pairs a six-row surface list with the
   assessment panel, and the near-even split starves the list: .slab's label
   column is a FIXED 230px, so a 588px column leaves ~330px for the sentence
   and every row wraps to three lines. The panel is the cheaper half — it is
   short rows and a quote, and it reads fine narrower. Overridden back to one
   column by the 880 block below, which is later in source at equal
   specificity. */
.two--wide{grid-template-columns:1.35fr .85fr}
/* The list opens the section's second half rather than following prose, so it
   drops .slab's 40px lead-in and its top border lines up with the panel's. */
.slab--flush{margin-top:0}
/* Section sub-heading. h3 is otherwise styled only inside .step and .prose,
   so a bare one here would render at the browser default. Deliberately a step
   below h2: the broker list is evidence for the section's claim, not a second
   claim of its own. */
.subhead{font-size:var(--t1); font-weight:600; margin-top:clamp(36px,4vw,52px)}

/* proof frames
   ── THE LAYOUT IS DRIVEN BY LEGIBILITY, NOT COMPOSITION ──────────────────
   The old grid (1.4fr/1fr, left cell spanning both rows) gave 686px and
   490px frames, and a screenshot's text size is governed by exactly one
   ratio: frame width over source width. Whole app screens pushed through
   those frames landed at 0.41x and 0.26x, which put `--fs-xs` — 13px, and
   tokens.css:174 calls it "the minimum readable size for desktop UI" — at
   5.3px and 3.4px. Unreadable, and no amount of resolution fixes it:
   effective DPR measures sharpness, and crisp-and-tiny is still tiny.

   The dashboard takes the full width. 1192px against a 1686px source is
   0.707x — 13px renders at 9.2px, still under the floor but nearly double
   what it was. Frame width alone cannot close the rest; see the note above
   .shotWrap--dash img for the capture change that does.

   ONE FRAME, NOT THREE (operator's call, and the arithmetic agrees). The two
   half-width frames were 588px against 1886px sources — 0.312x, putting the
   13px floor at 4.1px — and nothing short of turning them into cropped
   details could fix that. A detail crop is a fragment of a screen, and three
   fragments prove less than one screen you can actually read.

   What makes the cut cheap is that neither surface loses its only visual:
   #features already carries a rendered assessment panel for the Risk
   Officer, and names all seven surfaces in text. This section's job is
   "signed in, seconds later" — the screen a new account actually lands on,
   which is the dashboard.                                                  */
.shots{display:grid; grid-template-columns:1fr; margin-top:44px; align-items:start}
/* aspect-ratio, not min-height: the frame must keep its shape as the
   container flexes, or the crop budget changes with the viewport and the
   object-position below is tuned for one width only.

   1192/684 IS CUT TO A PANEL EDGE, not chosen for looks. The capture is
   1280x800 CSS and the equity-curve panel's bottom border sits at CSS y=735
   (source rows 1470-1471 at DPR 2); at this frame's 0.931x the cut lands just
   above it, so the frame's own border stands in for the panel's. Past the
   border there is a ~16 CSS px gutter before the calendar panel; shorter,
   and 1192/620 sliced the equity chart above its own date axis and left a
   chart with no x axis.
   RE-DERIVE THIS ON EVERY RECAPTURE, measured, not by eye: the ABW capture
   had the border at CSS 731 (frame 680); the ACA recapture put it at 735
   because the KPI row and risk strip rendered a few px taller. */
.shotWrap--dash .shot{aspect-ratio:1192/684}
/* THE CAPTION IS NOT IN THE IMAGE. It was, briefly, and it failed twice over:
   a label sitting on a screenshot reads as part of the app's UI rather than as
   a label for it, and the implementation could not even be made to work —
   `.shot` was a flex column, so the <b> AND the bare description text after it
   were both flex items, and while <b> can take a z-index an anonymous text
   node cannot. The scrim meant to protect the caption painted over half of it,
   which is why the label showed and its description did not.
   Frame holds the image and nothing else; the caption is its sibling. */
.shotWrap{margin:0; display:flex; flex-direction:column; gap:10px}
.shot{
  background:var(--raised); border:1px solid var(--line); border-radius:3px;
  min-height:210px; position:relative; overflow:hidden;
  /* Same specular lip as .read. These frames hold DARK app screenshots
     (Q-ABS-screenshots), and a dark image on a dark ground needs the frame to
     do the separating — which is exactly how the reference dark hero carries
     its product window. */
  box-shadow:inset 0 1px 0 var(--edge), var(--lift);
}
.shotWrap figcaption{color:#5a7a99; font-size:14px; line-height:1.45}
.shotWrap figcaption b{display:block; font-family:var(--display); font-weight:600; color:var(--tx2); font-size:15px; margin-bottom:2px}

/* ── THE CAPTURES ────────────────────────────────────────────────────────
   Q-ABS-screenshots. Three 1920x1080 captures into three frames of three
   DIFFERENT aspects (1.57:1 left, 2.33:1 right x2) — the grid forces that,
   so something is cropped in every frame and the only question is what.

   `cover`, not `fill`. `fill` was the computed default while these were
   empty divs and did nothing; the moment an <img> exists it stretches the
   image to the frame, which on a 1.78 source in a 2.33 frame would squash
   the UI by a quarter. That distortion is subtle enough to ship unnoticed
   and is exactly the class of thing Rule 86 is about — a product shot that
   is no longer what the product looks like.                                */
.shot img{
  position:absolute; inset:0; width:100%; height:100%;
  object-fit:cover;                     /* never `fill` — see above */
  display:block;
}

/* ── WHICH PART OF EACH CAPTURE SURVIVES ─────────────────────────────────
   THE SOURCES ARE PRE-CROPPED. Every capture arrived 1920x1080 with the
   app's own SCROLLBAR in frame — a viewport capture of a page that
   continues, which reads as an unfinished screenshot rather than a product
   shot. Measured rather than eyeballed: thumb #1A2D44 at x 1912..1917, its
   track to 1886, and the content panel's right border at x=1885, identical
   in all three. The files are now cut at 1885, so the panel border IS the
   right edge and no CSS has to fight it.

   THE SIDEBAR IS BACK, and the re-capture is why. The first capture was a
   1920-wide viewport, which forced a choice: 686px of frame could not hold
   both the 197px nav rail and the 34px scrollbar, so the rail was cropped.
   The replacement is captured at a 1280x800 VIEWPORT — not zoomed out; zoom
   shrinks the text, a narrower viewport does not — at DPR 2, so it arrives
   2560x1600 with no scrollbar at all and the rail intact. That matters more
   now than it did: with the analytics and risk-officer frames gone, the rail
   listing Dashboard / Analytics / AI Risk Officer / Journal / Trade Log is the
   only visual evidence of breadth left on the page.

   `top` because the frame is already cut to the equity panel's bottom
   border — there is nothing above it worth spending the crop on. */
.shotWrap--dash img{object-position:center top}



/* plain lists that aren't cards */
.slab{margin-top:40px; border-top:1px solid var(--line)}
.slab div{display:flex; gap:24px; padding:17px 0; border-bottom:1px solid var(--line); align-items:baseline}
.slab b{font-family:var(--display); font-weight:600; font-size:var(--t0); min-width:230px; flex:none}
.slab span{color:var(--tx2); font-size:15px}

/* pricing — one price, no comparison table */
.price{display:flex; align-items:flex-end; gap:16px; margin-top:30px; flex-wrap:wrap}
.price .now{font-family:var(--display); font-weight:700; font-size:clamp(48px,7vw,76px); color:var(--tx); line-height:1; letter-spacing:-.03em}
.price .was{font-family:var(--display); font-weight:500; font-size:var(--t2); color:#5a7a99; text-decoration:line-through; line-height:1.6}
.price .per{color:var(--tx2); font-size:var(--t0); line-height:2}
.founder{margin-top:14px; color:var(--gold); font-size:var(--t0)}

/* faq */
.faq{margin-top:40px; border-top:1px solid var(--line)}
.faq details{border-bottom:1px solid var(--line)}
.faq summary{
  cursor:pointer; padding:19px 0; font-family:var(--display); font-weight:600;
  font-size:var(--t1); list-style:none; display:flex; justify-content:space-between; gap:20px;
}
.faq summary::-webkit-details-marker{display:none}
.faq summary::after{content:'+'; color:var(--gold); font-weight:500}
.faq details[open] summary::after{content:'–'}
.faq p{padding:0 0 22px; color:var(--tx2); font-size:var(--t0)}
/* Supported contracts (Which markets). Symbols stay plain text separated by
   spaces so the drift test can split them; the gap is visual only. */
.faq .markets{
  display:grid; grid-template-columns:max-content 1fr; gap:10px 24px;
  margin:0 0 22px; font-size:var(--t0);
}
.faq .markets dt{color:var(--tx2)}
.faq .markets dd{margin:0; color:var(--tx); font-family:var(--display);
  font-weight:500; word-spacing:.55em}
@media (max-width:560px){
  .faq .markets{grid-template-columns:1fr; gap:2px}
  .faq .markets dd{margin-bottom:10px}
}

/* footer */
footer{padding:52px 0 64px; border-top:1px solid var(--line)}
.fgrid{display:flex; gap:44px; flex-wrap:wrap; align-items:flex-start}
.fgrid nav{display:flex; gap:26px; flex-wrap:wrap; margin-left:auto}
footer a{color:var(--tx2); text-decoration:none; font-size:15px}
/* 25px-tall targets in a row is a mis-tap waiting to happen on a phone.
   Padding rather than font-size, so the visual weight is unchanged. */
.fgrid nav a{display:inline-flex; align-items:center; min-height:44px}
footer a:hover{color:var(--tx)}
/* Deliberate exception to the global `p{max-width:68ch}` measure cap.
   At 74ch this sat at ~654px inside a 1192px shell — a stranded half-width
   column under a full-width .fgrid, which read as accidental rather than as
   a measure decision. Full width is ~135ch, well past comfortable measure
   for prose, but this is three lines of fine print at 14px: you make the
   return sweep twice, not thirty times. The shell's own --maxw (1320) is
   what bounds it, so it cannot run away on an ultra-wide display.
   If this text ever grows past ~5 lines, revisit — `columns:2` is the
   right answer at that length, not a narrower cap.

   `max-width:none` is REQUIRED and must not be "cleaned up" by deleting it:
   simply dropping the old 74ch does not release the width, it falls back to
   the global `p{max-width:68ch}` and the paragraph gets NARROWER than before.
   Measured: 601px on that fallback vs 1192px here. */
.disc{margin-top:34px; font-size:14px; color:#5a7a99; line-height:1.65; max-width:none}

/* focus — reuse the app's --focus recipe */
a:focus-visible,summary:focus-visible,.btn:focus-visible{
  outline:2px solid #7dd3fc; outline-offset:3px; border-radius:2px;
}

/* ═══ RESPONSIVE ══════════════════════════════════════════════════════════ */

/* SHORT VIEWPORTS — 1366×768 laptops leave ~650px of usable height after
   browser chrome. Holding the CTA above a fixed tape on a screen that short
   means the hero must compress; this tier does it deliberately rather than
   letting the button fall behind the tape. Measured: recovers ~150px.
   MUST stay below every rule it overrides — same specificity, so source
   order decides. */
@media (min-width:881px) and (max-height:900px){
  .hero{padding:13px 0 9px}
  /* Q-ABU-headline1280. The card's top-left corner sits ON the end of the
     headline throughout this tier — measured as text-range right edge minus
     the card's TRANSFORMED left edge, with the vertical overlap checked too
     (a horizontal intrusion means nothing if the boxes miss each other):
         1150x800  56px hidden, 22px vertical overlap
         1280x800  62px hidden, 38px
         1366x700  44px hidden, 46px
         1600x899  42px hidden, 56px
         1920x880  42px hidden, 56px   <- constant from ~1360 up
     Below ~1100 the card clears the headline band entirely (1024x800 reads
     -18px of vertical overlap), so the floor below does not have to serve it.
     The item was filed as a narrow band at ~1280 "clear by 1440"; it is not.
     It is the whole tier above ~1150, and it is invisible at 1920x910 only
     because 910 > 900 puts that size outside this block altogether.

     WHY THE SIZE IS THE LEVER AND NOT THE GEOMETRY. Clearing the card by
     moving it needs the vertical overlap plus a gap — ~64px of page pixels,
     which is ~80px of pre-zoom margin on .split .read's pull-up. Measured CTA
     clearance above the fixed tape at the tightest real size is 55px
     (1366x700; also 61px at 1920x910, 79px at 1280x800). So every fix that
     spends fold height — dropping the card, pushing the book down, or letting
     the headline wrap to a second line — puts the CTA back under the tape at
     the size that has least room. The headline's own width is the only lever
     that costs zero height.

     The 2.8vw term is what holds the clearance constant: the text's start and
     the card's left edge both track the container, so the required ratio is
     nearly the same at every width (needed 32.9px at 1150, 36.8 at 1280,
     38.7 at 1366, 38.9 at 1600+). 38px is the cap because it is the MINIMUM
     of the page's own headline clamp above — the short tier now bottoms out
     on a size the design already uses rather than on a new number.

     THE FLOOR IS 32, NOT 34 (--t3), and that is not a rounding choice. A
     clamp floor stops the vw term yielding, and the card is still closing in
     below 1214 where 34px would take over: measured at 1100x800 the card's
     corner reaches 16px into the headline's line box while 34px leaves 11px
     of the text behind it. 32px keeps the vw term binding down to ~1143 and
     clears it. Below ~1060 the card has dropped clear of the headline band
     entirely (1040x800 reads -17px of vertical overlap, 960x800 -40px), so
     nothing below that width needs the floor lower still — which is the only
     reason it can stop at 32 instead of chasing the stacking breakpoint. */
  .hero h1{font-size:clamp(32px,2.8vw,38px)}
  .quote{font-size:var(--t0)}
  .split{margin-top:18px}
  /* The PANEL is the tallest item in the split, so it — not the book — sets
     the row height and therefore the hero height. Shrinking the diary here
     bought nothing; this is where the height actually lives. */
  .read{padding:14px 18px}
  .row{padding:3px 0}
  .read .hd{padding-bottom:8px; margin-bottom:9px}
  .net{font-size:25px}
  .netRow{padding:0 0 7px}
  .statGrid{padding:9px 0; gap:6px 12px}
  .dirBlock{padding-top:7px}
  .verdict{margin-top:9px; padding-top:9px}
  .cap{margin-top:7px}
  .cta{margin-top:14px}
  /* The 1320 shell makes the diary wide, and aspect-ratio turns width into
     height — which is what pushed the CTA behind the tape at 768. A flatter
     book on short screens is also truer to a diary opened flat. */
  .quote{margin-top:12px; font-size:var(--t0)}
  .split{margin-top:16px}
  /* 5px of clearance is inside font-rendering noise; this buys ~17px. The
     hand and rule come down together with the book so the writing keeps
     filling the leaf rather than stranding blank rules. */
  .diary{aspect-ratio:640/280}
  .entry{--rule:29px}
  .entry .hand{font-size:21px}
  .entry .date{font-size:17px}
}

/* ═══ WIDE-SCREEN BREAKOUT ════════════════════════════════════════════════
   On a large monitor the shell leaves 300px of void a side at 1920 and 620px
   at 2560, but widening it uniformly is the wrong fix: prose is capped by
   reading measure (~68ch) and already renders at 588px, so it cannot use the
   space, and stretching the three-step grid to 1600px makes each column wide
   and thin. The ONLY element genuinely starved is the hero cluster — a 559px
   book on a 2560 screen is the page's memorable object rendered small.

   So the cluster alone breaks out of the text column, staying centred on it.
   The headline, quote and nav keep their 1320 alignment, which is what stops
   the breakout reading as a mistake. */
/* 901, NOT 900. `max-height:900px` on the short tier above and
   `min-height:900px` here BOTH match at exactly 900, and a 900px-tall viewport
   is a real one. In that overlap the two blocks contradict each other and the
   hero renders in a state that exists at neither neighbouring height:
       1600x899  .heroShell 1320px wide, headline starts at x=197
       1600x900  .heroShell 1161px wide, headline starts at x=276  <- neither
       1600x901  .heroShell 1317px wide, headline starts at x=198
   The 1161px is not a max-width being applied — computed max-width there is
   1536px. .heroShell is a flex item of .fold with `margin:0 auto`, and auto
   margins on the cross axis suppress the stretch, so the shell shrink-to-fits
   its content; this tier changes that content (a flatter book, a 30px hand)
   while the short tier is simultaneously shrinking the same objects, and the
   fit-content result collapses 159px. Consequence at exactly 900: the headline
   is pushed 79px right while the card moves only 13px, so the overlap above
   jumps from 42px to 109px — the worst case on the whole page.
   A viewport that is 900 tall is SHORT. The short tier owns it. */
@media (min-width:1420px) and (min-height:901px){
  /* Widen the hero CONTAINER rather than breaking the cluster out of it, so
     the headline, quote, book and CTA all share one left edge. Sections below
     stay at --maxw because prose is capped by reading measure and cannot use
     the extra width anyway. */
  .heroShell{max-width:min(1560px, calc(100vw - 64px))}
  /* A wider book is a TALLER book while aspect-ratio drives height, and at
     1660 that produced an 840x572 slab that dwarfed the panel and broke the
     fold by 33px. Flattening as it widens keeps the height flat — and a wide
     shallow spread is closer to how a book actually sits when opened. */
  .diary{aspect-ratio:640/330}
  /* The hand scales with the leaf, or a bigger book just means more blank
     paper: fill had collapsed to 45%. */
  .entry{--rule:42px}
  .entry .hand{font-size:30px}
  .entry .date{font-size:24px}
}

/* NOTE: .heroTop is display:block, so the grid properties here are inert —
   the headline and quote are stacked at every width already. The only live
   declaration was `max-width:56ch`, which WIDENS the quote. That widening is
   safe only once the card has stacked BELOW the quote, and the card stacks at
   880, not here — so between 880 and 1000 it was pushing the quote straight
   under the raised panel. Moved to the 880 block where it belongs. */
@media (max-width:1000px){
  .quote{margin-top:26px; padding-bottom:0}
}
@media (max-width:880px){
  .split{grid-template-columns:1fr; gap:18px}
  /* The quote can finally use the full column — this is the breakpoint where
     the card stacks BELOW it, so there is no raised panel to stay clear of.
     Moved here from the 1000 block, where it was widening the quote while the
     card was still beside it. */
  .quote{max-width:56ch}
  /* Scoped to match the hero placement rule above: once that became
     `.split .read` (0,2,0) an unscoped reset here (0,1,0) would no longer win
     and the hero would stay laid out for 12 columns on a phone. */
  /* transform:none is load-bearing, not tidiness. Stacked single-column, a
     rotated card has no empty gutter to swing its corners into — it pushed
     the document 50px wider than the viewport and produced a horizontal
     scrollbar on a phone. The book's own reset is further down; this is the
     card's. */
  .split .diary,.split .read{grid-area:auto; margin:0; align-self:auto; transform:none}
  /* 4 stat columns leaves ~60px per cell, narrower than the values it holds */
  .statGrid{grid-template-columns:repeat(2,1fr)}
  /* The glow's rotate(5deg) exists only to cancel .diary's rotate(-5deg).
     With the book unrotated here, leaving it would tilt the light by +5deg —
     the horizon problem, arriving by accident. Both reset together. */
  .diary{transform:none; aspect-ratio:640/430}
  .diary::before{transform:none}
  .steps{grid-template-columns:1fr; gap:28px}
  .two{grid-template-columns:1fr; gap:34px}
  .shots{grid-template-columns:1fr}
  /* One column: the dashboard stops spanning and every frame takes the same
     shape, so the three read as one stack. The aspect stays wide rather than
     matching the desktop dashboard's 1.92 — a 335px-wide frame at 1.92 is
     174px tall, which is less legible again, and at this width the captures
     are atmosphere whatever we do. */
  .shotWrap--dash{grid-column:auto}
  .shotWrap--dash .shot{aspect-ratio:16/10}
  .nav .lnk{display:none}          /* jumps are expendable on mobile */
  .login{display:inline; font-size:14px}   /* the way back in is not */
  .nav{gap:12px}
  .btn{padding:10px 14px; font-size:14px}
  /* Adding Log in pushed the bar to 348px of content in 335px. The wordmark
     is the largest item and the least load-bearing at this size — the mark
     alone still identifies the page. */
  .wordmark{font-size:16px}
  .mark svg{width:23px; height:23px}

  /* The quote rendered 159px tall against a 123px headline — larger than the
     thing it supports, which inverts the hierarchy. */
  .quote{font-size:var(--t0); max-width:none}

  /* Log in measured 39px; the CTA beside it is 44. */
  .login{display:inline-flex; align-items:center; min-height:44px}

  /* Caveat is a script face and 15px is below where it stays comfortably
     legible. The panel no longer laps the leaf at this width, so the writing
     column can take the space back and carry a larger hand. */
  /* left MUST clear the spine (140/640 = 22%) and the margin rule
     (180/640 = 28%) or the writing runs across the gutter onto the facing
     page. 30% starts it just inside the margin, where a pen would. */
  .entry{left:30%; right:7%}
  .entry .hand{font-size:17px}
  .entry .date{font-size:15px}
  /* No fold to respect at this width, so the book can be taller — which is
     what buys the narrower column enough lines. */
  .diary{aspect-ratio:640/470}

  /* 13px labels are the app's dense-dashboard floor; this is a marketing
     surface being read at arm's length. */
  .sk,.dirLabel,.vsrc{font-size:14px}
  .slab b{min-width:0; display:block}
  .slab div{flex-direction:column; gap:5px}
}

/* ═══ PROSE — legal and reference pages ═══════════════════════════════════
   Deliberately plainer than the marketing surface. Restraint wins here: these
   pages are read for accuracy, not persuasion, and a payment processor or a
   regulator is a plausible reader. No gold accents, no display type below the
   h1, generous measure. */
.prose{max-width:70ch; padding:clamp(40px,6vw,72px) 0 clamp(56px,8vw,96px)}
.prose h1{font-size:clamp(30px,4vw,43px); font-weight:700; margin-bottom:26px}
.prose h2{font-size:var(--t2); font-weight:600; max-width:none; margin:38px 0 12px}
.prose h3{font-family:var(--display); font-size:var(--t1); font-weight:600; margin:26px 0 8px}
.prose p{margin-bottom:16px; color:var(--tx2); line-height:1.7}
.prose li{margin-bottom:9px; color:var(--tx2); line-height:1.7}
.prose ul{margin:0 0 16px 20px}
.prose b{color:var(--tx)}
.prose a{color:var(--gold)}
.prose code{font-family:var(--mono,ui-monospace,monospace); font-size:.92em; color:var(--tx)}

/* ── Processor table — /privacy §3, the only table on the site ─────────────
   `.prose` caps at 70ch for reading measure, which a four-column table
   cannot live inside on a phone. So the table gets its OWN scroll container
   (.tw) rather than letting the page scroll sideways — a horizontally
   scrolling body is the one layout failure that breaks every other page too.
   Above 900px it breaks the measure cap by 60px each side, because a table
   is scanned, not read, and the cap exists for prose.
   `min-width` is what forces the scroll rather than letting cells crush. */
.prose .tw{overflow-x:auto; margin:0 0 20px; -webkit-overflow-scrolling:touch}
@media (min-width:900px){ .prose .tw{width:calc(100% + 120px); margin-left:-60px} }
.prose table{border-collapse:collapse; width:100%; min-width:640px; font-size:15px}
.prose th,.prose td{text-align:left; vertical-align:top; padding:10px 14px;
  border-bottom:1px solid var(--line)}
.prose th{color:var(--tx); font-family:var(--display); font-weight:600; font-size:14px;
  letter-spacing:.02em; border-bottom-color:var(--tx2)}
.prose td{color:var(--tx2); line-height:1.6}
.prose td b{color:var(--tx)}
/* The "what is NOT sent" claim in the Anthropic row. Promoted to its own
   line and to primary text colour — it is the strongest sentence in the
   document and reads as a footnote if left inline. */
.prose td em{display:block; margin-top:6px; font-style:normal; color:var(--tx); font-size:14px}
.prose .stub{
  border-left:2px solid var(--line); padding:14px 0 14px 18px;
  color:var(--tx2); background:none;
}
