/* ============================================================================
   Blocsme — landing
   Design system lifted from the product (pulse.html): SF stack, a fixed type
   scale, a fixed spacing scale, warm graphite canvas, one orange that only ever
   means "this just happened".
   ========================================================================= */

/* ============================================================================
   SF Pro, self-hosted

   The stack used to start with -apple-system, which meant the type was only
   ever SF on Apple hardware — everywhere else the page fell back to Segoe or
   Roboto and the whole scale shifted. These are the real faces, subset to the
   Latin ranges the product uses, so the page sets identically on every
   machine. 8 weights, 184 KB total.

   Chinese is not subset here; PingFang SC / Noto Sans SC still resolve per
   glyph through the fallback chain.
   ========================================================================= */
/* SF Arabic, the face Apple sets its own Arabic interfaces in, shipped from
   here rather than asked for by name — so an Arabic page looks the same on a
   Windows machine as it does on a Mac. One variable file carries every weight
   the site uses (1–1000 on wght) and an optical size axis (17–80) that Safari
   and Chrome move on their own as the type gets bigger: the 84px headline gets
   display proportions, the 13px caption gets text ones, from the same file.
   Subset to Arabic, its presentation forms and the punctuation that sits in an
   Arabic line — 220 KB for the script, against 856 KB for the whole font. */
@font-face{
  font-family:"SF Arabic";
  font-weight:1 1000;
  font-style:normal;
  font-display:swap;
  src:url("../assets/fonts/SF-Arabic.woff2") format("woff2-variations"),
      url("../assets/fonts/SF-Arabic.woff2") format("woff2");
}
/* The same SF Pro, with the Cyrillic the Latin subset left out. These are
   separate files behind a unicode-range, so a page in English or Arabic never
   asks for them — the browser fetches a face only when a glyph on the page
   falls inside its range. 220 KB across eight weights, paid for by Russian
   readers only. */
@font-face{ font-family:"SF Pro Text"; font-weight:400; font-style:normal; font-display:swap;
  src:url("../assets/fonts/SF-Pro-Text-Regular-Cyrillic.woff2") format("woff2");
  unicode-range:U+0400-045F,U+0460-052F,U+1C80-1C88,U+20B4,U+2116,U+2DE0-2DFF,U+A640-A69F; }
@font-face{ font-family:"SF Pro Text"; font-weight:500; font-style:normal; font-display:swap;
  src:url("../assets/fonts/SF-Pro-Text-Medium-Cyrillic.woff2") format("woff2");
  unicode-range:U+0400-045F,U+0460-052F,U+1C80-1C88,U+20B4,U+2116,U+2DE0-2DFF,U+A640-A69F; }
@font-face{ font-family:"SF Pro Text"; font-weight:600; font-style:normal; font-display:swap;
  src:url("../assets/fonts/SF-Pro-Text-Semibold-Cyrillic.woff2") format("woff2");
  unicode-range:U+0400-045F,U+0460-052F,U+1C80-1C88,U+20B4,U+2116,U+2DE0-2DFF,U+A640-A69F; }
@font-face{ font-family:"SF Pro Text"; font-weight:700; font-style:normal; font-display:swap;
  src:url("../assets/fonts/SF-Pro-Text-Bold-Cyrillic.woff2") format("woff2");
  unicode-range:U+0400-045F,U+0460-052F,U+1C80-1C88,U+20B4,U+2116,U+2DE0-2DFF,U+A640-A69F; }
@font-face{ font-family:"SF Pro Display"; font-weight:500; font-style:normal; font-display:swap;
  src:url("../assets/fonts/SF-Pro-Display-Medium-Cyrillic.woff2") format("woff2");
  unicode-range:U+0400-045F,U+0460-052F,U+1C80-1C88,U+20B4,U+2116,U+2DE0-2DFF,U+A640-A69F; }
@font-face{ font-family:"SF Pro Display"; font-weight:600; font-style:normal; font-display:swap;
  src:url("../assets/fonts/SF-Pro-Display-Semibold-Cyrillic.woff2") format("woff2");
  unicode-range:U+0400-045F,U+0460-052F,U+1C80-1C88,U+20B4,U+2116,U+2DE0-2DFF,U+A640-A69F; }
@font-face{ font-family:"SF Pro Display"; font-weight:700; font-style:normal; font-display:swap;
  src:url("../assets/fonts/SF-Pro-Display-Bold-Cyrillic.woff2") format("woff2");
  unicode-range:U+0400-045F,U+0460-052F,U+1C80-1C88,U+20B4,U+2116,U+2DE0-2DFF,U+A640-A69F; }
@font-face{ font-family:"SF Pro Display"; font-weight:800; font-style:normal; font-display:swap;
  src:url("../assets/fonts/SF-Pro-Display-Heavy-Cyrillic.woff2") format("woff2");
  unicode-range:U+0400-045F,U+0460-052F,U+1C80-1C88,U+20B4,U+2116,U+2DE0-2DFF,U+A640-A69F; }
@font-face{ font-family:"SF Pro Text"; font-weight:400; font-style:normal; font-display:swap;
  src:url("../assets/fonts/SF-Pro-Text-Regular.woff2") format("woff2"); }
@font-face{ font-family:"SF Pro Text"; font-weight:500; font-style:normal; font-display:swap;
  src:url("../assets/fonts/SF-Pro-Text-Medium.woff2") format("woff2"); }
@font-face{ font-family:"SF Pro Text"; font-weight:600; font-style:normal; font-display:swap;
  src:url("../assets/fonts/SF-Pro-Text-Semibold.woff2") format("woff2"); }
@font-face{ font-family:"SF Pro Text"; font-weight:700; font-style:normal; font-display:swap;
  src:url("../assets/fonts/SF-Pro-Text-Bold.woff2") format("woff2"); }
@font-face{ font-family:"SF Pro Display"; font-weight:500; font-style:normal; font-display:swap;
  src:url("../assets/fonts/SF-Pro-Display-Medium.woff2") format("woff2"); }
@font-face{ font-family:"SF Pro Display"; font-weight:600; font-style:normal; font-display:swap;
  src:url("../assets/fonts/SF-Pro-Display-Semibold.woff2") format("woff2"); }
@font-face{ font-family:"SF Pro Display"; font-weight:700; font-style:normal; font-display:swap;
  src:url("../assets/fonts/SF-Pro-Display-Bold.woff2") format("woff2"); }
@font-face{ font-family:"SF Pro Display"; font-weight:800; font-style:normal; font-display:swap;
  src:url("../assets/fonts/SF-Pro-Display-Heavy.woff2") format("woff2"); }

/* ----------------------------------------------------------------------------
   PingFang SC, self-hosted

   Apple's Chinese companion to SF Pro. A full weight is ~11 MB, so these are
   subset to the Han characters the products actually print — regenerate with
   tools/build-pingfang.py after any Chinese copy change, exactly as with
   tools/build-zh.py. local() first means an Apple machine uses the installed
   face and downloads nothing.

   The Latin faces stay ahead of this one in the stack, so only Han glyphs
   fall through to it.
   ------------------------------------------------------------------------- */
@font-face{ font-family:"PingFang SC"; font-weight:400; font-style:normal; font-display:swap;
  src:local("PingFang SC"), url("../assets/fonts/PingFangSC-Regular.woff2") format("woff2"); }
@font-face{ font-family:"PingFang SC"; font-weight:500; font-style:normal; font-display:swap;
  src:local("PingFang SC Medium"), local("PingFang SC"), url("../assets/fonts/PingFangSC-Medium.woff2") format("woff2"); }
@font-face{ font-family:"PingFang SC"; font-weight:600; font-style:normal; font-display:swap;
  src:local("PingFang SC Semibold"), url("../assets/fonts/PingFangSC-Medium.woff2") format("woff2"); }
@font-face{ font-family:"PingFang SC"; font-weight:700; font-style:normal; font-display:swap;
  src:local("PingFang SC Semibold"), url("../assets/fonts/PingFangSC-Bold.woff2") format("woff2"); }
@font-face{ font-family:"PingFang SC"; font-weight:800; font-style:normal; font-display:swap;
  src:url("../assets/fonts/PingFangSC-Heavy.woff2") format("woff2"); }

:root{
  --font-text: "SF Pro Text", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-display: "SF Pro Display", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;

  /* Type scale — every font-size on the page is one of these.
     11 uppercase label · 12 caption · 13 secondary · 14 body · 15 body emphasis
     17 card title · 20 section title · 23 panel head · 28 page headline
     34 record title · 44 display figure — plus three marketing display steps
     that the product itself never needs. Nothing in between.

     Spacing scale — every padding, margin and gap is one of these.
     2 4 6 8 10 12 14 16 18 20 inside a component · 24 32 between components
     40 48 64 80 96 120 between blocks. */

  --bg: #161617;
  --canvas: #161617;             /* the ground a section sits on; on dark it is --bg itself */
  --bg-deep: #0A0A0B;
  --bg-elevated: #1C1C1E;
  --bg-raised: #242426;

  --fill: rgba(235,235,245,.08);
  --fill-hover: rgba(235,235,245,.13);
  --fill-active: rgba(235,235,245,.20);
  --track: rgba(235,235,245,.18);

  --label: #F5F5F7;
  --label-2: #A1A1A6;
  --label-3: #8E8E93;        /* the product's caption grey, lifted to clear 4.5:1 on this canvas */

  --separator: rgba(255,255,255,.09);
  --separator-strong: rgba(255,255,255,.16);

  --ink: #F5F5F7;
  --ink-hover: #D2D2D7;
  --on-ink: #1D1D1F;
  --focus: #F5F5F7;

  --measure: 430px;              /* one column width for both halves of the auth pages */

  --live: #FF7A1A;               /* "this just happened" — never decoration */
  --live-soft: rgba(255,122,26,.16);
  --live-on-soft: #FFA25E;
  --recent: #32D74B;             /* a record checked or changed recently */
  --bad: #FF453A;                /* only ever a rejected entry — 5.4:1 on the canvas */
  --brand: #FF8A33;
  --brand-ink: #14100C;
  --grad: linear-gradient(135deg,#F9B233 0%,#F87A1E 45%,#E93A0E 100%);
  --grad-90: linear-gradient(90deg,#F9B233 0%,#F87A1E 45%,#E93A0E 100%);

  --hatch: rgba(245,245,247,.18);
  --hatch-pattern: repeating-linear-gradient(45deg, var(--hatch) 0 2.5px, transparent 2.5px 7px);

  --shadow-pop: 0 18px 48px -10px rgba(0,0,0,.6), 0 0 0 .5px rgba(255,255,255,.12);
  --shadow-panel: 0 40px 90px -50px rgba(0,0,0,.9);

  --gutter: 24px;
  --maxw: 1200px;
  --ease: cubic-bezier(.2,.8,.2,1);
  --ease-out: cubic-bezier(.16,1,.3,1);
}

/* ---------- reset ---------- */
*, *::before, *::after{ box-sizing:border-box; }
/* overflow-x lives here, not on body. A box with one axis not visible computes
   the other to auto, so body{overflow-x:hidden} quietly made BODY the scroll
   container — and on iOS Safari a scrolling body stops being the viewport for
   position:fixed. The nav then sat below a band of page content (the gap at the
   top of the window) and momentum scrolling jumped. The wide tracks clip
   themselves (.pslider, .zoom, .revs), so this is only a safety net. */
html{ -webkit-text-size-adjust:100%; scroll-behavior:smooth; overflow-x:hidden; }
@media (prefers-reduced-motion:reduce){ html{ scroll-behavior:auto; } }
body{
  margin:0; background:var(--bg); color:var(--label);
  font-family:var(--font-text); font-size:17px; line-height:1.5;
  -webkit-font-smoothing:antialiased; -moz-osx-font-smoothing:grayscale;
  letter-spacing:-.024em;
}
h1,h2,h3,h4,p,figure,blockquote,ul,ol{ margin:0; }

/* Headlines set their own line breaks where the phrasing needs one, and let the
   browser even out the rest. Without this a display line ends on a stranded
   word — "300+ project updates a / day.", "anyone asks you about / it." — at
   whatever width the last word happens not to fit. */
h1, h2, h3, .d1, .d2, .d3, .d4{ text-wrap:balance; }
.lead, .hero-sub{ text-wrap:pretty; }

/* An authored <br class="bw"> is a wide-screen luxury. Below the width where
   each clause still fits on its own line, the hard break causes the very bug it
   was written to prevent: the first clause wraps a second time and leaves one
   word stranded. So the break is dropped and text-wrap:balance above evens the
   lines out instead. Display sizes need more room, hence the second step. */
.bw{ display:none; }
@media (min-width:760px){ .bw{ display:inline; } }
.d1 .bw, .hero-h .bw{ display:none; }
@media (min-width:1040px){ .d1 .bw, .hero-h .bw{ display:inline; } }

/* ---------------------------------------------------------------------------
   Chinese

   PingFang SC is Apple's Chinese companion to SF Pro — same designers, same
   optical weight, so a mixed line of Latin and Han does not look like two
   fonts fighting. Windows gets Microsoft YaHei UI, Android the Source Han /
   Noto Sans CJK cut of the same idea. The Latin faces stay FIRST in the stack
   so digits, "Blocsme" and "$2.7T" keep rendering in SF and only the Han
   characters fall through to the CJK face.

   Two things have to change with the face. Han characters are full-width
   squares: the negative tracking that makes a 64px Latin headline tight jams
   them together, so tracking goes to zero and lets the glyphs breathe. And
   Han has no x-height to rest on, so body copy needs more leading than Latin
   to stay readable — 1.5 becomes 1.75.
   ------------------------------------------------------------------------- */
html[lang^="zh"]{
  --font-text: "SF Pro Text", -apple-system, BlinkMacSystemFont, "PingFang SC",
               "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei",
               "Source Han Sans SC", "Noto Sans CJK SC", sans-serif;
  --font-display: "SF Pro Display", -apple-system, BlinkMacSystemFont, "PingFang SC",
                  "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei",
                  "Source Han Sans SC", "Noto Sans CJK SC", sans-serif;
}
html[lang^="zh"] body{ line-height:1.75; }
html[lang^="zh"] h1, html[lang^="zh"] h2, html[lang^="zh"] h3, html[lang^="zh"] h4,
html[lang^="zh"] .d1, html[lang^="zh"] .d2, html[lang^="zh"] .d3, html[lang^="zh"] .d4{
  letter-spacing:0; line-height:1.3;
}
/* A figure that is a word becomes Han here ("Early" -> "提前"), and Han takes no
   negative tracking. The numerals stay Latin on either language, so .fig itself
   keeps its own. */
html[lang^="zh"] .fig.is-word{ letter-spacing:0; text-indent:0; }
/* Chinese paragraphs take no tracking, but a display figure is not prose:
   its numerals stay Latin in either language and keep their own set. The
   word variant above is the one that becomes Han. */
html[lang^="zh"] p:not(.fig), html[lang^="zh"] li{ letter-spacing:0; }
/* A break put in to fit an English headline to its column; the Chinese runs
   shorter and reads better unbroken. */
html[lang^="zh"] br.en-only{ display:none; }
/* An uppercase eyebrow does nothing to Han — there is no case — and the wide
   tracking only pulls the characters apart. */
html[lang^="zh"] .eyebrow{ letter-spacing:.04em; }
/* Han has no spaces, so a long unbroken run overflows a narrow column unless
   the browser is told it may break between characters. */
html[lang^="zh"]{ word-break:normal; line-break:strict; overflow-wrap:anywhere; }

/* ---------------------------------------------------------------------------
   ARABIC
   ---------------------------------------------------------------------------
   The face is SF Arabic — the one Apple draws its own interfaces in, and the
   companion to the SF Pro this site is set in, so a mixed line of Arabic and
   Latin does not look like two fonts arguing. It is a system font on Apple
   platforms and is not ours to ship, so it is asked for by name and the stack
   falls through: Geeza Pro on older Apple systems, Segoe UI on Windows, Noto
   Sans Arabic everywhere else. The Latin faces stay in front of it so digits,
   Blocsme and $2.7T still render in SF Pro and only Arabic letterforms fall
   through to the Arabic face.

   Three things change with the script.

   Tracking goes to zero. Arabic is cursive: letters join, and negative tracking
   does not tighten a word, it pulls the joins apart and breaks the stroke that
   runs through it.

   Leading goes up, 1.5 -> 1.7. Arabic has no x-height to sit on and carries
   marks above and below the baseline, so lines set for Latin collide.

   And the numerals stay Western. These are figures a buyer compares against a
   contract — $415.5M, 24,000, 90% — and the whole product writes them one way.
   ------------------------------------------------------------------------- */
html[lang^="ar"]{
  --font-text: "SF Pro Text", "SF Arabic", -apple-system, BlinkMacSystemFont,
               "Geeza Pro", "Segoe UI", "Noto Sans Arabic", "Noto Naskh Arabic",
               Tahoma, sans-serif;
  --font-display: "SF Pro Display", "SF Arabic", -apple-system, BlinkMacSystemFont,
                  "Geeza Pro", "Segoe UI", "Noto Sans Arabic", "Noto Naskh Arabic",
                  Tahoma, sans-serif;
}
/* ---------------------------------------------------------------------------
   RUSSIAN
   ---------------------------------------------------------------------------
   Same face, same scale. Two adjustments, both because Cyrillic is wider and
   more open than Latin at the same size: the negative tracking comes off the
   headlines, where -.04em closes the counters of о, е and с into blots, and
   the body gets a little more leading because Russian words are longer and
   lines run on. An uppercase eyebrow keeps its tracking — Cyrillic caps take
   it as well as Latin does.
   ------------------------------------------------------------------------- */
html[lang^="ru"] h1, html[lang^="ru"] h2, html[lang^="ru"] h3, html[lang^="ru"] h4,
html[lang^="ru"] .d1, html[lang^="ru"] .d2, html[lang^="ru"] .d3, html[lang^="ru"] .d4{
  letter-spacing:-.018em;
}
html[lang^="ru"] body{ line-height:1.6; }
html[lang^="ru"] p, html[lang^="ru"] li{ letter-spacing:-.008em; }
/* Subheads sit tighter than body text. Cyrillic at 18–32px carries more
   sidebearing than the Latin it was set for, so the smaller headings and the
   section ledes read loose at the display tracking. */
html[lang^="ru"] h3, html[lang^="ru"] h4,
html[lang^="ru"] .d3, html[lang^="ru"] .d4,
html[lang^="ru"] .zc-card-h, html[lang^="ru"] .faq-item summary,
html[lang^="ru"] .case-h, html[lang^="ru"] .shead h2{ letter-spacing:-.026em; }
html[lang^="ru"] .lead{ letter-spacing:-.016em; }
/* The break stays. Its two sides are two separate strings in the dictionary,
   so hiding it runs the sentences together with no space between them — which
   is exactly what it did. */

html[lang^="ar"]{ font-optical-sizing:auto; }
html[lang^="ar"] body{ line-height:1.7; }
/* Arabic needs more leading than Latin, not a lot more. 1.45 was set to clear
   the marks above and below the baseline and cleared the headline as well —
   at 84px that is a 38px gap between two lines of a single sentence, and the
   hero stopped reading as one block. The display sizes come back close to the
   Latin figure; the smaller headings keep a little more, because that is where
   the marks actually collide. */
html[lang^="ar"] h1, html[lang^="ar"] h2,
html[lang^="ar"] .d1, html[lang^="ar"] .d2{
  letter-spacing:0; line-height:1.18;
}
html[lang^="ar"] h3, html[lang^="ar"] h4,
html[lang^="ar"] .d3, html[lang^="ar"] .d4{
  letter-spacing:0; line-height:1.3;
}
html[lang^="ar"] p, html[lang^="ar"] li, html[lang^="ar"] .lead{ letter-spacing:0; }
/* A figure is not prose: its numerals are Latin in every language and keep the
   tracking they were drawn with. A figure that is a *word* becomes Arabic, and
   Arabic takes none. */
html[lang^="ar"] .fig.is-word{ letter-spacing:0; text-indent:0; }
/* A figure keeps Western numerals and therefore its own direction, isolated so
   it cannot drag the punctuation around it. But an isolated LTR run inside an
   RTL block still lands on the block's start edge only if it is told to: on
   its own it stacked to the left of its cell while every label beside it sat
   right, which is what made the stat row look unaligned. */
html[lang^="ar"] .num{ direction:ltr; unicode-bidi:isolate; text-align:right; }
[dir="rtl"] .figcell b, [dir="rtl"] .figcell span,
[dir="rtl"] .fig, [dir="rtl"] .sig-num b, [dir="rtl"] .rstats b,
[dir="rtl"] .live-value, [dir="rtl"] .live-delta,
[dir="rtl"] .foot-tel, [dir="rtl"] .foot-mail{ text-align:right; }
/* a phone number is an LTR run; without the isolate the leading + jumps */
[dir="rtl"] .foot-tel{ direction:ltr; unicode-bidi:isolate; }
/* An uppercase eyebrow does nothing to Arabic — there is no case — and the wide
   tracking only breaks the joins. */
html[lang^="ar"] .eyebrow{ letter-spacing:.02em; text-transform:none; }
/* The breaks stay. They were put in to fit an English headline to its column,
   and the Arabic runs to a similar measure — but more to the point, the two
   sides of such a break are two separate strings in the dictionary, and hiding
   the break between them ran the sentences together with no space at all. */

/* ---------- right to left ----------
   Most of the mirroring is free: the stylesheet asks for inline-start and
   inline-end rather than left and right, so the box model turns itself round.
   What is left is everything the cascade cannot flip on its own — a gradient
   with a direction baked into it, a shape drawn with a border, a transform in
   pixels, an icon that points somewhere. */
/* the arrowhead is drawn, not laid out: it is turned, not moved */
[dir="rtl"] .mp-req-arrow{ transform:scaleX(-1); }
/* ---------- the shelves are marquees, not layout ----------
   A drifting shelf is positioned in pixels by script, from a left origin, and
   duplicated so it can loop without a seam. Turning that round is not a mirror,
   it is a different animation: in RTL the track lays itself out from the right
   edge, runs off into negative space, and the two copies land on top of each
   other — which is exactly what it did. The track keeps its own direction and
   each card turns instead, so the cards read right to left and the shelf still
   loops. The same holds for the two tickers, whose keyframes translate by a
   fixed percentage. */
[dir="rtl"] .pslider, [dir="rtl"] .pslider-track,
[dir="rtl"] .marquee, [dir="rtl"] .marquee-track,
[dir="rtl"] .markets, [dir="rtl"] .markets-track,
[dir="rtl"] .revs, [dir="rtl"] .revs-track{ direction:ltr; }
[dir="rtl"] .tile,
[dir="rtl"] .rev-card,
[dir="rtl"] .marquee-track span,
[dir="rtl"] .markets-track > span{ direction:rtl; }
/* The shelf is pulled to the full width with a negative inline margin computed
   from the viewport. In RTL that margin resolves against the other edge, which
   is what pushed the reviews off their axis and left a strip of the section
   showing through beside them. Physical margins, because this is geometry. */
[dir="rtl"] .revs{ margin-inline:0; margin-left:calc(50% - 50vw); margin-right:calc(50% - 50vw); }

/* ---------- the skyline ----------
   The city is drawn into a canvas with its light and its density weighted to
   one side, to sit behind a headline that starts on the other. The headline
   changed sides, so the drawing does: one flip of the element, which costs
   nothing and keeps every frame the script draws. */
[dir="rtl"] .hero-bg, [dir="rtl"] .final-bg{ transform:scaleX(-1); }

/* a chevron, a caret, an arrow in a button — glyphs that mean "onward" */
[dir="rtl"] .btn svg use[href="#i-arrow"],
[dir="rtl"] .sec-cta svg use[href="#i-arrow"]{ transform-box:fill-box; transform-origin:center; transform:scaleX(-1); }
/* the overlapping avatars stack the other way */
[dir="rtl"] .faces span + span{ margin-inline-start:-9px; }
/* the quotation mark hangs off the reading edge */
[dir="rtl"] .rev-q::before{ transform:scaleX(-1); }

ul,ol{ padding:0; list-style:none; }
img,svg,video{ display:block; max-width:100%; }
button{ font:inherit; color:inherit; background:none; border:0; padding:0; cursor:pointer; }
a{ color:inherit; text-decoration:none; }
:focus-visible{ outline:2px solid var(--focus); outline-offset:2px; border-radius:4px; }
::selection{ background:var(--live); color:var(--brand-ink); }
.num{ font-variant-numeric:tabular-nums; font-feature-settings:"tnum" 1; }
.ellipsis{ min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.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;
}

/* ---------- layout primitives ---------- */
.wrap{ width:100%; max-width:var(--maxw); margin-inline:auto; padding-inline:var(--gutter); }
.wrap-wide{ max-width:1400px; }
.section{ padding-block:96px; position:relative; }
.section-tight{ padding-block:64px; }
@media (max-width:860px){
  .section{ padding-block:64px; }
  .section-tight{ padding-block:48px; }
}

/* ---------- type ---------- */
.eyebrow{
  display:inline-flex; align-items:center; gap:8px;
  font-size:11px; font-weight:700; letter-spacing:.1em; text-transform:uppercase;
  color:var(--label-2);
}
.eyebrow .dot{ width:5px; height:5px; border-radius:50%; background:var(--live); flex:0 0 auto; }

.d1{
  font-family:var(--font-display);
  font-size:clamp(40px, 6.4vw, 84px); line-height:1.0; font-weight:700; letter-spacing:-.04em;
}
.d2{
  font-family:var(--font-display);
  font-size:clamp(32px, 4.4vw, 56px); line-height:1.03; font-weight:700; letter-spacing:-.034em;
}
.d3{
  font-family:var(--font-display);
  font-size:clamp(26px, 3vw, 40px); line-height:1.08; font-weight:700; letter-spacing:-.028em;
}
.d4{ font-family:var(--font-display); font-size:23px; line-height:1.2; font-weight:700; letter-spacing:-.022em; }
.lead{ font-size:clamp(17px, 1.5vw, 20px); line-height:1.55; color:var(--label-2); letter-spacing:-.027em; }
.muted{ color:var(--label-2); }
.dim{ color:var(--label-3); }
.hot{ color:var(--live); }
.grad-text{ background:var(--grad-90); -webkit-background-clip:text; background-clip:text; color:transparent; }

/* ---------- buttons ---------- */
.btn{
  position:relative; display:inline-flex; align-items:center; justify-content:center; gap:8px;
  height:48px; padding:0 22px; border-radius:12px;
  font-size:15px; font-weight:600; white-space:nowrap;
  transition:background-color .15s var(--ease), color .15s var(--ease), transform .15s var(--ease), opacity .15s;
  letter-spacing:-.016em;
}
.btn:active{ transform:scale(.98); }
.btn-primary{ background:var(--ink); color:var(--on-ink); }
.btn-primary:hover{ background:var(--ink-hover); }
.btn-brand{ background:var(--grad); color:var(--brand-ink); }
.btn-brand:hover{ opacity:.9; }
.btn-ghost{ background:var(--fill); color:var(--label); }
.btn-ghost:hover{ background:var(--fill-hover); }
.btn-sm{ height:38px; padding:0 16px; font-size:14px; border-radius:10px; letter-spacing:-.011em; }
.btn-lg{ height:54px; padding:0 28px; font-size:17px; border-radius:14px; letter-spacing:-.024em; }

/* A large CTA whose label carries the whole offer. `nowrap` on .btn keeps a
   short label on one line; a label this long would simply push the page
   sideways on a phone, so this one is allowed to set to two lines and grows
   from the 54px floor instead of being pinned to it. */
.btn-wrap{
  white-space:normal; height:auto; min-height:54px; padding:12px 24px;
  line-height:1.25; text-align:center; max-width:100%;
}
@media (max-width:560px){
  .btn-lg{
    white-space:normal; height:auto; min-height:54px; padding:12px 22px;
    line-height:1.25; text-align:center; max-width:100%;
  }
}

/* ---------- reveal on scroll ---------- */
.rv{ opacity:0; transform:translateY(20px); transition:opacity .7s var(--ease-out), transform .7s var(--ease-out); }
.rv.is-in{ opacity:1; transform:none; }
.rv-d1{ transition-delay:.07s; } .rv-d2{ transition-delay:.14s; }
.rv-d3{ transition-delay:.21s; } .rv-d4{ transition-delay:.28s; }
@media (prefers-reduced-motion:reduce){
  .rv{ opacity:1; transform:none; transition:none; }
  *,*::before,*::after{ animation-duration:.001ms !important; animation-iteration-count:1 !important; transition-duration:.001ms !important; }
}

/* ============================================================================
   NAV
   ========================================================================= */
.nav{
  position:fixed; inset:0 0 auto 0; z-index:60; height:64px;
  display:flex; align-items:center;
  background:rgba(22,22,23,0); border-bottom:1px solid transparent;
  transition:background-color .25s var(--ease), border-color .25s var(--ease), backdrop-filter .25s;
}
.nav.is-stuck{
  background:rgba(22,22,23,.78); border-bottom-color:var(--separator);
  -webkit-backdrop-filter:saturate(180%) blur(20px); backdrop-filter:saturate(180%) blur(20px);
}
.nav-in{ display:flex; align-items:center; gap:24px; width:100%; max-width:1400px; margin-inline:auto; padding-inline:var(--gutter); }
.brand{ display:inline-flex; align-items:center; gap:9px; flex:0 0 auto; }
.brand-mark{ width:26px; height:26px; border-radius:8px; flex:0 0 auto; }
.brand-word{ height:15px; width:auto; color:var(--label); }
.nav-links{ display:flex; align-items:center; gap:4px; margin-inline-start:12px; }
.nav-links a{
  height:34px; padding:0 12px; border-radius:8px; display:inline-flex; align-items:center;
  font-size:14px; font-weight:500; color:var(--label-2);
  transition:color .12s, background-color .12s;
  letter-spacing:-.011em;
}
.nav-links a:hover{ color:var(--label); background:var(--fill); }
.nav-cta{ margin-inline-start:auto; display:flex; align-items:center; gap:10px; }
/* the offer in full while the bar has room for it, the short form once it doesn't */
.cta-short{ display:none; }
@media (max-width:1080px){ .cta-long{ display:none; } .cta-short{ display:inline; } }
@media (max-width:900px){ .nav-links{ display:none; } }
/* all three controls stay on a phone; the bar tightens instead of dropping one.
   The wordmark is the one thing on the bar that is not a control, so it is what
   gives way — the mark alone still reads as the brand. */
@media (max-width:520px){
  .nav-in{ gap:12px; }
  .nav-cta{ gap:6px; }
  .nav-cta .btn-sm{ padding:0 11px; font-size:13px; letter-spacing:-.006em; }
  .lang-btn{ gap:5px; padding:0 8px; }
  .lang-btn svg:last-child{ display:none; }
}

/* ============================================================================
   HERO
   ========================================================================= */
.hero{ position:relative; padding-top:136px; padding-bottom:0; overflow:hidden; }

/* The block city sits under everything, and the radial glow sits over it as haze
   rather than under it as a backdrop — which is the only reason both are here. */
.hero-bg{
  position:absolute; left:0; right:0; top:0; height:780px; z-index:0; pointer-events:none;
  -webkit-mask-image:linear-gradient(180deg, transparent 0, #000 13%, #000 50%, transparent 93%);
          mask-image:linear-gradient(180deg, transparent 0, #000 13%, #000 50%, transparent 93%);
}
/* the opacity is on the canvas, not the wrapper: on the wrapper it takes the
   scrim below down with it, and the scrim is what keeps the copy readable */
.hero-bg canvas{ display:block; width:100%; height:100%; opacity:.88; }

/* The stops are in pixels, not per cent, because the copy is: it is bounded by a
   max-width, so its right edge sits at roughly the same place on every screen.
   Solid to where the secondary type ends, then open as fast as it can.

   It has to be solid there, not merely dim. A lit --live tower is brighter than
   --label-2 text is, so anywhere one can pass behind that text the contrast is
   about 1.8:1 whatever the canvas opacity — the only fix is to not put the city
   there at all. Past that edge it can be as bright as it likes. */
.hero-bg::after{
  content:""; position:absolute; inset:0;
  background:linear-gradient(90deg,
    var(--bg) 0, var(--bg) 720px,
    rgba(22,22,23,.45) 820px, rgba(22,22,23,.1) 930px, transparent 1020px);
}
@media (max-width:860px){
  /* the copy runs the whole width here, so the city is texture or nothing */
  .hero-bg canvas{ opacity:.5; }
  .hero-bg::after{
    background:linear-gradient(90deg, var(--bg) 0, rgba(22,22,23,.9) 30%, rgba(22,22,23,.74) 100%);
  }
}

.hero::before{
  content:""; position:absolute; left:50%; top:-260px; width:min(1200px,140%); height:760px;
  transform:translateX(-50%); pointer-events:none; z-index:1;
  background:radial-gradient(50% 50% at 50% 50%, rgba(255,122,26,.13), transparent 70%);
  filter:blur(20px);
}
.hero > .wrap{ position:relative; z-index:2; }
.hero-in{ position:relative; z-index:2; }
.hero-badge{
  display:inline-flex; align-items:center; gap:9px; height:30px; padding:0; padding-inline:10px 13px;
  border-radius:15px; background:var(--live-soft); color:var(--live-on-soft);
  font-size:12px; font-weight:600; letter-spacing:.01em;
}
.hero h1{ margin-top:22px; max-width:17ch; }
/* Inside the headline a figure is not a separate display element — it is the
   same line of type, so it takes the headline's size and weight instead of the
   stat shelf's. All it keeps is what a numeral run actually needs: tabular,
   lining figures, and a shade more negative tracking, because numerals set
   wider than letters at the same size. */
.hero h1 .fig{
  font-size:inherit; font-weight:inherit; line-height:inherit;
  letter-spacing:-.046em; text-indent:0;
  font-variant-numeric:tabular-nums lining;
}
.hero-sub{ margin-top:22px; max-width:56ch; }
.hero-acts{ margin-top:32px; display:flex; flex-wrap:wrap; align-items:center; gap:12px; }
.hero-note{ margin-top:16px; font-size:13px; color:var(--label-3); display:flex; align-items:center; gap:8px; flex-wrap:wrap; letter-spacing:-.006em; }
.hero-note .sep{ width:3px; height:3px; border-radius:50%; background:var(--label-3); }

@media (max-width:860px){ .hero-bg{ height:560px; } }

/* ---------- hero product shot: the search / map interface ---------- */
.shot{
  position:relative; margin-top:56px;
  border-radius:20px 20px 0 0; overflow:hidden;
  border:1px solid var(--separator-strong); border-bottom:0;
  background:var(--bg-elevated);
  transform:perspective(2000px) rotateX(3deg) translateY(14px) scale(.985); transform-origin:50% 0;
  opacity:0; transition:transform 1.1s var(--ease-out), opacity .8s var(--ease-out);
}
.shot.is-in{ transform:perspective(2000px) rotateX(0) translateY(0) scale(1); opacity:1; }
/* the shot dissolves into the figures band under it — the fade has to end in the
   colour that is actually behind it, or the gap reads as a hole */
/* the shot fades out rather than being cut off, and casts nothing downward —
   the band below it should read as the next thing, not as something in shadow */
.shot::after{
  content:""; position:absolute; inset:auto 0 0 0; height:200px; pointer-events:none;
  background:linear-gradient(180deg, transparent, var(--bg) 92%);
}
.shot-bar{
  display:flex; align-items:center; gap:10px; height:44px; padding-inline:14px;
  border-bottom:1px solid var(--separator); background:var(--bg-raised);
}
.shot-dots{ display:flex; gap:6px; }
.shot-dots i{ width:10px; height:10px; border-radius:50%; background:var(--fill-active); }
.shot-url{
  flex:1; max-width:340px; margin-inline:auto; height:26px; border-radius:7px;
  background:var(--bg); display:flex; align-items:center; justify-content:center; gap:7px;
  font-size:12px; color:var(--label-3);
}

/* ============================================================================
   THE PRODUCT REPLICAS — shared chrome
   ========================================================================= */
.ui{ background:var(--bg); color:var(--label); font-size:14px; letter-spacing:-.011em; }
.ui-toolbar{
  display:flex; align-items:center; gap:10px; padding:10px 14px;
  border-bottom:1px solid var(--separator); background:var(--bg-elevated);
}
.ui-search{
  flex:1; min-width:0; max-width:420px; height:30px; border-radius:8px; background:var(--fill);
  display:flex; align-items:center; gap:8px; padding-inline:10px; font-size:13px; color:var(--label-3);
  white-space:nowrap; overflow:hidden;
  letter-spacing:-.006em;
}
.ui-search svg{ flex:0 0 auto; }
.kbd{
  margin-inline-start:auto; padding:1px 5px; border-radius:4px; background:var(--fill);
  font-size:11px; color:var(--label-3);
}
.chip{
  display:inline-flex; align-items:center; gap:6px; height:28px; padding:0 11px;
  border-radius:8px; background:var(--fill); color:var(--label-2);
  font-size:12px; font-weight:500; white-space:nowrap;
  transition:background-color .12s, color .12s;
}
.chip:hover{ background:var(--fill-hover); color:var(--label); }
.chip.is-on{ background:var(--fill-hover); color:var(--label); }
.chip .d{ width:6px; height:6px; border-radius:50%; background:var(--recent); }
.chip .d.hot{ background:var(--live); }

/* stage + progress — the product's own record vocabulary */
.stage{ display:inline-flex; align-items:center; gap:7px; font-size:12px; font-weight:500; color:var(--label); white-space:nowrap; min-width:0; }
.stage svg{ color:var(--label-2); flex:0 0 auto; }
/* Stage names run much longer in Russian ("Тендер на проектирование" against
   "Design tender"), so the label truncates wherever it is placed rather than
   spilling over whatever sits beside it. */
.stage > span{ min-width:0; overflow:hidden; text-overflow:ellipsis; }
.progress{ display:inline-flex; align-items:center; gap:8px; font-size:12px; font-weight:500; color:var(--label-2); white-space:nowrap; flex:0 0 auto; }
.progress .num{ min-width:32px; text-align:end; }
.bar{ width:44px; height:4px; border-radius:2px; background:var(--track); overflow:hidden; }
.bar i{ display:block; height:100%; border-radius:inherit; background:var(--label); transition:width 1.2s var(--ease-out); }
.is-recent{ color:var(--label); font-weight:600; }
.is-recent::before{
  content:""; display:inline-block; width:6px; height:6px; margin-inline-end:6px;
  border-radius:50%; background:var(--recent); vertical-align:1px;
}

/* ---------- project tile — lifted from the product's Discover view ---------- */
/* The same card the product uses: a surface you can see, not an outline you
   have to read. The hover lifts the surface rather than the edge. */
.tile{
  position:relative; display:flex; flex-direction:column; min-width:0; height:100%;
  border-radius:14px; overflow:hidden; background:var(--bg-elevated);
  color:inherit; text-decoration:none; cursor:pointer;
  transition:background-color .15s, box-shadow .15s, transform .25s var(--ease);
}
.tile:hover{ background:var(--bg-raised); box-shadow:0 10px 30px -18px rgba(0,0,0,.9); }
/* 3:2, not 16:9. A letterbox is the wrong shape for a photograph of a tower:
   whatever the crop, the roofline — the part that identifies the building —
   falls outside it. The extra third of height costs 47px of card. */
.tile-media{ display:block; position:relative; flex:0 0 auto; aspect-ratio:3/2; background:var(--fill); }
.tile-media img{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover; }
.tile-media.hatch{ display:grid; place-items:center; background-image:var(--hatch-pattern); }
.hatch-lock{
  display:inline-flex; align-items:center; gap:7px; padding:7px 13px; border-radius:999px;
  background:var(--bg); color:var(--label-2); font-size:12px; font-weight:500;
}
.tile-flag{
  position:absolute; inset-inline-start:10px; top:10px; z-index:2;
  display:inline-flex; align-items:center; gap:5px; height:22px; padding:0 9px; border-radius:7px;
  background:var(--recent); color:#08240F;
  font-size:11px; font-weight:700; letter-spacing:.04em; text-transform:uppercase;
}
.tile-body{ display:flex; flex-direction:column; flex:1; min-height:0; gap:8px; padding:12px 14px 14px; }
.tile-head{ display:grid; grid-template-columns:minmax(0,1fr) auto; column-gap:10px; align-items:start; }
.tile-title{
  display:-webkit-box; -webkit-box-orient:vertical; -webkit-line-clamp:2; overflow:hidden;
  min-height:2.7em; font-size:14px; font-weight:600; line-height:1.35;
  letter-spacing:-.011em;
}
.tile-value{ font-size:14px; font-weight:600; line-height:1.35; white-space:nowrap; letter-spacing:-.011em; }
.tile-meta{ display:flex; min-width:0; font-size:13px; color:var(--label-2); letter-spacing:-.006em; }
.tile-status{ display:flex; align-items:center; gap:10px; min-width:0; }
.tile-status .progress{ margin-inline-start:auto; }
.tile-foot{ margin-top:auto; padding-top:10px; border-top:1px solid var(--separator); }
.tile-teaser, .tile-updated{ display:block; font-size:12px; line-height:1.5; color:var(--label-3); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }

/* ============================================================================
   HERO SHOT — search + map
   ========================================================================= */
.srch{ display:grid; grid-template-columns:330px minmax(0,1fr); grid-template-rows:auto minmax(0,1fr); height:640px; }
.srch-filters{
  grid-column:1 / -1; display:flex; align-items:center; gap:6px; padding:10px 14px;
  border-bottom:1px solid var(--separator); overflow:hidden;
}
.srch-list{ border-inline-end:1px solid var(--separator); overflow:hidden; display:flex; flex-direction:column; }
.srch-count{ padding:12px 14px 8px; }
.srch-count b{ display:block; font-size:14px; font-weight:600; letter-spacing:-.011em; }
.srch-count span{ display:block; font-size:12px; color:var(--label-3); }
.srch-rows{ flex:1; min-height:0; overflow:hidden; -webkit-mask-image:linear-gradient(180deg,#000 calc(100% - 56px),transparent); mask-image:linear-gradient(180deg,#000 calc(100% - 56px),transparent); }
.srow{ position:relative; display:grid; grid-template-columns:52px minmax(0,1fr); gap:11px; padding:11px 14px; }
.srow + .srow{ border-top:1px solid var(--separator); }
.srow:hover{ background:rgba(235,235,245,.05); }
.srow-thumb{ width:52px; height:52px; border-radius:8px; object-fit:cover; background:var(--fill); }
.srow-thumb.hatch{ background-image:var(--hatch-pattern); }
.srow-main{ min-width:0; display:flex; flex-direction:column; gap:4px; }
.srow-top{ display:grid; grid-template-columns:minmax(0,1fr) auto; gap:8px; align-items:baseline; }
.srow-name{ font-size:13px; font-weight:600; line-height:1.3; letter-spacing:-.006em; }
.srow-val{ font-size:13px; font-weight:600; white-space:nowrap; letter-spacing:-.006em; }
.srow-sub{ font-size:12px; color:var(--label-2); }
.srow-status{ display:flex; align-items:center; gap:8px; margin-top:2px; }
.srow-new{
  position:absolute; inset-inline-start:6px; top:6px; z-index:2; height:18px; padding:0 6px; border-radius:5px;
  background:var(--recent); color:#0A2A12; font-size:10px; font-weight:700; letter-spacing:.03em;
  display:inline-flex; align-items:center;
}
.srch-map{
  position:relative; overflow:hidden;
  background:var(--bg-deep) radial-gradient(110% 80% at 52% 46%, rgba(255,255,255,.045), transparent 64%);
}
.srch-map canvas{ position:absolute; inset:0; width:100%; height:100%; }

/* ---------- the records, sitting on the map ----------
   Round, and inert: the map is a demonstration, not a control, so it takes no
   pointer input at all and the only thing that moves is the scripted cursor. */
.map-pins{ position:absolute; inset:0; pointer-events:none; }
.pin-anchor{ position:absolute; width:0; height:0; z-index:1; }
.pin-anchor.is-hot{ z-index:2; }
.pin-anchor.is-on{ z-index:3; }
.pin-dot{
  position:absolute; left:0; top:0; width:9px; height:9px; margin:-4.5px 0 0 -4.5px;
  border-radius:50%; background:var(--label);
  box-shadow:0 0 0 3px rgba(10,10,11,.8), 0 1px 4px rgba(0,0,0,.6);
  transition:transform .18s var(--ease), background-color .18s;
}
.pin-anchor.is-hot .pin-dot{ background:var(--live); }
.pin-anchor.is-on .pin-dot{ transform:scale(1.4); background:var(--live); }
.pin-anchor.is-tap .pin-dot{ transform:scale(.85); }
/* the ring only leaves a record that moved today */
.pin-anchor.is-hot::after{
  content:""; position:absolute; left:0; top:0; width:9px; height:9px; margin:-4.5px 0 0 -4.5px;
  border-radius:50%; border:1px solid var(--live);
  animation:pin-ping 2.8s var(--ease) infinite;
}
@keyframes pin-ping{ 0%{ transform:scale(1); opacity:.8 } 70%,100%{ transform:scale(3.6); opacity:0 } }

/* ---------- what the pins do not show ----------
   The product's own cluster badge: the count is the whole message, so it is
   given the room to be read, and the badge grows with what it holds. */
.map-clusters{ position:absolute; inset:0; pointer-events:none; }
.cl-anchor{ position:absolute; width:0; height:0; }
.cluster{
  position:absolute; left:0; top:0; transform:translate(-50%,-50%) scale(.82);
  display:inline-flex; align-items:center; justify-content:center; gap:6px;
  height:28px; min-width:28px; padding:0 10px; border-radius:14px;
  background:var(--bg-raised); color:var(--label);
  box-shadow:0 1px 3px rgba(0,0,0,.5), 0 0 0 .5px rgba(255,255,255,.16);
  font-variant-numeric:tabular-nums; white-space:nowrap;
  opacity:0; transition:opacity .5s var(--ease-out), transform .5s var(--ease-out);
  transition-delay:calc(var(--i) * .06s);
}
.is-in .cluster{ opacity:1; transform:translate(-50%,-50%) scale(1); }
.cluster b{ font-size:12px; font-weight:700; letter-spacing:-.01em; }
.cluster.is-md{ height:32px; min-width:32px; padding:0 11px; border-radius:16px; }
.cluster.is-md b{ font-size:13px; letter-spacing:-.006em; }
.cluster.is-lg{ height:38px; min-width:38px; padding:0 13px; border-radius:19px; }
.cluster.is-lg b{ font-size:15px; letter-spacing:-.016em; }
.cluster.is-xl{ height:46px; min-width:46px; padding:0 16px; border-radius:23px; }
.cluster.is-xl b{ font-size:18px; letter-spacing:-.025em; }
@media (prefers-reduced-motion:reduce){ .cluster{ opacity:1; transform:translate(-50%,-50%); } }

/* the preview card is the product's own project tile */
.mc{
  position:absolute; z-index:4; width:272px; pointer-events:none;
  opacity:0; transform:scale(.96); transform-origin:0 50%;
  filter:drop-shadow(0 18px 40px rgba(0,0,0,.65));
  transition:opacity .22s var(--ease), transform .22s var(--ease-out), left .32s var(--ease-out), top .32s var(--ease-out);
}
.mc.is-on{ opacity:1; transform:scale(1); }
.mc .tile{ background:var(--bg-elevated); border-color:var(--separator-strong); }
@media (max-width:560px){ .mc{ width:230px; } }

/* the view switch, and how the shot folds down on a narrow screen — these sit
   with the search panel and were lost when the pin styles were swapped in */
.srch-views{ display:flex; gap:2px; margin-inline-start:auto; padding:2px; border-radius:9px; background:var(--fill); }
.srch-views b{
  height:24px; padding:0 10px; border-radius:7px; display:inline-flex; align-items:center;
  font-size:12px; font-weight:500; color:var(--label-3);
}
.srch-views b.is-on{ background:var(--bg-raised); color:var(--label); }
@media (max-width:860px){
  .srch{ grid-template-columns:minmax(0,1fr); height:480px; }
  .srch-list{ display:none; }
}
@media (max-width:560px){
  .shot-url{ display:none; }
  .ui-toolbar{ padding:8px 10px; }
  .srch-filters{ padding:8px 10px; }
  .srch{ height:400px; }
}

/* ============================================================================
   THE THREE OBJECTIONS
   No badge, no "proof" label, no boxes. The objection is set quiet and large,
   the answer arrives in full white, and the evidence closes the column under a
   hairline. The contrast does the arguing.
   ========================================================================= */
.case{ display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:64px; align-items:center; }
.case.is-flip .case-vis{ order:-1; }
@media (max-width:940px){
  .case{ grid-template-columns:minmax(0,1fr); gap:36px; }
  .case.is-flip .case-vis{ order:0; }
}
.case-text{ max-width:52ch; }

.case-idx{
  display:flex; align-items:center; gap:10px;
  font-size:11px; font-weight:700; letter-spacing:.14em; text-transform:uppercase;
  color:var(--label-3);
}
.case-idx .num{ color:var(--live); }
.case-idx::after{ content:""; flex:1; height:1px; background:var(--separator); }

/* the objection, in the manufacturer's own words — quiet, and given room */
.case-q{
  position:relative; margin-top:26px; padding-inline-start:26px;
  font-size:clamp(19px,1.9vw,25px); line-height:1.4; font-weight:400; letter-spacing:-.015em;
  color:var(--label-2);
}
.case-q::before{
  content:"\201C"; position:absolute; inset-inline-start:-2px; top:-.12em;
  font-family:var(--font-display); font-size:2.4em; line-height:1; color:var(--separator-strong);
}
.case-q cite{
  display:block; margin-top:16px; font-size:12px; font-style:normal; font-weight:600;
  letter-spacing:.06em; text-transform:uppercase; color:var(--label-3);
}

.case-h{ margin-top:40px; }
.case-b{ margin-top:18px; font-size:17px; line-height:1.6; color:var(--label-2); letter-spacing:-.024em; }

/* the evidence: a fact under a hairline, not a badge */
.case-f{
  position:relative; margin-top:28px; padding-top:22px;
  border-top:1px solid var(--separator);
  font-size:14px; line-height:1.6; color:var(--label-3);
  letter-spacing:-.011em;
}
.case-f::before{
  content:""; position:absolute; inset-inline-start:0; top:-1px; width:52px; height:1px; background:var(--live);
}

/* ---------- stakeholder tree ---------- */
.tree{
  padding:22px; border-radius:18px; border:1px solid var(--separator);
  background:linear-gradient(180deg, rgba(255,255,255,.035), rgba(255,255,255,.008));
}
.tree-head{ display:flex; align-items:center; gap:10px; padding-bottom:14px; border-bottom:1px solid var(--separator); margin-bottom:6px; }
.tree-head b{ font-size:13px; font-weight:600; letter-spacing:-.006em; }
.tree-head span{ margin-inline-start:auto; font-size:12px; color:var(--label-3); }
.tnode{ position:relative; display:grid; grid-template-columns:32px minmax(0,1fr) auto; gap:11px; align-items:center; padding:11px 4px; }
.tnode + .tnode{ border-top:1px solid var(--separator); }
.tnode[data-lvl="1"]{ padding-inline-start:22px; } .tnode[data-lvl="2"]{ padding-inline-start:44px; }
.tnode::before{
  content:""; position:absolute; inset-inline-start:10px; top:0; bottom:0; width:1px; background:var(--separator); opacity:0;
}
.tnode[data-lvl="1"]::before,.tnode[data-lvl="2"]::before{ opacity:1; }
.tnode[data-lvl="2"]::before{ inset-inline-start:32px; }
.tnode-av{
  width:32px; height:32px; border-radius:10px; display:grid; place-items:center; flex:0 0 auto;
  background:var(--fill); color:var(--label-2); font-size:11px; font-weight:700; letter-spacing:.02em;
}
.tnode.is-you .tnode-av{ background:var(--grad); color:var(--brand-ink); }
.tnode-main{ min-width:0; }
.tnode-role{ display:block; font-size:11px; font-weight:600; letter-spacing:.06em; text-transform:uppercase; color:var(--label-3); }
.tnode-name{ display:block; font-size:14px; font-weight:600; line-height:1.35; margin-top:2px; letter-spacing:-.011em; }
.tnode-who{ display:block; font-size:12px; color:var(--label-2); margin-top:2px; }
.tnode-ch{ display:flex; gap:5px; flex:0 0 auto; }
.tnode-ch i{
  width:26px; height:26px; border-radius:8px; display:grid; place-items:center;
  background:var(--fill); color:var(--label-2);
}
.tnode.is-you .tnode-ch i{ background:var(--live-soft); color:var(--live-on-soft); }
.tree-foot{ margin-top:14px; padding-top:14px; border-top:1px solid var(--separator); font-size:12px; color:var(--label-3); }

/* ============================================================================
   LIVE FEED — the product's own "Right now across blocsme.com"
   ========================================================================= */
.live{
  --l-bg:#0A0A0B; --l-line:rgba(255,255,255,.08);
  --l-text:#F5F5F7; --l-text-2:rgba(235,235,245,.64); --l-text-3:rgba(235,235,245,.55);
  --l-fill:rgba(255,255,255,.07); --l-fill-hover:rgba(255,255,255,.13);
  --l-bar:rgba(255,255,255,.2); --l-scroll:rgba(255,255,255,.18);
  position:relative; overflow:hidden; border-radius:18px;
  background:var(--l-bg); color:var(--l-text);
  box-shadow:0 0 0 1px rgba(255,255,255,.07), 0 40px 90px -50px rgba(0,0,0,.9);
}
.live-head{ display:flex; align-items:center; flex-wrap:wrap; gap:8px 12px; padding:14px 20px; border-bottom:1px solid var(--l-line); }
.live-badge{
  display:inline-flex; align-items:center; gap:8px; flex:0 0 auto; height:22px; padding:0; padding-inline:8px 10px;
  border-radius:11px; background:var(--live-soft); color:var(--live-on-soft);
  font-size:11px; font-weight:700; letter-spacing:.08em; text-transform:uppercase;
}
.beacon{ position:relative; width:7px; height:7px; border-radius:50%; background:currentColor; flex:0 0 auto; }
.beacon::after{
  content:""; position:absolute; inset:-3px; border-radius:50%; border:1px solid currentColor;
  animation:beacon 2.4s var(--ease) infinite; opacity:0;
}
@keyframes beacon{ 0%{ transform:scale(.6); opacity:.8 } 100%{ transform:scale(1.9); opacity:0 } }
.live-title{ font-size:15px; font-weight:600; letter-spacing:-.01em; }
.live-updated{ margin-inline-start:auto; font-size:13px; color:var(--l-text-2); white-space:nowrap; letter-spacing:-.006em; }

.live-stats{ display:grid; grid-template-columns:repeat(4,minmax(0,1fr)); border-bottom:1px solid var(--l-line); }
.live-stat{ display:flex; align-items:flex-end; justify-content:space-between; gap:12px; min-width:0; padding:16px 20px; }
.live-stat + .live-stat{ border-inline-start:1px solid var(--l-line); }
.live-label{ font-size:12px; color:var(--l-text-2); white-space:nowrap; }
.live-value{ margin-top:6px; font-family:var(--font-display); font-size:clamp(26px,2.4vw,34px); line-height:1; font-weight:700; letter-spacing:-.03em; white-space:nowrap; }
.live-delta{ margin-top:8px; font-size:12px; color:var(--l-text-2); white-space:nowrap; }
.live-delta b{ font-weight:600; color:var(--l-text); }
.spark{ display:flex; align-items:flex-end; gap:2px; width:84px; height:40px; flex:0 0 auto; }
.spark i{ flex:1; min-height:2px; border-radius:1px; background:var(--l-bar); transition:height .6s var(--ease); }
.spark i:last-child{ background:var(--live); }
.bump{ animation:bump .5s var(--ease); }
@keyframes bump{ 0%{ transform:translateY(0) } 35%{ transform:translateY(-4px) } 100%{ transform:translateY(0) } }
@media (max-width:860px){
  .live-stats{ grid-template-columns:repeat(2,minmax(0,1fr)); }
  .live-stat:nth-child(odd){ border-inline-start:0; }
  .live-stat:nth-child(n+3){ border-top:1px solid var(--l-line); }
  .spark{ display:none; }
}

.live-body{ display:grid; grid-template-columns:minmax(0,1fr) 372px; height:470px; }
.map-stage{ position:relative; min-width:0; overflow:hidden; background:radial-gradient(120% 90% at 55% 45%, rgba(255,255,255,.04), transparent 62%); }
.map-canvas{ position:absolute; inset:0; width:100%; height:100%; }
.map-flag{
  position:absolute; z-index:2; pointer-events:none; max-width:250px; padding:8px 10px; border-radius:10px;
  background:rgba(30,30,32,.94); border:1px solid rgba(255,122,26,.45);
  box-shadow:0 12px 30px -12px rgba(0,0,0,.7); font-size:12px; line-height:1.35;
  transform:translate(-50%,-120%); opacity:0; transition:opacity .3s var(--ease);
}
.map-flag.is-on{ opacity:1; animation:flag-in .35s var(--ease); }
.map-flag b{ display:block; font-size:13px; font-weight:600; color:var(--l-text); letter-spacing:-.006em; }
.map-flag span{ display:block; color:var(--l-text-2); }
@keyframes flag-in{ from{ opacity:0; transform:translate(-50%,-112%) } }

.feed{ display:flex; flex-direction:column; min-height:0; border-inline-start:1px solid var(--l-line); }
.feed-head{ display:flex; align-items:baseline; justify-content:space-between; gap:12px; padding:14px 16px 8px; }
.feed-title{ font-size:15px; font-weight:600; letter-spacing:-.016em; }
.feed-all{ display:inline-flex; align-items:center; gap:6px; height:24px; padding:0 10px; border-radius:7px; background:var(--l-fill); color:var(--l-text-2); font-size:12px; font-weight:500; }
.feed-filter{ display:flex; gap:4px; padding:0 12px 10px; border-bottom:1px solid var(--l-line); overflow-x:auto; scrollbar-width:none; }
.feed-filter::-webkit-scrollbar{ display:none; }
.feed-chip{ height:26px; padding:0 10px; border-radius:7px; font-size:12px; font-weight:500; color:var(--l-text-2); white-space:nowrap; transition:background-color .12s, color .12s; }
.feed-chip:hover{ background:var(--l-fill); color:var(--l-text); }
.feed-chip[aria-pressed="true"]{ background:var(--l-fill-hover); color:var(--l-text); }
.feed-list{
  flex:1; min-height:0; overflow-y:auto; overscroll-behavior:contain; padding:6px 0 32px;
  scrollbar-width:thin; scrollbar-color:var(--l-scroll) transparent;
  -webkit-mask-image:linear-gradient(to bottom,#000 calc(100% - 44px),transparent);
          mask-image:linear-gradient(to bottom,#000 calc(100% - 44px),transparent);
}
.feed-list::-webkit-scrollbar{ width:6px; }
.feed-list::-webkit-scrollbar-thumb{ background:var(--l-scroll); border-radius:3px; }
.feed-item{ position:relative; display:grid; grid-template-columns:28px minmax(0,1fr) auto; column-gap:10px; padding:10px 16px; transition:background-color .12s; }
.feed-item:hover{ background:var(--l-fill); }
.feed-item::before{
  content:""; position:absolute; inset-inline-start:0; top:11px; bottom:11px; width:2px; border-start-end-radius:2px; border-end-end-radius:2px;
  background:var(--live); opacity:0; transition:opacity 1.4s ease;
}
.feed-item.is-new::before{ opacity:1; }
.feed-item.is-entering{ animation:feed-in .5s var(--ease); }
@keyframes feed-in{ from{ opacity:0; transform:translateY(-8px) } }
.feed-icon{ width:28px; height:28px; border-radius:50%; display:grid; place-items:center; background:var(--l-fill); color:var(--l-text-2); }
.feed-item.is-new .feed-icon{ background:var(--live-soft); color:var(--live-on-soft); }
.feed-main{ min-width:0; }
.feed-text{ font-size:13px; font-weight:500; line-height:1.4; letter-spacing:-.006em; }
.feed-sub{ margin-top:2px; font-size:12px; color:var(--l-text-3); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.feed-sub .name{ color:var(--l-text-2); }
.feed-time{ font-size:12px; color:var(--l-text-3); white-space:nowrap; }
@media (max-width:980px){
  .live-body{ grid-template-columns:minmax(0,1fr); height:auto; }
  .map-stage{ height:280px; }
  .feed{ border-inline-start:0; border-top:1px solid var(--l-line); height:420px; }
}

/* ============================================================================
   PROJECTS SLIDER
   ========================================================================= */
/* the track is far wider than the page, so the shelf itself does the clipping —
   leaving it to body{overflow-x} would still inflate the document's width */
.pslider{ position:relative; margin-top:48px; overflow:hidden; }
.pslider::before,.pslider::after{
  content:""; position:absolute; top:0; bottom:0; width:12%; z-index:2; pointer-events:none;
}
.pslider::before{ left:0; background:linear-gradient(90deg,var(--bg),transparent); }
.pslider::after{ right:0; background:linear-gradient(270deg,var(--bg),transparent); }
.pslider-track{ display:flex; gap:16px; width:max-content; will-change:transform; }
.pslider-track .tile{ width:282px; flex:0 0 auto; }
@media (max-width:560px){ .pslider-track .tile{ width:244px; } }

/* ============================================================================
   SIGNALS
   ========================================================================= */
/* No drop shadow. On a light section it was a grey smear under a white card,
   which is what a shadow does when the surface below it is already bright. */
.sig-panel{
  border-radius:18px; border:1px solid var(--separator); overflow:hidden;
  background:var(--bg);
}
.sig-top{ display:flex; align-items:center; gap:12px; padding:14px 20px; border-bottom:1px solid var(--separator); }
.sig-top h3{ font-size:15px; font-weight:600; letter-spacing:-.016em; }
.sig-top .when{ margin-inline-start:auto; font-size:12px; color:var(--label-3); }
.sig-num{ padding:15px 18px; min-width:0; }
.sig-num + .sig-num{ border-inline-start:1px solid var(--separator); }
.sig-num b{ display:block; font-family:var(--font-display); font-size:clamp(26px,2.4vw,34px); font-weight:700; letter-spacing:-.03em; line-height:1; }
.sig-num span{ display:block; margin-top:8px; font-size:12px; line-height:1.45; color:var(--label-2); }
@media (max-width:760px){
  .sig-num:nth-child(odd){ border-inline-start:0; }
  .sig-num:nth-child(n+3){ border-top:1px solid var(--separator); }
}

/* ---------- signals: photographs, a chart that grows, cards that arrive ---------- */
/* the cards land one after another, once the panel is on screen */

/* the lead story runs over its photograph */

/* a thumbnail is enough for the rest — out of flow, so a tall photo cannot
   stretch the card past its ratio the way a plain flex child would */

/* lead times, quarter by quarter — the chart is the sentence */
@media (prefers-reduced-motion:reduce){
}

/* 50% black was written for a light card on a dark page, where it had the
   card's own white to sit on. On a light section it lands at 3.21:1, under the
   4.5 floor for 12–14px — the palette's own caption grey is 4.9:1 and is the
   colour this was reaching for anyway. */
@media (max-width:940px){
}
@media (max-width:620px){
}

/* ============================================================================
   WHAT THE BASE BUILDS
   ========================================================================= */
.figrow{
  display:grid; grid-template-columns:repeat(4,minmax(0,1fr)); margin-top:48px;
  border:1px solid var(--separator); border-radius:16px; overflow:hidden;
}
.figcell{ padding:22px 24px; min-width:0; }
.figcell + .figcell{ border-inline-start:1px solid var(--separator); }
.figcell b{
  display:block; font-family:var(--font-display);
  font-size:clamp(26px,2.8vw,38px); font-weight:700; letter-spacing:-.03em; line-height:1;
}
.figcell span{ display:block; margin-top:8px; font-size:13px; color:var(--label-2); letter-spacing:-.006em; }
@media (max-width:760px){
  .figrow{ grid-template-columns:repeat(2,minmax(0,1fr)); }
  .figcell:nth-child(odd){ border-inline-start:0; }
  .figcell:nth-child(n+3){ border-top:1px solid var(--separator); }
}

.mixbar{ display:flex; gap:2px; margin-bottom:28px; }
.mixbar-part{ position:relative; min-width:74px; }
.mixbar-fill{ display:block; height:10px; border-radius:2px; background:var(--label); transform-origin:left; }
.mixbar-part:first-child .mixbar-fill{ border-radius:6px 2px 2px 6px; }
.mixbar-part:last-child .mixbar-fill{ border-radius:2px 6px 6px 2px; }
.mixbar-key{ display:flex; align-items:baseline; gap:5px; margin-top:9px; font-size:12px; color:var(--label-2); min-width:0; }
.mixbar-key b{ font-weight:600; color:var(--label); }
/* Once the group name goes, the share on its own needs about a third of the
   width the labelled part did — held at 74px the six parts add up wider than
   a phone, which widens the layout viewport and drags the nav out with it. */
@media (max-width:760px){
  .mixbar-part .mixbar-name{ display:none; }
  .mixbar-part{ min-width:34px; }
}

.type-groups{ display:grid; grid-template-columns:repeat(auto-fill,minmax(310px,1fr)); gap:16px; align-items:start; }
.tgroup{ padding:16px 18px 18px; border-radius:14px; background:var(--bg-elevated); }
.tgroup-head{ display:grid; grid-template-columns:30px minmax(0,1fr) auto; gap:11px; align-items:center; padding-bottom:10px; }
.tgroup-ic{ width:30px; height:30px; border-radius:9px; display:grid; place-items:center; background:var(--fill); color:var(--label-2); }
.tgroup-head > span{ min-width:0; }
.tgroup-name{ display:block; font-size:14px; font-weight:600; line-height:1.3; letter-spacing:-.011em; }
.tgroup-share{ display:block; margin-top:2px; font-size:12px; color:var(--label-3); }
.tgroup-tot{ font-family:var(--font-display); font-size:20px; font-weight:600; letter-spacing:-.02em; }
.trow{ position:relative; display:flex; align-items:center; justify-content:space-between; gap:12px; padding:9px 0; font-size:13px; letter-spacing:-.006em; }
.trow-name{ position:relative; z-index:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; color:var(--label); }
.trow-n{ position:relative; z-index:1; font-weight:600; white-space:nowrap; font-variant-numeric:tabular-nums; }
.trow-bg{
  position:absolute; inset-inline-start:-6px; top:4px; bottom:4px; z-index:0; border-radius:5px;
  background:var(--fill); width:0; transition:width 1s var(--ease-out);
}

/* Both the type rows and the ten reasons are a way into the product rather than
   a figure to read, so they carry the affordance the project tiles already use
   instead of a new one. The row keeps its own paint order: the bar is the only
   thing that answers the pointer, which is why the hover lands on .trow-bg. */
a.trow, a.reason{ color:inherit; text-decoration:none; cursor:pointer; }
a.trow .trow-bg{ transition:width 1s var(--ease-out), background-color .15s; }
/* The bar is the only thing that answers the pointer. The figure stays put:
   orange is reserved for live state on this page, and a number that changes
   colour under the cursor reads as a value changing. */
a.trow:hover .trow-bg{ background:var(--fill-hover); }
/* No card-level background here. --bg-row-hover is only defined under
   .is-light / .panel-light / .panel-dark and this section is a plain .section,
   so the declaration that used to sit here never resolved — it looked like a
   hover and was dead. The badge alone carries the state, in the neutral fill
   rather than the orange it used to take: orange is live state on this page,
   and ten of these lighting up under the cursor was the whole complaint.
   Specificity beats the .reason:hover rule further down, so order is moot. */
a.reason{ transition:background-color .15s; }
a.reason:hover .reason-n{ background:var(--fill-hover); color:var(--label); }
a.trow:focus-visible, a.reason:focus-visible{
  outline:2px solid var(--focus); outline-offset:2px; border-radius:8px;
}

/* ============================================================================
   ZERO COMMISSION
   Three columns, read across: what each one takes out of the same contract.
   Ours carries the brand and the only bright figures on the panel.
   ========================================================================= */

/* Ours inverts — the same move the page already uses for a standout surface
   (the pull-quote card, the primary button). A brand wash read as a different
   product; white against five dark columns cannot be missed. */


/* ============================================================================
   10 REASONS
   ========================================================================= */
.reasons{ display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:1px; background:var(--separator); border-radius:18px; overflow:hidden; }
.reason{ background:var(--bg); padding:26px 24px; display:grid; grid-template-columns:auto minmax(0,1fr); gap:16px; align-items:start; }
.reason-n{
  width:34px; height:34px; border-radius:11px; display:grid; place-items:center; flex:0 0 auto;
  background:var(--fill); color:var(--label-2);
  font-family:var(--font-display); font-size:14px; font-weight:600; font-variant-numeric:tabular-nums;
  letter-spacing:-.011em;
}
.reason:hover .reason-n{ background:var(--live-soft); color:var(--live-on-soft); }
.reason h3{ font-size:17px; font-weight:600; letter-spacing:-.015em; line-height:1.3; }
.reason p{ margin-top:8px; font-size:14px; line-height:1.55; color:var(--label-2); letter-spacing:-.011em; }
@media (max-width:760px){ .reasons{ grid-template-columns:minmax(0,1fr); } }

/* ============================================================================
   WHO IT IS FOR — the lane
   The argument is a trade route, so it is drawn as one: a real map of the eight
   Gulf markets and the Chinese manufacturing centres they buy from, the network
   between them baked once, and a pulse travelling one route at a time. Under it,
   the two ends named — and the reader's end inverted, since they are one of them.
   ========================================================================= */
/* No frame. The map is the picture, not a component in a card — a border and a
   radius around it turned a world into a widget. It runs the full width of the
   column, on the page's own ground. */
.lane{ margin-top:40px; }

/* the direction the pulses travel, stated once — the head is on the Gulf end,
   because that is the end everything on this map is going to */

/* The box matches what the projection actually draws for this bbox. Set wider
   than the map, fitExtent letterboxes it: at 104/38 there were 206px of nothing
   down each side and the world sat in the middle like a stamp. */
.lane-map{ position:relative; aspect-ratio:1.88; }
/* A radius can only be seen if there is something to round. The canvas was
   transparent — dots floating on the page — so clipping its corners clipped
   nothing. It gets its own ground, one step up from the section, and the corner
   reads. */
.lane-map canvas{
  display:block; width:100%; height:100%;
  /* the section itself is now --bg-elevated, so the map needs the darker
     ground to read as a separate surface rather than dissolving into it */
  background:var(--bg-deep); border-radius:28px;
}



@media (max-width:860px){
  /* The ratio stays at the desktop 1.88. The map is drawn cover-style inside a
     bbox whose own ratio is 1.37, so a taller box does not show more map — it
     shows more LATITUDE, and the latitude either side of the frame is open sea.
     At 1.5 the band above Kazakhstan and the water below the Gulf came into
     view as empty strips, which reads as the dots being cut off top and bottom.
     Same framing as the desktop, just smaller. */
  .lane-foot{ grid-template-columns:minmax(0,1fr); }
}

/* ---------- what "seller" actually covers ---------- */
.tags{ margin-top:14px; display:flex; flex-wrap:wrap; gap:6px; }
.chip.is-more{ background:transparent; border:1px dashed var(--separator-strong); color:var(--label-3); }
.chip.is-more:hover{ background:transparent; color:var(--label-2); }
@media (max-width:860px){
}


/* ============================================================================
   QUESTIONS
   The same accordion the pricing page uses — one component, both pages. On the
   landing each answer closes on the fact that settles it, set apart from the
   answer but not labelled: a claim that announces itself as proof reads as the
   opposite.
   ========================================================================= */
.faq{ max-width:780px; margin:40px auto 0; border-top:1px solid var(--separator); }
.faq-item{ border-bottom:1px solid var(--separator); }
.faq-item summary{
  position:relative; display:flex; align-items:center; gap:16px;
  padding:20px 34px 20px 0; cursor:pointer; list-style:none;
  font-size:16px; font-weight:600; letter-spacing:-.01em;
}
.faq-item summary::-webkit-details-marker{ display:none; }
.faq-item summary:focus-visible{ outline:2px solid var(--focus); outline-offset:-2px; border-radius:6px; }
.faq-sign{ position:absolute; inset-inline-end:4px; top:50%; width:13px; height:13px; margin-top:-6px; }
.faq-sign::before, .faq-sign::after{
  content:""; position:absolute; left:0; top:6px; width:13px; height:1.5px;
  background:var(--label-2); border-radius:1px; transition:transform .2s var(--ease);
}
.faq-sign::after{ transform:rotate(90deg); }
.faq-item[open] .faq-sign::after{ transform:rotate(0); }
.faq-a{ padding:0 34px 22px 0; }
.faq-a p{ font-size:15px; line-height:1.6; color:var(--label-2); letter-spacing:-.016em; }

/* scoped past `.faq-a p`, which would otherwise win on specificity */
.faq-a .faq-fact{
  margin-top:16px; padding-top:14px; border-top:1px solid var(--separator);
  font-size:13px; line-height:1.55; color:var(--label-3);
  letter-spacing:-.006em;
}
.faq-a .faq-fact b{
  font-family:var(--font-display); font-size:15px; font-weight:600;
  letter-spacing:-.01em; color:var(--label);
}

/* ============================================================================
   FINAL CTA + FOOTER
   ========================================================================= */
/* The closing block repeats the hero's promise, so it repeats its background —
   but the copy is centred here, so the city is pushed out to both edges instead
   of to one. Same skyline, different seed: it should rhyme, not repeat. */
.final{ overflow:hidden; }
.final-bg{
  position:absolute; left:0; right:0; top:0; height:640px; z-index:0; pointer-events:none;
  -webkit-mask-image:linear-gradient(180deg, transparent 0, #000 15%, #000 58%, transparent 96%);
          mask-image:linear-gradient(180deg, transparent 0, #000 15%, #000 58%, transparent 96%);
}
.final-bg canvas{ display:block; width:100%; height:100%; opacity:.88; }
/* same reasoning as the hero, measured out from the centre because the copy is */
.final-bg::after{
  content:""; position:absolute; inset:0;
  background:linear-gradient(90deg,
    transparent 0, rgba(22,22,23,.5) calc(50% - 570px), rgba(22,22,23,.95) calc(50% - 430px),
    var(--bg) calc(50% - 350px), var(--bg) calc(50% + 350px),
    rgba(22,22,23,.95) calc(50% + 430px), rgba(22,22,23,.5) calc(50% + 570px), transparent 100%);
}
/* the canvas is positioned, so the copy has to be too or it paints underneath */
.final > .wrap, .final-slider{ position:relative; z-index:2; }
@media (max-width:860px){ .final-bg{ height:480px; } }

.final-in{ text-align:center; }
.final h2{ max-width:20ch; margin-inline:auto; }
.final p{ margin-top:20px; max-width:56ch; margin-inline:auto; }
.final-acts{ margin-top:32px; display:flex; flex-wrap:wrap; gap:12px; justify-content:center; }
.final-note{ margin-top:18px; max-width:none; font-size:13px; color:var(--label-3); letter-spacing:-.006em; }

/* ============================================================================
   FOOTER
   Brand on its own column, then the three offices on one baseline.
   Headings carry the brand; everything under them is quiet.
   ========================================================================= */
.foot{ border-top:1px solid var(--separator); padding-block:60px 28px; }
.foot-grid{ display:grid; grid-template-columns:1.6fr repeat(3,1fr); gap:40px; }
/* 11 uppercase label · 13 secondary · 14 body — the page's own scale */
.foot h4{
  font-size:11px; font-weight:700; letter-spacing:.08em; text-transform:uppercase;
  color:var(--label);
}
.foot-col > h4 + *{ margin-top:20px; }
.foot ul{ display:grid; gap:12px; }
.foot ul a{ font-size:14px; color:var(--label-2); transition:color .12s; letter-spacing:-.011em; }
.foot ul a:hover{ color:var(--label); }

.foot-tag{ margin-top:20px; max-width:28ch; font-size:14px; line-height:1.6; color:var(--label-2); letter-spacing:-.011em; }
.social{ display:flex; gap:8px; margin-top:26px; }
.social a{
  width:38px; height:38px; border-radius:11px; display:grid; place-items:center;
  border:1px solid var(--separator); color:var(--label-2);
  transition:border-color .12s, color .12s, background-color .12s;
}
.social a:hover{ border-color:var(--separator-strong); background:var(--fill); color:var(--label); }

.foot-mail{ display:block; font-size:14px; color:var(--label-2); transition:color .12s; letter-spacing:-.011em; }
.foot-tel{ display:block; margin-top:10px; font-size:14px; color:var(--label-2); transition:color .12s; letter-spacing:-.011em; }
.foot-mail:hover, .foot-tel:hover{ color:var(--label); }
.foot-col p:not(.foot-tag){ margin-top:14px; font-size:13px; line-height:1.6; color:var(--label-3); letter-spacing:-.006em; }

.foot-base{
  margin-top:56px; padding-top:22px; border-top:1px solid var(--separator);
  display:flex; flex-wrap:wrap; align-items:center; gap:10px 24px;
  font-size:12px; color:var(--label-3);
}
.foot-markets{ margin-inline-start:auto; }

@media (max-width:1080px){
  .foot-grid{ grid-template-columns:repeat(3,minmax(0,1fr)); row-gap:44px; }
  .foot-brand{ grid-column:span 3; }
}
@media (max-width:720px){
  .foot-grid{ grid-template-columns:repeat(2,minmax(0,1fr)); gap:36px 28px; }
  .foot-brand{ grid-column:span 2; }
}
@media (max-width:480px){
  .foot-grid{ grid-template-columns:minmax(0,1fr); }
  .foot-brand{ grid-column:auto; }
  .foot-markets{ margin-inline-start:0; }
  /* One column on a phone: ragged-left columns under a centred page read as a
     mistake, so the whole footer centres with it. */
  .foot-col, .foot-base{ text-align:center; }
  .foot-tag{ margin-inline:auto; }
  .foot ul{ justify-items:center; }
  .social{ justify-content:center; }
  .foot-base{ justify-content:center; }
}

/* ---------- section head helper ---------- */
.shead{ max-width:64ch; }
.shead h2{ margin-top:18px; }
.shead p{ margin-top:20px; }
.shead-center{ margin-inline:auto; text-align:center; }
.shead-split{ display:grid; grid-template-columns:1.1fr .9fr; gap:48px; align-items:end; max-width:none; }
.shead-split p{ margin-top:0; }
@media (max-width:860px){ .shead-split{ grid-template-columns:minmax(0,1fr); gap:20px; align-items:start; } }

/* ---------- marquee ---------- */
.marquee{ overflow:hidden; border-block:1px solid var(--separator); padding-block:16px; }
.marquee-track{ display:flex; width:max-content; gap:0; animation:mq 44s linear infinite; }
.marquee-track span{ display:inline-flex; align-items:center; gap:22px; padding-inline-end:22px; font-size:13px; font-weight:500; color:var(--label-3); white-space:nowrap; letter-spacing:-.006em; }
.marquee-track i{ width:4px; height:4px; border-radius:50%; background:var(--live); flex:0 0 auto; }
@keyframes mq{ to{ transform:translateX(-50%) } }
.marquee:hover .marquee-track{ animation-play-state:paused; }

/* ============================================================================
   ADDITIONS
   ========================================================================= */

/* ---------- language picker ---------- */
.lang{ position:relative; }
.lang-btn{
  display:inline-flex; align-items:center; gap:6px; height:34px; padding:0 10px;
  border-radius:8px; color:var(--label-2); font-size:13px; font-weight:500;
  transition:background-color .12s, color .12s;
  letter-spacing:-.006em;
}
.lang-btn:hover, .lang-btn[aria-expanded="true"]{ background:var(--fill); color:var(--label); }
/* The entries became links to real pages, and this was still written for the
   buttons they used to be — so nothing matched, the <ul> kept its default
   padding and bullets, and the menu rendered as a bare list hanging off the
   corner. It is a <ul> now, so it also needs the list reset. */
.lang-menu{
  position:absolute; inset-inline-end:0; top:calc(100% + 8px); z-index:70; min-width:150px;
  margin:0; padding:6px; list-style:none; border-radius:12px;
  border:1px solid var(--separator);
  background:var(--bg-raised); box-shadow:var(--shadow-pop);
}
.lang-menu li{ list-style:none; }
.lang-menu a{
  display:flex; align-items:center; justify-content:space-between; gap:12px;
  width:100%; height:34px; padding:0 10px; border-radius:8px;
  font-size:14px; color:var(--label-2); text-align:start;
  transition:background-color .12s, color .12s;
  letter-spacing:-.011em;
}
.lang-menu a:hover{ background:var(--fill); color:var(--label); }
.lang-menu a[aria-current="true"]{ color:var(--label); }
.lang-menu a[aria-current="true"]::after{ content:"✓"; color:var(--live); }
.lang-menu a:focus-visible{ outline:2px solid var(--focus); outline-offset:-2px; }

/* The live panel is a picture of the product, so nothing in it is a control.
   `inert` in the markup does the real work — this is the visual half of it,
   and the belt for browsers that do not have inert yet. */
#liveblock{ pointer-events:none; -webkit-user-select:none; user-select:none; }

/* ---------- the mobile menu ---------- */
/* The two bars are positioned, not stacked: in flow each one rotates about its
   own box and they close into a chevron rather than a cross. Pinned to known
   offsets either side of the centre, ±2.5px brings both onto it. */
.burger{
  display:none; position:relative; width:40px; height:40px; padding:0; border:0;
  background:none; cursor:pointer; border-radius:10px; color:var(--label);
  transition:background-color .12s;
}
.burger:hover{ background:var(--fill); }
.burger:focus-visible{ outline:2px solid var(--focus); outline-offset:2px; }
.burger span{
  position:absolute; left:11px; width:18px; height:1.5px; border-radius:2px;
  background:currentColor; transition:transform .22s var(--ease);
}
.burger span:first-child{ top:17px; }
.burger span + span{ top:22px; }
.burger[aria-expanded="true"] span:first-child{ transform:translateY(2.5px) rotate(45deg); }
.burger[aria-expanded="true"] span + span{ transform:translateY(-2.5px) rotate(-45deg); }

.drawer{
  position:fixed; inset:64px 0 0; z-index:59;   /* under the fixed 64px nav */
  display:flex; flex-direction:column; gap:10px;
  padding:20px var(--gutter) 32px;
  background:var(--bg); overflow-y:auto; overscroll-behavior:contain;
  animation:drawerin .22s var(--ease-out);
}
/* A column flex container whose content is taller than it shrinks every item to
   fit — which squashed the 54px Get started button down to the 26px of its own
   text. The drawer scrolls instead, so nothing in it may shrink. */
.drawer > *{ flex:0 0 auto; }
@keyframes drawerin{ from{ opacity:0; transform:translateY(-8px); } to{ opacity:1; transform:none; } }
.drawer[hidden]{ display:none; }
.drawer-nav{ display:flex; flex-direction:column; }
.drawer-nav a{
  display:flex; align-items:center; min-height:48px; padding:0 4px;
  font-size:17px; font-weight:500; color:var(--label);
  border-bottom:1px solid var(--separator);
  letter-spacing:-.024em;
}
.drawer-lang{ display:flex; gap:8px; margin-top:16px; }
.drawer-lang a{
  display:inline-flex; align-items:center; min-height:40px; padding:0 14px;
  border-radius:10px; border:1px solid var(--separator);
  font-size:15px; color:var(--label-2);
  letter-spacing:-.016em;
}
.drawer-lang a[aria-current="true"]{ background:var(--fill); color:var(--label); }
.drawer-cta{ margin-top:16px; width:100%; }
.drawer-extra{ margin-top:28px; display:grid; gap:22px; }
.drawer-extra:empty{ display:none; }
.drawer-extra .foot-col h4{ font-size:13px; letter-spacing:-.006em; }
.drawer-extra .social{ display:flex; gap:10px; }

@media (max-width:900px){
  .burger{ display:grid; }
  .nav-cta .lang, .nav-cta .nav-start{ display:none; }
  /* the drawer is a layer over the page, so the page behind it must not move */
  body.nav-open{ overflow:hidden; }
}

/* Arabic runs longer than English for the same label — "RFQ" is three words —
   so the seven nav items stop fitting while there is still room in Latin, and
   they stack into two and three lines rather than wrapping gracefully. The bar
   hands over to the drawer earlier on these pages. The number is where the
   Arabic labels actually start to crowd, not a round figure. */
@media (max-width:1120px){
  html[lang^="ar"] .nav-links{ display:none; }
  html[lang^="ar"] .burger{ display:grid; }
}
@media (max-width:1000px){
  html[lang^="ar"] .nav-cta .nav-start{ display:none; }
}
@media (min-width:901px){
  .drawer{ display:none !important; }
}

/* ===========================================================================
   Mobile: three product shots that shrink instead of reflowing

   The app window, the live panel and the signals panel are pictures of the
   product. Reflowed to a phone they stop being that picture: the search column
   disappears, the sparklines go, four stat cells become two rows, and the
   bento collapses to a stack. What survives is a different screen from the one
   the visitor will actually log into.

   So on a phone they are not adapted, they are *reduced*: laid out at their
   desktop width (--zw) and scaled down by exactly viewport ÷ --zw, which keeps
   every proportion. js/landing.js sets the transform and the wrapper's height —
   a transform does not affect layout, so without that height the page would
   keep a full-size gap where the shrunken panel sits.

   The counter-rules below matter as much as the scale. A transform does not
   change the viewport, so every `@media (max-width:…)` inside these three still
   fires and reflows the interior before it is scaled. They are keyed to how
   much room the component has, not to the phone, so inside .zoomed they are put
   back to the layout they were written for.
   ========================================================================= */
.zoom > *{ transform-origin:top left; }
/* In RTL the oversized child is flush to the RIGHT edge of the wrapper and runs
   off to the left, so scaling about the left corner moved it entirely out of
   view — the Arabic hero shot and the live panel simply were not there. */
[dir="rtl"] .zoom > *{ transform-origin:top right; }

@media (max-width:980px){
  .zoomed .live-body{ grid-template-columns:minmax(0,1fr) 372px; height:470px; }
}
@media (max-width:940px){
}
@media (max-width:860px){
  .zoomed .srch{ grid-template-columns:330px minmax(0,1fr); height:640px; }
  .zoomed .srch-list{ display:flex; }
  .zoomed .live-stats{ grid-template-columns:repeat(4,minmax(0,1fr)); }
  .zoomed .live-stat:nth-child(odd){ border-inline-start:1px solid var(--l-line); }
  .zoomed .live-stat:nth-child(n+3){ border-top:0; }
  .zoomed .spark{ display:flex; }
}
@media (max-width:760px){
  /* The share bar repeats, in a form that has to be decoded, what the six cards
     under it already say in words. On a phone that is a row of unlabelled
     percentages — the labels do not fit — so it goes. */
  .mixbar{ display:none; }

}

@media (max-width:860px){
  /* Inside a .zoom the panel is laid out at --zw, so its own breakpoints are the
     wrong ones: the orb keeps its desktop shape and is scaled, not reflowed. */
}

@media (max-width:760px){
  /* "to the width of the phone" means the screen, not the text column — it
     bleeds past the gutters so the reduction is as large as it can be */
  .zoom{
    width:auto; overflow:hidden;
    margin-inline:calc(var(--gutter) * -1);
  }
  .zoom > *{ width:var(--zw, 1180px); max-width:none; border-radius:0; }
  .zoomed .sig-num:nth-child(odd){ border-inline-start:1px solid var(--separator); }
  .zoomed .sig-num:nth-child(n+3){ border-top:0; }

  /* The RFQ window, the seller's page and the signals panel are scaled rather
     than reflowed now. A media query asks the viewport, and the viewport is a
     phone — but these are laid out in a 1180px box, so every rule that would
     stack them has to be answered here. Each selector carries .zoomed, which
     outranks the single-class rule further down the file whatever the order. */
  .zoomed .rfq-body{ grid-template-columns:minmax(0,1fr) 364px; }
  .zoomed .rfq-meta{ grid-template-columns:repeat(4,minmax(0,1fr)); }
  .zoomed.mp{ grid-template-columns:minmax(0,1fr) 372px; }
  .zoomed .mp-req{ min-height:296px; }
  .zoomed .mp-stats{ grid-template-columns:repeat(4,minmax(0,1fr)); }
  .zoomed .orb{ grid-template-columns:1.5fr 1fr 1fr; }
  .zoomed .orb-core{ grid-row:span 2; grid-column:auto; min-height:330px; }
  /* Both cursors are the animation, not a pointer: they were hidden because a
     phone has no cursor, but inside the zoom this is a picture of a desktop. */
  .zoomed .rfq-cursor, .zoomed .mp-cursor{ display:block; }
  /* The halo reaches 200px above the panel and .zoom clips to its own box, so
     keeping it here would put the hard edge straight back. It is a desktop
     flourish and the scaled panel does not need it. */
  .zoomed .rfq-halo{ display:none; }

  /* The zero-commission panel joins them. Every size in it is a clamp against
     vw, and vw is the phone even when the box around it is 1180px — which is
     exactly why it looked cramped with an oversized figure. Pinned to the
     values the clamps reach on a desktop, so the scaled picture is the desktop
     picture. */
  /* This one is laid out at 760px rather than 1180px: its two figures ARE the
     argument, and at the wider box they scaled down to about 18px. The inner
     sizes are set for that narrower box, not copied from the desktop. */
  .zoomed.zcx .zcx-lanes{ height:360px; }
  .zoomed.zcx .zcx-cut{ font-size:52px; }
  .zoomed.zcx .zcx-lane{ padding:0 30px; }
  .zoomed.zcx .zcx-foot{ padding:14px 30px; }
  .zoomed.zcx .zcx-note{ font-size:14px; }
}
@media (max-width:620px){
}
@media (max-width:560px){
  .zoomed .shot-url{ display:flex; }
  .zoomed .srch-filters{ padding:10px 14px; }
  .zoomed .srch{ height:640px; }
}

/* ===========================================================================
   Mobile: three grids that become sliders

   Stacked, each of these ran to five or six screens of scrolling before the
   next argument started — the coverage groups worst of all. A slider keeps the
   whole set one thumb-swipe wide and puts the section back on one screen.

   All three use the same mechanism: the track bleeds to both edges of the
   viewport so a card can sit flush against the gutter, scroll-padding lines the
   next card up with the page's own margin, and scroll-snap stops it between
   cards. Nothing is hidden — it is the same content, along one axis instead of
   two.
   ========================================================================= */
@media (max-width:760px){
  .swipe{
    display:flex; flex-wrap:nowrap; gap:12px;
    margin-inline:calc(var(--gutter, 20px) * -1);
    padding-inline:var(--gutter, 20px);
    overflow-x:auto; overscroll-behavior-x:contain;
    scroll-snap-type:x mandatory; scroll-padding-inline-start:var(--gutter, 20px);
    -webkit-overflow-scrolling:touch;
    scrollbar-width:none;
  }
  .swipe::-webkit-scrollbar{ display:none; }
  .swipe > *{ flex:0 0 clamp(240px, 84%, 340px); scroll-snap-align:start; align-self:stretch; }

  /* .swipe is display:flex, so the grid rules these three carried have to go —
     grid-template-columns on a flex container is inert, but the widths and
     margins set alongside them are not. */
  .type-groups.swipe{ align-items:stretch; }
  /* On a phone the column that matters goes first: the reader should not have
     to swipe past two competitors to reach the one flat fee. */
  /* This one lives inside a rounded, clipped panel, so it bleeds to the panel's
     own padding rather than to the screen — the card edge is the right edge for
     it to run to. */
}

/* ============================================================================
   LIGHT SURFACES

   Two kinds of container invert. Everything inside them is written against the
   same tokens as the rest of the page, so flipping the tokens on a container
   flips the whole subtree — no second set of rules, nothing to keep in sync.

   The values are the product's own light theme, taken across unchanged: warm
   sand, not white. Someone who signs up should not feel the temperature move
   between the landing and the app.

   Two things cannot come across unchanged. The section is the canvas the cards
   lie on while a card is paper — on the old palette both were #FFFFFF, so a
   card was only ever its border. And the brand orange needs a darker cut: the
   page's #FF7A1A lands at 2.3:1 on sand, under the 3:1 a 7px beacon or a 2px
   rule needs to be seen at all. #E8590C is the same orange at 3.1:1 on the
   canvas and 3.6:1 on paper. It stays a mark; text on an orange wash is
   --live-on-soft, never --live.
   ========================================================================= */
.is-light, .panel-light{
  --canvas:        #EFEEE8;              /* the page the cards lie on */
  --bg:            #FEFEFC;              /* the card / paper */
  --bg-deep:       #EFEEE8;              /* "deeper" on light can only mean down to the canvas */
  --bg-elevated:   #FEFEFC;
  --bg-raised:     #F3F2EC;              /* nothing is brighter than paper, so raised reads as recessed */
  --surface-in:    #F3F2EC;              /* a block inside a block */
  --bg-row-hover:  #F5F4ED;

  --fill:          rgba(92,88,74,.075);
  --fill-hover:    rgba(92,88,74,.14);
  --fill-active:   rgba(92,88,74,.22);
  --track:         rgba(92,88,74,.18);

  /* the greys are the sand's own ink, not black at low alpha — black over a
     warm ground prints grey and drags the whole section cold */
  --label:         #1A1A18;              /* 15.0:1 on the canvas, 17.3:1 on paper */
  --label-2:       #57564F;              /* 6.3:1 / 7.3:1 */
  --label-3:       #6B6A64;              /* 4.7:1 / 5.4:1 — clears 4.5 at the 12px captions use it for */

  --separator:        rgba(92,88,74,.14);
  --separator-strong: rgba(92,88,74,.24);
  --hatch:            rgba(92,88,74,.24); /* the dark value is near-white and vanishes here */

  --live:          #E8590C;              /* the beacon — a mark, not text */
  --live-soft:     rgba(232,89,12,.12);  /* a point over the old .11: the wash has less room to separate from sand than from white */
  --live-on-soft:  #9A3412;              /* 5.5:1 on that wash over canvas, 6.2:1 over paper; 6.3:1 as plain text on canvas */
  --recent:        #146C2E;              /* 5.6:1 on canvas, 6.5:1 on paper */
  --recent-soft:   rgba(20,108,46,.10);

  /* the dark theme leaves these near-white: an inverted button or a focus ring
     in a light section would be paper on paper */
  --ink:           #1F1F1C;              /* --on-ink on it is 16.4:1 */
  --ink-hover:     #3A3A35;
  --on-ink:        #FEFEFC;
  --focus:         #1A1A18;

  color:var(--label);
}
/* A full-width section is the canvas and also gets the hairlines that separate
   it from its neighbours; a panel floating on a dark section is a card, so it
   takes paper and brings its own border. */
.is-light{ background:var(--canvas); border-block:1px solid var(--separator); }
.panel-light{ background:var(--bg); }

/* The mirror image: a dark slab inside a light section. The page's own dark
   values, re-declared on a container so the subtree flips back — every token
   the light block sets has to appear here, or it leaks in from above. */
.panel-dark{
  --canvas:        #161617;
  --bg:            #161617;
  --bg-deep:       #0A0A0B;
  --bg-elevated:   #1C1C1E;
  --bg-raised:     #242426;
  --surface-in:    #1C1C1E;
  --bg-row-hover:  rgba(235,235,245,.06);

  --fill:          rgba(235,235,245,.08);
  --fill-hover:    rgba(235,235,245,.13);
  --fill-active:   rgba(235,235,245,.20);
  --track:         rgba(235,235,245,.18);

  --label:         #F5F5F7;
  --label-2:       #A1A1A6;
  --label-3:       #8E8E93;

  --separator:        rgba(255,255,255,.09);
  --separator-strong: rgba(255,255,255,.16);
  --hatch:            rgba(245,245,247,.18);

  --live:          #FF7A1A;
  --live-soft:     rgba(255,122,26,.16);
  --live-on-soft:  #FFA25E;
  --recent:        #32D74B;
  --recent-soft:   rgba(50,215,75,.14);

  --ink:           #F5F5F7;
  --ink-hover:     #D2D2D7;
  --on-ink:        #1D1D1F;
  --focus:         #F5F5F7;

  background:var(--bg-elevated); color:var(--label);
}
.panel-dark .lead{ color:var(--label-2); }
.is-light .lead, .is-light .feed-sub, .is-light .live-delta{ color:var(--label-2); }


/* ---------- the orb: the market being read ----------
   A bento, with the canvas behind it. The cards are ordinary markup, so the
   content is there on the first frame rather than being typed out by an
   animation — the panel's claim is that the brief is already waiting at 07:00,
   and a viewer who arrives mid-cycle should see a full brief, not an empty
   column filling up. What the canvas adds is the part markup cannot show: the
   sphere reading, and a live wire running from it to every card it produced.
   The canvas sits at z-index 0 and the cards have their own ground, so a wire
   slips underneath a card instead of crossing it. */
.orb{
  position:relative; display:grid;
  grid-template-columns:1.5fr 1fr 1fr;
  /* The ground lives here, not on the sphere's cell: the canvas sits behind the
     grid, so a background on that cell would paint straight over the sphere.
     The cards carry their own, and the hairlines between them are borders
     rather than a 1px grid gap for the same reason. */
  background:var(--bg-deep);
  border-bottom:1px solid var(--separator);
}
.orb > canvas{
  position:absolute; inset:0; z-index:0;
  width:100%; height:100%; display:block; pointer-events:none;
}
/* the swap effect draws over the cards, so it sits above them */
.orb > #orb-fx{ z-index:2; }

/* A headline that wraps to two lines and one that does not must occupy the same
   box, or every swap would shove the card's meta line up and down. */
.obx-h{ min-height:2.64em; }
/* the kicker and the meta are not worth a particle system — they cross-fade
   while the headline is in pieces */
.obx-k, .obx-m{ transition:opacity .22s var(--ease); }
.obx.is-swapping .obx-k, .obx.is-swapping .obx-m{ opacity:0; }
.obx.is-swapping .obx-h{ opacity:0; }

/* the sphere's cell — empty on purpose, the canvas draws into it */
.orb-core{
  position:relative; z-index:1; grid-row:span 2; min-width:0;
  display:flex; flex-direction:column; justify-content:flex-end;
  padding:22px clamp(18px,2vw,26px); min-height:330px;
}
.orb-state{
  display:flex; align-items:center; gap:9px;
  font-size:13px; font-weight:600; letter-spacing:-.01em; color:var(--label);
}
.orb-pip{
  width:7px; height:7px; border-radius:50%; background:var(--live); flex:0 0 auto;
  animation:orbpip 2.2s var(--ease) infinite;
}
@keyframes orbpip{
  0%{ box-shadow:0 0 0 0 rgba(255,122,26,.5); }
  70%{ box-shadow:0 0 0 9px rgba(255,122,26,0); }
  100%{ box-shadow:0 0 0 0 rgba(255,122,26,0); }
}
.orb-sub{
  display:flex; align-items:center; gap:8px; margin-top:7px;
  font-size:12px; color:var(--label-3); font-variant-numeric:tabular-nums;
}
.orb-sub b{ color:var(--label-2); font-weight:600; }

/* the cards the sweep produced */
.obx{
  position:relative; z-index:1; min-width:0;
  padding:20px clamp(16px,1.6vw,22px) 22px;
  background:var(--bg);
  border-inline-start:1px solid var(--separator);
}
.obx:nth-of-type(3), .obx:nth-of-type(4){ border-top:1px solid var(--separator); }
.obx-k{
  font-size:11px; font-weight:700; letter-spacing:.07em; text-transform:uppercase;
  color:var(--label-3);
}
.obx-h{
  margin-top:10px; font-size:clamp(15px,1.4vw,17px); font-weight:600;
  letter-spacing:-.012em; line-height:1.32; color:var(--label);
}
.obx-m{
  display:flex; align-items:center; gap:8px; margin-top:12px;
  font-size:11px; color:var(--label-3); font-variant-numeric:tabular-nums;
}

@media (max-width:860px){
  .orb{ grid-template-columns:1fr 1fr; }
  .orb-core{ grid-row:auto; grid-column:1 / -1; min-height:260px; }
  .obx:nth-of-type(odd){ border-inline-start:0; }
  .obx{ border-top:1px solid var(--separator); }
}
@media (max-width:560px){
  .orb{ grid-template-columns:1fr; }
  .orb-core{ min-height:240px; }
  .obx{ border-inline-start:0; }
}

/* ===========================================================================
   THE RFQ — the artefact, not a description of it

   A manufacturer's first question about an RFQ is never "does it exist", it is
   "what exactly is being bought, how much of it, and to what spec". So the
   section shows the record itself: the same badge, the same four dates, the
   same scope and conditions, the same two files and the same named person the
   platform puts in front of a supplier.

   Hierarchy by size and weight, one accent. The only orange is the status pill,
   which is the one thing on the card that says "this is live" — everything else
   is the page's greys.
   ========================================================================= */
/* The card is not a landing block, it is a screen. So it sits in the same window
   chrome the hero uses, and a cursor works it: the whole point is that this is
   what you are looking at once you are inside. */
.rfq-win{
  position:relative; border-radius:20px; overflow:hidden;
  border:1px solid var(--separator); background:var(--bg);
  box-shadow:0 40px 90px -40px rgba(0,0,0,.8);
}
.rfq{ background:var(--bg); }
.rfq-top{ padding:26px clamp(20px,2.4vw,32px) 22px; }
.rfq-badge{
  display:inline-flex; align-items:center; gap:8px; height:26px; padding:0 11px;
  border-radius:99px; background:var(--live-soft); color:var(--live-on-soft);
  font-size:11px; font-weight:700; letter-spacing:.08em; text-transform:uppercase;
}
.rfq-badge .beacon{ width:6px; height:6px; color:var(--live); }
.rfq-title{
  margin-top:14px; font-family:var(--font-display);
  font-size:clamp(23px,2.6vw,34px); font-weight:700; letter-spacing:-.03em; line-height:1.1;
}
.rfq-for{ margin-top:10px; display:grid; gap:2px; }
.rfq-for b{ font-size:15px; font-weight:600; color:var(--label); letter-spacing:-.016em; }
.rfq-for span{ font-size:13px; color:var(--label-3); letter-spacing:-.006em; }

/* four cells, hairline-ruled — the dates a supplier plans around */
.rfq-meta{
  display:grid; grid-template-columns:repeat(4,minmax(0,1fr)); gap:1px;
  background:var(--separator); border-block:1px solid var(--separator);
}
.rfq-meta > div{ padding:16px clamp(20px,2.4vw,32px) 18px; background:var(--bg); min-width:0; }
.rfq-k{ font-size:11px; font-weight:700; letter-spacing:.08em; text-transform:uppercase; color:var(--label-3); }
.rfq-v{
  margin-top:6px; font-family:var(--font-display); font-size:clamp(17px,1.7vw,23px);
  font-weight:600; letter-spacing:-.02em; white-space:nowrap;
}
.rfq-n{ margin-top:3px; font-size:12px; line-height:1.4; color:var(--label-3); }

.rfq-body{ display:grid; grid-template-columns:minmax(0,1fr) 364px; gap:1px; background:var(--separator); }
.rfq-scope, .rfq-side{ padding:24px clamp(20px,2.4vw,32px) 28px; background:var(--bg); min-width:0; }
.rfq-h{ font-size:14px; font-weight:600; letter-spacing:-.01em; }
.rfq-h2{ margin-top:26px; padding-top:22px; border-top:1px solid var(--separator); }
.rfq-p{ margin-top:10px; max-width:56ch; font-size:15px; line-height:1.6; color:var(--label-2); letter-spacing:-.016em; }
.rfq-sub{
  margin-top:22px; font-size:11px; font-weight:700; letter-spacing:.08em;
  text-transform:uppercase; color:var(--label-3);
}
.rfq-list{ margin-top:10px; display:grid; gap:7px; list-style:none; }
.rfq-list li{
  position:relative; padding-inline-start:18px; max-width:60ch;
  font-size:14px; line-height:1.55; color:var(--label-2);
  letter-spacing:-.011em;
}
.rfq-list li::before{
  content:""; position:absolute; inset-inline-start:2px; top:.62em; width:5px; height:5px;
  border-radius:50%; background:var(--separator-strong);
}

.rfq-docs{ margin-top:12px; display:grid; gap:8px; list-style:none; }
.rfq-docs li{
  display:grid; grid-template-columns:auto minmax(0,1fr) auto; gap:11px; align-items:center;
  padding:10px 12px; border-radius:11px; background:var(--fill);
  transition:background-color .2s var(--ease), transform .2s var(--ease-out);
}
.rfq-docs li.is-hot{ background:var(--fill-hover); transform:translateY(-1px); }
.rfq-ext{
  display:grid; place-items:center; width:34px; height:34px; border-radius:8px;
  background:var(--bg-raised); color:var(--label-3);
  font-size:10px; font-weight:700; letter-spacing:.06em;
}
.rfq-doc{ min-width:0; display:grid; gap:2px; }
.rfq-doc b{ font-size:13px; font-weight:600; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; letter-spacing:-.006em; }
.rfq-doc span{ font-size:12px; color:var(--label-3); }

.rfq-who{ margin-top:12px; display:grid; grid-template-columns:auto minmax(0,1fr); gap:11px; align-items:center; }
.rfq-av{
  display:grid; place-items:center; width:38px; height:38px; border-radius:50%;
  background:var(--fill); color:var(--label-2); font-size:13px; font-weight:600;
  letter-spacing:-.006em;
}
.rfq-who-t{ min-width:0; display:grid; gap:2px; }
.rfq-who-t b{ font-size:14px; font-weight:600; letter-spacing:-.011em; }
.rfq-who-t span{ font-size:12px; line-height:1.4; color:var(--label-3); }
.rfq-line{
  margin-top:10px; display:flex; align-items:baseline; justify-content:space-between; gap:12px;
  font-size:13px; color:var(--label-3);
  letter-spacing:-.006em;
}
.rfq-line b{ flex:1; min-width:0; font-weight:500; color:var(--label-2); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }

/* The two things a cursor can press: pull a file, take a number.
   The file control is an icon, not the word "Download" — spelled out it ate
   enough of a 364px column to truncate the filename it sits next to, which is
   the one thing in the row that has to be readable. */
.rfq-get, .rfq-copy{
  flex:0 0 auto; display:inline-flex; align-items:center; justify-content:center;
  height:28px; border-radius:8px;
  background:var(--bg-raised); color:var(--label-3);
  font-size:11px; font-weight:600; letter-spacing:.02em; white-space:nowrap;
  transition:background-color .2s var(--ease), color .2s var(--ease), transform .2s var(--ease-out);
}
.rfq-copy{ padding:0 10px; }
.rfq-get{ width:28px; }
.rfq-get-d{ transform:rotate(90deg); }
.rfq-get-k{ display:none; }
.rfq-get.is-hit .rfq-get-d{ display:none; }
.rfq-get.is-hit .rfq-get-k{ display:block; }
.rfq-get.is-hot, .rfq-copy.is-hot{ background:var(--fill-hover); color:var(--label); }
/* the moment it is pressed it says what happened — in the brand, because
   something just did happen, which is the one thing --live is for */
.rfq-get.is-hit, .rfq-copy.is-hit{
  background:var(--live-soft); color:var(--live-on-soft); transform:scale(.96);
}

/* One cursor, driven by js/landing.js. transform only, so it rides the
   compositor and never touches layout. */
.rfq-cursor{
  position:absolute; left:0; top:0; z-index:5; pointer-events:none;
  opacity:0; transform:translate3d(0,0,0);
  filter:drop-shadow(0 4px 10px rgba(0,0,0,.6));
  transition:opacity .35s var(--ease), transform .62s var(--ease-out);
}
.rfq-cursor.is-on{ opacity:1; }
/* the press: a ring that opens out of the point and fades */
.rfq-cursor::after{
  content:""; position:absolute; left:-4px; top:-4px; width:12px; height:12px;
  border-radius:50%; border:1.5px solid var(--live); opacity:0;
}
.rfq-cursor.is-click::after{ animation:cursorhit .5s var(--ease-out); }
@keyframes cursorhit{
  from{ opacity:.9; transform:scale(.4); }
  to  { opacity:0;  transform:scale(3.4); }
}

/* No boxes. Three claims under a screenshot are text, and a border around each
   one put three more rectangles next to a page that has enough of them — the
   hairline they hang from is the same device the rest of the page uses. */
.rfq-points{
  margin-top:40px; display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:32px;
}
.rfq-points article{ padding-top:0; }
.rfq-point-h{ font-size:17px; font-weight:600; letter-spacing:-.015em; line-height:1.3; }
.rfq-point-p{ margin-top:10px; font-size:14px; line-height:1.6; color:var(--label-2); letter-spacing:-.011em; }

@media (max-width:980px){
  .rfq-body{ grid-template-columns:minmax(0,1fr); }
  .rfq-points{ grid-template-columns:minmax(0,1fr); gap:24px; }
  /* a pointer is a desktop idea; a phone has a finger and no cursor to show */
  .rfq-cursor{ display:none; }
}
@media (max-width:680px){
  .rfq-meta{ grid-template-columns:repeat(2,minmax(0,1fr)); }
}

/* ---------- the two sides, as two cards ----------
   This was two columns of six labelled definitions — accurate, and nobody read
   past the first. A visitor is one of these two things and wants to find their
   own side in a second, so each side is a card with a name, one sentence and
   the roles it covers as tags. */
.who-cards{
  margin-top:20px; display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:16px;
}
.who-card{
  padding:clamp(24px,3vw,40px); border-radius:20px;
  background:var(--bg-raised);
}
.who-k{
  font-size:11px; font-weight:700; letter-spacing:.12em; text-transform:uppercase;
  color:var(--label-3);
}
.who-card.is-you .who-k{ color:var(--live-on-soft); }
.who-h{
  margin-top:10px; font-family:var(--font-display);
  font-size:clamp(28px,3.4vw,44px); font-weight:700; letter-spacing:-.032em; line-height:1;
}
.who-p{ margin-top:14px; max-width:34ch; font-size:16px; line-height:1.55; color:var(--label-2); letter-spacing:-.02em; }
.who-tags{ margin-top:22px; display:flex; flex-wrap:wrap; gap:8px; list-style:none; }
.who-tags li{
  display:inline-flex; align-items:center; height:34px; padding:0 14px; border-radius:99px;
  border:1px solid var(--separator-strong); color:var(--label-2);
  font-size:12px; font-weight:600; letter-spacing:.06em; text-transform:uppercase;
}
/* The side the reader is on carries the brand outline — one card is highlighted,
   and it is the one this page is written for. */
.who-card.is-you .who-tags li{ border-color:rgba(255,122,26,.42); color:var(--live-on-soft); }
@media (max-width:860px){
  .who-cards{ grid-template-columns:minmax(0,1fr); }
  .who-tags li{ height:32px; padding:0 12px; font-size:11px; }
}

/* ---------- how we charge ----------
   Three columns of somebody else's arithmetic used to make this argument: what a
   trading company takes, what a marketplace takes, what we take. It proved the
   point by spending most of its space on the competition. The claim stands on
   its own — what the fee buys, and the three things it is not. */
@media (max-width:860px){
}

/* ---------- a section's own call to action, centred under it ---------- */
.sec-cta{ display:flex; justify-content:center; margin-top:48px; }

/* ---------- the shelf runs two rows, the second offset against the first ---------- */
.pslider-track.is-row2{ margin-top:16px; }


/* ---------- the figures, as a full-width band under the hero ---------- */
.figband{ border-block:1px solid var(--separator); background:var(--bg-elevated); }
.figband .figrow{
  display:grid; grid-template-columns:repeat(4,minmax(0,1fr));
  margin:0; border:0; border-radius:0;
}
.figband .figcell{ padding:28px 24px; }
@media (max-width:760px){
  .figband .figrow{ grid-template-columns:repeat(2,minmax(0,1fr)); }
  .figband .figcell:nth-child(odd){ border-inline-start:0; }
  .figband .figcell:nth-child(n+3){ border-top:1px solid var(--separator); }
}

/* ---------- what every call to action promises ---------- */
.cta-note{
  margin-top:16px; display:flex; flex-wrap:wrap; align-items:center; justify-content:center;
  gap:8px 10px; font-size:13px; color:var(--label-3);
  letter-spacing:-.006em;
}
.cta-note .sep{ width:3px; height:3px; border-radius:50%; background:var(--label-3); }
.hero-acts + .cta-note{ justify-content:flex-start; }

/* ---------- the markets, read at a glance ---------- */
.markets{ border-bottom:1px solid var(--separator); padding-block:18px; overflow:hidden; }
.markets-track{ display:flex; width:max-content; animation:mq 52s linear infinite; }
.markets-track > span{
  display:inline-flex; align-items:center; gap:30px; padding-inline-end:30px;
  font-size:15px; font-weight:500; letter-spacing:.01em; white-space:nowrap; color:var(--label-2);
}
.markets-track i{ width:5px; height:5px; border-radius:50%; background:var(--live); flex:0 0 auto; }
.markets-track b{ font-weight:600; color:var(--label-3); }
.markets:hover .markets-track{ animation-play-state:paused; }

/* ============================================================================
   THE SELLING BLOCKS — headline first, then the proof, then the button
   ========================================================================= */
.case-h{ margin-top:0; }
.case-lede{ margin-top:22px; font-size:clamp(16px,1.5vw,19px); line-height:1.6; color:var(--label-2); letter-spacing:-.026em; }
.case-lede b{ color:var(--label); font-weight:600; }
.case-list{ margin-top:24px; display:grid; gap:12px; }
.case-list li{
  position:relative; padding-inline-start:26px; font-size:15px; line-height:1.55; color:var(--label-2);
  letter-spacing:-.016em;
}
.case-list li b{ color:var(--label); font-weight:600; }
.case-list li::before{
  content:""; position:absolute; inset-inline-start:4px; top:.62em; width:6px; height:6px;
  border-radius:50%; background:var(--label-3);
}

/* ---------- ask a researcher ---------- */
.ask-in{ display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:64px; align-items:center; }
@media (max-width:940px){ .ask-in{ grid-template-columns:minmax(0,1fr); gap:36px; } }
.ask-text{ max-width:52ch; }
.thread{ position:relative;
  padding:20px; border-radius:18px; border:1px solid var(--separator);
  background:var(--bg-elevated); box-shadow:var(--shadow-panel);
  display:flex; flex-direction:column; gap:12px;
}
.thread-head{ display:flex; align-items:center; gap:11px; padding-bottom:14px; border-bottom:1px solid var(--separator); }
.faces{ display:flex; }
.faces span{
  width:30px; height:30px; border-radius:50%; display:grid; place-items:center;
  background:var(--bg-raised); border:2px solid var(--bg-elevated); color:var(--label-2);
  font-size:9px; font-weight:700; letter-spacing:.02em;
}
.faces span + span{ margin-inline-start:-9px; }
.thread-who{ min-width:0; }
.thread-who b{ display:block; font-size:13px; font-weight:600; letter-spacing:-.006em; }
.thread-who span{ display:block; font-size:12px; color:var(--label-3); }
/* The line used to be nowrap outright, which held on one line in English and
   pushed the page 13px wide in Russian. Only the figure has to stay
   unbroken; the sentence around it may wrap. */
.thread-sla{ margin-inline-start:auto; font-size:12px; color:var(--recent); font-weight:600; text-align:end; }
.thread-sla b{ white-space:nowrap; }
.bub{ max-width:88%; padding:12px 15px; border-radius:16px; font-size:14px; line-height:1.5; letter-spacing:-.011em; }
.bub.is-you{ align-self:flex-end; background:var(--fill-hover); color:var(--label); border-bottom-right-radius:5px; }
.bub.is-us{ align-self:flex-start; background:var(--bg-raised); border:1px solid var(--separator); border-bottom-left-radius:5px; max-width:100%; }
.bub.is-us > b{ display:block; font-size:11px; font-weight:700; letter-spacing:.07em; text-transform:uppercase; color:var(--label-3); margin-bottom:8px; }
.bub.is-us p + p{ margin-top:10px; }
.bub.is-us b{ color:var(--label); font-weight:600; }
.bub-foot{ display:block; margin-top:12px; padding-top:10px; border-top:1px solid var(--separator); font-size:12px; color:var(--recent); }
.bub.is-typing{ align-self:flex-start; display:flex; gap:4px; padding:14px 15px; background:var(--bg-raised); border:1px solid var(--separator); border-bottom-left-radius:5px; }
.bub.is-typing i{ width:6px; height:6px; border-radius:50%; background:var(--label-3); animation:typing 1.2s ease-in-out infinite; }
.bub.is-typing i:nth-child(2){ animation-delay:.16s } .bub.is-typing i:nth-child(3){ animation-delay:.32s }
@keyframes typing{ 0%,60%,100%{ opacity:.25; transform:translateY(0) } 30%{ opacity:1; transform:translateY(-3px) } }
/* the thread plays itself once it is on screen */
.thread .bub{ opacity:0; transform:translateY(8px); transition:opacity .4s var(--ease-out), transform .4s var(--ease-out); }
.thread.is-on .bub[data-step="1"]{ opacity:1; transform:none; }
.thread.is-on.step2 .bub[data-step="2"]{ opacity:1; transform:none; }
/* The typing bubble is taken out of flow rather than removed at step 3: it used
   to be display:none'd, which collapsed its height and made the whole block jump
   at the exact moment the answer landed. Out of flow it never contributes height
   in the first place, so nothing moves.

   But out of flow it also needs somewhere to be. It had no top, and the static
   position of an absolutely positioned child of a column flex container is the
   container's own content corner — not the line it would have sat on. So the
   typing dots flew to the top of the panel and landed on the heading. The two
   of them share a slot now: the answer gives the slot its height, the dots sit
   at the top of it, which is exactly where the answer begins. */
.bub-slot{ position:relative; display:flex; flex-direction:column; }
.thread .bub[data-step="2"]{ position:absolute; inset-inline-start:0; top:0; }
.thread.is-on.step3 .bub[data-step="2"]{ opacity:0; }
.thread.is-on.step3 .bub[data-step="3"]{ opacity:1; transform:none; }
@media (prefers-reduced-motion:reduce){
  .thread .bub{ opacity:1; transform:none; }
  .thread .bub[data-step="2"]{ opacity:0; }
}

/* ---------- the close ---------- */
.final-in{ text-align:center; }
.final-in h2{ max-width:18ch; margin-inline:auto; }
.final-in .lead{ margin-top:22px; max-width:52ch; margin-inline:auto; }
.final-acts{ margin-top:32px; display:flex; justify-content:center; }
.final-shot{ margin-top:64px; }
.final-strip{ display:grid; grid-template-columns:repeat(5,minmax(0,1fr)); gap:12px; }
.fs-card{ display:block; text-align:start; border-radius:14px; overflow:hidden; border:1px solid var(--separator); background:var(--bg-elevated); }
.fs-card img{ width:100%; aspect-ratio:16/10; object-fit:cover; }
.fs-card b{ display:block; padding:11px 12px 0; font-size:13px; font-weight:600; line-height:1.3; letter-spacing:-.006em; }
.fs-card span{ display:block; padding:4px 12px 12px; font-size:12px; color:var(--label-3); }
.fs-more{
  display:grid; place-content:center; text-align:center; gap:6px; border-radius:14px;
  border:1px dashed var(--separator-strong); background:rgba(255,255,255,.02);
}
.fs-more b{ font-family:var(--font-display); font-size:clamp(20px,2vw,28px); font-weight:600; letter-spacing:-.03em; }
.fs-more span{ font-size:12px; color:var(--label-3); }
@media (max-width:860px){ .final-strip{ grid-template-columns:repeat(2,minmax(0,1fr)); } .fs-more{ grid-column:span 2; padding:20px; } }


/* the thread keeps the product's surfaces too */
.thread{ background:var(--bg); box-shadow:none; }
.thread-sla{ color:var(--label-3); font-weight:500; }
.bub.is-us{ background:var(--bg-elevated); }
.bub-foot{ color:var(--label-3); }

/* ---------- the block visuals, in the product's own vocabulary ---------- */
.vpanel{ border:1px solid var(--separator); border-radius:14px; overflow:hidden; background:var(--bg); }
.vpanel-head{ display:flex; align-items:center; gap:12px; padding:14px 16px; border-bottom:1px solid var(--separator); }
.vpanel-title{ font-size:14px; font-weight:600; letter-spacing:-.011em; }
.vpanel-meta{ margin-inline-start:auto; display:inline-flex; align-items:center; gap:7px; font-size:12px; color:var(--label-3); }
.vpanel-meta .beacon{ width:6px; height:6px; color:var(--live); }
.vpanel-foot{ padding:13px 16px; border-top:1px solid var(--separator); font-size:12px; color:var(--label-3); }

/* ---------- project participants, as the product lists them ----------
   Grouped by role, each group headed with its count, each company a row with
   its initials, the person on it and the three ways to reach them. */
.party-body{ padding:6px 0 10px; }
.group + .group{ border-top:1px solid var(--separator); }
.group-head{
  display:flex; align-items:center; justify-content:space-between; gap:12px;
  padding:12px 16px 6px;
  font-size:11px; font-weight:700; letter-spacing:.08em; text-transform:uppercase; color:var(--label-3);
}
.group-head .num{ letter-spacing:0; }
.person{
  display:grid; grid-template-columns:32px minmax(0,1fr) auto; gap:12px; align-items:center;
  padding:9px 16px;
  opacity:0; transform:translateY(6px);
  transition:opacity .42s var(--ease-out), transform .42s var(--ease-out);
  transition-delay:calc(var(--i) * .1s);
}
.parties.is-on .person{ opacity:1; transform:none; }
.avatar-m{
  width:32px; height:32px; border-radius:50%; display:grid; place-items:center;
  background:var(--fill); color:var(--label-2); font-size:11px; font-weight:700;
}
.person-main{ min-width:0; }
.person-name{ display:block; font-size:14px; font-weight:600; line-height:1.35; letter-spacing:-.011em; }
.person-role{ display:block; margin-top:2px; font-size:12px; color:var(--label-2); }
.person-actions{ display:flex; gap:4px; }
.person-actions i{
  width:28px; height:28px; border-radius:8px; display:grid; place-items:center;
  background:var(--fill); color:var(--label-2);
}
/* the buyer's row lights up once the rest of the tree has landed, and its three
   channels come in one after another — the point of the panel, made to happen */
.person.is-mark .avatar-m{
  background:var(--fill); color:var(--label-2);
  transition:background-color .4s var(--ease), color .4s var(--ease);
}
.parties.is-lit .person.is-mark .avatar-m{ background:var(--live-soft); color:var(--live-on-soft); }
.person.is-mark .person-actions i{
  transition:background-color .35s var(--ease), color .35s var(--ease), transform .35s var(--ease-out);
}
.parties.is-lit .person.is-mark .person-actions i{ background:var(--live-soft); color:var(--live-on-soft); }
.parties.is-lit .person.is-mark .person-actions i:nth-child(1){ transition-delay:.05s }
.parties.is-lit .person.is-mark .person-actions i:nth-child(2){ transition-delay:.15s }
.parties.is-lit .person.is-mark .person-actions i:nth-child(3){ transition-delay:.25s }
.person.is-mark{ position:relative; }
.person.is-mark::before{
  content:""; position:absolute; inset-inline-start:0; top:4px; bottom:4px; width:2px; border-start-end-radius:2px; border-end-end-radius:2px;
  background:var(--live); opacity:0; transition:opacity .4s var(--ease);
}
.parties.is-lit .person.is-mark::before{ opacity:1; }
/* the tail row carries no avatar, so it gets the whole width and indents to
   the same column the names sit in */
.person.is-more{ display:block; padding:2px 16px 6px; padding-inline-start:60px; }
.person.is-more .person-role{ color:var(--label-3); }
@media (prefers-reduced-motion:reduce){ .person{ opacity:1; transform:none; } }

/* ---------- the research log, on the live feed's own row ---------- */
.rstats{ display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); border-bottom:1px solid var(--separator); }
.rstats > span{ padding:14px 16px; font-size:12px; color:var(--label-3); }
.rstats > span + span{ border-inline-start:1px solid var(--separator); }
.rstats b{ display:block; margin-bottom:5px; font-family:var(--font-display); font-size:24px; font-weight:600; letter-spacing:-.03em; color:var(--label); }
.rfeed{
  /* Five rows showed about one change per visit at the old cadence. The window
     is taller so the log reads as a shift in progress rather than a ticker. */
  height:392px; overflow:hidden; padding:6px 0;
  /* This <ul> also carries .feed-list, which is a real scroller and asks for
     overscroll-behavior:contain. Here overflow is hidden, so the element can
     never scroll — and contain then stopped the wheel from reaching the page
     at all: the cursor landed on the log and the page froze. */
  overscroll-behavior:auto;
  -webkit-mask-image:linear-gradient(180deg,#000 calc(100% - 40px),transparent);
          mask-image:linear-gradient(180deg,#000 calc(100% - 40px),transparent);
}
.rfeed li{ display:grid; grid-template-columns:28px minmax(0,1fr) auto; column-gap:11px; padding:9px 16px; }
.rfeed li.is-new{ animation:feed-in .45s var(--ease); }
.rf-icon{ width:28px; height:28px; border-radius:50%; display:grid; place-items:center; background:var(--fill); color:var(--label-2); }
.rfeed li.is-new .rf-icon{ background:var(--live-soft); color:var(--live-on-soft); }
.rf-main{ min-width:0; }
.rf-act{ display:block; font-size:13px; font-weight:500; line-height:1.4; letter-spacing:-.006em; }
.rf-loc{ display:block; margin-top:2px; font-size:12px; color:var(--label-3); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.rf-t{ font-size:12px; color:var(--label-3); white-space:nowrap; }

/* ---------- the contact the researcher came back with ---------- */
.vcard{
  display:grid; grid-template-columns:32px minmax(0,1fr); gap:10px 12px;
  margin-top:14px; padding:13px; border-radius:12px;
  border:1px solid var(--separator); background:var(--bg);
}
.vcard .person-main{ align-self:center; }
.vcard-rows{ grid-column:1 / -1; display:grid; gap:7px; padding-top:11px; border-top:1px solid var(--separator); }
.vcard-row{ display:flex; align-items:center; gap:9px; font-size:13px; letter-spacing:-.006em; }
.vcard-row svg{ color:var(--label-3); flex:0 0 auto; }
.reveal{ font-style:normal; color:var(--label-2); transition:color .3s; }
.reveal.is-out{ color:var(--label); font-weight:600; animation:reveal .45s var(--ease); }
@keyframes reveal{ from{ opacity:.35; filter:blur(3px) } to{ opacity:1; filter:none } }

/* ---------- what customers won ----------
   The number carries the card. It is set at display size in the brand's own
   scale, the quote sits under it at reading size, and the person closes the
   column — so a row of these scans as six results before it reads as six
   opinions. One card on white keeps the grid from going flat. */

/* the lead card gets the room its number deserves */


@media (max-width:940px){
}
@media (max-width:620px){
}

/* ---------- the close ---------- */
.final-in{ text-align:center; }
.final-in h2{ max-width:18ch; margin-inline:auto; }
.final-in .lead{ margin-top:22px; max-width:52ch; margin-inline:auto; }
.final-acts{ margin-top:32px; display:flex; justify-content:center; }
.final-shot{ margin-top:64px; }
.final-strip{ display:grid; grid-template-columns:repeat(5,minmax(0,1fr)); gap:12px; }
.fs-card{ display:block; text-align:start; border-radius:14px; overflow:hidden; border:1px solid var(--separator); background:var(--bg-elevated); }
.fs-card img{ width:100%; aspect-ratio:16/10; object-fit:cover; }
.fs-card b{ display:block; padding:11px 12px 0; font-size:13px; font-weight:600; line-height:1.3; letter-spacing:-.006em; }
.fs-card span{ display:block; padding:4px 12px 12px; font-size:12px; color:var(--label-3); }
.fs-more{
  display:grid; place-content:center; text-align:center; gap:6px; border-radius:14px;
  border:1px dashed var(--separator-strong); background:rgba(255,255,255,.02);
}
.fs-more b{ font-family:var(--font-display); font-size:clamp(20px,2vw,28px); font-weight:600; letter-spacing:-.03em; }
.fs-more span{ font-size:12px; color:var(--label-3); }
@media (max-width:860px){ .final-strip{ grid-template-columns:repeat(2,minmax(0,1fr)); } .fs-more{ grid-column:span 2; padding:20px; } }


/* the thread keeps the product's surfaces too */
.thread{ background:var(--bg); box-shadow:none; }
.thread-sla{ color:var(--label-3); font-weight:500; }
.bub.is-us{ background:var(--bg-elevated); }
.bub-foot{ color:var(--label-3); }

/* ---------- the block visuals, in the product's own vocabulary ---------- */
.vpanel{ border:1px solid var(--separator); border-radius:14px; overflow:hidden; background:var(--bg); }
.vpanel-head{ display:flex; align-items:center; gap:12px; padding:14px 16px; border-bottom:1px solid var(--separator); }
.vpanel-title{ font-size:14px; font-weight:600; letter-spacing:-.011em; }
.vpanel-meta{ margin-inline-start:auto; display:inline-flex; align-items:center; gap:7px; font-size:12px; color:var(--label-3); }
.vpanel-meta .beacon{ width:6px; height:6px; color:var(--live); }
.vpanel-foot{ padding:13px 16px; border-top:1px solid var(--separator); font-size:12px; color:var(--label-3); }

/* ---------- project participants, as the product lists them ----------
   Grouped by role, each group headed with its count, each company a row with
   its initials, the person on it and the three ways to reach them. */
.party-body{ padding:6px 0 10px; }
.group + .group{ border-top:1px solid var(--separator); }
.group-head{
  display:flex; align-items:center; justify-content:space-between; gap:12px;
  padding:12px 16px 6px;
  font-size:11px; font-weight:700; letter-spacing:.08em; text-transform:uppercase; color:var(--label-3);
}
.group-head .num{ letter-spacing:0; }
.person{
  display:grid; grid-template-columns:32px minmax(0,1fr) auto; gap:12px; align-items:center;
  padding:9px 16px;
  opacity:0; transform:translateY(6px);
  transition:opacity .42s var(--ease-out), transform .42s var(--ease-out);
  transition-delay:calc(var(--i) * .1s);
}
.parties.is-on .person{ opacity:1; transform:none; }
.avatar-m{
  width:32px; height:32px; border-radius:50%; display:grid; place-items:center;
  background:var(--fill); color:var(--label-2); font-size:11px; font-weight:700;
}
.person-main{ min-width:0; }
.person-name{ display:block; font-size:14px; font-weight:600; line-height:1.35; letter-spacing:-.011em; }
.person-role{ display:block; margin-top:2px; font-size:12px; color:var(--label-2); }
.person-actions{ display:flex; gap:4px; }
.person-actions i{
  width:28px; height:28px; border-radius:8px; display:grid; place-items:center;
  background:var(--fill); color:var(--label-2);
}
/* the buyer's row lights up once the rest of the tree has landed, and its three
   channels come in one after another — the point of the panel, made to happen */
.person.is-mark .avatar-m{
  background:var(--fill); color:var(--label-2);
  transition:background-color .4s var(--ease), color .4s var(--ease);
}
.parties.is-lit .person.is-mark .avatar-m{ background:var(--live-soft); color:var(--live-on-soft); }
.person.is-mark .person-actions i{
  transition:background-color .35s var(--ease), color .35s var(--ease), transform .35s var(--ease-out);
}
.parties.is-lit .person.is-mark .person-actions i{ background:var(--live-soft); color:var(--live-on-soft); }
.parties.is-lit .person.is-mark .person-actions i:nth-child(1){ transition-delay:.05s }
.parties.is-lit .person.is-mark .person-actions i:nth-child(2){ transition-delay:.15s }
.parties.is-lit .person.is-mark .person-actions i:nth-child(3){ transition-delay:.25s }
.person.is-mark{ position:relative; }
.person.is-mark::before{
  content:""; position:absolute; inset-inline-start:0; top:4px; bottom:4px; width:2px; border-start-end-radius:2px; border-end-end-radius:2px;
  background:var(--live); opacity:0; transition:opacity .4s var(--ease);
}
.parties.is-lit .person.is-mark::before{ opacity:1; }
/* the tail row carries no avatar, so it gets the whole width and indents to
   the same column the names sit in */
.person.is-more{ display:block; padding:2px 16px 6px; padding-inline-start:60px; }
.person.is-more .person-role{ color:var(--label-3); }
@media (prefers-reduced-motion:reduce){ .person{ opacity:1; transform:none; } }

/* ---------- the research log, on the live feed's own row ---------- */
.rstats{ display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); border-bottom:1px solid var(--separator); }
.rstats > span{ padding:14px 16px; font-size:12px; color:var(--label-3); }
.rstats > span + span{ border-inline-start:1px solid var(--separator); }
.rstats b{ display:block; margin-bottom:5px; font-family:var(--font-display); font-size:24px; font-weight:600; letter-spacing:-.03em; color:var(--label); }
.rfeed{
  /* Five rows showed about one change per visit at the old cadence. The window
     is taller so the log reads as a shift in progress rather than a ticker. */
  height:392px; overflow:hidden; padding:6px 0;
  /* This <ul> also carries .feed-list, which is a real scroller and asks for
     overscroll-behavior:contain. Here overflow is hidden, so the element can
     never scroll — and contain then stopped the wheel from reaching the page
     at all: the cursor landed on the log and the page froze. */
  overscroll-behavior:auto;
  -webkit-mask-image:linear-gradient(180deg,#000 calc(100% - 40px),transparent);
          mask-image:linear-gradient(180deg,#000 calc(100% - 40px),transparent);
}
.rfeed li{ display:grid; grid-template-columns:28px minmax(0,1fr) auto; column-gap:11px; padding:9px 16px; }
.rfeed li.is-new{ animation:feed-in .45s var(--ease); }
.rf-icon{ width:28px; height:28px; border-radius:50%; display:grid; place-items:center; background:var(--fill); color:var(--label-2); }
.rfeed li.is-new .rf-icon{ background:var(--live-soft); color:var(--live-on-soft); }
.rf-main{ min-width:0; }
.rf-act{ display:block; font-size:13px; font-weight:500; line-height:1.4; letter-spacing:-.006em; }
.rf-loc{ display:block; margin-top:2px; font-size:12px; color:var(--label-3); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.rf-t{ font-size:12px; color:var(--label-3); white-space:nowrap; }

/* ---------- the contact the researcher came back with ---------- */
.vcard{
  display:grid; grid-template-columns:32px minmax(0,1fr); gap:10px 12px;
  margin-top:14px; padding:13px; border-radius:12px;
  border:1px solid var(--separator); background:var(--bg);
}
.vcard .person-main{ align-self:center; }
.vcard-rows{ grid-column:1 / -1; display:grid; gap:7px; padding-top:11px; border-top:1px solid var(--separator); }
.vcard-row{ display:flex; align-items:center; gap:9px; font-size:13px; letter-spacing:-.006em; }
.vcard-row svg{ color:var(--label-3); flex:0 0 auto; }
.reveal{ font-style:normal; color:var(--label-2); transition:color .3s; }
.reveal.is-out{ color:var(--label); font-weight:600; animation:reveal .45s var(--ease); }
@keyframes reveal{ from{ opacity:.35; filter:blur(3px) } to{ opacity:1; filter:none } }


/* ---------- the research log, made loud ----------
   Three copies of the claim have to agree: the figures, the wire and the row
   that just landed. The figures resolve once, the wire runs on a clock of its
   own so the panel is never completely still, and exactly one row is ever
   orange — it hands the colour back the moment the next one arrives, so "just
   now" keeps meaning just now. Scoped to #rfeed-panel because #parties is the
   other .vpanel and already runs its own reveal: an unscoped .vpanel-head::after
   or .is-new rule would land on top of it. */

/* the wire itself — the one thing here that moves without a row to move it,
   so the ~1.3s gaps between arrivals stop reading as a dead panel */
#rfeed-panel .vpanel-head{ position:relative; }
#rfeed-panel .vpanel-head::after{
  content:""; position:absolute; inset-inline:0; bottom:-1px; height:2px;
  background:linear-gradient(90deg, transparent 0%, var(--live) 50%, transparent 100%);
  opacity:0;
}
#rfeed-panel.is-live .vpanel-head::after{ animation:rf-sweep 3.2s var(--ease) infinite; }
@keyframes rf-sweep{
  0%{ opacity:0; transform:translateX(-100%) }
  12%{ opacity:.9 }
  70%{ opacity:.9 }
  100%{ opacity:0; transform:translateX(100%) }
}

/* The figures arrive rather than sit there. The .26s floor is the panel's own
   .rv fade getting out of the way first (.7s over a .14s delay, and its
   observer fires before this one) — the loudest moment of the block is wasted
   on a surface that is still half transparent. */
#rfeed-panel .rstats > span{
  opacity:0; transform:translateY(10px);
  transition:opacity .5s var(--ease-out) .26s, transform .5s var(--ease-out) .26s;
}
#rfeed-panel .rstats > span:nth-child(2){ transition-delay:.35s; }
#rfeed-panel .rstats > span:nth-child(3){ transition-delay:.44s; }
#rfeed-panel.is-on .rstats > span{ opacity:1; transform:none; }
/* 160+ and 10+ are quantities and count; 24/7 is not one, so it focuses
   instead — borrowing the panel's own reveal rather than inventing a motion */
#rfeed-panel.is-on .rstats > span:nth-child(3) b{ animation:reveal .5s var(--ease) .6s backwards; }

/* this window re-lays-out about fifty times a minute; nothing outside it has
   to be measured again when it does */
#rfeed-panel .rfeed{ contain:layout; }

/* The arrival pushes the column down by its own height instead of fading in on
   the spot — the difference between a ticker and a shift. The negative start
   margin puts the list exactly where it was before the insert, so the row
   slides down out of the clip and every row below it moves. .is-land is the
   one-shot the JS hands on at the next arrival; it is kept apart from .is-new
   so that scrolling the panel out and back cannot replay an arrival that is
   long over. */
#rfeed-panel .rfeed li{ position:relative; }
#rfeed-panel .rfeed li.is-new{ animation:none; }
#rfeed-panel .rfeed li.is-land{ animation:rf-in .42s var(--ease-out) 1; }
/* the fallback is a measured row, not a value off the spacing scale: the JS
   sets --h from the row's own height before it adds .is-land, so a two-line
   row slides its own two lines and the fallback is never the one used */
@keyframes rf-in{
  from{ margin-block-start:calc(var(--h, 56px) * -1); opacity:.15 }
  to{ margin-block-start:0; opacity:1 }
}

/* one pass of light across the row that landed, mixed up from --live rather
   than taken from --live-soft: at 12% on sand that token is below the
   threshold anything reads at scrolling speed */
#rfeed-panel .rfeed li.is-land::after{
  content:""; position:absolute; inset-block:0; inset-inline:2px 0;
  pointer-events:none; opacity:0;
  background:linear-gradient(90deg, transparent 0%, color-mix(in srgb, var(--live) 22%, transparent) 50%, transparent 100%);
  animation:rf-wash .75s var(--ease-out) 1;
}
@keyframes rf-wash{
  0%{ opacity:0; transform:translateX(-40%) }
  25%{ opacity:1 }
  100%{ opacity:0; transform:translateX(40%) }
}

/* The whole accent budget goes on one object: a solid disc on the newest row.
   At 28px it is the only thing on this panel a fast scroller can resolve —
   13px text and a 2px rail are not — and because exactly one row is ever
   marked, the disc appears to walk down the column a row per arrival. The mark
   goes on in a fifth of a second and comes off over a second and a half: the
   eye is pulled to the arrival and then let go of slowly, which is what stops
   fourteen marked rows from piling up into decoration. */
#rfeed-panel .rfeed li::before{
  content:""; position:absolute; inset-inline-start:0; top:6px; bottom:6px; width:2px;
  border-start-end-radius:2px; border-end-end-radius:2px;
  background:var(--live); opacity:0; transition:opacity 1.4s ease;
}
#rfeed-panel .rfeed li.is-new::before{ opacity:1; transition-duration:.18s; }
#rfeed-panel .rf-icon{ position:relative; transition:background-color 1.4s ease, color 1.4s ease; }
#rfeed-panel .rfeed li.is-new .rf-icon{
  /* --on-ink rather than a literal white: the token is paper in this section
     and ink on dark, so the glyph keeps its contrast on either ground */
  background:var(--live); color:var(--on-ink); transition-duration:.18s;
}
#rfeed-panel .rfeed li.is-land .rf-icon::after{
  content:""; position:absolute; inset:-4px; border-radius:50%;
  border:2px solid var(--live); opacity:0;
  animation:rf-ping .85s var(--ease-out) 1;
}
@keyframes rf-ping{ 0%{ transform:scale(.72); opacity:.85 } 100%{ transform:scale(1.5); opacity:0 } }
/* the place is what proves "10+ countries", so the place is what lights */
#rfeed-panel .rf-loc, #rfeed-panel .rf-t{ transition:color 1.4s ease; }
#rfeed-panel .rfeed li.is-new .rf-loc,
#rfeed-panel .rfeed li.is-new .rf-t{ color:var(--live-on-soft); transition-duration:.18s; }

/* the two sweeps are the only things on this panel with a handed direction */
[dir="rtl"] #rfeed-panel.is-live .vpanel-head::after{ animation-name:rf-sweep-rtl; }
@keyframes rf-sweep-rtl{
  0%{ opacity:0; transform:translateX(100%) }
  12%{ opacity:.9 }
  70%{ opacity:.9 }
  100%{ opacity:0; transform:translateX(-100%) }
}
[dir="rtl"] #rfeed-panel .rfeed li.is-land::after{ animation-name:rf-wash-rtl; }
@keyframes rf-wash-rtl{
  0%{ opacity:0; transform:translateX(40%) }
  25%{ opacity:1 }
  100%{ opacity:0; transform:translateX(-40%) }
}

@media (prefers-reduced-motion:reduce){
  /* The global kill switch at the top of this file already collapses every
     animation; what it cannot do is reveal the figures, which start at
     opacity 0 waiting for .is-on. The still frame is the three figures at
     their final values and one marked row — the claim at rest, not an empty
     list. The four decorative pseudo-elements go rather than flash through a
     .001ms animation. */
  #rfeed-panel .rstats > span{ opacity:1; transform:none; }
  #rfeed-panel.is-on .rstats > span:nth-child(3) b{ animation:none; }
  #rfeed-panel .vpanel-head::after,
  #rfeed-panel .rfeed li.is-land::after,
  #rfeed-panel .rfeed li.is-land .rf-icon::after{ display:none; }
}

/* ---------- what people actually said ---------- */
.revs{
  margin-top:48px; display:grid; gap:14px;
  grid-template-columns:repeat(3,minmax(0,1fr));
}
.rev{
  margin:0; padding:24px; border-radius:16px;
  border:1px solid var(--separator); background:var(--bg);
  display:flex; flex-direction:column;
}
.rev p{ font-size:15px; line-height:1.55; color:var(--label); letter-spacing:-.016em; }
.rev footer{ margin-top:auto; padding-top:18px; }
.rev footer b{ display:block; font-size:13px; font-weight:600; letter-spacing:-.006em; }
.rev footer span{ display:block; margin-top:3px; font-size:12px; line-height:1.4; color:var(--label-3); }
.rev.is-lead{ grid-column:span 2; }
.rev.is-lead p{ font-family:var(--font-display); font-size:clamp(19px,2vw,26px); line-height:1.35; letter-spacing:-.02em; }
.rev.is-wide{ grid-column:span 2; }
.rev.is-mark{ background:#F3F2EC; border-color:transparent; }
.rev.is-mark p{ color:#1A1A18; }
.rev.is-mark footer b{ color:#1A1A18; }
.rev.is-mark footer span{ color:#6B6A64; }
@media (max-width:620px){
  .revs{ grid-template-columns:minmax(0,1fr); }
  .rev.is-lead, .rev.is-wide{ grid-column:auto; }
}

/* the closing shelf carries the same cards as the 150+ shelf */
.final-slider{ margin-top:64px; text-align:start; }
/* a pin the cluster swallowed is part of its count, not a second mark */
.pin-anchor.is-hidden{ display:none; }



/* ===========================================================================
   MY PAGE — the seller's own storefront

   The section has to carry one idea: you publish once, and the demand comes
   back on its own. So it is drawn as two halves of the same object — the page
   on the left, what it returns on the right — and the only thing that moves is
   an enquiry arriving. Everything is built from the page's own tokens, so the
   mock is the design system rather than a picture of some other product.
   ========================================================================= */
.mp{
  display:grid; grid-template-columns:minmax(0,1fr) 372px; gap:20px;
  margin-top:48px; align-items:start;
}

/* ---- the published page ---- */
.mp-page{
  border:1px solid var(--separator); border-radius:20px; overflow:hidden;
  background:var(--bg-elevated);
  box-shadow:0 40px 90px -50px rgba(0,0,0,.8);
}
/* The mock's chrome bar is a step down from the page it heads. On the dark
   theme --bg does that on its own; in sand paper and card are the same value,
   so the bar takes the recessed surface instead. */
.is-light .mp-bar{ background:var(--surface-in); }

.mp-bar{
  display:flex; align-items:center; gap:7px;
  padding:0 16px; height:42px;
  border-bottom:1px solid var(--separator); background:var(--bg);
}
.mp-dot{ width:9px; height:9px; border-radius:50%; background:var(--fill-active); }
.mp-url{
  margin-inline-start:12px; padding:3px 12px; border-radius:99px;
  background:var(--fill); color:var(--label-3);
  font-size:12px; font-variant-numeric:tabular-nums;
}
.mp-body{ padding:clamp(20px,2.4vw,30px); }

.mp-kick{
  display:flex; align-items:center; gap:7px;
  font-size:11px; font-weight:700; letter-spacing:.07em; text-transform:uppercase;
  color:var(--label-3);
}
.mp-name{
  margin-top:9px; font-family:var(--font-display);
  font-size:clamp(23px,2.4vw,28px); font-weight:600; letter-spacing:-.022em; line-height:1.14;
}
.mp-claim{ margin-top:9px; max-width:46ch; font-size:15px; line-height:1.5; color:var(--label-2); letter-spacing:-.016em; }
.mp-verified{
  display:inline-flex; align-items:center; gap:7px; margin-top:14px;
  height:26px; padding:0 11px; border-radius:99px;
  background:var(--recent-soft); color:var(--recent);
  font-size:11px; font-weight:700; letter-spacing:.05em;
}

.mp-stats{
  display:grid; grid-template-columns:repeat(4,minmax(0,1fr)); gap:14px 12px;
  margin:22px 0 0; padding:18px 0; border-block:1px solid var(--separator);
}
.mp-stats dt{ grid-row:2; font-size:11px; color:var(--label-3); }
.mp-stats dd{
  grid-row:1; margin:0; font-family:var(--font-display);
  font-size:20px; font-weight:600; letter-spacing:-.02em;
}

.mp-k{
  margin-top:20px; font-size:11px; font-weight:700; letter-spacing:.07em;
  text-transform:uppercase; color:var(--label-3);
}
.mp-cat{ list-style:none; margin:12px 0 0; padding:0; }
.mp-cat li{
  padding:13px 0; border-top:1px solid var(--separator);
}
.mp-cat li:first-child{ border-top:0; }
.mp-p-h{ font-size:14px; font-weight:600; line-height:1.4; letter-spacing:-.011em; }
.mp-p-m{
  display:flex; align-items:center; flex-wrap:wrap; gap:8px;
  margin-top:6px; font-size:12px; color:var(--label-3);
}
.mp-p-m b{ color:var(--label); font-weight:600; }

/* ---- what the page brings back ---- */
.mp-inbox{
  display:flex; flex-direction:column;
  border:1px solid var(--separator); border-radius:20px;
  background:var(--bg-elevated); padding:20px;
}
.mp-inbox-head{ display:flex; align-items:baseline; justify-content:space-between; gap:12px; }
.mp-inbox-t{
  display:flex; align-items:center; gap:8px;
  font-size:13px; font-weight:600; letter-spacing:-.01em;
}
/* The figure that carries the whole claim used to be a 12px grey caption that
   swapped from 3 to 4 in silence — the stillest pixel in a block about things
   arriving. A number needs no narrative: it resolves in one frame from across
   the page, which is all a scroller gives this section, so it is set at the
   page-headline step and rolls when it changes. The sentence stays whole and
   the digit sits inside it, so every locale keeps its own word order. */
.mp-inbox-n{
  font-size:12px; color:var(--label-3); font-variant-numeric:tabular-nums;
  white-space:nowrap; line-height:1;
}
.mp-count-n{
  display:inline-block; margin-inline-end:2px;
  font-family:var(--font-display); font-size:28px; font-weight:600;
  letter-spacing:-.022em; line-height:1; color:var(--live);
  animation:mproll .52s var(--ease-out) both;
}
@keyframes mproll{
  0%  { opacity:0; transform:translateY(8px) scale(.9); }
  55% { opacity:1; transform:translateY(0) scale(1.18); }
  100%{ opacity:1; transform:none; }
}
.mp-req{ list-style:none; margin:16px 0 0; padding:0; min-height:296px; }
.mp-req li{
  position:relative; padding:12px 10px; margin-inline:-10px; border-radius:10px;
  border-top:1px solid var(--separator);
  animation:mpin .5s var(--ease-out) both;
}
.mp-req li:first-child{ border-top:0; }
/* the one that just landed holds the brand for a moment, then lets go — the
   point of this panel is the arriving, so the arrival has to be visible */
.mp-req li.is-new{ animation:mpin .5s var(--ease-out) both, mpflash 2.4s var(--ease) both; }
@keyframes mpflash{
  0%,60%{ background:var(--live-soft); }
  100%  { background:transparent; }
}
/* A 16% wash sliding to transparent is the quietest move a panel can make, and
   it was the only thing marking the arrival. The rail gives the landing a hard
   edge that resolves at a glance; it strikes down the row and burns off with
   the tint, so one event still reads as one event. */
.mp-req li::before{
  content:""; position:absolute; inset-inline-start:0; top:10px; bottom:10px; width:2px;
  border-radius:2px; background:var(--live); opacity:0;
}
.mp-req li.is-new::before{ animation:mprail 2.4s var(--ease) both; }
@keyframes mprail{
  0%  { opacity:1; transform:scaleY(0); transform-origin:50% 0; }
  14% { opacity:1; transform:scaleY(1); }
  70% { opacity:1; transform:scaleY(1); }
  100%{ opacity:0; transform:scaleY(1); }
}
.mp-req-new{
  flex:0 0 auto; height:18px; padding:0 7px; border-radius:99px;
  display:inline-flex; align-items:center;
  background:var(--live); color:#fff;
  font-size:10px; font-weight:700; letter-spacing:.05em; text-transform:uppercase;
  animation:mppop .34s var(--ease-out) both, mpchip .8s var(--ease) .34s 2;
}
@keyframes mppop{ from{ opacity:0; transform:scale(.6); } to{ opacity:1; transform:none; } }
@keyframes mpchip{ 0%,100%{ box-shadow:0 0 0 0 transparent } 45%{ box-shadow:0 0 0 4px var(--live-soft) } }
.mp-req-h{ display:flex; align-items:center; justify-content:space-between; gap:8px; }
.mp-req-p{ font-size:13px; font-weight:600; line-height:1.35; letter-spacing:-.006em; }
.mp-req-w{ flex:0 0 auto; font-size:11px; color:var(--live); font-variant-numeric:tabular-nums; }
.mp-req-n{ margin-top:5px; font-size:12px; line-height:1.45; color:var(--label-2); }
.mp-req-m{ margin-top:6px; font-size:11px; color:var(--label-3); font-variant-numeric:tabular-nums; }
@keyframes mpin{ from{ opacity:0; transform:translateY(-14px) scale(.97); } to{ opacity:1; transform:none; } }
.mp-inbox-f{
  margin-top:auto; padding-top:16px; border-top:1px solid var(--separator);
  font-size:12px; line-height:1.45; color:var(--label-3);
}

/* ---- the three points ---- */
.mp-points{
  display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:32px;
  margin-top:48px;
}
.mp-point-h{ font-size:15px; font-weight:600; letter-spacing:-.01em; }
.mp-point-p{ margin-top:8px; font-size:14px; line-height:1.55; color:var(--label-2); letter-spacing:-.011em; }

@media (max-width:1000px){
  .mp{ grid-template-columns:minmax(0,1fr); }
  .mp-req{ min-height:0; }
}
@media (max-width:760px){
  .mp-points{ grid-template-columns:minmax(0,1fr); gap:24px; }
  .mp-stats{ grid-template-columns:repeat(2,minmax(0,1fr)); }
}

/* ---------- shadows follow the surface they fall on ----------
   Both of these carried 0 40px 90px -40/50px rgba(0,0,0,.8) — written when each
   panel sat on the page's near-black and needed that much to lift off it. On
   sand the same shadow reads as a smudge under the card rather than light
   around it, so the light sections get their own, mixed from the ground's own
   warm ink instead of black; the light-on-light storefront gets the softer of
   the two because its border already does the separating. */
.is-light .rfq-win{ box-shadow:0 30px 70px -45px rgba(92,88,74,.55); }
.is-light .mp-page{ box-shadow:0 18px 44px -32px rgba(92,88,74,.34); }
/* The one dark object on a sand section: money is easier to watch on black, and
   the panel needs a ground of its own now that the section behind it is no
   longer the same colour as a card. */
.zcx{
  position:relative; border-radius:24px; overflow:hidden;
  border:1px solid var(--separator-strong);
  background:var(--bg-deep);
  box-shadow:0 30px 70px -45px rgba(92,88,74,.55);
}
.zcx canvas{
  position:absolute; inset:0; z-index:0;
  display:block; width:100%; height:100%; pointer-events:none;
}
.zcx-lanes{
  position:relative; z-index:1;
  display:grid; grid-template-rows:1fr 1fr;
  height:clamp(300px, 34vw, 420px);
}
.zcx-lane{
  display:flex; flex-direction:column; justify-content:center;
  padding:0 clamp(20px,3vw,44px);
}
.zcx-who{
  display:flex; align-items:center; gap:9px;
  font-size:12px; font-weight:700; letter-spacing:.08em; text-transform:uppercase;
  color:var(--label-3);
}
.zcx-lane.is-us .zcx-who{ color:var(--label); }
.zcx-dot{
  width:8px; height:8px; border-radius:50%; background:var(--live);
  box-shadow:0 0 0 0 rgba(255,122,26,.5); animation:orbpip 2.2s var(--ease) infinite;
}
.zcx-cut{
  margin-top:8px; font-family:var(--font-display);
  font-size:clamp(30px,4.6vw,56px); font-weight:600; letter-spacing:-.03em;
  line-height:1; font-variant-numeric:tabular-nums;
  color:var(--label-3);
}
.zcx-cut.is-zero{ color:var(--live); }
.zcx-note{ margin-top:8px; font-size:13px; color:var(--label-3); letter-spacing:-.006em; }
.zcx-lane.is-us .zcx-note{ color:var(--label-2); }

.zcx-foot{
  position:relative; z-index:1;
  padding:14px clamp(20px,3vw,44px); border-top:1px solid var(--separator);
  font-size:12px; color:var(--label-3); font-variant-numeric:tabular-nums;
}
.zcx-foot .num{ color:var(--label); font-weight:600; }

/* the three promises */
.zc-grid{
  display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:32px;
  margin-top:44px;
}
.zc-card-h{ font-size:17px; font-weight:600; letter-spacing:-.015em; }
.zc-card-p{ margin-top:10px; font-size:14px; line-height:1.6; color:var(--label-2); letter-spacing:-.011em; }

@media (max-width:860px){
  .zcx-lanes{ height:clamp(260px,52vw,340px); }
  .zc-grid{ grid-template-columns:minmax(0,1fr); gap:24px; }
}

/* ---------- the enquiry names what brought it in ----------
   A request that simply appeared said nothing about why. Each one now carries
   the catalogue item it came in against, and that item lights up on the page to
   the left at the same moment, so the chain — you listed it, a buyer found it,
   the enquiry landed — is visible rather than asserted. */
.mp-req-match{
  display:flex; align-items:center; gap:7px; margin-top:7px;
  font-size:11px; color:var(--label-3);
}
.mp-req-match b{
  min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
  font-weight:600; color:var(--live-on-soft);
}
.mp-req-arrow{
  flex:0 0 auto; width:12px; height:1px; background:var(--live); position:relative;
}
.mp-req-arrow::after{
  content:""; position:absolute; right:-1px; top:-2px;
  border-left:4px solid var(--live); border-block:2.5px solid transparent;
}
/* ---------- and you can watch it arrive ----------
   The row used to be in the inbox already and the one move was a tint fading
   out, so the section's claim had to be read rather than watched. The arrival
   has a cause now: a buyer opens a listing, the listing lights, and one orange
   packet carries the enquiry across the gutter into the inbox, where the panel
   answers at its own size and the row rises to meet it. Orange has exactly one
   job here — it is the request in flight. Every colour is a token that both
   .is-light and .panel-dark declare, so the same code reads on the sand
   section and on the dark panel sitting inside it.

   The moving highlights are mixed up from --live rather than taken from
   --live-soft: that token was tuned as a wash sitting behind text, and at 12%
   on sand it is under the threshold anything reads at scrolling speed. */
.mp{ position:relative; }

/* the buyer. transform only, so it rides the compositor and never lays out */
.mp-cursor{
  position:absolute; left:0; top:0; z-index:7; pointer-events:none;
  opacity:0; transform:translate3d(0,0,0);
  filter:drop-shadow(0 4px 10px rgba(0,0,0,.35));
  transition:opacity .3s var(--ease), transform .62s var(--ease-out);
}
.mp-cursor.is-on{ opacity:1; }
/* the frame it is placed in rather than travelling to: without this the first
   reveal is a 620ms glide out of the figure's top-left corner */
.mp-cursor.is-warp{ transition:none; }

/* the request, in flight */
.mp-flight{
  position:absolute; left:0; top:0; z-index:6; pointer-events:none;
  width:10px; height:10px; margin:-5px 0 0 -5px; border-radius:50%;
  background:var(--live); opacity:0;
  box-shadow:0 0 0 5px color-mix(in srgb, var(--live) 30%, transparent),
             0 0 20px 6px color-mix(in srgb, var(--live) 45%, transparent);
  transition:opacity .2s var(--ease);
  will-change:transform;
}
.mp-flight.is-on{ opacity:1; }
/* the tail: one stretched blur angled along the chord it travels, so the depth
   costs a pseudo-element instead of a particle system */
.mp-flight::after{
  content:""; position:absolute; left:50%; top:50%;
  width:32px; height:6px; margin:-3px 0 0 -16px; border-radius:99px;
  background:linear-gradient(90deg, transparent, var(--live));
  opacity:.5; filter:blur(3px);
  transform:rotate(var(--a,0deg)) translateX(-14px);
}
.mp-flight.is-land::before{
  content:""; position:absolute; left:50%; top:50%;
  width:14px; height:14px; margin:-7px 0 0 -7px;
  border-radius:50%; border:2px solid var(--live);
  animation:mpburst .52s var(--ease-out) both;
}
@keyframes mpburst{ from{ opacity:.9; transform:scale(.5); } to{ opacity:0; transform:scale(4.2); } }

/* the published page is being read, not sitting there */
.mp-page{ position:relative; }
.mp-page::after{
  content:""; position:absolute; inset:0; pointer-events:none; opacity:0;
  background:linear-gradient(105deg, transparent 38%,
             color-mix(in srgb, var(--live) 26%, transparent) 50%, transparent 62%);
}
.mp-page.is-read::after{ animation:mpsweep 1.05s var(--ease-out) both; }
@keyframes mpsweep{
  0%  { opacity:0; transform:translateX(-26%); }
  22% { opacity:1; }
  100%{ opacity:0; transform:translateX(26%); }
}

/* the listing the buyer just opened */
.mp-cat li{
  position:relative; border-radius:8px; margin-inline:-10px; padding-inline:10px;
  transition:background-color .3s var(--ease), box-shadow .3s var(--ease);
}
.mp-cat li::before{
  content:""; position:absolute; inset-inline-start:0; top:6px; bottom:6px; width:2px;
  border-radius:2px; background:var(--live);
  transform:scaleY(0); transform-origin:50% 0;
  transition:transform .34s var(--ease-out);
}
.mp-cat li.is-hit{
  background:var(--live-soft);
  box-shadow:0 6px 18px -10px var(--live);
}
.mp-cat li.is-hit::before{ transform:scaleY(1); }
.mp-cat li.is-hit .mp-p-h,
.mp-cat li.is-hit .mp-p-m b{ color:var(--live-on-soft); }

/* The panel answers at its own size, so the arrival registers from across the
   page rather than at the size of one 13px row. One answer at panel scale and
   one at row scale is the whole budget: four orange events inside the same
   second stop being an arrival and become a flare. */
.mp-inbox{ position:relative; }
.mp-inbox::after{
  /* -1px out and the border-box radius, so the rim sits exactly on the panel's
     own hairline instead of a pixel inside it, which reads as a double line */
  content:""; position:absolute; inset:-1px; border-radius:20px; pointer-events:none;
  opacity:0; box-shadow:inset 0 0 0 1px var(--live), inset 0 0 24px -10px var(--live);
}
.mp-inbox.is-land::after{ animation:mprim .9s var(--ease-out) both; }
@keyframes mprim{ 0%{ opacity:0 } 18%{ opacity:.55 } 100%{ opacity:0 } }
.mp-inbox-t .beacon{ width:8px; height:8px; color:var(--live); }
.mp-inbox-t .beacon::after{ animation-duration:1.8s; }

@media (max-width:980px){
  /* a pointer is a desktop idea; a phone has a finger and no cursor to show */
  .mp-cursor{ display:none; }
}

@media (prefers-reduced-motion:reduce){
  /* The global kill switch collapses every animation above to its end state,
     which leaves the two movers at opacity 0 — but a .001ms pass over a
     decorative overlay can still flash one frame, so they go entirely. The
     still frame is the JS's own: three enquiries waiting, the count, and the
     listing the newest one came in against lit with its rail. */
  .mp-cursor, .mp-flight,
  .mp-page::after, .mp-inbox::after{ display:none; }
}

/* the tiers a project's companies fall into, the way the product lists them */
.tiers{
  display:flex; flex-wrap:wrap; gap:6px;
  padding:12px 16px; border-bottom:1px solid var(--separator);
}
.tier{
  display:inline-flex; align-items:center; gap:6px; height:24px; padding:0 9px;
  border-radius:99px; background:var(--fill); color:var(--label-3);
  font-size:11px; font-weight:600; white-space:nowrap;
}
.tier b{ color:var(--label-2); font-weight:700; font-variant-numeric:tabular-nums; }
.tier.is-on{ background:var(--live-soft); color:var(--live-on-soft); }
.tier.is-on b{ color:var(--live-on-soft); }

/* ---------- the participants resolving, row by row ----------
   The panel used to land its rows and then hold still for good, and the one
   thing it exists to say — that the buyer's details are the product — was
   carried by rules keyed to .is-mark, which no row in any locale ever carried.
   The row the Ask block answers with is marked in the markup now, and the panel
   plays the transaction instead of describing it: every row arrives redacted, a
   verification pass clears them in the order it reaches them, and the buyer's
   row keeps the orange. That is the accent's only job on this panel.

   Appended here on purpose. Everything above from .party-body down appears in
   this file twice, verbatim, so anything written into the first copy is undone
   by the second. Sitting after both, these win without either being touched. */

/* the wings of the pass are mixed from the accent rather than named outright,
   so the band follows whichever cut of the orange the section is on — #FF7A1A
   on the canvas, #E8590C once a section is sand — with no second declaration
   left behind to drift */
.parties{ --scan-tint:color-mix(in srgb, var(--live) 26%, transparent); }

/* overflow:hidden because the band overhangs the column by its own height at
   each end of the travel and the panel only clips at its outer edge — without
   it the first frames of every lap wash orange over the title and the tiers */
.party-body{ position:relative; overflow:hidden; }
/* z-index:0 and not just position: the row's wash sits behind its own content
   at -1, which needs the row to be the stacking context it is measured against */
.parties .person{ position:relative; z-index:0; }

/* The verification pass. Its height is a share of the column rather than a pixel
   count, so the travel below is expressed in its own percentages and nothing
   has to be re-measured when the rows wrap to three lines on a phone. */
.party-body::before{
  content:""; position:absolute; inset-inline:0; top:0; height:40%;
  z-index:2; pointer-events:none; opacity:0;
  transform:translateY(-100%);
  background:linear-gradient(180deg,
    transparent 0%,
    var(--scan-tint) 42%,
    var(--live) calc(50% - 1px),
    var(--live) calc(50% + 1px),
    var(--scan-tint) 58%,
    transparent 100%);
}
/* linear, and 1000ms, because the driver schedules each row's reveal as a
   straight fraction of this travel; on an ease the band is four rows past the
   row it is supposed to be clearing. Duration and timing function are both
   duplicated in SCAN_MS — neither changes alone. */
.parties.is-scan .party-body::before{ animation:party-scan 1000ms linear forwards; }
@keyframes party-scan{
  0%{ transform:translateY(-100%); opacity:0; }
  6%{ opacity:1; }
  /* the line is at full strength while it crosses the buyer's row and gives way
     after it: the eye is handed to the orange rather than dragged past it to
     the bottom of a list it has already been sold on */
  56%{ opacity:1; }
  72%{ opacity:.45; }
  92%{ opacity:.45; }
  100%{ transform:translateY(250%); opacity:0; }
}

/* The redaction. It hangs off the text column, not off the row, so it contains
   the name's blur halo at any width and never has to be told where the avatar
   ends or the channel chips begin — the row's own grid answers both. It wipes
   on a transform rather than clip-path so the direction can follow the script. */
.parties .person-main{ position:relative; }
.parties .person-main::after{
  content:""; position:absolute; inset:-5px -6px; z-index:1; pointer-events:none;
  border-radius:6px; background:var(--fill-active);
  transform:scaleX(1); transform-origin:left;
  transition:transform .36s var(--ease);
}
[dir="rtl"] .parties .person-main::after{ transform-origin:right; }
/* the tail row is a note, not a company — it has nothing to withhold */
.parties .person.is-more .person-main::after{ display:none; }
.parties .person.is-clear .person-main::after{ transform:scaleX(0); }

/* blurred under the slab, so clearing reads as focus pulling in rather than as
   a box being lifted off — the language the Ask block's masked phone and email
   already resolve in */
.parties .person-name{
  filter:blur(6px); opacity:.38;
  transition:filter .42s var(--ease-out), opacity .42s var(--ease-out);
}
/* blur(0) and not none: interpolating a filter list against the keyword is
   where Safari gives up and snaps */
.parties .person.is-clear .person-name{ filter:blur(0); opacity:1; }
.parties .person-role{
  opacity:0; transform:translateY(4px);
  transition:opacity .32s var(--ease-out) .06s, transform .32s var(--ease-out) .06s;
}
.parties .person.is-clear .person-role{ opacity:1; transform:none; }
/* the shorthand carries background-color too: the .is-mark rule above sets that
   same property and would otherwise lose its fill transition to this one */
.parties .person .avatar-m{
  color:transparent;
  transition:color .28s var(--ease) .1s, background-color .4s var(--ease);
}
.parties .person.is-clear .avatar-m{ color:var(--label-2); }
.parties .person .person-actions i{
  opacity:0; transform:scale(.82);
  transition:opacity .26s var(--ease) .12s, transform .32s var(--ease-out) .12s,
             background-color .35s var(--ease), color .35s var(--ease);
}
.parties .person.is-clear .person-actions i{ opacity:1; transform:none; }

/* The buyer's row. The rail wipes out of its own centre rather than fading in,
   so the eye is given a direction into the row instead of a dot appearing, and
   it carries a glow because 3px of orange on a dark panel is a hairline until
   it does. */
.parties .person.is-mark::before{
  width:3px; box-shadow:0 0 10px color-mix(in srgb, var(--live) 55%, transparent);
  transform:scaleY(.2); transform-origin:center;
  transition:opacity .3s var(--ease), transform .3s var(--ease-out);
}
.parties.is-lit .person.is-mark::before{ transform:scaleY(1); }
/* the row takes a wash off that rail and falls away across it: at a glance the
   eye finds one lit row in a grey list before it has read a word of either */
.parties .person.is-mark::after{
  content:""; position:absolute; inset:0; z-index:-1; pointer-events:none;
  background:linear-gradient(90deg, var(--live-soft), transparent 70%);
  transform:scaleX(0); transform-origin:left;
  transition:transform .5s var(--ease);
}
[dir="rtl"] .parties .person.is-mark::after{
  background:linear-gradient(270deg, var(--live-soft), transparent 70%);
  transform-origin:right;
}
.parties.is-lit .person.is-mark::after{ transform:scaleX(1); }
.parties.is-lit .person.is-mark .person-actions i{ transform:none; }
.parties.is-lit .person.is-mark .avatar-m{ color:var(--live-on-soft); }

/* the mark landing on the avatar, with one ring leaving it. The 2px ring in the
   panel's own background is what keeps a 16px disc legible where it overlaps
   the initials, on either surface. */
.parties .avatar-m{ position:relative; }
.vmark{
  position:absolute; inset-block-end:-2px; inset-inline-end:-2px;
  width:16px; height:16px; border-radius:50%;
  display:grid; place-items:center;
  background:var(--live); color:var(--bg);
  box-shadow:0 0 0 2px var(--bg),
             0 6px 16px -4px color-mix(in srgb, var(--live) 55%, transparent);
  opacity:0; transform:scale(.4);
  transition:opacity .26s var(--ease), transform .38s cubic-bezier(.34,1.56,.64,1);
}
.parties.is-badge .person.is-mark .vmark{ opacity:1; transform:none; }
.vmark::after{
  content:""; position:absolute; inset:0; border-radius:50%;
  border:1.5px solid var(--live); opacity:0;
}
.parties.is-badge .person.is-mark .vmark::after{ animation:vmark-ping 760ms var(--ease) .16s 1; }
@keyframes vmark-ping{
  0%{ transform:scale(1); opacity:.75 }
  100%{ transform:scale(2.6); opacity:0 }
}

/* the chips are walked by the driver, so they need a fill to move through */
.parties .tier{ transition:background-color .3s var(--ease), color .3s var(--ease); }
.parties .tier b{ transition:color .3s var(--ease); }

@media (prefers-reduced-motion:reduce){
  .party-body::before{ display:none; }
  .parties .person-main::after{ display:none; }
  .parties .person-name{ filter:none; opacity:1; }
  .parties .person-role{ opacity:1; transform:none; }
  .parties .person .avatar-m{ color:var(--label-2); }
  .parties .person .person-actions i{ opacity:1; transform:none; }
  .parties .person.is-mark::before{ transform:none; }
  .vmark{ opacity:1; transform:none; }
  .vmark::after{ display:none; }
}

/* ---------- what an answer costs you and how long it takes ----------
   The panel used to head with three initials and "answered in 4 h", which
   implied a chat with named people. It is a written request against an annual
   allowance, so it shows the allowance and the promise instead. */
.quota{
  display:inline-flex; align-items:baseline; gap:4px; margin-inline-start:auto;
  padding:4px 10px; border-radius:99px; background:var(--fill);
  font-variant-numeric:tabular-nums;
}
.quota b{ font-size:15px; font-weight:700; color:var(--live); letter-spacing:-.016em; }
.quota span{ font-size:12px; color:var(--label-3); }
.thread-sla{
  display:flex; align-items:center; gap:8px;
  margin:0 0 4px; padding:10px 0 0;
  font-size:12px; color:var(--label-2);
}
.thread-sla b{ color:var(--label); font-weight:600; }
.sla-dot{
  width:7px; height:7px; border-radius:50%; background:var(--recent); flex:0 0 auto;
}
@keyframes quotatick{ 0%{ transform:translateY(-4px); opacity:.4; } 100%{ transform:none; opacity:1; } }
.quota b.is-tick{ animation:quotatick .34s var(--ease) both; }

/* ---------- the comparison, weighted ----------
   Both lanes read as equals, so the eye had nothing to catch on. The
   marketplace lane is the one making the argument, so it is named in a chip
   that states the rate, and its figure carries the weight; ours answers it. */
.zcx-lane.is-them{ background:rgba(255,255,255,.028); }
.zcx-tag{
  display:inline-flex; align-items:center; height:24px; padding:0 11px;
  border-radius:99px; background:rgba(235,235,245,.14); color:var(--label);
  font-size:12px; font-weight:700; letter-spacing:.06em; text-transform:uppercase;
}
.zcx-lane.is-them .zcx-cut{ color:var(--label); }
.zcx-lane.is-them .zcx-note{ color:var(--label-2); }

/* a record that just arrived in the hero feed */
@keyframes srowin{ from{ opacity:0; transform:translateY(-10px); } to{ opacity:1; transform:none; } }
.srow.is-fresh{ animation:srowin .42s var(--ease) both; }

/* ===========================================================================
   THE REVIEWS — a shelf that drifts

   The same mechanism as the arrivals shelf: two identical runs on one track,
   translated leftward every frame and wrapped at the halfway mark, so it never
   ends and never seams. Scrolling the page pushes it along faster.

   Nothing here is a control. Arrows, a drag and a progress bar all came and
   went: each one asked the reader to operate the section before it would show
   them anything, and the section's only job is to be read on the way past.
   ========================================================================= */
/* The window runs the full width of the screen so a card is always clipped by
   the edge — that is what says there are more of them. The first card still
   starts on the container's own line: the track is offset to it at rest. */
.revs{
  margin-top:40px; overflow:hidden;
  margin-inline:calc(50% - 50vw); padding-block:2px;
}
.revs-track{
  display:flex; gap:16px; width:max-content;
  will-change:transform;
}

.rev-card{
  flex:0 0 clamp(300px, 27vw, 392px);
  display:flex; flex-direction:column; min-height:540px;
  padding:28px; border-radius:24px; background:#F3F2EC;
}
.rev-top{ display:flex; align-items:center; gap:14px; }
.rev-face{
  flex:0 0 auto; display:block; width:56px; height:56px;
  border-radius:50%; overflow:hidden;
  background:linear-gradient(180deg, #E7E5DC, #D9D7CC);
}
.rev-face img{
  display:block; width:100%; height:100%;
  object-fit:cover; object-position:50% 0;
  /* object-fit fills a box but cannot zoom past it, and these are full-length
     cut-outs — so the image is scaled inside the frame, anchored to the top,
     which crops the legs and never the head */
  transform:scale(1.55); transform-origin:50% 0;
}
/* trade on one line, where it is on another */
.rev-trade{ min-width:0; }
.rev-trade b{
  display:block; font-size:12px; font-weight:700; letter-spacing:.06em;
  text-transform:uppercase; line-height:1.3; color:#1A1A18;
}
.rev-trade > span{
  display:block; margin-top:4px; font-size:12px; line-height:1.3; color:#6B6A64;  /* 4.8:1 on the card */
}
.rev-trade > span{
  display:block; margin-top:4px; font-size:12px; line-height:1.3; color:rgba(29,29,31,.68);
}

/* the number is the argument, set the way every other number on this page is */
/* ---------------------------------------------------------------------------
   Display figure

   A style of its own, not a step of the heading scale. A headline is read as a
   sentence; a figure is read as a single shape, so it is set heavier and very
   much tighter than any headline would tolerate — SF Pro Display Heavy is drawn
   with enough sidebearing to take -.055em without the digits touching.

   The unit rides at .58 of the numeral and one weight down: "$", "%" and "×"
   are read second, after the number they qualify. Digits are tabular so a
   column of cards lines up and a figure does not change width as the shelf
   drifts. And the numeral's left sidebearing is wider than its optical edge, so
   the whole figure is pulled back to sit flush with the text above it.

   A word in the figure slot ("Early", "No") is not a number: it loses the
   tabular figures and half the tracking, because letters set that tight stop
   being readable.
   ------------------------------------------------------------------------- */
.fig{
  font-family:var(--font-display);
  font-weight:800; font-size:clamp(44px,4.6vw,64px); line-height:.9;
  letter-spacing:-.055em;
  font-variant-numeric:tabular-nums lining;
  font-feature-settings:"tnum" 1, "lnum" 1;
  text-indent:-.045em;
}
.fig-u{
  font-style:normal; font-size:.58em; font-weight:700;
  letter-spacing:-.03em; vertical-align:.02em;
}
.fig.is-word{
  font-size:clamp(38px,3.8vw,52px); letter-spacing:-.03em;
  font-variant-numeric:normal; text-indent:-.02em;
}

.rev-fig{
  margin-top:26px; color:#1A1A18;
}
.rev-fig span{
  display:block; margin-top:12px; text-indent:0;
  font-family:var(--font-text); font-size:13px; font-weight:400;
  letter-spacing:-.006em; line-height:1.4; color:#6B6A64;
}
.rev-fig span{
  display:block; margin-top:12px; text-indent:0;
  font-family:var(--font-text); font-size:13px; font-weight:400;
  letter-spacing:-.006em; line-height:1.4; color:rgba(29,29,31,.68);
}

.rev-card blockquote{
  margin:24px 0 0; position:relative; padding-top:24px;
  font-size:15px; line-height:1.6; color:#57564F;      /* 6.6:1 on the card */
  letter-spacing:-.016em;
}

.rev-by{ margin-top:auto; padding:22px 0 0; position:relative; }
.rev-by b{ display:block; font-size:14px; font-weight:600; color:#1A1A18; letter-spacing:-.011em; }
.rev-by span{ display:block; margin-top:3px; font-size:12px; line-height:1.45; color:#6B6A64; }
.rev-by b{ display:block; font-size:14px; font-weight:600; color:#1D1D1F; letter-spacing:-.011em; }
.rev-by span{ display:block; margin-top:3px; font-size:12px; line-height:1.45; color:rgba(29,29,31,.70); }

@media (max-width:760px){
  .rev-card{ flex-basis:clamp(270px, 86%, 340px); min-height:500px; padding:24px; }
}

/* ---------- what the design review turned up ----------
   Three of the small sizes sat at 3.2–3.7:1 on the card, against a 4.5:1
   minimum for anything up to 17pt, so their ink was darkened until each one
   cleared it. And a shelf that moves on its own has to stop when someone is
   reading it: hovering or tabbing into the section holds it, which is the
   content answering attention rather than another control in the corner. */
@media (prefers-reduced-motion:reduce){
  /* with the drift off, the cards past the third one were unreachable — the
     window clips and there was nothing left to move it. It becomes an ordinary
     scroller so every review can still be read. */
  .revs{ overflow-x:auto; scroll-snap-type:x mandatory; scrollbar-width:none; }
  .revs::-webkit-scrollbar{ display:none; }
  .revs-track{ transform:none !important; }
  .rev-card{ scroll-snap-align:start; }
}

/* ===========================================================================
   ASK A RESEARCHER — the answer landing

   The block sells one thing: a named contact with a phone number, arriving.
   The loop is weighted onto that last beat, and every use of the brand colour
   belongs to the answer path — the allowance being spent, the two days running
   out, the card lighting, the digits resolving — so the eye is pulled to the
   contact and to nothing else on the panel.

   Appended at the end deliberately. Four of these rules tie on specificity
   with the thread rules further up and are decided by source order alone;
   moved earlier, the exit stops playing and the digits resolve grey. The
   stylesheet also carries a duplicated run around those rules (the `.thread`
   surface and the whole `.vcard` block appear twice) — do not deduplicate it
   here, appending wins over both copies and that is all this depends on.
   ========================================================================= */

/* The panel takes the product's own flat surface, so it is the same colour as
   the section behind it and has no edge for peripheral vision to catch. Its
   depth has to be lit rather than painted: a bloom that exists only while the
   answer is on screen. */
.thread::before{
  content:""; position:absolute; inset:-1px; z-index:0; pointer-events:none;
  border-radius:inherit; opacity:0;
  background:radial-gradient(130% 80% at 50% 108%, var(--live-soft) 0%, transparent 68%);
  transition:opacity .8s var(--ease);
}
.thread.step3::before{ opacity:1; }
.thread > *{ position:relative; z-index:1; }

/* the question is thrown, not faded */
.thread .bub.is-you{
  transform:translate3d(20px, 10px, 0) scale(.97);
  transition:opacity .42s var(--ease-out), transform .52s var(--ease-out);
}
.thread.is-on .bub.is-you{ transform:none; }

/* one of the twenty-five being spent is the first thing on the panel to move */
@keyframes ask-tick{
  0%  { transform:translateY(-10px) scale(.9);  opacity:0; }
  58% { transform:translateY(2px)   scale(1.08); opacity:1; }
  100%{ transform:none;                          opacity:1; }
}
.thread .quota b.is-tick{ display:inline-block; animation:ask-tick .46s var(--ease-out) both; }
.thread .quota{ transition:background-color .4s var(--ease), box-shadow .4s var(--ease); }
.thread .quota.is-lit{ background:var(--live-soft); box-shadow:0 0 0 1px var(--live-soft); }
/* --live on --live-soft is the low-contrast pairing the token block warns off;
   the ink that belongs on that fill is --live-on-soft, figure included. */
.thread .quota.is-lit b,
.thread .quota.is-lit span{ color:var(--live-on-soft); }

/* two business days, served in front of you rather than promised */
.thread-sla{ position:relative; padding-bottom:12px; }
.thread-sla::after{
  content:""; position:absolute; inset-inline-start:0; bottom:0;
  width:0; height:2px; border-radius:2px;
  background:var(--live); box-shadow:0 0 14px var(--live-soft);
  transition:width .78s var(--ease-out);
}
.thread.is-on .thread-sla::after{ width:34%; }
.thread.step2 .thread-sla::after{ width:72%; }
.thread.step3 .thread-sla::after{ width:100%; }
@keyframes ask-sla{ 0%,55%{ color:var(--live); } 100%{ color:var(--label); } }
.thread.step3 .thread-sla b{ animation:ask-sla .9s var(--ease) both; }

/* the researcher working, loud enough to be worth waiting through */
.thread.step2 .bub.is-typing i{ background:var(--live); }
.thread.step2 .bub.is-typing{ animation:ask-work 1.6s var(--ease) infinite; }
@keyframes ask-work{
  0%  { box-shadow:0 0 0 0   var(--live-soft); }
  70% { box-shadow:0 0 0 12px transparent; }
  100%{ box-shadow:0 0 0 0   transparent; }
}

/* the answer lands with weight, then the panel settles back into a document */
.thread .bub.is-us{
  transform:translateY(16px) scale(.975);
  transition:opacity .5s var(--ease-out), transform .62s var(--ease-out);
}
.thread.is-on.step3 .bub.is-us{ transform:none; }
.thread.step3 .bub.is-us{ animation:ask-land 1s var(--ease-out) both; }
@keyframes ask-land{
  0%  { box-shadow:0 0 0 0   var(--live-soft), 0 0    0   0    transparent; }
  32% { box-shadow:0 0 0 4px var(--live-soft), 0 20px 44px -24px var(--live); }
  100%{ box-shadow:0 0 0 0   transparent,      0 0    0   0    transparent; }
}

/* THE FOCAL POINT.
   The contact is what the feature sells, so it arrives a beat after the
   sentence that introduces it, carries the only ring on the panel, and takes
   one sweep of light. The ring is a border colour as well as a shadow so it
   survives on a light surface, where --live-soft is only 12% ink. */
.thread .vcard{
  position:relative; overflow:hidden;
  opacity:0; transform:translateY(14px) scale(.985);
  transition:opacity .5s var(--ease-out) .26s, transform .62s var(--ease-out) .26s;
}
.thread.step3 .vcard{
  opacity:1; transform:none;
  animation:ask-card 1.5s var(--ease-out) .26s both;
}
@keyframes ask-card{
  0%  { border-color:var(--live);      box-shadow:0 0 0 4px var(--live-soft), 0 22px 46px -26px var(--live); }
  52% { border-color:var(--live);      box-shadow:0 0 0 2px var(--live-soft), 0 14px 34px -26px var(--live); }
  100%{ border-color:var(--separator); box-shadow:0 0 0 0   transparent,      0 0    0    0    transparent; }
}
.thread .vcard::after{
  content:""; position:absolute; inset:0; pointer-events:none; opacity:0;
  background:linear-gradient(105deg, transparent 34%, var(--live-soft) 50%, transparent 66%);
  transform:translateX(-120%);
}
.thread.step3 .vcard::after{ animation:ask-shine 1.1s var(--ease-out) .42s both; }
@keyframes ask-shine{
  0%  { transform:translateX(-120%); opacity:0; }
  16% { opacity:1; }
  100%{ transform:translateX(120%);  opacity:0; }
}
/* the sweep follows the reading direction, and translateX does not flip itself */
[dir="rtl"] .thread.step3 .vcard::after{ animation-name:ask-shine-rtl; }
@keyframes ask-shine-rtl{
  0%  { transform:translateX(120%);  opacity:0; }
  16% { opacity:1; }
  100%{ transform:translateX(-120%); opacity:0; }
}
.thread.step3 .vcard .avatar-m{ animation:ask-pop .6s var(--ease-out) .34s both; }
@keyframes ask-pop{
  0%  { transform:scale(.55);  opacity:0; }
  62% { transform:scale(1.09); opacity:1; }
  100%{ transform:none;        opacity:1; }
}

/* The payload. The number arrives in the brand colour and settles into text, so
   the eye is pulled to it exactly once and can then read it. Its own keyframe
   name rather than a redefinition of `reveal`: that name also drives the
   research panel's figures further up the file. */
@keyframes ask-reveal{
  0%  { opacity:.22; filter:blur(5px); color:var(--live);  transform:translateY(2px); }
  44% { opacity:1;   filter:none;      color:var(--live);  transform:none; }
  100%{ opacity:1;   filter:none;      color:var(--label); transform:none; }
}
.thread .reveal.is-out{ animation:ask-reveal .62s var(--ease) both; }
/* the icon flares on the row that is resolving — the class comes from the
   unmask loop, so it tracks whichever schedule that pass is running */
@keyframes ask-icon{
  0%,38%{ color:var(--live);    transform:scale(1.2); }
  100%  { color:var(--label-3); transform:none; }
}
.thread .vcard-row.is-lit svg{ animation:ask-icon .8s var(--ease) both; }

/* The loop leaves rather than being cut. `is-exit`, not `is-out` — inside this
   same panel `is-out` already means "this masked value has resolved". */
.thread.is-exit.is-on .bub[data-step],
.thread.is-exit.is-on .vcard{
  opacity:0; transform:translateY(-10px);
  transition:opacity .36s var(--ease), transform .36s var(--ease);
}

@media (prefers-reduced-motion:reduce){
  /* the still frame is the finished answer: card landed and ringed, contact
     readable, the two days already served */
  /* .thread.step3::before outranks a bare .thread::before, and the REDUCED
     branch of the js puts step3 on at load, so the bloom has to be turned off
     at the same weight it was turned on */
  .thread::before, .thread.step3::before{ opacity:0; }
  .thread .bub{ transition:none; }
  .thread .bub.is-you, .thread .bub.is-us{ transform:none; }
  .thread .bub.is-typing i{ animation:none; }
  .thread .vcard{ opacity:1; transform:none; transition:none; border-color:var(--live); }
  .thread .vcard::after{ display:none; }
  .thread-sla::after,
  .thread.is-on .thread-sla::after,
  .thread.step3 .thread-sla::after{ width:100%; transition:none; }
  .thread.step3 .bub.is-us, .thread.step3 .vcard,
  .thread.step3 .vcard .avatar-m, .thread .vcard-row.is-lit svg,
  .thread.step3 .thread-sla b, .thread.step2 .bub.is-typing,
  .thread .quota b.is-tick{ animation:none; }
  .thread .reveal.is-out{ animation:none; color:var(--label); }
}

/* ===========================================================================
   THE RFQ SCREEN, ASSEMBLING

   The block's claim is that you can SEE the enquiry — what is bought, how much,
   to what spec, with the papers. The panel showed all of that and none of it
   moved: a 22px pointer on an 1100px card, and the two biggest objects on it,
   the title and the four figures, static.

   So the record arrives, and it arrives at the size of the card. One wide band
   of --live crosses the whole panel in a single pass and the figures and the
   spec light up behind its leading edge. A 44px chrome strip or a 26px pill is
   invisible to an eye that is already scrolling; large-area luminance change is
   the only thing that is not, and the pointer walk is for the visitor who has
   already stopped.

   The orange keeps the one job its token was declared for — "this just
   happened". It is the sweep, the pill igniting, the rule that lands under a
   figure, the bar on a file that attaches. Nothing else is coloured.

   Every keyframe below ends on the element's own resting state and none of them
   fill forwards, so taking a class off is a no-op. That is what keeps a
   half-built card from ever being the thing left on screen.
   ========================================================================= */

/* The glow cannot live inside .rfq-win: that box clips so the card can keep its
   corners, and the card is opaque anyway. The window gets a stage and the glow
   sits behind it, unclipped — and after it in source, because a sibling
   combinator only reads forwards. isolate, because .rv drops its transform once
   the reveal lands and the stacking context these two z-indexes rely on would
   go with it. color-mix rather than a written-out rgba, so the halo follows
   --live onto whatever surface the card is moved to. */
.rfq-stage{
  position:relative; isolation:isolate; margin-top:40px;
  --halo:color-mix(in srgb, var(--live) 26%, transparent);
}
.is-light .rfq-stage, .panel-light .rfq-stage{
  --halo:color-mix(in srgb, var(--live) 18%, transparent);
}
.rfq-stage .rfq-win{ z-index:1; }

.rfq-halo{
  position:absolute; inset:-200px -32px -120px; z-index:0; pointer-events:none;
  border-radius:48px; opacity:0;
  /* Every stop has to reach transparent INSIDE this box, or the box edge is
     where the colour stops and that edge is a straight line. The old top
     gradient sat 6% down with a 42% radius, so it was still near full strength
     at the top edge and drew an orange rule across the section above the
     window. The bloom's vertical radius is a length now and the box is opened
     up to clear it; the horizontal radii stay percentages so a 390px box fades
     out at its sides too. */
  background:
    radial-gradient(54% 260px at 50% 200px, var(--halo) 0%, transparent 72%),
    radial-gradient(62% 56%    at 50% 54%,  var(--halo) 0%, transparent 78%);
  /* opacity is the transition and scale is the animation, so the two never
     fight over one property: the glow fades up once and breathes forever */
  transition:opacity 1.1s var(--ease-out);
  animation:rfqbreath 6s var(--ease) infinite;
}
@keyframes rfqbreath{ 0%,100%{ transform:scale(.985); } 50%{ transform:scale(1.03); } }
.rfq-win.is-live ~ .rfq-halo{ opacity:1; }

/* The sweep: the record loading into the window, at the width of the window.
   It rides OVER the content, not under it — the card and every row in it are
   opaque, so a band behind them would light nothing — at an alpha low enough
   that the type under it stays type for the time it takes to cross. .rfq-win
   already clips, so the band keeps the card's corners.

   90deg, not a tilt: the band's box is as tall as the card and barely a
   quarter as wide, and on a gradient line that long a 10-degree lean pushes
   the end stops off the box's vertical edges, which then show as two hard
   seams down the card. Square to the travel it fades out where it ends. It is
   also symmetric, so RTL needs no second gradient — only the keyframe. */
.rfq-scan{
  position:absolute; inset-block:0; inset-inline-start:0; width:56%;
  z-index:4; pointer-events:none; opacity:0;
  background:linear-gradient(90deg,
    transparent 0%,
    color-mix(in srgb, var(--live) 12%, transparent) 30%,
    color-mix(in srgb, var(--live) 38%, transparent) 50%,
    color-mix(in srgb, var(--live) 12%, transparent) 70%,
    transparent 100%);
}
/* linear, and this is the one place on the page that is. Every other easing
   token here decelerates hard — under var(--ease-out) the band cleared the
   whole card in its first 160ms and then sat off the right edge for 600ms,
   which reads as a flicker. Light crossing a surface travels at one speed. */
.rfq-win.is-scan .rfq-scan{ animation:rfqscan .82s linear; }
@keyframes rfqscan{
  0%  { opacity:0; transform:translateX(-104%); }
  12% { opacity:1; }
  84% { opacity:1; }
  100%{ opacity:0; transform:translateX(182%); }
}
/* a sweep is a direction, and the cascade cannot flip one baked into a keyframe */
@keyframes rfqscan-rtl{
  0%  { opacity:0; transform:translateX(104%); }
  12% { opacity:1; }
  84% { opacity:1; }
  100%{ opacity:0; transform:translateX(-182%); }
}
[dir="rtl"] .rfq-win.is-scan .rfq-scan{ animation-name:rfqscan-rtl; }

/* The focal point. "Open to quotes" is the one thing on the card that says the
   enquiry is still open — and it already never stops: .rfq-badge .beacon runs
   an expanding ring forever. So this is a one-shot and only a one-shot. A
   second infinite ring round the same 26px pill would drift against the first
   and read as a fault rather than as a pulse. */
.rfq-win.is-ignite .rfq-badge{ animation:rfqignite .62s var(--ease-out); }
@keyframes rfqignite{
  0%  { transform:scale(1);    background-color:var(--live-soft); }
  34% { transform:scale(1.07); background-color:color-mix(in srgb, var(--live) 32%, transparent); }
  100%{ transform:scale(1);    background-color:var(--live-soft); }
}

/* The four figures, arriving behind the band. The cell itself does not move —
   it is a tile in a 1px hairline grid and translating it opens a gap under the
   type — so the type inside it moves and the cell stays put. The steps are the
   band's crossing time divided by four columns, which is what makes the two
   read as one event instead of two. */
.rfq-meta > div{ position:relative; }
.rfq-meta > div:nth-child(1){ --step:0ms; }
.rfq-meta > div:nth-child(2){ --step:120ms; }
.rfq-meta > div:nth-child(3){ --step:240ms; }
.rfq-meta > div:nth-child(4){ --step:360ms; }
.rfq-win.is-figs .rfq-v{ animation:rfqfig .52s var(--ease-out) var(--step,0ms) backwards; }
.rfq-win.is-figs .rfq-k,
.rfq-win.is-figs .rfq-n{ animation:rfqfade .52s var(--ease) var(--step,0ms) backwards; }
@keyframes rfqfig{ from{ opacity:0; transform:translateY(12px); filter:blur(4px); } }
@keyframes rfqfade{ from{ opacity:0; } }

/* the rule that lands under a figure the moment it has resolved — which is why
   no cell on this card is ever counted up to a value the rule has already
   underlined: the one figure that counts finishes inside this same window */
.rfq-meta > div::after{
  content:""; position:absolute; inset-inline:0; bottom:0; height:2px;
  background:var(--live); opacity:0; pointer-events:none;
  transform:scaleX(0); transform-origin:left center;
}
[dir="rtl"] .rfq-meta > div::after{ transform-origin:right center; }
.rfq-win.is-figs .rfq-meta > div::after{ animation:rfqrule 1.05s var(--ease-out) var(--step,0ms) backwards; }
@keyframes rfqrule{
  0%  { opacity:1; transform:scaleX(0); }
  38% { opacity:1; transform:scaleX(1); }
  100%{ opacity:0; transform:scaleX(1); }
}

/* the spec, read line by line. No colour on these — the orange is spoken for. */
.rfq-list li:nth-child(1){ --step:0ms; }
.rfq-list li:nth-child(2){ --step:90ms; }
.rfq-list li:nth-child(3){ --step:180ms; }
.rfq-scope .rfq-list + .rfq-sub + .rfq-list li{ --step:300ms; }
.rfq-scope .rfq-list + .rfq-sub + .rfq-list li:nth-child(2){ --step:390ms; }
.rfq-win.is-scope .rfq-list li{ animation:rfqline .44s var(--ease-out) var(--step,0ms) backwards; }
@keyframes rfqline{ from{ opacity:.2; transform:translateX(-10px); } }
@keyframes rfqline-rtl{ from{ opacity:.2; transform:translateX(10px); } }
[dir="rtl"] .rfq-win.is-scope .rfq-list li{ animation-name:rfqline-rtl; }

/* The documents attaching — the beat that makes "2 documents" true in front of
   the visitor without ever printing a number that is not. The row already owns
   a transform transition for its hover lift, so this animation carries no
   forwards fill: a finished keyframe would pin transform:none on the row and
   .is-hot could never lift it again. */
.rfq-docs li{ position:relative; }
.rfq-docs li::before{
  content:""; position:absolute; inset-block:0; inset-inline-start:0; width:2px;
  border-start-start-radius:11px; border-end-start-radius:11px;
  background:var(--live); opacity:0; pointer-events:none;
  transform:scaleY(0); transform-origin:top;
}
.rfq-docs li.is-add{ animation:rfqrow .5s var(--ease-out); }
.rfq-docs li.is-add::before{ animation:rfqattach .68s var(--ease-out); }
@keyframes rfqrow{ from{ opacity:.3; transform:translateY(10px); } }
@keyframes rfqattach{
  0%  { opacity:1; transform:scaleY(0); }
  40% { opacity:1; transform:scaleY(1); }
  100%{ opacity:0; transform:scaleY(1); }
}

/* a second ring, a beat behind the first: one ring on an 1100px panel is a
   detail, two read as a press from across the room */
.rfq-cursor::after{ border-width:2px; }
.rfq-cursor::before{
  content:""; position:absolute; left:-4px; top:-4px; width:12px; height:12px;
  border-radius:50%; border:1.5px solid var(--live); opacity:0; pointer-events:none;
}
.rfq-cursor.is-click::before{ animation:cursorhit .62s var(--ease-out) .13s; }

/* At 680px the four cells become a 2x2, so the stagger has to follow the band
   rather than the source order: 1 and 3 are the left column and light together,
   2 and 4 are the right one. Four descending steps would read as a diagonal
   wipe across a grid the band crosses in two. */
@media (max-width:680px){
  .rfq-meta > div:nth-child(3){ --step:0ms; }
  .rfq-meta > div:nth-child(4){ --step:120ms; }
}

/* The driver does not start under this setting, so none of the classes above
   are ever added — these are belt and braces, so that whatever happens the
   still frame is the finished record and the glow is off. The global reduce
   rule collapses durations but leaves animation-delay alone, which is why this
   block exists rather than being relied upon. */
@media (prefers-reduced-motion:reduce){
  .rfq-halo, .rfq-scan,
  .rfq-meta > div::after, .rfq-docs li::before{ display:none; }
  .rfq-badge, .rfq-v, .rfq-k, .rfq-n, .rfq-list li, .rfq-docs li{
    animation:none !important; opacity:1; transform:none; filter:none;
  }
}

/* landing-v2: where the app's own styles reach this page */
img, svg, video, canvas{ vertical-align:baseline; }
html section[id]{ scroll-margin-top:0; }
button, input, select, textarea{ letter-spacing:normal; }
h1, h2, h3, h4, h5, h6{ font-weight:700; }
.nav{ top:var(--landing-edit-bar-h, 0px); }
.drawer{ top:calc(64px + var(--landing-edit-bar-h, 0px)); }
html[data-v2-edit] .nav{ z-index:40; }
html[data-v2-edit] .drawer{ z-index:39; }
