/* Altrady Charts: self-contained stylesheet for the charts host.
 *
 * Deliberately NOT Tailwind. The marketing site's tailwind.css is 24 KB gzipped
 * and carries utilities this page never uses; this file is ~1/3 of that and lets
 * the page be art-directed rather than assembled from utilities. It also means
 * the charts host shares no CSS with the marketing site, which matches the
 * isolation the layout already enforces for cookies and tracking.
 *
 * Fonts are the ones already committed for the marketing site, so no new binaries.
 * @font-face lives here because it is declared in landing_pages.css, which the
 * charts layout does not load.
 */

@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 100 800;
  font-display: swap;
  src: url("/assets/jetbrains-mono-latin-68dbce1c.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+2074, U+20AC, U+2122, U+2191,
    U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 100 800;
  font-display: swap;
  src: url("/assets/jetbrains-mono-latin-ext-b0c48b7a.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: "Roboto";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("/assets/roboto-latin-e71a8ea2.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+2074, U+20AC, U+2122, U+2191,
    U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Roboto";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("/assets/roboto-latin-ext-ebbeca11.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: "Plus Jakarta Sans";
  font-style: normal;
  font-weight: 200 800;
  font-display: swap;
  src: url("/assets/plus-jakarta-sans-latin-d2ff26bc.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+2074, U+20AC, U+2122, U+2191,
    U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Plus Jakarta Sans";
  font-style: normal;
  font-weight: 200 800;
  font-display: swap;
  src: url("/assets/plus-jakarta-sans-latin-ext-ff4456f1.woff2") format("woff2");
  unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF,
    U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

:root {
  /* Mapped onto the Brand Style Guide tokens in brand_tokens.css. The short
     names stay because the whole sheet is written against them; the values now
     come from one place. Raised surfaces step up to brand navy, so the page has
     two visible surface levels instead of one flat ground. */
  --bg: var(--brand-black);
  --bg-raise: #141b2b;
  --panel: var(--brand-navy);
  --border: var(--brand-card-border);
  --border-soft: rgba(30, 74, 170, 0.28);
  --t1: var(--brand-white);
  --t2: var(--brand-light);
  --t3: var(--brand-gray-500);
  --t-secondary: var(--brand-gray-300);
  /* Primary: fills, borders, large accents. */
  --blue: var(--brand-blue);
  --blue-deep: var(--brand-blue-deep);
  /* Small text, links, eyebrows and badges. Brand blue fails AA at small sizes
     on the dark ground. */
  --blue-lift: var(--brand-blue-text);
  /* Every call to action, via .btn--primary. Kept on the action blue the live
     site already ships rather than moved onto the primary, so the buttons stay
     the colour people know. */
  --brand: var(--brand-blue-action);
  --mono: var(--brand-font-code);
  /* Headings in Plus Jakarta Sans, body copy in Roboto, per the brand guide.
     Both self-hosted, so neither costs a third-party connection. */
  --sans: var(--brand-font-heading);
  --body: var(--brand-font-body);
  --gutter: 24px;
  --maxw: 1240px;
  color-scheme: dark;
}

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--bg);
  color: var(--t2);
  font: 400 17px/1.6 var(--body);
  -webkit-font-smoothing: antialiased;
}
img, video { display: block; max-width: 100%; height: auto; }
a { color: inherit; }

.wrap { width: 100%; max-width: var(--maxw); margin-inline: auto; padding-inline: var(--gutter); }
.wrap-wide { width: 100%; max-width: 1600px; margin-inline: auto; padding-inline: var(--gutter); }

/* ---------- type ---------- */
.eyebrow {
  font: 600 12px/1 var(--mono);
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--blue-lift);
  margin: 0 0 20px;
}
/* Explicit, because these inherited the body font before it became Roboto. */
h1, h2, h3, h4, h5, h6 { font-family: var(--sans); }
h1, h2, h3 { color: var(--t1); margin: 0; text-wrap: balance; letter-spacing: -.03em; font-weight: 700; }
h1 { font-size: clamp(52px, 9.2vw, 120px); line-height: .98; letter-spacing: -.04em; }
/* Three presentation tiers. The point is that a major moment should not be able
   to look like a compact one by accident, so the scale lives on the tier rather
   than being chosen per section. */
h2 { font-size: clamp(30px, 4vw, 52px); line-height: 1.06; }
.section--major h2 { font-size: clamp(40px, 6.2vw, 86px); line-height: 1.0; letter-spacing: -.035em; }
.section--compact h2 { font-size: clamp(26px, 3vw, 38px); line-height: 1.12; }
h3 { font-size: clamp(21px, 2.2vw, 28px); line-height: 1.2; letter-spacing: -.02em; }
.section--compact h3 { font-size: clamp(19px, 1.8vw, 23px); }
.lede { font-size: clamp(17px, 1.5vw, 20px); line-height: 1.6; color: var(--t2); max-width: 58ch; margin: 24px 0 0; }
.section--major .lede { font-size: clamp(18px, 1.8vw, 23px); max-width: 54ch; margin-top: 28px; }
.section--compact .lede { font-size: 16px; max-width: 50ch; margin-top: 16px; }

/* "Build on it." and "Build it." are the only places colour carries meaning. */
.accent {
  background: linear-gradient(104deg, #7ab8ff 0%, var(--blue-lift) 38%, var(--blue) 100%);
  -webkit-background-clip: text; background-clip: text;
  color: transparent; -webkit-text-fill-color: transparent;
}
.sub { font-size: 16px; color: var(--t3); max-width: 54ch; margin: 16px 0 0; }
.dim { color: var(--t3); }

/* ---------- sections ---------- */
/* Rhythm: peaks and quiet moments rather than an even drumbeat. */
.section { padding-block: clamp(96px, 13vh, 170px); position: relative; overflow-x: clip; }   /* editorial */
.section--major { padding-block: clamp(136px, 19vh, 250px); }
/* Three transitions measured too loose at desktop: the space after a major
   moment's media read as a break in the page rather than a breath. Trimmed
   ~13% on the trailing edge only. The leading edge and every other section
   keep their rhythm. */
.section--snug-end { padding-bottom: clamp(104px, 14.8vh, 194px); }
.section--compact { padding-block: clamp(60px, 7.5vh, 96px); }
.section--tight { padding-block: clamp(72px, 9vh, 120px); }

/* Chapter atmosphere: a near-black-blue lift behind major moments only. Kept
   under 8% alpha so it reads as depth, not as a gradient panel. */
/* overflow-x: clip, not hidden: clip creates no scroll container and does not
   trap position: sticky, and it leaves overflow-y visible so the media shadows
   still bleed vertically. The glow below is deliberately wider than the
   viewport, and without this it added 30px of page scroll at 1440 and 79px at
   390, which made every section read as if it were cut off on the right. */
.atmos { position: relative; isolation: isolate; overflow-x: clip; }
.atmos::before {
  content: ""; position: absolute; left: 50%; translate: -50% 0; top: -4%;
  width: min(1500px, 120vw); height: 70%;
  background: radial-gradient(52% 58% at 50% 20%, rgba(1,122,255,.075), transparent 72%);
  z-index: -1; pointer-events: none;
}
/* Re-based on the brand near-black so deep sections no longer fall to #000. */
.atmos--deep { background: linear-gradient(180deg, #0f1112 0%, #0d1218 42%, #0c1016 60%, #0f1112 100%); }

/* Brand corner glow. The guide puts the blue bloom in a corner rather than
   centred overhead, so the page opens on one corner and closes on the mirrored
   one. Its own layer behind content, never interactive. */
.glow-corner { position: relative; isolation: isolate; overflow-x: clip; }
.glow-corner::after {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background:
    radial-gradient(58% 52% at 2% 0%, rgba(1, 122, 255, .17), transparent 70%),
    radial-gradient(46% 42% at 100% 10%, rgba(1, 122, 255, .07), transparent 72%);
}
.glow-corner--end::after {
  background:
    radial-gradient(60% 56% at 100% 100%, rgba(1, 122, 255, .18), transparent 70%),
    radial-gradient(44% 40% at 0% 88%, rgba(1, 122, 255, .07), transparent 74%);
}
@media (max-width: 760px) {
  /* Tighter on a phone: a glow sized for a 1440px corner washes out a 390px one. */
  .glow-corner::after {
    background: radial-gradient(80% 42% at 8% 0%, rgba(1, 122, 255, .16), transparent 72%);
  }
  .glow-corner--end::after {
    background: radial-gradient(84% 44% at 92% 100%, rgba(1, 122, 255, .17), transparent 72%);
  }
}
.rule { height: 1px; background: linear-gradient(90deg, transparent, var(--border-soft) 18%, var(--border-soft) 82%, transparent); border: 0; margin: 0; }

/* Number tiles. Used for the built-in indicator count, where a figure in prose
   is easy to skim past. Tabular figures so the numbers line up. */
.tiles { display: grid; gap: 12px; grid-template-columns: repeat(3, minmax(0, 1fr));
  margin-top: 26px; }
.split__cta { margin: 24px 0 0; }
.tile { background: var(--panel); border: 1px solid var(--border); border-radius: 14px;
  padding: 18px 20px; }
.tile__n { font: 700 clamp(30px, 3.4vw, 42px)/1 var(--sans); color: var(--t1);
  letter-spacing: -.03em; font-variant-numeric: tabular-nums; display: block; }
.tile__l { font-size: 13px; line-height: 1.45; color: var(--t3); margin: 9px 0 0;
  display: block; }
@media (max-width: 760px) {
  .tiles { grid-template-columns: 1fr 1fr; gap: 10px; }
  .tile { padding: 15px 16px; }
  .tile:last-child { grid-column: 1 / -1; }
}

/* Logo clear space, per the guide: nothing may sit closer to the mark than the
   height of its own symbol. Applied as padding on the link so the lockup keeps
   its margin whatever sits beside it in the header. */
.wordmark { padding: 4px 8px 4px 0; }
.wordmark__logo { margin-right: 2px; }

/* "Coming soon" badge: pill on the brand blue at low opacity with a live dot,
   so it reads as a status rather than another label. */
.badge--soon { background: rgba(1, 122, 255, .12); border-color: rgba(1, 122, 255, .42);
  color: var(--blue-lift); padding: 5px 12px 5px 10px; border-radius: 999px; }
.badge--soon::before { content: ""; width: 6px; height: 6px; border-radius: 50%;
  background: var(--blue); box-shadow: 0 0 0 3px rgba(1, 122, 255, .22); flex: 0 0 auto; }

/* ---------- buttons ---------- */
.btn {
  display: inline-flex; align-items: center; gap: 8px;
  font: 600 15px/1 var(--sans); padding: 15px 24px; border-radius: 10px;
  text-decoration: none; border: 1px solid transparent; transition: filter .15s ease, border-color .15s ease;
}
.btn--primary { background: var(--brand); color: #fff; }
.btn--primary:hover { filter: brightness(1.14); }
.btn--ghost { border-color: var(--border); color: var(--t1); }
.btn--ghost:hover { border-color: #3a3a42; }
.cta-row { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 36px; }

/* ---------- media ---------- */
/* Framed screenshots: the product shot sits inside a frame on the brand's dark
   ground, with a hairline edge and a thin blue inner ring, rather than bleeding
   straight into the page. The frame is padding on .shot, so the media keeps its
   own smaller radius inside it. */
.shot { position: relative; border-radius: 16px; background: var(--bg-raise);
  border: 1px solid var(--border); padding: 8px;
  box-shadow: inset 0 0 0 1px rgba(1, 122, 255, .07),
              0 30px 90px -40px rgba(1, 122, 255, .35); }
.shot > img, .shot > video { width: 100%; aspect-ratio: 16 / 10; object-fit: cover;
  border-radius: 9px; display: block; background: #000; }

/* The scale ladder.
 *
 * Three bands, deliberately narrow in spread: a peak should read as a peak
 * without becoming edge-to-edge, and a supporting proof should still be big
 * enough to actually look at. Nothing sits near 300px and nothing near 1760px.
 *
 *   major       ~1280   hero, flywheel, scripts, backtest, trade
 *   editorial    ~700   footprint, indicators, signal-bot, migration, ai, marketplace
 *   support      ~620   trade menu, replay, layouts, speed, mobile
 */
.media-major { width: 100%; max-width: 1300px; margin-inline: auto; padding-inline: var(--gutter); }
.media-major--draw { max-width: 1180px; }
.media-major .shot { border-radius: 20px; padding: 10px;
  box-shadow: inset 0 0 0 1px rgba(1, 122, 255, .08),
              0 50px 140px -60px rgba(1,122,255,.45); }
.media-major .shot > img, .media-major .shot > video { border-radius: 11px; }
.media-wide { width: 100%; max-width: 1480px; margin-inline: auto; padding-inline: var(--gutter); }
.media-compact { width: 100%; max-width: 920px; margin-inline: auto; padding-inline: var(--gutter); }

/* Media columns are capped directly rather than left to grid fractions: with
   .split--media-first the media lands in the narrower track and silently shrank
   to ~480px, which is what made Signal Bot and Footprint too small to read. */
@media (min-width: 900px) {
  .editorial .split__media { max-width: 700px; }
  .proof .split__media { max-width: 620px; }
  .proof--sm .split__media { max-width: 560px; }
}

/* A restrained glow behind the biggest product moments, never a gradient wash. */
.glow { position: relative; }
.glow::before {
  content: ""; position: absolute; inset: auto 8% -12% 8%; height: 55%;
  background: radial-gradient(60% 100% at 50% 100%, rgba(1,122,255,.20), transparent 72%);
  filter: blur(42px); z-index: -1; pointer-events: none;
}

.badge {
  display: inline-flex; align-items: center; gap: 7px;
  font: 600 11px/1 var(--mono); letter-spacing: .14em; text-transform: uppercase;
  color: var(--blue-lift); border: 1px solid rgba(81,162,255,.32);
  background: rgba(1,122,255,.08); padding: 7px 12px; border-radius: 999px; margin-bottom: 20px;
}
.badge::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: var(--blue-lift); }

/* ---------- header ---------- */
.site-head {
  position: sticky; top: 0; z-index: 20; background: rgba(15, 17, 18, .78);
  backdrop-filter: blur(12px); border-bottom: 1px solid var(--border-soft);
}
.site-head__in { display: flex; align-items: center; gap: 28px; height: 64px; }
.wordmark { display: flex; align-items: center; gap: 9px; font: 700 15px/1 var(--sans); color: var(--t1); text-decoration: none; letter-spacing: -.01em; }
.wordmark span { color: var(--t3); font-weight: 500; }
/* Sized by height so the mark keeps its own aspect ratio and the 64px header
   bar is unchanged. 22px matches the optical weight of the 15px "Charts" beside
   it, which is why it is not the asset's native 24px. */
.wordmark__logo { height: 22px; width: auto; display: block; }
.site-nav { display: none; gap: 24px; margin-left: auto; font: 500 14px/1 var(--sans); }
/* Active section. The underline is the carrier, not colour alone. */
.site-nav a.is-active { color: var(--brand-white); position: relative; }
.site-nav a.is-active::after { content: ""; position: absolute; left: 0; right: 0;
  bottom: -22px; height: 2px; background: var(--brand-blue); border-radius: 2px; }
.site-nav a { color: var(--t3); text-decoration: none; }
.site-nav a:hover { color: var(--t1); }
.site-head .btn { padding: 10px 16px; font-size: 14px; margin-left: auto; }
@media (min-width: 900px) { .site-nav { display: flex; } .site-head .btn { margin-left: 0; } }

/* ---------- hero ---------- */
.hero { padding-block: clamp(96px, 16vh, 196px) 0; text-align: center; overflow-x: clip; }
.hero .lede { margin-inline: auto; }
.hero .cta-row { justify-content: center; }
.hero__spec {
  margin: 52px 0 0; font: 500 13px/1.9 var(--mono); color: var(--t3);
  letter-spacing: .02em;
}
/* The hero shot runs wider than any other still and is cropped from the top so
   it reads as a workspace continuing past the fold, not a framed screenshot. */
.hero__shot { margin-top: clamp(68px, 9vw, 120px); }
.hero__shot .shot { border-radius: 18px 18px 0 0; box-shadow: 0 -2px 0 rgba(81,162,255,.14), 0 80px 180px -60px rgba(1,122,255,.55); }
.hero__shot .shot > img { aspect-ratio: 16 / 8.6; object-position: center top; }

/* ---------- layout primitives ---------- */
.split { display: grid; gap: clamp(32px, 4vw, 64px); align-items: center; }
@media (min-width: 900px) {
  .split { grid-template-columns: 1fr 1fr; }
  /* Editorial sections deliberately avoid the 50/50 feature row. */
  .split--wide-media { grid-template-columns: 0.72fr 1.28fr; }
  .split--wider-media { grid-template-columns: 0.56fr 1.44fr; }
  .split--text-led { grid-template-columns: 1.1fr 0.9fr; }
  .split--offset { align-items: start; }
  .split--offset .split__text { padding-top: clamp(20px, 5vw, 76px); }
  .split--media-first > .split__media { order: -1; }
}
.split__text { min-width: 0; }
.split__media { min-width: 0; }

.stack-lead { max-width: 760px; }
.stack-lead--center { margin-inline: auto; text-align: center; }
.stack-lead--center .lede { margin-inline: auto; }

.duo { display: grid; gap: clamp(28px, 3.5vw, 48px); }
@media (min-width: 900px) { .duo { grid-template-columns: 1fr 1fr; align-items: start; } }

.trio { display: grid; gap: 20px; margin-top: 44px; }
@media (min-width: 760px) { .trio { grid-template-columns: 1fr 1fr; } }

.mini h3 { font-size: 19px; margin-bottom: 8px; }
.mini p { font-size: 15px; color: var(--t3); margin: 0; max-width: 46ch; }
.mini .shot { margin-bottom: 18px; border-radius: 10px; box-shadow: none; }

/* Compact proof: a quiet row, visually subordinate on purpose. */
.proof { display: grid; gap: clamp(28px, 3vw, 48px); align-items: center; }
@media (min-width: 900px) { .proof { grid-template-columns: 1fr 1fr; } }

/* Editorial: promoted supporting capabilities that deserve a section of their
   own rather than a row at the bottom of someone else's. */
.editorial { display: grid; gap: clamp(32px, 4vw, 64px); align-items: center; }
@media (min-width: 900px) {
  /* Asymmetric on purpose: an even split left the media at ~565px, under the
     600-700 an editorial moment needs to be readable. The wide track follows
     the media, whichever side it sits on. */
  .editorial { grid-template-columns: 0.8fr 1.2fr; }
  .editorial--media-first { grid-template-columns: 1.2fr 0.8fr; }
  .editorial--media-first > .split__media { order: -1; }
}
.editorial h3 { font-size: clamp(24px, 2.6vw, 34px); }
.editorial .sub { font-size: 16.5px; }
.proof .shot { box-shadow: 0 20px 60px -40px rgba(1,122,255,.3); }
.proof h2 + .lede { margin-top: 14px; }

/* ---------- final cta ---------- */
.finale {
  text-align: center; min-height: 100svh;
  display: grid; align-content: center;
  padding-block: clamp(96px, 14vh, 180px);
  overflow-x: clip;
}
.finale__lines { display: grid; gap: 0; }
.finale__lines span {
  display: block; font-weight: 700;
  font-size: clamp(54px, 13vw, 184px); line-height: .94; letter-spacing: -.05em; color: var(--t1);
}
.finale .lede { margin-inline: auto; margin-top: clamp(32px, 4vw, 56px); font-size: clamp(17px, 1.6vw, 21px); }
.finale .cta-row { margin-top: 40px; }

/* ---------- waitlist ---------- */
.waitlist { max-width: 560px; margin: clamp(32px, 4vw, 48px) auto 0; text-align: left; }
.waitlist__label { display: block; font: 600 13px/1 var(--mono); letter-spacing: .1em; text-transform: uppercase; color: var(--t3); margin-bottom: 10px; }
.waitlist__row { display: flex; flex-wrap: wrap; gap: 10px; }
.waitlist__input {
  flex: 1 1 260px; min-width: 0; background: var(--panel); color: var(--t1);
  border: 1px solid var(--border); border-radius: 10px; padding: 15px 16px;
  font: 400 16px/1.2 var(--sans);
}
.waitlist__input::placeholder { color: #6b6b74; }
.waitlist__input:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; border-color: var(--blue); }
.waitlist__error { color: #ff6b6b; font-size: 14px; margin: 12px 0 0; }
.waitlist__success { color: var(--t1); font-size: 17px; margin: 0; }
/* Offscreen, not display:none: bots skip hidden inputs but fill rendered ones. */
.waitlist__trap { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* ---------- footer ---------- */
.site-foot { border-top: 1px solid var(--border-soft); padding-block: 40px 48px; }
.site-foot__in { display: flex; flex-wrap: wrap; gap: 24px; align-items: flex-start; justify-content: space-between; font-size: 14px; color: var(--t3); }
.site-foot__name { color: var(--t1); font-weight: 700; margin: 0; letter-spacing: -.01em; }
.site-foot__tag { margin: 6px 0 0; color: var(--t3); }
/* Deliberately quieter than the tagline above it: an attribution line, not a
   second piece of positioning copy. */
.site-foot__by { margin: 14px 0 0; color: #6f6f78; font-size: 13px; }
.site-foot__by a { color: var(--t3); }
.site-foot__by a:hover { color: var(--t1); }
.site-foot__links { display: flex; flex-wrap: wrap; gap: 8px 24px; }
.site-foot a { color: var(--t3); text-decoration: none; }
.site-foot a:hover { color: var(--t1); }
@media (max-width: 760px) { .site-foot__in { flex-direction: column; gap: 20px; } }

/* ---------- mobile intent ----------
 * Phones get their own composition, not the desktop one squeezed into 390px.
 *
 * Three things are deliberate here:
 *
 * 1. Type is re-scaled rather than left to the desktop clamp()s. Those bottom
 *    out at sizes chosen for a 1440px canvas (h1 at 52px, a major h2 at 40px),
 *    which on a phone spend four or five lines on one heading and push the
 *    media below two screens of scrolling. The sizes below stay editorial, just
 *    sized for the canvas they are actually on.
 *
 * 2. Product shots are 16:10 desktop captures. Showing a whole desktop UI at
 *    phone width makes it an unreadable thumbnail, so each crops to its
 *    meaningful region through data-focus rather than scaling down uniformly.
 *
 * 3. Vertical rhythm is re-cut per transition, not scaled globally, because the
 *    desktop gaps were tuned against desktop type sizes.
 */
@media (max-width: 760px) {
  :root { --gutter: 20px; }
  body { font-size: 16px; }

  /* --- type --------------------------------------------------------------- */
  /* Tracking eases back as size drops: -.04em is a display setting and becomes
     crowding once the heading is only ~44px. */
  h1 { font-size: clamp(36px, 11.4vw, 50px); line-height: 1.04; letter-spacing: -.028em; }
  h2 { font-size: clamp(25px, 7vw, 30px); line-height: 1.12; letter-spacing: -.022em; }
  .section--major h2 { font-size: clamp(29px, 8.4vw, 36px); line-height: 1.08; letter-spacing: -.026em; }
  .section--compact h2 { font-size: clamp(23px, 6.2vw, 27px); line-height: 1.16; }
  h3 { font-size: clamp(19px, 5.1vw, 22px); line-height: 1.26; letter-spacing: -.012em; }
  .editorial h3 { font-size: clamp(20px, 5.4vw, 23px); }

  /* ch caps are a desktop measure; at phone width the gutter is the constraint,
     so the caps are released and the gutters do the work. */
  .lede, .section--major .lede, .section--compact .lede, .sub, .mini p { max-width: none; }
  .lede { font-size: 16.5px; line-height: 1.58; margin-top: 18px; }
  .section--major .lede { font-size: 17px; margin-top: 20px; }
  .section--compact .lede { font-size: 16px; margin-top: 14px; }
  .sub { font-size: 15.5px; line-height: 1.6; margin-top: 14px; }
  .editorial .sub { font-size: 15.5px; }
  .eyebrow { margin-bottom: 14px; }

  .hero { text-align: left; }
  .hero .lede, .hero .cta-row { margin-inline: 0; justify-content: flex-start; }
  .stack-lead--center { text-align: left; }
  .stack-lead--center .lede { margin-inline: 0; }
  .cta-row .btn { flex: 1 1 auto; justify-content: center; }

  /* --- vertical rhythm, cut per transition -------------------------------- */
  .section { padding-block: 68px; }
  .section--major { padding-block: 80px; }
  .section--snug-end { padding-bottom: 60px; }
  .section--compact { padding-block: 52px; }
  /* The hero ends on media, so it needs no trailing air of its own. */
  .hero { padding-block: 60px 0; }
  .hero__shot { margin-top: 36px; }
  .hero__spec { margin-top: 30px; font-size: 12px; line-height: 1.8; }
  .cta-row { margin-top: 26px; }
  /* The per-section lead-ins are inline clamp()s tuned for desktop; on a phone
     one consistent step is enough, so they are overridden wholesale. */
  .media-major, .media-wide, .media-compact { margin-top: 30px !important; }
  .editorial, .proof, .duo { gap: 24px; }
  .wrap.editorial, .wrap.proof, .wrap.duo { margin-top: 42px !important; }
  .duo h3 { margin-top: 20px !important; }

  /* --- product media ------------------------------------------------------ */
  .shot > img, .shot > video { aspect-ratio: 4 / 3.4; object-fit: cover; }
  .shot[data-focus="left"] > img, .shot[data-focus="left"] > video { object-position: 12% center; }
  .shot[data-focus="right"] > img, .shot[data-focus="right"] > video { object-position: 88% center; }
  .shot[data-focus="center"] > img, .shot[data-focus="center"] > video { object-position: center; }
  .shot[data-focus="top"] > img, .shot[data-focus="top"] > video { object-position: center 14%; }
  /* The hero is the establishing shot, so it keeps more of the frame. */
  .hero__shot .shot > video, .hero__shot .shot > img { aspect-ratio: 4 / 3.2; object-position: 30% top; }

  /* Two visuals need more than a crop anchor on a phone.

     mobile: three phones composed side by side. Any cover crop slices the outer
     two in half, which reads as an accident rather than a decision, so this one
     shows the whole composition instead.

     chart-types: a grid of twelve tiles. Cropping from the centre cut the first
     and last columns mid-chart; anchoring left keeps whole tiles and lets the
     crop fall on the right edge, where it reads as "there is more". */
  .shot[data-shot="mobile"] > video, .shot[data-shot="mobile"] > img {
    aspect-ratio: 16 / 10; object-fit: contain;
  }
  .shot[data-shot="chart-types"] > img { object-position: left 12%; }

  .media-stage, .media-wide, .media-compact { padding-inline: var(--gutter); }
  .atmos::before { width: 140vw; }
  .glow::before { display: none; }

  /* --- final cta ---------------------------------------------------------- */
  /* min-height: 100svh left a half-empty screen under the button, which read as
     the page having ended early. The finale is sized by its content here and
     closes straight into the footer. */
  .finale { min-height: 0; padding-block: 72px 52px; }
  .finale__lines span { font-size: clamp(42px, 13.2vw, 58px); line-height: 1.0; letter-spacing: -.035em; }
  .finale .lede { margin-top: 20px; font-size: 16.5px; }
  .waitlist { margin-top: 28px; max-width: none; }
  .waitlist__row { gap: 12px; }
  .waitlist__input { flex: 1 1 100%; padding: 14px 15px; }
  .waitlist__row .btn { width: 100%; justify-content: center; padding: 15px 22px; }

  /* --- footer ------------------------------------------------------------- */
  .site-foot { padding-block: 28px 34px; }
  .site-foot__in { gap: 18px; }
}

/* The narrowest phones still in common use. Only the two display sizes that
   crowd at 375px are touched; everything else already fits. */
@media (max-width: 380px) {
  :root { --gutter: 18px; }
  h1 { font-size: 35px; }
  .finale__lines span { font-size: 41px; }
}

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

/* --- library ---------------------------------------------------------------
   /library and its detail pages, on the Brand Style Guide tokens.

   Surfaces: the page sits on --brand-black and every card, control and panel
   steps up to brand navy, so there are two readable levels rather than one
   flat ground. Radii follow the guide: 12px controls, 16px cards, 999px pills.

   Zero em dashes, per the Charts copy rule. */
/* overflow-x: clip, not hidden: the hero glow below bleeds past the hero on
   purpose, and without a clip here that bleed widens the page and gives the
   whole site a horizontal scrollbar. clip does not create a scroll container,
   so the detail page's position: sticky sidebar still works through it, which
   is why hidden is wrong. */
.lib { background: var(--bg); color: var(--t1); overflow-x: clip; }
.lib__inner { max-width: 1200px; margin-inline: auto; padding-inline: var(--gutter);
  padding-block: calc(var(--brand-space) * 7) calc(var(--brand-space) * 12); }

.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

/* hero: the guide's glow, behind the page hero only */
.lib__hero { position: relative; isolation: isolate; text-align: center;
  padding-block: calc(var(--brand-space) * 6) 0; }
.lib__hero::before {
  /* Bleeds wider than the hero so the bloom falls off outside the text column
     rather than ending on its edge. Clipped at the page by .lib. */
  content: ""; position: absolute; inset: -40% -20% -60% -20%; z-index: -1;
  background: var(--brand-hero-glow); pointer-events: none;
}
.lib__intro { max-width: 680px; margin-inline: auto; }
.lib__title { font-family: var(--sans); font-weight: 600;
  font-size: clamp(34px, 4.6vw, 56px); line-height: 1.06; letter-spacing: -.025em;
  color: var(--brand-white); margin: 0; }
.lib__sub { font-family: var(--body); color: var(--brand-gray-300);
  font-size: clamp(15px, 1.5vw, 17.5px); line-height: 1.6;
  margin: calc(var(--brand-space) * 2) auto 0; max-width: 640px; }

/* search */
.lib__search { position: relative; margin: calc(var(--brand-space) * 4) auto 0;
  max-width: 480px; }
.lib__search-icon { position: absolute; left: 16px; top: 50%; translate: 0 -50%;
  width: 16px; height: 16px; color: var(--brand-gray-500); pointer-events: none; }
.lib__search input { width: 100%; height: 48px; font: 400 15px/1 var(--body);
  color: var(--brand-light); background: var(--brand-navy);
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: var(--brand-radius-control); padding: 0 56px 0 42px; }
.lib__search input::placeholder { color: var(--brand-gray-500); }
.lib__search input:hover { border-color: rgba(255, 255, 255, 0.2); }
.lib__search input:focus-visible { outline: none; border-color: var(--brand-blue);
  box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.35); }
/* The "/" hint, hidden once the field has focus or content. */
.lib__kbd { position: absolute; right: 12px; top: 50%; translate: 0 -50%;
  font: 500 12px/1 var(--mono); color: var(--brand-gray-500);
  border: 1px solid rgba(255, 255, 255, 0.12); border-radius: 6px;
  padding: 4px 7px; pointer-events: none; }
.lib__search input:focus-visible ~ .lib__kbd,
.lib__search input:not(:placeholder-shown) ~ .lib__kbd { opacity: 0; }

/* toolbar: type tabs left, category pills right, one row under the search */
.lib__toolbar { display: flex; flex-wrap: wrap; align-items: center;
  justify-content: space-between; gap: calc(var(--brand-space) * 2);
  margin-top: calc(var(--brand-space) * 5); }
.lib__tabs { display: inline-flex; gap: 4px; background: var(--brand-navy);
  border: 1px solid var(--border); border-radius: var(--brand-radius-control);
  padding: 4px; flex: 0 0 auto; }
.lib__tab { appearance: none; background: none; border: 0; border-radius: 9px;
  cursor: pointer; font: 600 14px/1 var(--body); color: var(--brand-gray-500);
  padding: 9px 15px; display: inline-flex; align-items: center; gap: 7px; }
.lib__tab[aria-selected="true"] { background: var(--brand-blue);
  color: var(--brand-white); }
.lib__tab:hover { color: var(--brand-light); }
.lib__tab[aria-selected="true"]:hover { color: var(--brand-white); }
.lib__tab:focus-visible { outline: 2px solid var(--brand-blue); outline-offset: 2px; }
.lib__count { font: 700 11px/1 var(--mono); color: var(--brand-gray-500);
  background: rgba(255, 255, 255, 0.06); border-radius: var(--brand-radius-pill);
  padding: 2px 7px; }
.lib__tab[aria-selected="true"] .lib__count { color: var(--brand-white);
  background: rgba(255, 255, 255, 0.18); }

.lib__pills { display: flex; gap: 7px; flex: 0 1 auto; min-width: 0; }
.lib__pill { appearance: none; cursor: pointer; font: 500 13.5px/1 var(--body);
  color: var(--brand-gray-300); background: transparent;
  border: 1px solid var(--border); border-radius: var(--brand-radius-pill);
  padding: 8px 15px; white-space: nowrap; }
.lib__pill:hover { border-color: var(--brand-blue-deep); color: var(--brand-white); }
.lib__pill[aria-pressed="true"] { background: var(--brand-blue);
  border-color: var(--brand-blue); color: var(--brand-white); }
.lib__pill:focus-visible { outline: 2px solid var(--brand-blue); outline-offset: 2px; }

/* results: an eyebrow over a grid on the page ground, no wrapping box */
.lib__results { font: 700 11.5px/1 var(--body); text-transform: uppercase;
  letter-spacing: .13em; color: var(--brand-gray-500);
  margin: calc(var(--brand-space) * 6) 0 calc(var(--brand-space) * 2); }
.lib__grid { display: grid; gap: 24px; grid-template-columns: repeat(3, minmax(0, 1fr));
  align-items: start; }

/* card */
/* The library's controller filters by toggling the hidden attribute. A class
   that sets display (cards are flex) would otherwise beat it and keep every
   card on screen, so hidden always wins inside the library. */
.lib [hidden] { display: none !important; }
.lib__card { position: relative; background: var(--brand-card);
  border: 1px solid var(--border); border-radius: var(--brand-radius-card);
  overflow: hidden; display: flex; flex-direction: column; min-width: 0;
  transition: transform .16s ease, border-color .16s ease, box-shadow .16s ease; }
.lib__card:hover { transform: translateY(-2px); border-color: var(--brand-blue);
  box-shadow: 0 12px 30px -10px rgba(37, 99, 235, 0.45); }
/* The title link is the card's hit area: one focusable element, whole card
   clickable, and the focus ring lands on the card rather than the text. */
.lib__card:focus-within { border-color: var(--brand-blue);
  box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.4); }
.lib__card-link::after { content: ""; position: absolute; inset: 0; }
.lib__card-link:focus-visible { outline: none; }
.lib__thumb { display: block; background: var(--bg-raise); aspect-ratio: 16 / 9;
  overflow: hidden; border-bottom: 1px solid var(--border);
  border-radius: calc(var(--brand-radius-card) - 1px) calc(var(--brand-radius-card) - 1px) 0 0; }
.lib__thumb-img { width: 100%; height: 100%; object-fit: cover; display: block; }
.lib__body { padding: 16px 18px 18px; display: flex; flex-direction: column;
  gap: var(--brand-space); }
.lib__meta { display: flex; align-items: center; gap: 8px; margin: 0;
  font: 400 12px/1 var(--body); color: var(--brand-gray-500); }
.lib__meta-mark { width: 18px; height: 18px; border-radius: 50%; flex: 0 0 auto; }
.lib__author { color: var(--brand-gray-300); font-weight: 500; }
.lib__type { font: 700 10px/1 var(--body); text-transform: uppercase;
  letter-spacing: .09em; color: var(--brand-blue-text);
  border: 1px solid var(--brand-card-border); border-radius: var(--brand-radius-pill);
  padding: 4px 9px; margin-left: auto; }
.lib__card-title { font-family: var(--sans); font-weight: 600; font-size: 18px;
  line-height: 1.3; margin: 2px 0 0; letter-spacing: -.012em; }
.lib__card-title a { color: var(--brand-white); text-decoration: none; }
.lib__card:hover .lib__card-title a { color: var(--brand-blue-text); }
.lib__card-sum { font: 400 14px/1.55 var(--body); color: var(--brand-gray-300);
  margin: 0; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; }
.lib__card-cta { font: 500 13.5px/1 var(--body); color: var(--brand-blue-text);
  margin: 6px 0 0; }

/* empty state */
.lib__empty { text-align: center; padding: calc(var(--brand-space) * 6) 20px;
  border: 1px dashed var(--border); border-radius: var(--brand-radius-card);
  background: rgba(15, 23, 42, 0.4); }
.lib__empty-title { font-family: var(--sans); font-weight: 600; font-size: 17px;
  color: var(--brand-white); margin: 0; }
.lib__empty-text { font: 400 14.5px/1.6 var(--body); color: var(--brand-gray-300);
  margin: 8px 0 16px; }
.lib__reset { appearance: none; cursor: pointer; font: 600 14px/1 var(--body);
  color: var(--brand-white); background: var(--brand-blue);
  border: 1px solid var(--brand-blue); border-radius: var(--brand-radius-control);
  padding: 11px 18px; }
.lib__reset:hover { background: var(--brand-blue-deep); border-color: var(--brand-blue-deep); }
.lib__reset:focus-visible { outline: 2px solid var(--brand-blue); outline-offset: 2px; }

/* skeletons, shown only while an async load is in flight */
.lib__skeleton { background: var(--brand-card); border: 1px solid var(--border);
  border-radius: var(--brand-radius-card); overflow: hidden; }
.lib__skeleton-thumb { aspect-ratio: 16 / 9; background: var(--bg-raise); }
.lib__skeleton-line { height: 12px; margin: 14px 18px; border-radius: 6px;
  background: linear-gradient(90deg, rgba(255,255,255,.05), rgba(255,255,255,.11), rgba(255,255,255,.05));
  background-size: 200% 100%; animation: lib-shimmer 1.4s linear infinite; }
.lib__skeleton-line:last-child { width: 60%; margin-bottom: 20px; }
@keyframes lib-shimmer { from { background-position: 200% 0 } to { background-position: -200% 0 } }
@media (prefers-reduced-motion: reduce) {
  .lib__skeleton-line { animation: none; }
  .lib__card { transition: none; }
}

@media (max-width: 1000px) { .lib__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 640px) {
  .lib__grid { grid-template-columns: 1fr; }
  .lib__toolbar { flex-direction: column; align-items: stretch; }
  .lib__tabs { display: flex; }
  .lib__tab { flex: 1 1 auto; justify-content: center; }
  /* Pills scroll rather than wrap into a tall block on a phone. */
  .lib__pills { overflow-x: auto; scrollbar-width: none; padding-bottom: 2px; }
  .lib__pills::-webkit-scrollbar { display: none; }
}

/* --- library detail --------------------------------------------------------
   12 column grid: the article takes 8 (about a 720px measure), the sidebar 4
   and sticks under the header. Below 980px the sidebar unsticks and the CTA
   becomes a fixed bottom bar, so the action stays reachable on a phone without
   a second full-width card in the flow. */
.lib--detail .lib__inner { padding-block: calc(var(--brand-space) * 5)
  calc(var(--brand-space) * 12); }

.lib__crumb { font: 400 13px/1 var(--body); color: var(--brand-gray-500);
  margin: 0 0 calc(var(--brand-space) * 2); display: flex; flex-wrap: wrap;
  align-items: center; gap: 8px; }
.lib__crumb a { color: var(--brand-gray-500); text-decoration: none; }
.lib__crumb a:hover { color: var(--brand-blue-text); text-decoration: underline; }
.lib__crumb a:focus-visible { outline: 2px solid var(--brand-blue); outline-offset: 2px;
  border-radius: 4px; }
.lib__crumb-sep { color: rgba(255, 255, 255, 0.22); }

/* Wide enough for the longest entry name on one line at the clamped 46px.
   "EMA 20/50 Crossover with ATR Stop" needs about 800px and was wrapping after
   "Crossover" at 760. The lede keeps its own 62ch cap below, so widening this
   does not stretch body copy. */
.lib__detail-head { max-width: 880px; }
.lib__detail-title { font-family: var(--sans); font-weight: 600;
  font-size: clamp(30px, 3.9vw, 46px); line-height: 1.08; letter-spacing: -.022em;
  color: var(--brand-white); margin: 0; }
.lib__detail-lede { font: 400 clamp(16px, 1.5vw, 18px)/1.6 var(--body);
  color: var(--brand-gray-300); margin: calc(var(--brand-space) * 2) 0 0; max-width: 62ch; }
.lib__headrow { display: flex; flex-wrap: wrap; align-items: center;
  gap: calc(var(--brand-space) * 2); margin-top: calc(var(--brand-space) * 3); }
.lib__tag { font: 700 11px/1 var(--body); text-transform: uppercase;
  letter-spacing: .09em; color: var(--brand-blue-text);
  background: rgba(37, 99, 235, 0.14); border: 1px solid var(--brand-card-border);
  border-radius: var(--brand-radius-pill); padding: 6px 12px; }

/* Chart / Source code segmented control, same shape as the library toolbar */
.lib__viewer { margin-top: calc(var(--brand-space) * 4); }
.lib__viewtabs { display: inline-flex; gap: 4px; background: var(--brand-navy);
  border: 1px solid var(--border); border-radius: var(--brand-radius-control);
  padding: 4px; margin-bottom: calc(var(--brand-space) * 2); }
.lib__viewtab { appearance: none; background: none; border: 0; border-radius: 9px;
  cursor: pointer; font: 600 14px/1 var(--body); color: var(--brand-gray-500);
  padding: 9px 16px; }
.lib__viewtab[aria-selected="true"] { background: var(--brand-blue); color: var(--brand-white); }
.lib__viewtab:hover { color: var(--brand-light); }
.lib__viewtab[aria-selected="true"]:hover { color: var(--brand-white); }
.lib__viewtab:focus-visible { outline: 2px solid var(--brand-blue); outline-offset: 2px; }

/* The live preview, framed. aspect-ratio is on the iframe so the box reserves
   its height before the terminal paints and nothing shifts. */
.lib__hero-chart { border: 1px solid var(--brand-card-border);
  border-radius: var(--brand-radius-card); overflow: hidden; background: var(--bg-raise);
  box-shadow: 0 0 0 1px rgba(37, 99, 235, 0.08), 0 24px 60px -30px rgba(37, 99, 235, 0.4); }
.lib__hero-chart iframe { width: 100%; aspect-ratio: 16 / 9; border: 0; display: block; }
/* At phone width 16:9 leaves a sliver of plot under the terminal's own bars,
   so the frame goes taller instead. */
@media (max-width: 640px) { .lib__hero-chart iframe { aspect-ratio: 4 / 5; max-height: 70vh; } }
.lib__caption { font: 400 13px/1.5 var(--body); color: var(--brand-gray-500);
  margin: calc(var(--brand-space) * 1.5) 0 0; }
.lib__legal { font: 400 12px/1.5 var(--body); color: var(--brand-gray-500);
  margin: calc(var(--brand-space) * 1.5) 0 0; }

/* grid */
.lib__layout { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: calc(var(--brand-space) * 5); align-items: start;
  margin-top: calc(var(--brand-space) * 6); }
.lib__article { grid-column: span 8; min-width: 0; }
.lib__aside { grid-column: span 4; position: sticky;
  top: calc(64px + var(--brand-space) * 3); display: flex; flex-direction: column;
  gap: calc(var(--brand-space) * 2); }

.lib__ctabox { background: var(--brand-card); border: 1px solid var(--border);
  border-radius: var(--brand-radius-card); padding: 20px; }
.lib__ctabox-title { font-family: var(--sans); font-weight: 600; font-size: 16px;
  color: var(--brand-white); margin: 0; }
.lib__ctabox-text { font: 400 13.5px/1.6 var(--body); color: var(--brand-gray-300);
  margin: 8px 0 16px; }
.lib__ctabox-cta { width: 100%; justify-content: center; text-align: center; }

/* On this page, with scroll-spy */
.lib__toc { background: var(--brand-card); border: 1px solid var(--border);
  border-radius: var(--brand-radius-card); padding: 16px 18px; }
.lib__toc-title { font: 700 11px/1 var(--body); text-transform: uppercase;
  letter-spacing: .12em; color: var(--brand-gray-500); margin: 0 0 12px; }
.lib__toc ol { list-style: none; margin: 0; padding: 0; display: flex;
  flex-direction: column; gap: 2px; }
.lib__toc a { display: block; font: 400 13.5px/1.4 var(--body);
  color: var(--brand-gray-300); text-decoration: none; padding: 7px 10px;
  border-radius: 8px; border-left: 2px solid transparent; }
.lib__toc a:hover { color: var(--brand-white); background: rgba(255, 255, 255, 0.04); }
.lib__toc a[aria-current="true"] { color: var(--brand-blue-text);
  border-left-color: var(--brand-blue); background: rgba(37, 99, 235, 0.1); }
.lib__toc a:focus-visible { outline: 2px solid var(--brand-blue); outline-offset: 2px; }

/* sections: 64px above an H2, 16px below, no full-width rule */
.lib__section { margin-top: calc(var(--brand-space) * 8); scroll-margin-top: 88px; }
.lib__section:first-child { margin-top: 0; }
.lib__h2 { font-family: var(--sans); font-weight: 600;
  font-size: clamp(24px, 2.4vw, 32px); line-height: 1.22; letter-spacing: -.018em;
  color: var(--brand-white); margin: 0 0 calc(var(--brand-space) * 2);
  padding: 0; border: 0; }

/* mobile: sidebar unsticks, the action becomes a bottom bar */
.lib__bottombar { display: none; }
@media (max-width: 980px) {
  .lib__layout { grid-template-columns: 1fr; gap: calc(var(--brand-space) * 4); }
  .lib__article, .lib__aside { grid-column: 1 / -1; }
  .lib__aside { position: static; }
  /* The CTA card is replaced by the fixed bar, so it does not appear twice. */
  .lib__aside .lib__ctabox { display: none; }
  .lib__toc { display: none; }
  .lib__bottombar { display: block; position: fixed; left: 0; right: 0; bottom: 0;
    z-index: 30; background: rgba(15, 23, 42, 0.94); backdrop-filter: blur(12px);
    border-top: 1px solid var(--border);
    padding: 12px var(--gutter) calc(12px + env(safe-area-inset-bottom, 0px)); }
  .lib__bottombar .btn { width: 100%; justify-content: center; }
  /* Room for the bar so it never covers the last line of the page. */
  .lib--detail .lib__inner { padding-bottom: calc(var(--brand-space) * 14); }
}

/* --- code block ------------------------------------------------------------
   Shared by the source-code tab and the calculation formula, so both look the
   same and neither can clip. The <pre> scrolls inside itself; the page never
   does. A soft-wrap toggle is offered for long lines. */
.lib__codewrap { border: 1px solid var(--border); border-radius: var(--brand-radius-card);
  overflow: hidden; background: var(--brand-navy); }
.lib__codebar { display: flex; align-items: center; gap: 10px;
  padding: 10px 12px 10px 16px; border-bottom: 1px solid var(--border);
  background: rgba(15, 23, 42, 0.6); }
.lib__codelang { font: 700 11px/1 var(--body); text-transform: uppercase;
  letter-spacing: .11em; color: var(--brand-gray-500); }
.lib__codestatus { font: 400 12.5px/1 var(--body); color: var(--brand-gray-500);
  margin-left: auto; }
.lib__codestatus[data-state="ok"] { color: var(--brand-blue-text); }
.lib__codestatus[data-state="manual"] { color: #f0b429; }
.lib__codebtn { appearance: none; cursor: pointer; font: 600 12.5px/1 var(--body);
  color: var(--brand-gray-300); background: rgba(255, 255, 255, 0.05);
  border: 1px solid var(--border); border-radius: 8px; padding: 7px 11px; }
.lib__codebtn:hover { color: var(--brand-white); border-color: var(--brand-blue-deep); }
.lib__codebtn:focus-visible { outline: 2px solid var(--brand-blue); outline-offset: 2px; }
.lib__codewrap .lib__code { margin: 0; border: 0; border-radius: 0;
  background: transparent; padding: 0; }

/* Line numbers come from a counter on each line, so they are not selectable and
   copying the block never picks them up. */
.lib__code--block { overflow-x: auto; -webkit-overflow-scrolling: touch;
  font: 400 14px/1.7 var(--mono); color: var(--brand-light);
  padding: 16px 0; counter-reset: line; }
.lib__code--block code { display: block; min-width: max-content; }
.lib__line { display: block; padding: 0 18px 0 0; white-space: pre; }
.lib__line::before { content: counter(line); counter-increment: line;
  display: inline-block; width: 2.5em; margin-right: 18px; padding-left: 16px;
  text-align: right; color: var(--brand-gray-500); user-select: none;
  -webkit-user-select: none; }
/* Soft wrap, toggled from the header bar. */
.lib__codewrap[data-wrap="on"] .lib__code--block { overflow-x: visible; }
.lib__codewrap[data-wrap="on"] .lib__code--block code { min-width: 0; }
.lib__codewrap[data-wrap="on"] .lib__line { white-space: pre-wrap;
  text-indent: -0.001px; padding-left: calc(2.5em + 34px); }
.lib__codewrap[data-wrap="on"] .lib__line::before { margin-left: calc(-2.5em - 34px);
  position: absolute; }

/* Syntax colours from the brand palette plus the chart palette's green. */
.tok--comment { color: var(--brand-gray-500); font-style: italic; }
.tok--keyword { color: var(--brand-blue-text); }
.tok--type    { color: #7fb4ff; }
.tok--string  { color: #4ec98a; }
.tok--number  { color: #4ec98a; }
.tok--call    { color: var(--brand-white); }

/* The formula uses the same component, so it cannot clip either. */
.lib__formula { font: 400 14px/1.7 var(--mono); color: var(--brand-light);
  background: var(--brand-navy); border: 1px solid var(--border);
  border-radius: var(--brand-radius-card); padding: 16px 18px; margin: 0;
  overflow-x: auto; }

/* --- article ---------------------------------------------------------------
   Roboto 17px at 1.7, brand light on the dark ground, bold lead-ins in white. */
.lib__prose > * { max-width: 74ch; }
.lib__prose > .lib__table-wrap, .lib__prose > .lib__codewrap,
.lib__prose > .lib__callout, .lib__prose > .lib__formula { max-width: none; }
.lib__prose > :first-child { margin-top: 0; }
.lib__prose p { font: 400 17px/1.7 var(--body); color: var(--brand-light);
  margin: 0 0 calc(var(--brand-space) * 2); }
.lib__prose ul, .lib__prose ol { font: 400 17px/1.7 var(--body);
  color: var(--brand-light); margin: 0 0 calc(var(--brand-space) * 2);
  padding-left: 22px; }
.lib__prose li { margin-bottom: calc(var(--brand-space) * 1.5); }
.lib__prose li strong, .lib__prose p strong { color: var(--brand-white); font-weight: 600; }
.lib__prose a { color: var(--brand-blue-text); }
.lib__prose a:focus-visible { outline: 2px solid var(--brand-blue); outline-offset: 2px;
  border-radius: 3px; }
/* Scoped to a code element that is NOT inside a pre. Unscoped, this chip
   background landed on every line of a code block as well, because those lines
   are code elements too, and the block read as a stack of highlighted strips. */
.lib__prose :not(pre) > code { font: 400 .92em/1 var(--mono); color: var(--brand-white);
  background: rgba(255, 255, 255, 0.07); border-radius: 4px; padding: 2px 5px; }
.lib__prose em { color: var(--brand-white); font-style: italic; }
.lib__note { font: 400 15px/1.6 var(--body); color: var(--brand-gray-300); }

/* Settings table: readable at 15.5px, header as eyebrows, scrolls in its own
   box so the columns keep their alignment on a phone. */
.lib__table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch;
  border: 1px solid var(--border); border-radius: var(--brand-radius-card);
  margin: calc(var(--brand-space) * 2) 0; }
.lib__table { width: 100%; border-collapse: collapse; font: 400 15.5px/1.55 var(--body);
  min-width: 520px; }
.lib__table th { text-align: left; padding: 12px 16px; font: 700 11px/1 var(--body);
  text-transform: uppercase; letter-spacing: .1em; color: var(--brand-gray-500);
  background: rgba(15, 23, 42, 0.7); border-bottom: 1px solid var(--border);
  white-space: nowrap; }
.lib__table td { padding: 13px 16px; color: var(--brand-gray-300); vertical-align: top;
  border-bottom: 1px solid var(--border-soft); }
.lib__table tbody tr:last-child td { border-bottom: 0; }
.lib__table tbody tr:hover td { background: rgba(37, 99, 235, 0.07); }
.lib__table td:first-child { color: var(--brand-white); font-weight: 500; white-space: nowrap; }

/* One component, two variants. The surface, border and radius are the brand
   card in both; only the icon colour changes, so amber stays a state colour on
   a glyph and never becomes a second brand colour on a box. */
.lib__callout { display: grid; grid-template-columns: 20px 1fr;
  gap: calc(var(--brand-space) * 1.5); align-items: start;
  background: var(--brand-card); border: 1px solid var(--brand-card-border);
  border-radius: var(--brand-radius-card); padding: 18px 20px;
  margin: calc(var(--brand-space) * 2) 0; }
.lib__callout-icon { display: block; width: 20px; height: 20px; margin-top: 3px; }
.lib__callout-icon svg { width: 20px; height: 20px; display: block; }
.lib__callout--info .lib__callout-icon { color: var(--brand-blue-text); }
.lib__callout--caution .lib__callout-icon { color: #f0b429; }
.lib__callout p { margin: 0 0 8px; }
.lib__callout ul, .lib__callout ol { margin-bottom: 0; }
.lib__callout p:last-child, .lib__callout ul:last-child { margin-bottom: 0; }
.lib__callout-body > :first-child { margin-top: 0; }

/* The disclaimer under an empty results state. Small and muted on purpose: it
   is required context, not a message to lead with. */
.lib__fineprint { font: 400 13px/1.6 var(--body); color: var(--brand-gray-500);
  margin: calc(var(--brand-space) * 1.5) 0 0; }

/* --- FAQ -------------------------------------------------------------------
   Buttons with aria-expanded rather than details/summary, because the height
   animation needs a measurable panel. Server-rendered either way: the panels
   carry their text and are only collapsed once the controller connects. */
.lib__faq { border-top: 1px solid var(--border-soft); }
.lib__faq-item { border-bottom: 1px solid var(--border-soft); }
.lib__faq-q { appearance: none; background: none; border: 0; width: 100%;
  min-height: 56px; display: flex; align-items: center; justify-content: space-between;
  gap: 16px; cursor: pointer; text-align: left; padding: 14px 4px;
  font: 600 16.5px/1.45 var(--body); color: var(--brand-white);
  font-family: var(--sans); }
.lib__faq-q:hover { color: var(--brand-blue-text); }
.lib__faq-q:focus-visible { outline: 2px solid var(--brand-blue); outline-offset: -2px;
  border-radius: 6px; }
.lib__faq-chev { width: 11px; height: 11px; flex: 0 0 auto; border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor; rotate: 45deg; translate: 0 -2px;
  transition: rotate .22s ease, translate .22s ease; color: var(--brand-gray-500); }
.lib__faq-q[aria-expanded="true"] .lib__faq-chev { rotate: 225deg; translate: 0 2px;
  color: var(--brand-blue-text); }
.lib__faq-a { overflow: hidden; transition: height .26s ease; }
.lib__faq-a p { font: 400 16.5px/1.7 var(--body); color: var(--brand-light);
  margin: 0; padding: 0 44px 20px 4px; }
@media (prefers-reduced-motion: reduce) {
  .lib__faq-chev, .lib__faq-a { transition: none; }
}

/* --- related card ----------------------------------------------------------
   The library grid card, sized to the article column. */
.lib__related { position: relative; display: block; max-width: 420px;
  background: var(--brand-card); border: 1px solid var(--border);
  border-radius: var(--brand-radius-card); overflow: hidden; text-decoration: none;
  transition: transform .16s ease, border-color .16s ease, box-shadow .16s ease; }
.lib__related:hover { transform: translateY(-2px); border-color: var(--brand-blue);
  box-shadow: 0 12px 30px -10px rgba(37, 99, 235, 0.45); }
.lib__related:focus-visible { outline: none; border-color: var(--brand-blue);
  box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.4); }
.lib__related-media { display: block; background: var(--bg-raise); aspect-ratio: 16 / 9;
  overflow: hidden; border-bottom: 1px solid var(--border); }
.lib__related-media img { width: 100%; height: 100%; object-fit: cover; display: block; }
.lib__related-body { display: flex; flex-direction: column; gap: var(--brand-space);
  padding: 16px 18px 18px; }
.lib__related-kind { display: flex; align-items: center; gap: 8px;
  font: 400 12px/1 var(--body); color: var(--brand-gray-500); }
.lib__related-title { font-family: var(--sans); font-weight: 600; font-size: 18px;
  line-height: 1.3; color: var(--brand-white); }
.lib__related:hover .lib__related-title { color: var(--brand-blue-text); }
.lib__related-sum { font: 400 14px/1.55 var(--body); color: var(--brand-gray-300);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; }
.lib__related-cta { font: 500 13.5px/1 var(--body); color: var(--brand-blue-text);
  margin-top: 4px; }
@media (prefers-reduced-motion: reduce) { .lib__related { transition: none; } }

/* Base for the code block. .lib__codewrap resets what it needs on top; the
   strategy page used to style a standalone <pre class="lib__code"> from here,
   and now renders the same source-code tab as the indicator page instead. */
.lib__code { background: var(--brand-navy); border: 1px solid var(--border);
  border-radius: var(--brand-radius-card); padding: 16px 18px; overflow-x: auto;
  font: 400 13.5px/1.7 var(--mono); color: var(--brand-light);
  margin: calc(var(--brand-space) * 2) 0; max-width: none; }
