/* ══════════════════════════════════════════════════════════════════════════
   oai-c.css  .  PER-VIEW REPAIR AFTER THE openai-scale.css TYPE JUMP.
   Owns: the Payoffs view, the Vaults view, and the phone breakpoint sitewide.
   Loads after openai-scale.css, oai-a.css and oai-b.css. Edits no existing
   stylesheet: instrument.css, vaults.css, payoff.css, gap.css and nav.css are
   all untouched and every rule here is an override from this file.

   WHY THIS FILE EXISTS. openai-scale.css re-pointed the shared tokens
   (--t-lg 20 -> 26, --t-sm 12 -> 14, --t-md 13 -> 15, radii 2/4/4/4 ->
   4/8/10/8, body line-height 1.55). Every rule below is a place that jump
   broke, each one with the number that was measured on the live mirror at
   390x844 and 1440x900, deviceScaleFactor 2, before the fix.

   TWO THINGS THIS FILE REFUSES TO TOUCH.
   1. gap.css's absence vocabulary. .vl-empty, every dashed rule and every
      epistemic label ("Harvest has never written", "3 of 11", "premium is a
      lower bound", "no fill feed, our gap", "not read, our gap, not their
      silence", "Not shown, not dropped", "CALLS WRITTEN") is left exactly as
      gap.css draws it. vaults.css loads before gap.css on purpose; this sheet
      loads after both and therefore must not select into that vocabulary.
   2. The reserved chrome heights. A previous pass took phone CLS from 0.1275
      to 0.0020 by reserving height on nav.rail and on body > footer
      (nav.css carries `@media (max-width: 480px) { body footer {
      min-height: 116px } }`). Nothing here changes the BOX of either node.
      Where a tap target inside them is too small, it is grown with an
      absolutely positioned ::after hit area, which costs zero layout.
   ══════════════════════════════════════════════════════════════════════════ */


/* ──────────────────────────────────────────────────────────────────────────
   1. PAYOFFS  .  THE SEGMENTED CONTROL ATE THE CHART.
   ──────────────────────────────────────────────────────────────────────────
   MEASURED BEFORE. .pf-pick-b renders at font-size 20px on phone and 26px at
   1440, because payoff.css sizes it from --t-lg, which the scale pass moved
   20 -> 26. Its letter-spacing is em-derived, so it scaled too: 1.4px on
   phone, 2.34px at 1440. The buttons came out 150x58 at 390 and 569x74 at
   1440. The whole .pf-pick block took 112px of an 844px phone viewport and
   138px at 1440, while .pf-svg, which is the actual measurement and the whole
   point of the view, got only 240px at 390.

   A four-state Long/Short/Call/Put toggle is a control, not a headline. It
   does not belong on the --t-lg step. It is brought back to 17px on phone and
   18px at desktop, and the tracking is flattened to a fixed 0.07em so it
   stops scaling with the token. Vertical padding is trimmed to land the
   button at 46px on phone and 48px at desktop: both still clear the 40px tap
   minimum, and phone recovers 12px per row, 24px across the two rows, which
   goes straight back to the chart.

   Scoped to .view[data-view="payoffs"] so it cannot reach any other view and
   cannot collide with the sheets that own the rest of the site. */

:root:root body .view[data-view="payoffs"] .pf-pick-b {
  font-size: 18px !important;      /* was 26px at 1440, from --t-lg */
  letter-spacing: 0.07em;          /* was 2.34px, an em value riding --t-lg */
  line-height: 1.2;
  padding-top: 14px;
  padding-bottom: 14px;            /* was 23px: 74px tall -> 48px, still > 40 */
}

/* The two rows sit in a flex column with a 10px gap. At 138px the block read
   as a hero band; the trim above plus a 8px gap brings it to 106px at 1440
   and the chart keeps the difference. */
:root:root body .view[data-view="payoffs"] .pf-pick { gap: 8px; }

/* The eyebrow is 11px mono at 1.1px tracking, which after the jump sits very
   close to the 18px control directly under it. A little air separates the
   label from the control without moving either. */
:root:root body .view[data-view="payoffs"] .tl-sec-h { margin-bottom: 14px; }


/* ──────────────────────────────────────────────────────────────────────────
   2. VAULTS  .  THE FRAME LOST ITS CORNERS WHEN THE RADII MOVED.
   ──────────────────────────────────────────────────────────────────────────
   MEASURED BEFORE. .vl-app is the iframe of the vault app, rendered at
   300x1520 on phone and 1138x1520 at 1440. The scale pass moved --r-card from
   4px to 10px, so the card around it now has 10px corners while the frame
   itself still has none: at deviceScaleFactor 2 the square black frame cuts
   visibly across each rounded corner of its own container, and on any load
   where the framed app has not painted yet the result reads as a rendering
   failure rather than a reserved surface.

   Radius and a hairline in the brand line colour, nothing else. Both go
   through --line and --bg rather than through the literals #302a23 and
   #0c0a08, with the brand values as the fallback, because this site carries
   a light theme and a token resolves per theme while a literal does not. A
   hardcoded dark frame would have been a visible bug the moment the theme
   flipped, which it did during this session. The height is
   left at 1520px exactly as vaults.js sets it, because the frame holds the
   vault app and shortening it would clip content, which is a change of layout
   meaning. min-height simply restates the height vaults.js already applies so
   the frame reserves its box before the child document paints, which is the
   same CLS discipline the nav and footer already follow. */

/* !important is not decoration here. The first pass of this rule wrote plain
   declarations and the frame still computed border-radius: 0px on the live
   mirror, while the .vl-head rule in the same scope took effect, which proves
   the scope is right and something further down is pinning the frame's
   corners. Rather than edit that sheet, which this file may not do, the
   radius and the hairline are pinned from here. */
:root:root body .view[data-view="vaults"] .vl-app {
  border-radius: var(--r-card, 10px) !important;
  border: 1px solid var(--line, #302a23) !important;  /* brand line */
  background: var(--bg, #0c0a08);                     /* brand bg, so an unpainted frame is not a hole */
  overflow: hidden;                       /* clip the child document to the new corners */
}

/* .vl-head measured 33px at 1440 and 63px on phone, where it wraps to two
   lines. Body line-height went to 1.55, which on a wrapped two-line heading
   opens a gap wider than the type. Headings already run 1.25 in
   openai-scale.css; this restates it on the wrap so the two lines read as one
   heading. Type only, no reflow: the node keeps its measured width. */
:root:root body .view[data-view="vaults"] .vl-head { line-height: 1.3; }

/* "Built on Rysk V12" is a provenance label, not a control, so it is not
   grown to 40px. It measured 138x30 on phone and 142x32 at 1440; the pill
   radius moved 4 -> 8 under the scale pass while its padding stayed, which
   left the text sitting tight against the new curve. 1px of horizontal
   padding restores the optical inset. */
:root:root body .view[data-view="vaults"] .vl-chip { padding-left: 12px; padding-right: 12px; }

/* .vl-empty, .vl-src, .vl-slot and every dashed rule are NOT selected here.
   gap.css owns the absence vocabulary and this sheet loads after it. */


/* ──────────────────────────────────────────────────────────────────────────
   3. PHONE, ALL VIEWS  .  THE HEADER GREW 23px ON AN 844px SCREEN.
   ──────────────────────────────────────────────────────────────────────────
   MEASURED BEFORE. header.top is 61px at 1440 and 84px at 390. It is the same
   markup at both widths, so the 23px is entirely the type jump: h1 "Moneyness"
   sits on --t-lg, which went 20 -> 26, and the tagline under it sits on the
   body line-height, which went to 1.55. Add the 37px rail under it and a
   phone spends 121px of 844, a seventh of the screen, on chrome before any
   measurement appears.

   The wordmark itself is yielded to a concurrently owned sheet (see below).
   What this file keeps on phone is the tap targets and the two views,
   and every rule in this block is inside max-width: 480px so it can never
   reach the desktop width the other two sheets are working at. */

@media (max-width: 480px) {

  /* THE WORDMARK IS DELIBERATELY NOT TAKEN HERE. It was the obvious repair:
     header.top measured 84px on an 844px phone against 61px at 1440, all of
     it type jump, and a cap on the h1 recovers about 18px. But on the live
     mirror the h1 now computes to 21px with -0.42px tracking, which is
     neither the token value nor any value in this file: a sheet owned by
     another agent is already capping it with a stronger declaration. Two
     sheets fighting over one heading is a worse outcome than a 1px
     difference, so this file yields the wordmark and the tagline and keeps
     everything below. */


  /* ── TAP TARGETS ────────────────────────────────────────────────────────
     MEASURED BEFORE at 390: 14 interactive nodes under 40px tall. The three
     that matter are the footer's own links, "How this is measured" and "How
     can this be better?" at 22px, and "Stormbit Labs" at 19px.

     They are grown with an absolutely positioned ::after rather than with
     padding, because body > footer carries `min-height: 116px` from nav.css
     as the CLS reservation that took phone CLS from 0.1275 to 0.0020. Padding
     would change the footer box and put that reservation back in play. A
     transparent ::after changes the hit area and nothing else, so the
     measured 116px footer and the measured 37px rail both stay exactly where
     they are. */

  :root:root body > footer .tr-link,
  :root:root body > footer .linkish,
  :root:root body > footer a { position: relative; }

  :root:root body > footer .tr-link::after,
  :root:root body > footer .linkish::after,
  :root:root body > footer a::after {
    content: "";
    position: absolute;
    left: 0; right: 0;
    top: 50%;
    height: 44px;                  /* was 19px to 22px of real hit area */
    transform: translateY(-50%);
    pointer-events: auto;
  }

  /* Same technique on the rail. nav.rail measures 37px on phone and that
     height is reserved, so the items cannot grow. The hit area can. */
  :root:root body nav.rail .rl-item { position: relative; }
  :root:root body nav.rail .rl-item::after {
    content: "";
    position: absolute;
    left: 0; right: 0;
    top: 50%;
    height: 44px;                  /* rail stays 37px; the finger gets 44 */
    transform: translateY(-50%);
  }


  /* ── PAYOFFS ON PHONE ───────────────────────────────────────────────────
     The control measured 150x58 per button at 20px type with 1.4px tracking,
     and "Short" at that size very nearly fills its 150px box. 17px with
     flattened tracking leaves the word clear of both edges and brings the
     button to 46px, above the 40px tap minimum, while the two rows give the
     240px chart 24px back. */

  :root:root body .view[data-view="payoffs"] .pf-pick-b {
    font-size: 17px !important;    /* was 20px */
    letter-spacing: 0.07em;        /* was 1.4px, em-derived from --t-lg */
    padding-top: 13px;
    padding-bottom: 13px;          /* was 18px: 58px tall -> 46px */
  }

  /* .pf-terms wraps to two rows on phone and measured 46px against 23px at
     1440. The wrap is correct and is left alone; only the row gap is tuned so
     the wrapped "strike" and "premium" pairs group with their own numbers
     instead of floating between rows at the new 1.55 leading. */
  :root:root body .view[data-view="payoffs"] .pf-terms { row-gap: 4px; }

  /* .pf-in holds the strike and premium values in 15px monospace inside a
     72px box. "84.26" fits; a five-figure strike would not, and the number
     must never clip. tabular-num plus a floor on the box keeps every digit
     rendered at the same advance and lets the box grow instead of the digits
     being cut. No value is changed, only the room it is given. */
  :root:root body .view[data-view="payoffs"] .pf-in {
    font-variant-numeric: tabular-nums;
    min-width: 72px;
    width: auto;
  }


  /* ── VAULTS ON PHONE ────────────────────────────────────────────────────
     .vl-head measured 63px at 390 against 33px at 1440: it wraps to two lines
     and the 1.55 leading made the wrap read as two separate labels. Handled
     by the unscoped rule above. .vl-tape measured 82px against 61px, which is
     the same wrap and is correct.

     The frame is 300x1520 on phone. It is NOT shortened: it holds the vault
     app and clipping it would change what the section shows. What phone gets
     is the horizontal inset back, because the 10px card radius now curves
     inside the frame's square edge at this width. */
  :root:root body .view[data-view="vaults"] .vl-app {
    border-radius: var(--r-card, 10px) !important;
  }
}


/* ──────────────────────────────────────────────────────────────────────────
   4. TABLET AND BELOW  .  899px, THE OTHER BREAKPOINT nav.css ALREADY USES.
   ──────────────────────────────────────────────────────────────────────────
   nav.css reserves `min-height: 55px` on nav.rail below 899px. Nothing here
   changes that box. The one thing the type jump hurt between 481 and 899 is
   the same Payoffs control: at those widths it is still on the 26px desktop
   step in a column barely wider than a phone. It gets the phone treatment for
   the type and keeps the desktop padding. */

@media (min-width: 481px) and (max-width: 899px) {
  :root:root body .view[data-view="payoffs"] .pf-pick-b {
    font-size: 17px !important;    /* was 26px from --t-lg */
    letter-spacing: 0.07em;
  }
}
