/* ── Self-hosted brand fonts (IBM Plex, OFL 1.1) ──────────────────────────
   In the stylesheet rather than a per-page <link>: every page already loads
   this file, so the faces cannot go missing on nine of twelve pages the way
   Inter did. Three weights; 700 is deliberately absent. */
/* Space Grotesk carries the headlines. Body stays IBM Plex, so display and body
   are finally two different voices rather than one weight apart. Chosen after
   measuring the field: the market makers with presence all run a distinctive
   display face (saans, Surt, Slussen, PPMori, untitledSans) and the ones that
   look generic run Poppins or Inter. Cumberland, the most institutional name on
   that list, runs Space Grotesk too.
   One variable file covers both weights, 22 KB, self-hosted like the others. */
@font-face {
  font-family: "Space Grotesk";
  font-style: normal;
  font-weight: 500 700;
  font-display: swap;
  src: url("fonts/space-grotesk-var.woff2") format("woff2");
}
@font-face {
  font-family: "IBM Plex Sans";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("fonts/ibm-plex-sans-400.woff2") format("woff2");
}
@font-face {
  font-family: "IBM Plex Sans";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("fonts/ibm-plex-sans-500.woff2") format("woff2");
}
@font-face {
  font-family: "IBM Plex Sans";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("fonts/ibm-plex-sans-600.woff2") format("woff2");
}
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("fonts/ibm-plex-mono-400.woff2") format("woff2");
}
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("fonts/ibm-plex-mono-500.woff2") format("woff2");
}
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("fonts/ibm-plex-mono-600.woff2") format("woff2");
}

/* ═══════════════════════════════════════════════════════════════════════════
   Onchain Bureau — umbrella design system

   Used by eight of the twelve pages (home, the two product pages, the three
   service pages, work, legal). The other four (install / search / activate /
   wallet-connect) still load terminal.css and still have their own class names,
   but as of 2026-08-22 terminal.css is re-skinned onto THESE tokens: same ground,
   same ink ramp, same cyan accent, same 1200/840/24px container. A visitor no
   longer changes brand at /install. Merging the class vocabularies is a separate
   job (146 of terminal.css's 185 classes have no equivalent here).

   BRAND RULE ("The Desk") — ONE accent at the parent, cyan. It is the hue the
   live onchainbureau.com already uses. Green is DEMOTED to semantic-only (up /
   verified / live); it is no longer a second brand colour, because expressing
   the two-engine duality chromatically *inside a sentence* is the single thing
   that made the old homepage read as generic crypto SaaS. The duality is now
   carried structurally — two labelled walls, two canvases — not by two hues.

   AMENDED 2026-08-23, by the owner, deliberately. The chromatic budget below
   ("under 5% of any screen, at most 3 accent-coloured elements") is RETIRED. It
   was being met - measured at 2.5% against its own 5% ceiling - and the site was
   the poorer for it: against a competitor set, the restraint read as thinness
   rather than as discipline. Keeping the sentence while ignoring it would be
   worse than either choice, so it is struck rather than quietly disobeyed.

   .t-trade / .t-grow now run on the SERVICE cards too, not only product pages.
   That is not decoration: each service belongs to one of the two engines
   (Market Making and Treasury are Trading, Algorithmic Marketing is Growth), so
   the hue is stating a real affiliation the page already asserts in words. A
   third hue for the third card was considered and REJECTED - it would invent a
   distinction that does not exist.

   Red is SEMANTIC ONLY (loss/failure) and amber is value/rewards only. Those two
   are unchanged: a status colour that also decorates cannot signal status.
   Structure is drawn with 1px hairlines at 9%, never with blur gradients.
   ═══════════════════════════════════════════════════════════════════════════ */

:root {
  /* #0A0A0B, not pure #000 — black causes halation against ivory text. */
  /* Tinted, not pure black. A survey of 13 market-maker sites put this one at the
     darkest end of the set, and every competitor tints its ground: navy at Jump
     and Enflux, green at Kairon and Wintermute, #1d202e at Acheron. Undifferentiated
     near-black is what a template defaults to, and it reads that way.
     Cool blue-grey here because the accent is cyan. Contrast is barely touched:
     ink 18.13 -> 17.47, faint 6.16 -> 5.94, both far above the 4.5 floor. */
  --void: #0c1016;
  --panel: #121722;
  --panel-2: #0f141c;
  --raise: rgba(255, 255, 255, 0.03);
  --raise-2: rgba(255, 255, 255, 0.07);
  --line: rgba(255, 255, 255, 0.09);
  --line-2: rgba(255, 255, 255, 0.16);

  --ink: #f4f5f6;
  --dim: #a8acb3; /* 9.1:1 */
  --faint: #8b9098; /* 5.2:1 — was #61656c at 3.59:1, which failed WCAG AA */

  /* ONE accent at the parent, and it stays cyan — that is the hue the live
     onchainbureau.com uses and the axis the whole brand architecture hangs on.
     What changed is saturation: #22d3ee computes to S 86% / L 53%, which lands
     inside the "neon" band (S >= 85%, L 45-70%) that the directive bans and that
     reads as generic crypto-SaaS. #34B4C8 is S ~60% at the same hue: still
     unmistakably the same brand, no longer a highlighter. */
  --accent: #34b4c8;
  --accent-ink: #04181d;
  --accent-soft: rgba(52, 180, 200, 0.14);

  --trade: #34b4c8;
  --grow: #4ade80;
  --up: #4ade80; /* up / verified / live ONLY */
  --down: #f74551; /* down / rejected / failed ONLY */
  --value: #fbbf24; /* reward / notional value ONLY */

  /* Declared AND loaded — the @font-face block at the top of this file is why.
     The previous comment here claimed Inter was "already linked in every page
     head"; it was linked in three of twelve, so nine pages quietly rendered in
     system-ui. Putting the faces in the stylesheet every page already loads is
     the fix that cannot drift page by page. */
  --display: "Space Grotesk", "IBM Plex Sans", ui-sans-serif, system-ui, sans-serif;
  --sans: "IBM Plex Sans", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --mono: "IBM Plex Mono", ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;

  /* SCALE — h1 drops from clamp(40,6.4vw,70)/w600 to a lighter, tighter grotesk. */
  --h1: clamp(38px, 4.4vw, 54px);
  --h2: clamp(26px, 2.6vw, 34px);
  --h3: 18px;
  --body: 16px;
  --sub: 17px;
  --data: 13px;
  --label: 11px;

  /* SHAPE — the pill is retired except on status dots and the LIVE chip. */
  --r-sm: 2px;
  --r-md: 4px;
  --r-lg: 4px; /* was 8px — the band starts at 6 */
  --pill: 9999px; /* status dots and avatars ONLY */

  /* DENSITY */
  --sec: 72px;
  --sec-tight: 44px;
  --pad: 20px;
  --maxw: 1200px;
}

/* Numbers are tabular everywhere. Magnitude must be comparable down a column. */
.num,
.price,
td,
th,
.stat b,
.quotes b {
  font-variant-numeric: tabular-nums lining-nums;
}

.t-trade {
  --accent: var(--trade);
  --accent-ink: #032027;
  --accent-soft: rgba(52, 180, 200, 0.16);
}
.t-grow {
  --accent: var(--grow);
  --accent-ink: #04140b;
  --accent-soft: rgba(74, 222, 128, 0.16);
}

* {
  box-sizing: border-box;
}

/* Form controls do not inherit font-family. Without this, every <button> falls
   back to the UA default: the submit button on all seven form pages was
   rendering in Arial while the rest of the site was IBM Plex. Inputs and
   selects had been fixed once inside .deskform; button was missed, and a rule
   scoped to one component could only ever be missed again. */
button,
input,
select,
textarea {
  font-family: inherit;
}
html {
  scroll-behavior: smooth;
}
body {
  margin: 0;
  background: var(--void);
  color: var(--ink);
  font-family: var(--sans);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}
.wrap {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 0 24px;
}
.narrow {
  max-width: 840px;
  margin: 0 auto;
  padding: 0 24px;
}

h1,
h2,
h3,
h4 {
  margin: 0;
  font-weight: 600;
  letter-spacing: normal;
  text-wrap: balance;
}
/* Display face on the two sizes big enough to show its character. h3/h4 stay on
   the body face: at 17px Space Grotesk reads as a slightly odd IBM Plex rather
   than as a decision, and the point of a display face is that it is legible AS a
   choice. Tracking tightens as size grows, which is what optical sizing would do
   if this were a variable optical axis. */
h1,
h2 {
  font-family: var(--display);
  letter-spacing: -0.035em;
}
h1 {
  font-size: clamp(40px, 6.4vw, 70px);
  line-height: 1.14;
}
h2 {
  font-size: clamp(27px, 3.9vw, 44px);
  line-height: 1.17;
}
h3 {
  font-size: 18px;
  line-height: 1.3;
}
h4 {
  font-size: 15px;
}
p {
  margin: 0;
}
a {
  color: inherit;
}
.sub {
  color: var(--dim);
  font-size: clamp(15px, 1.5vw, 17.5px);
  max-width: 62ch;
}
.center {
  text-align: center;
  margin-left: auto;
  margin-right: auto;
}
.num {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
}
.mono {
  font-family: var(--mono);
}
.acc {
  color: var(--accent);
}
.up {
  color: var(--grow);
}
.dn {
  color: var(--down);
}
.vl {
  color: var(--value);
}
.faint {
  color: var(--faint);
}
.dim {
  color: var(--dim);
}
/* the two product hues, usable inline in parent-brand copy */
.c-trade {
  color: var(--trade);
}
.c-grow {
  color: var(--grow);
}

/* Chart canvases MUST carry an explicit CSS width. Without one the intrinsic
   `width` attribute drives layout, so a canvas first measured inside a hidden
   container gets pinned to 1px and can never recover. */
canvas.chart {
  display: block;
  width: 100%;
}
canvas.diagram {
  display: block;
  width: 100%;
  height: 230px;
}
.vis-flush {
  padding: 0 !important;
}

.eyebrow {
  display: inline-block;
  padding: 6px 16px;
  border-radius: var(--pill);
  border: 1px solid var(--line-2);
  background: rgba(255, 255, 255, 0.02);
  color: var(--dim);
  font-size: 13px;
}

/* Panels are drawn with a 1px hairline, not a gradient border and not a 24px
   radius. "Structure by hairline, never by blur" is the rule that separates a
   trading surface from a marketing page — and the gradient-edge treatment was
   another stock crypto-SaaS component. Kept as .edge so no markup changes. */
.edge {
  position: relative;
  border-radius: var(--r-lg);
  background: var(--panel);
  border: 1px solid var(--line);
}

/* ── nav ──
   A flat, full-bleed 56px bar with a single hairline underneath. The floating
   translucent pill it replaced is the most-copied component in crypto SaaS and
   was the loudest "generic" tell on the page; every firm we benchmarked
   (Wintermute, GSR, Keyrock, Flowdesk) uses a flat bar. Vertical space here is
   spent on content, not chrome. */
.nav {
  position: sticky;
  top: 0;
  z-index: 80;
  width: 100%;
  margin: 0;
  height: 56px;
  display: flex;
  align-items: center;
  gap: 18px;
  padding: 0 max(24px, calc((100vw - var(--maxw)) / 2 + 24px));
  border-radius: 0;
  background: rgba(10, 10, 11, 0.86);
  border: 0;
  border-bottom: 1px solid var(--line);
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
}
.brand {
  display: flex;
  align-items: center;
  gap: 9px;
  font-weight: 600;
  font-size: 15px;
  white-space: nowrap;
  text-decoration: none;
}
.brand svg {
  flex: none;
  color: var(--ink);
}
.nav-links {
  display: flex;
  gap: 6px;
  margin: 0 auto;
  align-items: center;
}
.nav-links > a {
  color: var(--dim);
  text-decoration: none;
  font-size: 15px;
  padding: 6px 10px;
  border-radius: 4px;
}
.nav-links > a:hover {
  color: var(--ink);
  background: var(--raise);
}

/* dropdown — CSS-only via :hover + :focus-within, no JS to desync */
.drop {
  position: relative;
}
.drop > button {
  display: flex;
  align-items: center;
  gap: 6px;
  background: transparent;
  border: 0;
  cursor: pointer;
  color: var(--dim);
  font-family: var(--sans);
  font-size: 15px;
  padding: 6px 10px;
  border-radius: 4px;
}
.drop > button:hover {
  color: var(--ink);
  background: var(--raise);
}
.drop-menu {
  position: absolute;
  top: calc(100% + 10px);
  left: 50%;
  transform: translateX(-50%) translateY(-6px);
  min-width: 268px;
  padding: 7px;
  border-radius: 4px;
  background: rgba(16, 16, 18, 0.97);
  border: 1px solid var(--line-2);
  -webkit-backdrop-filter: blur(16px);
  backdrop-filter: blur(16px);
  box-shadow: 0 20px 50px rgba(0, 0, 0, 0.6);
  opacity: 0;
  visibility: hidden;
  transition:
    opacity 0.16s ease,
    transform 0.16s ease,
    visibility 0.16s;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.drop:hover .drop-menu,
.drop:focus-within .drop-menu {
  opacity: 1;
  visibility: visible;
  transform: translateX(-50%) translateY(0);
}
.drop-menu a {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 10px 12px;
  border-radius: 4px;
  text-decoration: none;
  color: var(--dim);
}
.drop-menu a:hover {
  background: var(--raise-2);
  color: var(--ink);
}
.drop-menu .dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  margin-top: 7px;
  flex: none;
  background: var(--faint);
}
.drop-menu .dot.trade {
  background: var(--trade);
}
.drop-menu .dot.grow {
  background: var(--grow);
}
.drop-menu b {
  display: block;
  font-size: 13px;
  font-weight: 600;
  color: var(--ink);
}
.drop-menu span {
  display: block;
  font-size: 13px;
  color: var(--faint);
  line-height: 1.4;
}

.nav-toggle {
  display: none;
  background: transparent;
  border: 1px solid var(--line-2);
  color: var(--dim);
  border-radius: 4px;
  padding: 6px 11px;
  cursor: pointer;
  font-size: 15px;
}

/* ── buttons ── */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  padding: 12px 22px;
  /* Squared, not pilled. The pill button is the other half of the generic
     crypto-SaaS signature (see the nav note above); none of the firms in this
     category use one. */
  border-radius: var(--r-md);
  font-size: 15px;
  font-weight: 500;
  text-decoration: none;
  cursor: pointer;
  border: 1px solid transparent;
  white-space: nowrap;
  transition:
    transform 0.16s ease,
    filter 0.16s ease,
    border-color 0.16s ease,
    background 0.16s ease;
}
.btn.solid {
  background: var(--accent);
  color: var(--accent-ink);
}
.btn.solid:hover {
  filter: brightness(1.08);
  transform: translateY(-2px);
}
.btn.ghost {
  background: var(--raise);
  color: var(--ink);
  border-color: var(--line-2);
}
.btn.ghost:hover {
  border-color: var(--accent);
  transform: translateY(-2px);
}
.btn.sm {
  padding: 8px 18px;
  font-size: 13px;
}
.btn.full {
  width: 100%;
}
a:focus-visible,
button:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

/* ── hero ── */
/* overflow:hidden clips the oversized aurora — body{overflow-x:hidden} alone
   does not stop it growing the document's scrollWidth on narrow viewports. */
/* The inner-page hero adopts the same left-aligned Desk grammar as .hero-desk,
   so the seven pages that still use it re-grammar without touching their markup.
   Centre-stacked hero + blurred aurora is the stock crypto-SaaS opening; none of
   the firms in this category use either. */
.hero {
  position: relative;
  padding: clamp(48px, 7vw, 84px) 0 clamp(32px, 5vw, 56px);
  text-align: left;
  overflow: hidden;
  border-bottom: 1px solid var(--line);
}
.hero .inner {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 18px;
}
.hero h1 {
  font-size: var(--h1);
  font-weight: 500;
  letter-spacing: -0.045em;
  line-height: 1.02;
}
.hero .sub {
  max-width: 58ch;
}
/* .center is still on this markup from the old grammar — neutralise it. */
.hero .center {
  text-align: left;
  margin-left: 0;
  margin-right: 0;
}
.hero .eyebrow {
  padding: 0;
  border: 0;
  background: none;
  border-radius: 0;
  font-family: var(--mono);
  font-size: var(--label);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--faint);
}
/* Aurora retired. It was a 1500px blurred gradient that also pushed the
   document 14px wider than a 390px viewport (horizontal scroll on mobile) and
   forced a 52px blur composite on every paint. Structure by hairline. */
.aurora {
  display: none;
}
/* the umbrella hero blends both product hues — you see the two halves before you scroll */
.aurora.duo {
  background:
    radial-gradient(30% 30% at 36% 46%, rgba(34, 211, 238, 0.22), transparent 70%),
    radial-gradient(30% 30% at 64% 46%, rgba(74, 222, 128, 0.22), transparent 70%),
    radial-gradient(40% 34% at 50% 62%, rgba(255, 255, 255, 0.05), transparent 74%);
}
.aurora.mono-glow {
  background:
    radial-gradient(38% 34% at 50% 46%, var(--accent-soft), transparent 70%),
    radial-gradient(46% 40% at 50% 70%, rgba(255, 255, 255, 0.04), transparent 75%);
}
.fade-txt {
  background: linear-gradient(180deg, #fff 26%, #82868c 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.cta-row {
  display: flex;
  gap: 11px;
  flex-wrap: wrap;
  justify-content: center;
}
.trust {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  justify-content: center;
}
.trust span {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--faint);
  border: 1px solid var(--line);
  border-radius: var(--pill);
  padding: 4px 12px;
}

section {
  /* Air is most of what separates these sites from ours. Measured top padding
     across the field: Kairon 120, CLS 117, Gravity 112, GSR 95; ours averaged
     66 across all sections. Density was reading as cheapness. */
  padding: 120px 0;
  position: relative;
}
section.tight {
  padding: 76px 0;
}
/* Section heads are LEFT-aligned and label-led. Centred eyebrow-pill + centred
   display heading is the stock SaaS section grammar; every firm in this
   category left-aligns and leads with a small mono label instead. Changing it
   here re-grammars every section on every page at once. */
.sec-head {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 12px;
  text-align: left;
  margin-bottom: 36px;
}
.sec-head h2 {
  font-size: var(--h2);
  font-weight: 400;
  letter-spacing: -0.02em;
  line-height: 1.15;
}
.sec-head .sub {
  margin-left: 0;
  margin-right: 0;
  max-width: 58ch;
}
/* The markup carries .center on these subheads from the old centred grammar;
   neutralise it here rather than editing the same line on seven pages. */
.sec-head .center {
  text-align: left;
  margin-left: 0;
  margin-right: 0;
}
/* The eyebrow becomes the mono label the rest of the page uses. */
.sec-head .eyebrow {
  padding: 0;
  border: 0;
  background: none;
  border-radius: 0;
  font-family: var(--mono);
  font-size: var(--label);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--faint);
}

/* ── reveal ──
   ocb-motion.js drives these with Motion and writes inline opacity/transform,
   which outrank these rules. The transition below is the fallback path for when
   vendor/motion.js is unavailable: ocb.js still adds .in, so the section reveals
   on the CSS curve instead. Both paths use the same cubic on purpose. */
.rv {
  opacity: 0;
  transform: translateY(22px);
  transition:
    opacity 0.7s cubic-bezier(0.2, 0.7, 0.3, 1),
    transform 0.7s cubic-bezier(0.2, 0.7, 0.3, 1);
}
.rv.in {
  opacity: 1;
  transform: none;
}

/* ── above-the-fold entrance ──
   [data-load] elements are held for the frame between first paint and
   pageLoad(), so the hero's entrance starts from 0 rather than snapping there.
   Scoped to .ocb-preload, which an inline <head> script adds AND removes on a
   1.2s timer, so this can never strand the hero invisible: if every script after
   the head fails, the timer still fires. Never style [data-load] unscoped. */
.ocb-preload [data-load] {
  opacity: 0;
}
@media (prefers-reduced-motion: reduce) {
  .ocb-preload [data-load] {
    opacity: 1;
  }
}

/* ── stats ── */
.stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(158px, 1fr));
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: 22px;
  overflow: hidden;
}
.stat {
  background: #030303;
  padding: 24px 20px;
  display: flex;
  flex-direction: column;
  gap: 5px;
}
.stat b {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  font-size: clamp(24px, 3vw, 32px);
  font-weight: 600;
  letter-spacing: -0.03em;
  line-height: 1;
}
.stat span {
  color: var(--faint);
  font-size: 13px;
}

/* ── cards ── */
/* min() on the track floor, not a bare px. `minmax(380px, 1fr)` makes 380px a
   HARD minimum, so on a 375px phone the card was wider than the viewport and
   the page scrolled sideways. `min(380px, 100%)` keeps the identical two-up
   layout wherever there is room and lets the track collapse to the container
   below that, which is the only behaviour that was ever wanted. */
.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
  gap: 18px;
}
.cards.two {
  grid-template-columns: repeat(auto-fit, minmax(min(380px, 100%), 1fr));
}
.card {
  padding: 24px;
  display: flex;
  flex-direction: column;
  gap: 15px;
}
.card .vis {
  border-radius: 4px;
  background: linear-gradient(180deg, #0c0c10, #050508);
  border: 1px solid var(--line);
  padding: 16px;
  min-height: 190px;
  display: flex;
  flex-direction: column;
  gap: 9px;
  justify-content: center;
  overflow: hidden;
}
.card h3 {
  display: flex;
  align-items: center;
  gap: 9px;
  flex-wrap: wrap;
}
.card h3 em {
  font-style: normal;
  font-family: var(--mono);
  font-size: 11px;
  color: var(--accent);
  border: 1px solid var(--accent);
  border-radius: var(--pill);
  padding: 2px 9px;
  opacity: 0.85;
}
.card p {
  color: var(--dim);
  font-size: 15px;
}
.card .price {
  font-family: var(--mono);
  font-size: 13px;
  color: var(--faint);
}
.card .price b {
  color: var(--ink);
  font-weight: 600;
}
.card-cta {
  display: flex;
  gap: 9px;
  flex-wrap: wrap;
  margin-top: auto;
  padding-top: 4px;
}

/* list primitives used inside card visuals */
.bar {
  display: flex;
  align-items: center;
  gap: 9px;
  font-family: var(--mono);
  font-size: 11px;
  color: var(--faint);
}
.bar .track {
  flex: 1 1 auto;
  height: 6px;
  border-radius: var(--pill);
  background: var(--raise-2);
  overflow: hidden;
}
.bar .track i {
  display: block;
  height: 100%;
  background: var(--accent);
  border-radius: var(--pill);
}
.bar .track i.v {
  background: var(--value);
}
.tick {
  display: flex;
  align-items: center;
  gap: 9px;
  font-size: 13px;
}
.tick .d {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--accent);
  flex: none;
}
.tick .t {
  color: var(--dim);
  flex: 1 1 auto;
  min-width: 0;
}
.tick .n {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  font-size: 11px;
  color: var(--faint);
}

.book {
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-family: var(--mono);
  font-size: 11px;
}
.book div {
  display: flex;
  justify-content: space-between;
  gap: 10px;
  padding: 3px 7px;
  border-radius: 4px;
  position: relative;
  overflow: hidden;
}
.book .ask {
  color: var(--down);
}
.book .bid {
  color: var(--grow);
}
.book .ask::before,
.book .bid::before {
  content: "";
  position: absolute;
  inset: 0 auto 0 0;
  width: var(--w, 30%);
  opacity: 0.13;
}
.book .ask::before {
  background: var(--down);
}
.book .bid::before {
  background: var(--grow);
}
.book .mid {
  color: var(--dim);
  justify-content: center;
  letter-spacing: 0.09em;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  margin: 3px 0;
}
.book span {
  position: relative;
}

/* ── split rows (engine panels) ── */
.split-row {
  display: grid;
  grid-template-columns: 1.05fr 1fr;
  gap: 26px;
  align-items: center;
}
.split-row.flip > .txt {
  order: 2;
}
.txt {
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.txt h2 {
  font-size: clamp(24px, 3vw, 34px);
}

/* ── tables ── */
/* min-width:0 is required: as a grid/flex child the default min-width:auto
   refuses to shrink below the table's min-width, blowing out the whole row. */
.tblwrap {
  overflow-x: auto;
  min-width: 0;
  border: 1px solid var(--line);
  border-radius: 4px;
  background: var(--panel);
}
table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
  min-width: 460px;
}
th,
td {
  text-align: left;
  padding: 11px 15px;
  border-bottom: 1px solid var(--line);
}
th {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--faint);
  font-weight: 500;
}
td.n {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  text-align: right;
}
tr:last-child td {
  border-bottom: 0;
}

/* ── steps ── */
.steps {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 18px;
}
.step {
  padding: 22px;
  display: flex;
  flex-direction: column;
  gap: 9px;
}
.step .k {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--accent);
}
.step p {
  color: var(--dim);
  font-size: 15px;
}

/* ── numbered policy list (legal pages) ── */
.numlist {
  display: flex;
  flex-direction: column;
  gap: 13px;
  margin-top: 16px;
}
.numlist .stp {
  display: flex;
  gap: 13px;
  align-items: flex-start;
  color: var(--dim);
  font-size: 15px;
  line-height: 1.6;
}
.numlist .stp > .n {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--accent);
  flex: none;
  min-width: 20px;
  padding-top: 4px;
}
.numlist .h {
  color: var(--ink);
  font-weight: 600;
}
.numlist a {
  color: var(--accent);
}

.legal-toc {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  margin: 16px 0 4px;
}
.legal-toc a {
  font-family: var(--mono);
  font-size: 13px;
  color: var(--accent);
  text-decoration: none;
  border: 1px solid var(--line-2);
  border-radius: var(--pill);
  padding: 4px 13px;
}
.legal-toc a:hover {
  border-color: var(--accent);
}
.legal-sec {
  scroll-margin-top: 90px;
}
.legal-sec + .legal-sec {
  margin-top: 28px;
  padding-top: 28px;
  border-top: 1px solid var(--line);
}

/* ── marquee ── */
.marq {
  overflow: hidden;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  padding: 16px 0;
}
.marq-in {
  display: flex;
  gap: 44px;
  width: max-content;
  animation: ocbslide 36s linear infinite;
}
.marq span {
  font-family: var(--mono);
  font-size: 13px;
  color: var(--faint);
  white-space: nowrap;
  letter-spacing: 0.04em;
}
@keyframes ocbslide {
  from {
    transform: translateX(0);
  }
  to {
    transform: translateX(-50%);
  }
}

/* ── final CTA ──
   Left-aligned, hairline-topped, and no blurred radial. 106/116px of padding
   around a centred stack was a fifth of the page height spent on a sign-off. */
.final {
  text-align: left;
  position: relative;
  overflow: hidden;
  padding: var(--sec) 0;
  border-top: 1px solid var(--line);
}
.final .inner {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 18px;
}
.final h2 {
  font-size: var(--h2);
  font-weight: 400;
  letter-spacing: -0.02em;
  line-height: 1.15;
}
.final .center {
  text-align: left;
  margin-left: 0;
  margin-right: 0;
}

/* ── footer ── */
footer {
  padding: 52px 0 72px;
  border-top: 1px solid var(--line);
}
.fcols {
  display: grid;
  grid-template-columns: 1.4fr repeat(3, 1fr);
  gap: 28px;
}
.fcol h4 {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--faint);
  font-weight: 500;
  margin-bottom: 12px;
}
.fcol ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.fcol a {
  color: var(--dim);
  text-decoration: none;
  font-size: 13px;
}
.fcol a:hover {
  color: var(--ink);
}
.fbrand p {
  color: var(--faint);
  font-size: 13px;
  margin-top: 10px;
  max-width: 34ch;
}
.fbot {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  margin-top: 34px;
  padding-top: 20px;
  border-top: 1px solid var(--line);
  color: var(--faint);
  font-size: 13px;
}

@media (max-width: 900px) {
  .split-row {
    grid-template-columns: 1fr;
  }
  .split-row.flip > .txt {
    order: 0;
  }
  .fcols {
    grid-template-columns: 1fr 1fr;
  }
}
@media (max-width: 760px) {
  .nav {
    padding-right: 12px;
  }
  .nav-links {
    display: none;
    position: absolute;
    top: calc(100% + 10px);
    left: 0;
    right: 0;
    flex-direction: column;
    align-items: stretch;
    gap: 2px;
    padding: 10px;
    background: rgba(16, 16, 18, 0.98);
    border: 1px solid var(--line-2);
    border-radius: 18px;
  }
  .nav-links.open {
    display: flex;
  }
  .nav-toggle {
    display: block;
    margin-left: auto;
  }
  .drop-menu {
    position: static;
    transform: none;
    opacity: 1;
    visibility: visible;
    box-shadow: none;
    background: transparent;
    border: 0;
    min-width: 0;
    padding: 0 0 0 10px;
  }
  .drop > button {
    width: 100%;
    justify-content: space-between;
  }
  .fcols {
    grid-template-columns: 1fr;
  }
}
@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
  .marq-in {
    animation: none;
  }
  .rv {
    opacity: 1;
    transform: none;
    transition: none;
  }
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    transition-duration: 0.001ms !important;
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
   THE DESK — homepage blocks
   Six blocks, one idea each. Structure by hairline, never by gradient.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── hero: asymmetric. h1 left at 2/3, subhead right at optical centre. ── */
.hero-desk {
  border-bottom: 1px solid var(--line);
  padding: clamp(56px, 9vw, 104px) 0 clamp(40px, 6vw, 64px);
}
.hero-desk .inner {
  display: grid;
  grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr);
  gap: clamp(28px, 5vw, 72px);
  align-items: end;
}
.hero-desk h1 {
  margin: 0;
  font-size: var(--h1);
  font-weight: 500;
  letter-spacing: -0.045em;
  line-height: 1.02;
  color: var(--ink);
}
/* The product pages put their .sub inside a left-aligned column rather than
   in a right-hand cell, so it takes the glass panel treatment only on the
   homepage. Here it stays plain text at a readable measure. */
.hero-desk .sub {
  margin: 0;
  font-size: var(--sub);
  line-height: 1.5;
  color: var(--dim);
  max-width: 54ch;
}
.hero-desk .cta-row {
  margin-top: 28px;
  display: flex;
  align-items: center;
  gap: 18px;
  flex-wrap: wrap;
}
.hero-desk .trust {
  margin-top: 22px;
  font-family: var(--mono);
  font-size: var(--label);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--faint);
}
@media (max-width: 860px) {
  .hero-desk .inner {
    grid-template-columns: 1fr;
    align-items: start;
  }
}

/* ── the live-quote strip: real market data, the one thing expensive to fake ──
   NAME NOTE: this is .quotes, NOT .tick — `.tick` is already the bullet-row
   component below (29 uses across five pages). Naming this block .tick made
   its border-bottom/background win on source order and restyled every one of
   them. Check for an existing selector before adding a component here. */
.quotes {
  border-bottom: 1px solid var(--line);
  background: var(--panel-2);
}

/* On a phone the bar carries only a wordmark, a toggle and a CTA, but the
   default 18px gap plus 24px gutters still pushed it past the viewport. 480px
   rather than 380px because the CTA label is per-page: /market-making and
   /algorithmic-marketing carry a longer one and overflowed at 390px while the
   others were fine, which is exactly the kind of thing a breakpoint chosen
   against a single page misses. */
@media (max-width: 480px) {
  .nav {
    gap: 10px;
    padding-left: 14px;
    padding-right: 10px;
  }
  .brand {
    min-width: 0;
    overflow: hidden;
    white-space: nowrap;
  }
}

/* ── card hover ──
   Reveal targets get their hover feedback HERE, not from ocb-motion.js. Both
   reveal() and springHover() would otherwise animate the same "y" on the same
   node and race each other. Border-color is untouched by any animation, and
   brightening a hairline is the elevation move this system already uses
   everywhere else, so a card lifts by getting sharper rather than by moving. */
.edge.card,
.edge.card .vis {
  transition: border-color 160ms ease-out;
}
.edge.card:hover {
  border-color: var(--line-2);
}
/* ── the depth chart ──
   The live depth chart under the quote strip. The two read as one market band:
   the strip carries the prices, the book carries the depth behind them, and the
   strip's bottom hairline is the join, so the book declares no top border.

   Deliberately full-bleed. A depth curve is a wide, short shape; boxing it in
   the 1200px container would waste the one thing it has to say. */
.depth {
  margin: 0;
  border-bottom: 1px solid var(--line);
  background: var(--panel-2);
}
.depth figcaption {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px 18px;
  max-width: var(--maxw);
  margin: 0 auto;
  /* 24px, matching .wrap, NOT var(--pad). --pad is 20px and .wrap hardcodes
     24px, so the token and the container disagree; using the token here put the
     caption 4px off every other left edge on the page. The token is the thing
     that is wrong, but fixing it means auditing every call site, so this aligns
     to the container that actually ships. */
  padding: 12px 24px 0;
  font-family: var(--mono);
  font-size: var(--label);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--faint);
}
.depth-pair {
  color: var(--dim);
}
/* Tabular so the price does not jitter sideways on every 30s refresh. */
.depth-spread {
  font-variant-numeric: tabular-nums lining-nums;
  letter-spacing: 0.04em;
  text-transform: none;
  color: var(--ink);
}
.depth-note {
  margin-left: auto;
}
.depth-plot {
  height: 200px;
  padding: 0 24px; /* matches .wrap and the figcaption above; see the note there */
  max-width: var(--maxw);
  margin: 0 auto;
}
.depth-plot svg {
  display: block;
  width: 100%;
  height: 100%;
}
/* Each wall sweeps out FROM THE SPINE, so its transform origin has to sit on the
   spine — not on its own centre, which is where an unqualified origin lands.
   `transform-box: view-box` with `50% 100%` was the tidier expression of that and
   was measured NOT to take effect here: the computed origin came back as
   250px/86px, i.e. the fill box. So the origin is stated per side against the
   fill box instead, which every engine agrees on. The bid path's box spans
   x 0..500 with the spine at its right edge; the ask path's spans 500..1000 with
   the spine at its left. */
.depth-side {
  transform-box: fill-box;
}
.depth-bid {
  transform-origin: 100% 100%;
}
.depth-ask {
  transform-origin: 0% 100%;
}
.depth-spine {
  stroke: var(--line-2);
  stroke-width: 1;
}
.depth .unavailable {
  display: block;
  padding: 84px 0;
  text-align: center;
  font-family: var(--mono);
  font-size: var(--label);
  letter-spacing: 0.06em;
  color: var(--faint);
}
@media (max-width: 720px) {
  .depth-plot {
    height: 132px;
  }
  .depth-note {
    margin-left: 0;
  }
}
/* The strip used to be `hidden` until data arrived and to re-hide itself on
   failure, so a fetch error was indistinguishable from a page that never had a
   market strip. The rule it was protecting is right (never render an invented
   quote), but silence is not the only way to honour it: show placeholders while
   loading, and say so out loud when the feed is unreachable. */
.q-skel {
  display: inline-block;
  width: 92px;
  height: 13px;
  border-radius: 2px;
  background: var(--raise-2);
  animation: label-pulse 1.5s ease-in-out infinite;
}
.quotes .unavailable {
  font-family: var(--mono);
  font-size: var(--label);
  letter-spacing: 0.06em;
  color: var(--faint);
}
.quotes.is-failed .live .dot {
  background: var(--faint);
}
@keyframes label-pulse {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0.45;
  }
}
.quotes .inner {
  display: flex;
  align-items: center;
  gap: 28px;
  /* Horizontal padding must be RESTATED, not zeroed. The element is
     `class="wrap inner"`, and `.quotes .inner` (0,2,0) outranks `.wrap` (0,1,0),
     so `padding: 14px 0` silently cancelled .wrap's 24px gutter. On desktop the
     1200px max-width hid it — the strip lined up with the container anyway. On a
     phone nothing binds the width, so the live quotes sat flush against the
     screen edge while the hero above them was indented 24px. */
  padding: 14px 24px;
  flex-wrap: wrap;
}
.quotes .live {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-family: var(--mono);
  font-size: var(--label);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--faint);
  white-space: nowrap;
}
.quotes .dot {
  width: 6px;
  height: 6px;
  border-radius: var(--pill);
  background: var(--up);
  box-shadow: 0 0 0 3px rgba(74, 222, 128, 0.14);
}
.quotes .row {
  display: flex;
  gap: 26px;
  flex-wrap: wrap;
  align-items: baseline;
}
.quotes .q {
  display: inline-flex;
  align-items: baseline;
  gap: 8px;
  font-family: var(--mono);
  font-size: var(--data);
}
.quotes .q i {
  font-style: normal;
  color: var(--faint);
  letter-spacing: 0.06em;
}
.quotes .q b {
  font-weight: 500;
  color: var(--ink);
}
.quotes .q s {
  text-decoration: none;
  /* These re-render on every poll. Proportional digits change width as the
     value changes, so the row twitches sideways while it updates: the prices
     were already tabular and the deltas next to them were not. */
  font-variant-numeric: tabular-nums;
}
.quotes .q s.up {
  color: var(--up);
}
.quotes .q s.down {
  color: var(--down);
}
/* The desk band reuses .quotes wholesale for layout, dot and as-of, and adds
   only the one element the market strip does not have: a single line of counts
   where that strip carries a row of quotes. */
.pulse p {
  margin: 0;
  font-family: var(--mono);
  font-size: var(--label);
  letter-spacing: 0.06em;
  color: var(--ink);
}
.quotes .as-of {
  margin-left: auto;
  font-family: var(--mono);
  font-size: var(--label);
  color: var(--faint);
  letter-spacing: 0.06em;
}
@media (max-width: 720px) {
  .quotes .as-of {
    margin-left: 0;
    width: 100%;
  }
}

/* ── rate card: nobody else in the category publishes one ── */
.rate {
  width: 100%;
  border-collapse: collapse;
  font-size: 15px;
}
.rate caption {
  text-align: left;
  font-family: var(--mono);
  font-size: var(--label);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--faint);
  padding-bottom: 16px;
}
.rate th,
.rate td {
  text-align: left;
  padding: 15px 18px 15px 0;
  border-bottom: 1px solid var(--line);
  vertical-align: baseline;
}
.rate thead th {
  font-family: var(--mono);
  font-size: var(--label);
  font-weight: 400;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--faint);
  border-bottom-color: var(--line-2);
}
.rate tbody th {
  font-weight: 400;
  color: var(--ink);
}
.rate td {
  font-family: var(--mono);
  font-size: 15px;
  color: var(--dim);
}
.rate td.lead {
  color: var(--ink);
}
.rate .foot {
  margin-top: 14px;
  font-size: 13px;
  color: var(--faint);
}
@media (max-width: 640px) {
  /* `min-width: 0` is the actual fix, and it is not obvious.
     The generic `table { min-width: 460px }` rule above exists for tables inside
     `.tblwrap`, which sets `overflow-x: auto` so a wide table scrolls INSIDE its
     own box. `.rate` has no such wrapper, so it inherited the 460px floor and
     pushed the homepage 109px wider than a 375px phone — the entire page slid
     sideways, on the one section the page is built to reach. Stacking the rows
     did not help because a min-width floor outranks any amount of stacking.
     The display:block trio goes with it: once the cells are blocks, leaving the
     table, caption and tbody as table boxes keeps table layout running around
     content that is no longer laid out as a table. */
  .rate,
  .rate caption,
  .rate tbody {
    display: block;
  }
  .rate {
    min-width: 0;
  }
  .rate thead {
    display: none;
  }
  .rate tbody th,
  .rate td {
    display: block;
    padding: 4px 0;
    border: 0;
  }
  .rate tbody tr {
    display: block;
    padding: 14px 0;
    border-bottom: 1px solid var(--line);
  }
  .rate td::before {
    content: attr(data-l) " ";
    color: var(--faint);
    font-size: var(--label);
    letter-spacing: 0.1em;
    text-transform: uppercase;
  }
}

/* ── two labelled walls, real marks — replaces the one mixed ribbon ── */
.walls {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
}
.walls > div {
  background: var(--void);
  padding: var(--pad);
}
.walls h3 {
  margin: 0 0 14px;
  font-family: var(--mono);
  font-size: var(--label);
  font-weight: 400;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--faint);
}
.walls ul {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.walls li {
  font-family: var(--mono);
  font-size: 13px;
  color: var(--dim);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  padding: 5px 10px;
}
@media (max-width: 720px) {
  .walls {
    grid-template-columns: 1fr;
  }
}

/* ── who we work with ── */
.buyers {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
}
.buyers div {
  background: var(--void);
  padding: var(--pad);
  font-size: 15px;
  color: var(--dim);
}
.buyers b {
  display: block;
  color: var(--ink);
  font-weight: 500;
  margin-bottom: 5px;
}

/* ── contact form — the site had no lead capture at all ── */
.deskform {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
}
.deskform label {
  display: block;
  font-family: var(--mono);
  font-size: var(--label);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--faint);
  margin-bottom: 7px;
}
.deskform input,
.deskform select,
.deskform textarea {
  width: 100%;
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  color: var(--ink);
  font: inherit;
  font-size: 15px;
  padding: 11px 13px;
}
.deskform input:focus,
.deskform select:focus,
.deskform textarea:focus {
  outline: 2px solid var(--accent-soft);
  outline-offset: 1px;
  border-color: var(--accent);
}
.deskform .full {
  grid-column: 1 / -1;
}
.deskform .row-end {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  gap: 18px;
  flex-wrap: wrap;
}
.deskform .alt {
  font-size: 13px;
  color: var(--faint);
}
@media (max-width: 640px) {
  .deskform {
    grid-template-columns: 1fr;
  }
}

/* Visually hidden but announced — for table headers that are structurally
   required but visually redundant. */
.vh {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* section labels + the closing block */
.walls-h {
  margin: 0 0 16px;
  font-family: var(--mono);
  font-size: var(--label);
  font-weight: 400;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--faint);
}
.final-h {
  font-size: var(--h2);
  font-weight: 400;
  letter-spacing: -0.02em;
  line-height: 1.15;
}
.final-sub {
  margin: 12px 0 28px;
}

/* single-column variant of the wall, for pages with only one list */
.walls.one {
  grid-template-columns: 1fr;
}

/* Honeypot. Off-screen rather than display:none — bots commonly skip hidden
   fields but happily fill positioned ones, and screen readers skip it via
   aria-hidden + tabindex=-1 on the wrapper. */
.hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* ═══════════════════════════════════════════════════════════════════════════
   THE HERO, in the kokonut / bklit / motion.dev idiom.

   The earlier pass kept the old restraint: flat ground, hairlines, one solid
   accent, no gradients, no glass. That was the ban list's aesthetic, and the ban
   list was set aside. This is the direction actually asked for.

   What each reference contributes, concretely:
     kokonut  layered depth. A glow BEHIND, glass IN FRONT, and a gradient-filled
              display face. Softer radii (10-14px) rather than 4px.
     bklit    the chart is the hero, framed and lit, with a gradient area fill
              rather than a flat one.
     motion   the page arrives. Spring entrance, scroll-linked parallax on the
              ambient layer, the book sweeping out from the spread.

   Restraint still applies in ONE place: the chromatic budget. The glow is a
   single hue at low alpha, the gradient text runs white to grey rather than
   white to neon, and the accent stays #34b4c8. Layering creates the richness,
   not saturation.
   ═══════════════════════════════════════════════════════════════════════════ */

.hero-desk,
.hero {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  padding-block: clamp(52px, 7.5vh, 92px) clamp(40px, 5.5vh, 68px);
}

/* Layer 0.5: the live book, behind the type and in front of the glow. The
   depth renderer emits its svg with preserveAspectRatio:none, so it fills
   whatever box it is handed; here that box is the entire hero. The mask is the
   part that matters -- an unmasked book puts a bright cyan wall directly under
   the headline. Fading it in from the middle leaves the type side clean and
   lets the depth carry the right half, which is exactly the half that was
   empty. */
.hero-book {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  opacity: 0.34;
  -webkit-mask-image: linear-gradient(90deg, transparent 6%, #000 62%);
  mask-image: linear-gradient(90deg, transparent 6%, #000 62%);
}
.hero-book .depth-plot,
.hero-book svg {
  display: block;
  width: 100%;
  height: 100%;
}
/* Without this the content sits in the same stacking context as the ground and
   the book paints over the headline. */
.hero .wrap.inner {
  position: relative;
  z-index: 1;
}
@media (max-width: 820px) {
  /* On a phone the type occupies the full width, so there is no clean half to
     give the book. It reads as noise behind the headline instead of as depth. */
  .hero-book {
    display: none;
  }
}

/* Layer 1: the ambient glow. Sits behind everything, one hue, low alpha. */
@property --amb-y {
  syntax: "<length>";
  inherits: true;
  initial-value: 0px;
}
.hero-desk::before,
.hero::before {
  content: "";
  position: absolute;
  inset: -30% -10% auto -10%;
  height: 150%;
  z-index: -2;
  translate: 0 var(--amb-y, 0px);
  background:
    radial-gradient(58% 46% at 22% 18%, rgba(52, 180, 200, 0.2), transparent 68%),
    radial-gradient(46% 40% at 82% 6%, rgba(52, 180, 200, 0.11), transparent 70%);
  pointer-events: none;
  will-change: transform;
}

/* Layer 2: a fine grid, masked so it fades out rather than ending in a hard
   edge. This is the one texture in the design; it reads as a trading surface
   rather than decoration. */
.hero-desk::after,
.hero::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background-image:
    linear-gradient(rgba(255, 255, 255, 0.028) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255, 255, 255, 0.028) 1px, transparent 1px);
  background-size: 64px 64px;
  -webkit-mask-image: radial-gradient(72% 62% at 40% 34%, #000 0%, transparent 76%);
  mask-image: radial-gradient(72% 62% at 40% 34%, #000 0%, transparent 76%);
  pointer-events: none;
}

/* The display face, much larger and much tighter than before, with a vertical
   gradient fill. background-clip:text is the whole trick; the fallback colour on
   the line above it is what shows if a browser refuses the clip. */
.hero-desk h1 {
  /* 72px, not 92. At 92 the two-line break the copy is written for became four
     lines with "token." orphaned on its own, and the hero ate the whole fold so
     the live book fell below it. The <br> in the markup is the intended break;
     no max-width, or it fights that. */
  font-size: clamp(36px, 4.9vw, 64px);
  line-height: 1.02;
  /* NOTE: this is the SECOND .hero-desk h1 in this file (the first is ~line 1255)
     and it wins on order, so this is the one that has any effect. Editing the
     other one changes nothing, which cost a round trip to discover. */
  letter-spacing: -0.045em;
  font-weight: 500;
  color: var(--ink);
  /* The fade stops at 0.82, not 0.62. Lower than that and the second line reads
     as disabled text rather than as a gradient. */
  background: linear-gradient(176deg, #ffffff 6%, #e2e7ea 58%, rgba(226, 231, 234, 0.82) 100%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}

/* The eyebrow the hero never had. A live-status chip, which is honest here
   because the market strip below it really is live. */
.hero-tag {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  margin-bottom: 22px;
  padding: 7px 14px 7px 11px;
  border-radius: 9999px;
  border: 1px solid rgba(255, 255, 255, 0.1);
  background: rgba(255, 255, 255, 0.035);
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--dim);
}
.hero-tag .dot {
  width: 6px;
  height: 6px;
  border-radius: 9999px;
  background: var(--up);
  box-shadow: 0 0 0 3px rgba(74, 222, 128, 0.16);
}

/* The explanation column becomes a glass panel: the kokonut move, and it gives
   the asymmetric hero a right-hand mass it did not have. */
.hero-desk .sub {
  align-self: end;
  padding: 22px 24px;
  border-radius: 14px;
  border: 1px solid rgba(255, 255, 255, 0.08);
  background: linear-gradient(
    180deg,
    rgba(255, 255, 255, 0.055) 0%,
    rgba(255, 255, 255, 0.022) 100%
  );
  -webkit-backdrop-filter: blur(18px);
  backdrop-filter: blur(18px);
  font-size: clamp(15px, 1.4vw, 16.5px);
  line-height: 1.62;
  color: var(--dim);
}

/* The primary CTA carries the only gradient with any chroma in it, and a glow
   sized to the button rather than a generic drop shadow. */
.hero-desk .btn.solid,
.hero .btn.solid {
  border: 0;
  border-radius: 11px;
  padding: 14px 22px;
  font-weight: 600;
  color: #04181d;
  background: linear-gradient(135deg, #4cc9dd 0%, #34b4c8 46%, #258b9c 100%);
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.28) inset,
    0 10px 30px -10px rgba(52, 180, 200, 0.55);
  transition:
    transform 0.18s cubic-bezier(0.2, 0.7, 0.3, 1),
    box-shadow 0.18s ease-out,
    filter 0.18s ease-out;
}
.hero-desk .btn.solid:hover,
.hero .btn.solid:hover {
  transform: translateY(-2px);
  filter: brightness(1.06);
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.28) inset,
    0 16px 40px -12px rgba(52, 180, 200, 0.68);
}

.hero-desk .btn.ghost,
.hero .btn.ghost {
  border-radius: 11px;
  padding: 14px 20px;
  border: 1px solid rgba(255, 255, 255, 0.12);
  background: rgba(255, 255, 255, 0.03);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  transition:
    transform 0.18s cubic-bezier(0.2, 0.7, 0.3, 1),
    border-color 0.18s ease-out,
    background 0.18s ease-out;
}
.hero-desk .btn.ghost:hover,
.hero .btn.ghost:hover {
  transform: translateY(-2px);
  border-color: rgba(255, 255, 255, 0.22);
  background: rgba(255, 255, 255, 0.06);
}

/* flex-start, not the inherited center. .cta-row is centred by default, which
   is right where it is used under a centred section head, but in the hero it put
   the buttons 184px to the right of the headline and trust line that bracket
   them. Everything in this column now shares one left edge. */
.hero-desk .cta-row,
.hero .cta-row {
  justify-content: flex-start;
  margin-top: 30px;
  gap: 12px;
}
.hero-desk .trust,
.hero .trust {
  margin-top: 20px;
  color: var(--faint);
}

/* The product-page display face. It already carried half of this treatment: the
   second line is a .fade-txt span doing background-clip:text. That gradient
   bottomed out at #82868c, which is dim enough that the line read as secondary
   copy rather than as part of the headline, so it now lands on the same stop the
   homepage uses. */
.hero h1 {
  /* 64px put us mid-pack against the field: Cumberland sets 96, Gravity 80,
     Kairon 72, CLS 70. On a page whose whole argument is that the desk is
     serious, a mid-pack headline is a mid-pack claim. 6.2vw reaches the cap at
     about 1420px, so the growth is real on a laptop rather than only on a
     display. */
  font-size: clamp(38px, 6.2vw, 88px);
  line-height: 0.98;
  letter-spacing: -0.045em;
}
/* background-IMAGE, not the background shorthand. The shorthand resets every
   background-* longhand to its initial value, including the background-clip:text
   that the base .fade-txt rule sets. Overriding with the shorthand therefore
   un-clipped the gradient, and since the base rule also sets color:transparent
   the second line of every product-page headline rendered as a solid white
   rectangle with the words invisible inside it. */
.fade-txt {
  background-image: linear-gradient(178deg, #ffffff 12%, rgba(226, 231, 234, 0.78) 100%);
}
.hero .eyebrow {
  position: relative;
  padding: 0 0 0 26px;
  border: 0;
  border-radius: 0;
  background: none;
}
.hero .eyebrow::before {
  content: "";
  position: absolute;
  left: 0;
  top: 50%;
  width: 16px;
  height: 1px;
  background: linear-gradient(90deg, var(--accent), rgba(52, 180, 200, 0.15));
}

/* ── the book, framed and lit ──
   bklit's contribution: the chart stops being a strip under the hero and becomes
   a lit object. Glass frame, gradient area fill (already validated as a
   sequential ramp), and a glow beneath it so it sits ON the page rather than in
   a box drawn on it. */
.depth {
  position: relative;
  border: 0;
  background: transparent;
  padding: 0 24px clamp(28px, 5vh, 56px);
  max-width: calc(var(--maxw) + 48px);
  margin: 0 auto;
}
.depth-frame {
  position: relative;
  border-radius: 16px;
  border: 1px solid rgba(255, 255, 255, 0.085);
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.04), rgba(255, 255, 255, 0.015));
  -webkit-backdrop-filter: blur(18px);
  backdrop-filter: blur(18px);
  box-shadow: 0 30px 80px -40px rgba(52, 180, 200, 0.45);
  overflow: hidden;
}
.depth figcaption {
  max-width: none;
  padding: 15px 20px 0;
}
.depth-plot {
  max-width: none;
  padding: 0 8px 8px;
  height: 232px;
}
.depth .depth-spine {
  stroke: rgba(255, 255, 255, 0.22);
}

@media (max-width: 860px) {
  .hero-desk h1 {
    max-width: none;
  }
  .hero-desk .sub {
    padding: 18px 18px;
  }
  .depth-plot {
    height: 150px;
  }
}

/* The ambient layer is the only thing that parallaxes, and only if the viewer
   has not asked for less motion. */
@media (prefers-reduced-motion: reduce) {
  .hero-desk::before {
    transform: none !important;
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
   THE BODY, carried through in the same idiom as the hero.

   The audit's finding about this page was not the palette, it was the rhythm:
   "every section is section > .wrap > .sec-head + grid, repeated about twelve
   times; nothing changes scale, background, or bleed between sections." A hero
   that has depth sitting on a body that has none reads worse than either, so
   the treatment continues rather than stopping at the fold.

   Three moves, in order of how much they do:
     1. .edge becomes glass. It is the one container primitive on the page, so
        restyling it reaches every card, panel and step at once.
     2. Sections alternate. A tinted band every other section gives the page a
        pulse instead of a flat run.
     3. Grids cascade rather than arriving all at once.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── the one container primitive ──
   A 1px border plus a top bevel is what makes glass read as glass: the bevel is
   the light catching the top edge. `inset 0 1px 0` has no blur, so it is a
   hairline, not a shadow. */
.edge {
  border-radius: 14px;
  border: 1px solid rgba(255, 255, 255, 0.075);
  background: linear-gradient(
    180deg,
    rgba(255, 255, 255, 0.045) 0%,
    rgba(255, 255, 255, 0.014) 62%,
    rgba(255, 255, 255, 0.022) 100%
  );
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.055);
  transition:
    border-color 0.22s ease-out,
    transform 0.22s cubic-bezier(0.2, 0.7, 0.3, 1),
    box-shadow 0.22s ease-out;
}

/* Only cards lift. A panel that is not a link should not pretend to be one. */
.edge.card:hover,
.edge.step:hover {
  transform: translateY(-3px);
  border-color: rgba(255, 255, 255, 0.16);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.08),
    0 22px 50px -28px rgba(52, 180, 200, 0.5);
}

/* The product cards carry their own hue, so their glow follows --accent rather
   than the parent cyan. .t-trade and .t-grow already swap that variable. */
.edge.card.t-grow:hover {
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.08),
    0 22px 50px -28px rgba(74, 222, 128, 0.42);
}

/* ── section rhythm ──
   Every other section gets a faint tinted band. Subtle on purpose: the point is
   that the eye registers a change of ground between sections, not that anyone
   notices a colour.

   That comment described an intention this file never implemented: the rule
   below named #engines and #contact, so it fired on 2 of 8 sections and left
   FOUR CONSECUTIVE sections - about two viewports, measured at ~2,000px - with
   no change of ground at all. That dead stretch is what reads as flat.

   Two tiers now. A neutral wash alternates across every even section and does
   the rhythmic work; #engines and #contact keep their stronger accent tint and
   rules, because they are the anchors of the page rather than merely even. */
section {
  position: relative;
}
section:nth-of-type(even)::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: linear-gradient(
    180deg,
    rgba(255, 255, 255, 0.014),
    rgba(255, 255, 255, 0.006) 42%,
    transparent
  );
}
#engines,
#contact {
  isolation: isolate;
}
#engines::before,
#contact::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    radial-gradient(62% 70% at 50% 0%, rgba(52, 180, 200, 0.085), transparent 72%),
    linear-gradient(180deg, rgba(255, 255, 255, 0.018), transparent 40%);
  pointer-events: none;
}
#engines,
#contact {
  border-block: 1px solid rgba(255, 255, 255, 0.06);
}

/* ── section heads ──
   Bigger, tighter, and the eyebrow gets a rule so it reads as a marker rather
   than as small text that happens to be above a heading. */
.sec-head h2 {
  font-size: clamp(26px, 3.1vw, 40px);
  line-height: 1.08;
  letter-spacing: -0.028em;
}
.sec-head .eyebrow,
.walls-h {
  position: relative;
  padding-left: 26px;
  border: 0;
  border-radius: 0;
  background: none;
}
.sec-head .eyebrow::before,
.walls-h::before {
  content: "";
  position: absolute;
  left: 0;
  top: 50%;
  width: 16px;
  height: 1px;
  background: linear-gradient(90deg, var(--accent), rgba(52, 180, 200, 0.15));
}

/* ── the rate card ──
   It is the page's strongest differentiator and it was set as a bare table.
   Framing it makes it read as a published price list rather than as data that
   happened to be left on the page. */
.rate {
  border-collapse: separate;
  border-spacing: 0;
}
.rate caption {
  padding-bottom: 20px;
}
.rate tbody tr {
  transition: background 0.18s ease-out;
}
.rate tbody tr:hover {
  background: rgba(255, 255, 255, 0.022);
}
.rate td,
.rate th {
  border-bottom: 1px solid rgba(255, 255, 255, 0.07);
}

/* ── the two walls ──
   Chips get the same glass treatment so they belong to the same object family
   as the cards. */
.walls > div {
  border-radius: 14px;
  border: 1px solid rgba(255, 255, 255, 0.07);
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.035), rgba(255, 255, 255, 0.012));
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05);
}

/* The closing statement earns the same gradient face as the hero: it is the
   same sentence, and it should land the same way. */
.final-h {
  font-size: clamp(30px, 4.2vw, 56px);
  line-height: 1.04;
  letter-spacing: -0.032em;
  background: linear-gradient(176deg, #ffffff 6%, #e2e7ea 58%, rgba(226, 231, 234, 0.82) 100%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}

@media (prefers-reduced-motion: reduce) {
  .edge,
  .edge.card:hover,
  .edge.step:hover {
    transform: none !important;
  }
}

/* A chart that could not load says so rather than showing nothing at all. Same
   rule as the quote strip and the depth chart: real, or absent and stated. */
.vis-failed::after {
  content: "chart unavailable";
  display: block;
  padding: 44px 0;
  text-align: center;
  font-family: var(--mono);
  font-size: var(--label);
  letter-spacing: 0.06em;
  color: var(--faint);
}

/* ── film grain ──
   A 200x200 fractal-noise tile, inline as a data URI, tiled by CSS. Two reasons
   it is an SVG filter and not a PNG: random noise is incompressible, so the same
   tile as PNG is 4KB at 64px and 66KB at 256px, and the SVG is 540 bytes; and
   an 8-bit dark cyan radial on #0a0a0b BANDS visibly on cheap laptop panels, which
   is most of what makes a dark site look cheap. Grain dithers the banding away.

   Fixed rather than scrolling, so it reads as a property of the screen instead of
   the page. pointer-events:none because it sits above everything. Kept at 3.2% -
   at that level nobody sees grain, they just stop seeing bands.

   The contrast is baked into the tile via feColorMatrix rather than finished with
   a CSS filter on the overlay: filter on a full-viewport fixed element promotes a
   compositing layer for the whole page and costs a re-rasterise on every resize. */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 9;
  pointer-events: none;
  opacity: 0.032;
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22200%22%20height%3D%22200%22%3E%3Cfilter%20id%3D%22g%22%20x%3D%220%22%20y%3D%220%22%20width%3D%22100%25%22%20height%3D%22100%25%22%3E%3CfeTurbulence%20type%3D%22fractalNoise%22%20baseFrequency%3D%22.82%22%20numOctaves%3D%223%22%20stitchTiles%3D%22stitch%22%2F%3E%3CfeColorMatrix%20type%3D%22saturate%22%20values%3D%220%22%2F%3E%3C%2Ffilter%3E%3Crect%20width%3D%22200%22%20height%3D%22200%22%20filter%3D%22url(%23g)%22%2F%3E%3C%2Fsvg%3E");
  background-size: 200px 200px;
}
@media print {
  body::after {
    display: none;
  }
}

/* ── engine affiliation on cards ──
   Every service belongs to one of the two engines, and the page says so in
   words: Market Making and Treasury are Trading, Algorithmic Marketing is
   Growth. .t-trade / .t-grow already swap --accent on those cards, but under the
   old chromatic budget the hue was too quiet to read, so three cards that are
   genuinely two different things looked like three of the same thing.

   A 2px rule along the top edge, in the card own accent. Structural rather than
   decorative: it is the same information as the label, given to the eye first.
   No third hue - only two engines exist, and inventing a third colour for the
   third card would assert a distinction that is not there. */
.card.t-trade,
.card.t-grow {
  position: relative;
  overflow: hidden;
}
.card.t-trade::before,
.card.t-grow::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 2px;
  background: linear-gradient(90deg, var(--accent), transparent 78%);
  opacity: 0.85;
}
.card.t-trade:hover::before,
.card.t-grow:hover::before {
  opacity: 1;
}
@media (prefers-reduced-motion: no-preference) {
  .card.t-trade::before,
  .card.t-grow::before {
    transition: opacity 160ms ease-out;
  }
}

/* ── engine families ──
   The reference this borrows its shape from marks each strategy family with a
   large hairline numeral. Numbers are wrong here: these four are parallel, not a
   sequence, and numbering things that have no order is the tell that the marker
   is decoration.

   The marker is the controller name instead. pmm_perp is what the module is
   actually called in the codebase, which makes it the one piece of chrome on
   this page that cannot be written by someone who does not have the code. Same
   argument as the live order book in the hero: show the thing that is expensive
   to fake. */
.engines-list {
  display: grid;
  gap: 2px;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: var(--r-md, 10px);
  overflow: hidden;
}
.eng {
  background: var(--panel);
  padding: 20px 22px;
}
.eng-id {
  display: inline-block;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.06em;
  color: var(--accent);
  background: var(--accent-soft);
  border: 1px solid rgba(52, 180, 200, 0.28);
  border-radius: 5px;
  padding: 2px 7px;
  margin-bottom: 10px;
}
.eng h3 {
  font-size: 18px;
  margin: 0 0 7px;
}
.eng p {
  margin: 0;
  color: var(--dim);
  font-size: 15px;
  line-height: 1.62;
  max-width: 68ch;
}
@media (min-width: 860px) {
  .engines-list {
    grid-template-columns: 1fr 1fr;
  }
}

/* ── the three pillars ──
   Deliberately three wide cards rather than another 3-across of the same shape
   the page already uses twice: each one carries a claim and then the mechanism
   underneath it, because a claim without its mechanism is the thing every desk
   in this category already says. */
.pillars {
  display: grid;
  gap: 14px;
}
.pillar {
  padding: 22px;
}
.pillar h3 {
  font-size: 18px;
  margin: 0 0 9px;
}
.pillar p {
  margin: 0 0 10px;
  color: var(--dim);
  font-size: 15px;
  line-height: 1.62;
}
/* .pillar .pillar-detail, not .pillar-detail: the rule above is (0,1,1) and a
   bare class is (0,1,0), so a single-class selector loses to it. The font-family
   applied (nothing competes for it) while the size and colour silently did not,
   which is the specificity trap that leaves a rule looking like it works. */
.pillar .pillar-detail {
  font-family: var(--mono);
  font-size: 13px;
  line-height: 1.7;
  color: var(--faint);
  border-top: 1px solid var(--line);
  padding-top: 10px;
  margin-bottom: 0;
}
@media (min-width: 980px) {
  .pillars {
    grid-template-columns: repeat(3, 1fr);
  }
}

/* ── mechanism schematic ──
   A drawn figure, not a chart. The site rule is that anything shaped like data
   must BE data (the hero book is a live Binance feed for exactly that reason),
   so this one is labelled Schematic in the markup and its caption says the rung
   widths are illustrative. It explains an ordering — lean, then shrink, then
   stop quoting a side — which is a mechanism, not a measurement.

   Single hue on purpose. Bid and ask are told apart by which side of the spine
   they sit on, the same encoding the hero depth chart uses, which also survives
   colour blindness. */
.mech {
  margin: 22px 0 0;
  padding: 20px 22px 14px;
  border: 1px solid var(--line);
  border-radius: var(--r-md, 10px);
  background: var(--panel);
}
.mech-cap {
  max-width: 66ch;
  margin-bottom: 16px;
}
.mech-cap h3 {
  font-size: 15px;
  margin: 10px 0 6px;
}
.mech-cap p {
  margin: 0;
  font-size: 13px;
  line-height: 1.6;
  color: var(--dim);
}
.dg-fig svg,
.mech svg {
  width: 100%;
  height: auto;
  display: block;
  overflow: visible;
}
.dg-cap {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  fill: var(--ink);
  text-anchor: middle;
}
.dg-note {
  font-family: var(--mono);
  font-size: 10px;
  fill: var(--faint);
  text-anchor: middle;
}
/* The boundary is the whole point of the custody figure, so it outweighs the
   hairlines that merely organise it. */
.dg-wall {
  stroke: rgba(255, 255, 255, 0.32);
  stroke-width: 2;
}
/* A branch the dispatcher never took is still worth drawing: its absence is
   the mechanism. Recede it rather than delete it. */
.dg-off {
  opacity: 0.45;
}
.dg-dot {
  fill: var(--accent);
  opacity: 0.72;
}
/* The honesty line under a figure that encodes a shape rather than a value.
   Same job as "rung widths are illustrative" on the inventory schematic. */
.dg-caveat {
  margin-top: 10px;
  font-family: var(--mono);
  font-size: 10px;
  color: var(--faint);
}
.dg-flow {
  fill: none;
  stroke: var(--accent);
  stroke-width: 1.5;
}
.dg-flow-blocked {
  stroke: var(--line-2);
  stroke-dasharray: 3 4;
}
.dg-head {
  fill: var(--accent);
}
.dg-stop {
  stroke: var(--line-2);
  stroke-width: 2;
}
.dg-lead {
  stroke: var(--line-2);
  stroke-width: 1;
}
.dg-spine {
  stroke: var(--line-2);
  stroke-width: 1;
}
.dg-bid {
  fill: var(--accent);
  opacity: 0.85;
}
.dg-ask {
  fill: var(--accent);
  opacity: 0.42;
}
@media (max-width: 720px) {
  .mech svg {
    min-width: 520px;
  }
  .mech {
    overflow-x: auto;
  }
}

/* The decay curves are generated from target(t) = mark + (target0 - mark) * 2^(-t/halfLife)
   rather than drawn by eye, so the shape is the policy and not an impression of it. */
.dg-curve {
  fill: none;
  stroke: var(--accent);
  stroke-width: 2;
  stroke-linecap: round;
}
.dg-curve-slow {
  opacity: 0.42;
  stroke-dasharray: 3 4;
}
