/* VectorOS landing v2 — page styles
   Sits on top of landing.css (shared primitives, topbar, ctas, sections,
   pricing, refs grid, pos matrix). Adds the structures unique to v2:
     · Hero with typewriter caret
     · Pull-quote (untagged) between 01 and 02
     · Sources-of-context grid (4 standard cells + 1 double-wide SOON cell)
     · Quiet pause (untagged) before the final CTA
*/

html { scroll-behavior: smooth; }

/* =========================================================================
   Hero — overrides landing.css to make the typewriter the centerpiece.
   Full-viewport opening screen with a quiet schematic decor layer.
   ========================================================================= */
.hero--v2 {
  min-height: 100vh;
  padding-top: calc(var(--topbar-h) + 180px);
  padding-bottom: 120px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  position: relative;
}
.hero--v2 .shell { width: 100%; position: relative; z-index: 2; }
.hero--v2 .hero__content {
  max-width: min(900px, 78%);
}@media (max-width: 900px) {
  .hero--v2 {
    min-height: auto;
    padding-top: calc(var(--topbar-h) + 96px);
    padding-bottom: 80px;
  }
  .hero--v2 .hero__content { max-width: 100%; }
}

/* ---------- Hero decor: graticule + schematic marks ---------- */
.hero__decor {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 1;
  overflow: hidden;
  color: var(--fg-3);
  /* Caret position fed in from JS — used by .hero__grid--bright to brighten
     a circle of grid lines under the caret. */
  --hero-cell: calc(clamp(40px, 5.6vw, 76px) * 1.04);
  --mx: 50%;
  --my: 50%;
}
.hero__grid {
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(to right,  var(--line-1) 1px, transparent 1px),
    linear-gradient(to bottom, var(--line-1) 1px, transparent 1px);
  background-size: var(--hero-cell) var(--hero-cell);
  background-position: -0.5px -0.5px;
  -webkit-mask-image: radial-gradient(ellipse 80% 70% at 72% 50%, #000 0%, rgba(0,0,0,0.55) 40%, transparent 78%);
          mask-image: radial-gradient(ellipse 80% 70% at 72% 50%, #000 0%, rgba(0,0,0,0.55) 40%, transparent 78%);
  opacity: 0.85;
}
/* Brighter grid lines, revealed in a soft circle that follows the mouse. */
.hero__grid--bright {
  background-image:
    linear-gradient(to right,  rgba(255,255,255,0.085) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(255,255,255,0.085) 1px, transparent 1px);
  -webkit-mask-image:
    radial-gradient(circle 240px at var(--mx, 50%) var(--my, 50%),
                    #000 0%, rgba(0,0,0,0.5) 45%, transparent 100%);
          mask-image:
    radial-gradient(circle 240px at var(--mx, 50%) var(--my, 50%),
                    #000 0%, rgba(0,0,0,0.5) 45%, transparent 100%);
  opacity: 0;
  transition: opacity 320ms ease;
}
.hero__grid--bright.is-visible { opacity: 1; }
@media (hover: none) {
  .hero__grid--bright { display: none; }
}
@media (max-width: 900px) {
  .hero__grid { opacity: 0.5; }
}

.hero__eyebrow {
  font-family: var(--font-mono);
  font-size: var(--t-label);
  letter-spacing: var(--tr-label);
  text-transform: uppercase;
  color: var(--fg-3);
  display: inline-flex; align-items: center; gap: 10px;
  margin-bottom: 32px;
}
.hero__eyebrow .dot { width: 6px; height: 6px; background: var(--accent); display: inline-block; }
.hero__eyebrow strong { color: var(--fg-1); font-weight: 500; }

/* Typewriter heading — large, light, with a graceful min-height so the
   layout never jumps as the question grows/shrinks. */
.tw-heading {
  font-family: var(--font-sans);
  font-weight: var(--w-light);
  font-size: clamp(40px, 5.6vw, 76px);
  line-height: 1.04;
  letter-spacing: -0.02em;
  color: var(--fg-1);
  margin: 0 0 32px;
  /* Lock the typing area so growing/shrinking text never reflows the layout
     below. max-width forces the longest question to wrap consistently;
     min-height reserves enough vertical space for the tallest result. */
  max-width: 18ch;
  min-height: calc(1.04em * 3);  /* three lines reserved */
  /* No `text-wrap: balance` — it equalises line lengths and prematurely
     pushes words onto a new line even when space remains. Plain wrapping
     fills each line greedily, which is what we want for the typewriter. */
  text-wrap: wrap;
  overflow-wrap: normal;
  word-break: normal;
}
/* ---------- Typewriter caret + character animations ---------- */
.tw-heading .tw {
  position: relative;
  display: inline-block;
  vertical-align: top;
  white-space: normal;
}
.tw-heading .tw-text {
  display: inline;
  white-space: normal;
  word-break: normal;
  overflow-wrap: normal;
}

/* Words: keep all chars in a word together — no mid-word breaks. */
.tw-heading .tw-word {
  display: inline-block;
  white-space: nowrap;
}

/* Per-character blur in/out. The OUT animation is delayed so the caret
   reaches behind the letter first, then the letter dissolves. */
.tw-heading .tw-ch {
  display: inline-block;
  white-space: pre;
  animation: tw-ch-in 220ms cubic-bezier(.2,.6,.2,1) both;
  will-change: opacity, filter, transform;
}
.tw-heading .tw-ch.is-out {
  animation: tw-ch-out 220ms cubic-bezier(.4,0,.7,.5) 40ms both;
}
@keyframes tw-ch-in {
  0%   { opacity: 0; filter: blur(7px); transform: translateY(2px); }
  100% { opacity: 1; filter: blur(0);   transform: none; }
}
@keyframes tw-ch-out {
  0%   { opacity: 1; filter: blur(0);   transform: none; }
  100% { opacity: 0; filter: blur(7px); transform: translateY(-2px); }
}

/* Caret: thin, full cell height, absolutely positioned, smoothly tracks
   the typing edge via translate() transitions. Blinks only during HOLD. */
.tw-heading .tw-caret {
  position: absolute;
  left: 0;
  top: 0;
  width: 2px;
  /* Set inline via style.height to match the measured line box. Fallback to
     1.04em (one grid cell) before measurement runs. */
  height: 1.04em;
  background: var(--accent);
  border-radius: 1px;
  pointer-events: none;
  will-change: transform;
}
.tw-heading .tw-caret[data-blinking="true"] {
  animation: tw-caret-pulse 1.1s ease-in-out infinite;
}
@keyframes tw-caret-pulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.12; }
}
@media (prefers-reduced-motion: reduce) {
  .tw-heading .tw-caret { animation: none; opacity: 1; transition: none; }
  .tw-heading .tw-ch    { animation: none; }
  .tw-heading .tw-ch.is-out { display: none; }
}

.hero--v2 .hero__lede {
  max-width: 62ch;
  font-size: 18px;
  line-height: 1.6;
  color: var(--fg-2);
  margin: 0 0 40px;
}
.hero--v2 .hero__lede strong { color: var(--fg-1); font-weight: 500; }

/* Side telemetry strip — top-right of hero, optional, mono. */
.hero__strip {
  position: absolute;
  top: 100px;
  right: 48px;
  display: flex; flex-direction: column; gap: 8px;
  font-family: var(--font-mono);
  font-size: var(--t-label);
  letter-spacing: var(--tr-label);
  text-transform: uppercase;
  color: var(--fg-3);
  text-align: right;
  z-index: 2;
}
.hero__strip .k { color: var(--fg-3); }
.hero__strip .v { color: var(--fg-1); font-weight: 500; }
@media (max-width: 900px) { .hero__strip { display: none; } }

/* =========================================================================
   Section captions — center-align with hairline arms.
   ========================================================================= */
.cap-band {
  margin-top: 48px;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 24px;
}
.cap-band::before,
.cap-band::after {
  content: ""; height: 1px; background: var(--line-2);
  display: block;
}
.cap-band .text {
  font-family: var(--font-mono);
  font-size: var(--t-label);
  letter-spacing: var(--tr-label);
  text-transform: uppercase;
  color: var(--fg-2);
  white-space: nowrap;
}
.cap-band .text .accent { color: var(--accent); }

/* =========================================================================
   Pull-quote — untagged section between 01 and 02.
   Big quiet type on the left, BeamLocus visual on the right.
   ========================================================================= */
.pull {
  padding: var(--pad-section) 0;
  background: transparent;
  border-bottom: var(--border-subtle);
  position: relative;
  overflow: hidden;
  min-height: 880px;
}
/* Pull-quote sections own their full top/bottom padding now — no beam
   landing from above so the previous section doesn't need to drop its
   border or padding. */
.pull .shell {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 64px;
  align-items: center;
  position: relative;
  z-index: 1;
}
.pull__col-text {
  /* Text claims the left half; the right half is reserved for the visual. */
}
@media (max-width: 1000px) {
  .pull { min-height: 0; }
  .pull .shell { grid-template-columns: 1fr; gap: 48px; }
}

/* Full-bleed BeamLocus — the arc spans the entire section width.
   locusXRatio in the JSX pushes the locus and its nodes into the right
   half so they don't collide with the text. */
.pull__beam,
.pull__field {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}
.pull__beam > div,
.pull__field > div { position: absolute; inset: 0; }
.pull__beam > div > svg,
.pull__field > div > svg { width: 100% !important; height: 100% !important; }
.pull__beam .bl { background: transparent !important; }
.pull__beam .bl-parent-label { fill: var(--fg-3); }

/* SphereField variant of the pull section: text is left-aligned in the
   left half, the field visualization fills the right half. The pull
   section sits between 01 and 02 — we want the canvas to feel open,
   so we drop the dividing hairlines on both sides without changing
   any vertical rhythm (sections keep their own padding). */
.pull--field {
  padding: var(--pad-section) 0;
  min-height: 720px;
  border-bottom: 0;
  border-top: 0;
}
.section:has(+ .pull--field) { border-bottom: 0; }
.pull--field .pull__col-text { text-align: left; }
.pull--field .pull__text { text-wrap: balance; }
/* The right grid column was kept for the BeamLocus variant. For the
   SphereField version the field is full-bleed behind the text, so we
   collapse the shell to a single column \u2014 the text uses the full width
   and the big quote never wraps mid-phrase. */
.pull--field .shell {
  grid-template-columns: minmax(0, 1fr);
}
.pull--field .pull__text em { white-space: nowrap; }
/* The SphereField spans the entire section width — spheres are spread
   across the whole canvas and the left-column text floats on top of
   them with z-index. The field itself keeps pointer-events: none and
   the SphereField uses a window-level mousemove listener so the bolt
   keeps tracking even when the cursor is over the headline text. */
.pull--field .pull__field {
  left: 0;
}
.pull--field .pull__field svg { pointer-events: none; }
@media (max-width: 1000px) {
  .pull--field .pull__field { left: 0; position: relative; height: 420px; }
}

.pull__text {
  font-family: var(--font-sans);
  font-weight: var(--w-light);
  font-size: clamp(36px, 4.2vw, 64px);
  line-height: 1.06;
  letter-spacing: -0.02em;
  color: var(--fg-2);
  text-wrap: balance;
  margin: 0;
  /* Opaque ground-coloured halo so the moving sphere field reads muted
     directly under the text. Multiple stacked shadows compound into a
     soft, fully-opaque dim around each glyph. */
  text-shadow:
    0 0 16px var(--bg-0),
    0 0 32px var(--bg-0),
    0 0 56px var(--bg-0);
}
.pull__text .lead-in {
  display: block;
  color: var(--fg-3);
  margin-bottom: 18px;
}
.pull__text em {
  font-style: normal;
  color: var(--fg-1);
  font-weight: 280;                    /* slightly heavier than --w-light, still airy */
  /* Scales by the system: floor at --t-h1 (40), peak at --t-display × 2
     (≈112px) so the meta-question reads as the loudest type on the page
     without breaking the type ramp. */
  font-size: clamp(var(--t-h1), 7vw, calc(var(--t-display) * 2));
  letter-spacing: -0.03em;
  line-height: 1.0;
  display: block;
  margin-top: 8px;
}
.pull__sig {
  display: none;
}

/* =========================================================================
   Sources — 6 standard cards on a 3-col grid + double-wide SOON card.
   ========================================================================= */
.src-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0;
  border: var(--border);
}
@media (max-width: 1000px) {
  .src-grid { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 700px) {
  .src-grid { grid-template-columns: 1fr; }
}
.src-cell {
  padding: var(--pad-card);
  display: flex; flex-direction: column; gap: 14px;
  min-height: 200px;
  border-right: var(--border-subtle);
  border-bottom: var(--border-subtle);
  position: relative;
}
/* 3-col layout: strip right border off every 3rd cell */
.src-cell:nth-child(3n) { border-right: 0; }
@media (max-width: 1000px) {
  .src-cell { border-right: var(--border-subtle); }
  .src-cell:nth-child(3n) { border-right: var(--border-subtle); }
  .src-cell:nth-child(2n) { border-right: 0; }
}
@media (max-width: 700px) {
  .src-cell,
  .src-cell:nth-child(2n),
  .src-cell:nth-child(3n) { border-right: 0; }
}
.src-cell--wide {
  grid-column: span 2;
  border-right: 0;
  border-bottom: 0;
  background: var(--bg-2);
  min-height: 200px;
}
.src-cell--wide::before {
  content: ""; position: absolute; top: 0; left: 0;
  width: 16px; height: 2px; background: var(--accent);
}
.src-cell__head {
  display: flex; align-items: center; justify-content: space-between;
  font-family: var(--font-mono);
  font-size: var(--t-label);
  letter-spacing: var(--tr-label);
  color: var(--fg-3);
  text-transform: uppercase;
}
.src-cell__head .soon {
  color: var(--accent);
  display: inline-flex; align-items: center; gap: 6px;
}
.src-cell__head .soon::before {
  content: ""; width: 6px; height: 6px; background: var(--accent);
}
.src-cell__title {
  font-family: var(--font-sans);
  font-weight: var(--w-light);
  font-size: 26px;
  line-height: 1.1;
  letter-spacing: -0.01em;
  color: var(--fg-1);
  text-wrap: balance;
}
.src-cell--wide .src-cell__title {
  font-size: 32px;
  max-width: 38ch;
}
.src-cell__products {
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.04em;
  color: var(--fg-2);
}
.src-cell__body {
  font-size: 14px;
  line-height: 1.55;
  color: var(--fg-2);
  margin-top: auto;
  text-wrap: pretty;
  max-width: 38ch;
}
.src-cell--wide .src-cell__body { max-width: 60ch; }
.src-cell__body strong { color: var(--fg-1); font-weight: 500; }
.src-cell__body p { margin: 0; }
.src-cell__body p + p { margin-top: 0.9em; }
.src-cell__body em {
  font-style: normal;
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.04em;
  color: var(--fg-3);
  text-transform: uppercase;
  display: block;
  margin-top: 10px;
}

.src-footnote {
  margin-top: 24px;
  padding: 18px 24px;
  border: var(--border-subtle);
  display: flex; align-items: center; gap: 16px;
  font-family: var(--font-mono);
  font-size: var(--t-label);
  letter-spacing: var(--tr-label);
  text-transform: uppercase;
  color: var(--fg-2);
}
.src-footnote .mark {
  width: 8px; height: 8px; background: var(--fg-2); flex-shrink: 0;
}
.src-footnote .accent { color: var(--accent); }

/* =========================================================================
   Quiet pause — untagged, no decor.
   ~80% body type, muted color, generous vertical room.
   ========================================================================= */
.quiet {
  padding: 160px 0;
  background: var(--bg-1);
  border-bottom: var(--border-subtle);
}
@media (max-width: 900px) {
  .quiet { padding: 96px 0; }
}
.quiet .shell {
  display: flex;
  justify-content: center;
}
.quiet p {
  max-width: 56ch;
  margin: 0;
  font-family: var(--font-sans);
  font-size: 18px;
  line-height: 1.8;
  letter-spacing: 0.005em;
  color: var(--fg-3);
  text-wrap: pretty;
  font-style: italic;
}
.quiet p .open {
  color: var(--fg-2);
}
.quiet p strong {
  font-weight: var(--w-regular);
  font-style: normal;
  font-family: var(--font-mono);
  font-size: 16px;
  letter-spacing: 0.02em;
  color: var(--fg-1);
}

/* =========================================================================
   Final block — keeps landing.css .final but tightens the heading copy.
   ========================================================================= */
.final--v2 h2 {
  font-size: clamp(56px, 7vw, 96px);
}
.final--v2 .eyebrow .tick { background: var(--accent); }

/* Final + BeamLocus variant: 2-column grid mirroring the pull section.
   Text and CTAs sit on the left; the locus diagram fills the right half. */
.final--beam {
  text-align: left;
  position: relative;
  overflow: hidden;
  min-height: 720px;
  padding: var(--pad-section) 0;
}
.final--beam .shell {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 64px;
  align-items: center;
  position: relative;
  z-index: 1;
}
.final--beam .final__col-text {
  text-align: left;
}
.final--beam h2 {
  text-align: left;
  margin: 0 0 32px;
  max-width: 14ch;
  text-wrap: balance;
}
.final--beam p {
  text-align: left;
  margin: 0 0 40px;
  max-width: 42ch;
}
.final--beam .cta-row {
  justify-content: flex-start;
}
.final--beam .final__beam {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}
.final--beam .final__beam > div { position: absolute; inset: 0; }
.final--beam .final__beam > div > svg { width: 100% !important; height: 100% !important; }
.final--beam .final__beam .bl { background: transparent !important; }
.final--beam .final__beam .bl-parent-label { fill: var(--fg-3); }
@media (max-width: 1000px) {
  .final--beam { min-height: 0; }
  .final--beam .shell { grid-template-columns: 1fr; gap: 48px; }
  .final--beam .final__beam { position: relative; inset: auto; height: 360px; order: 2; }
}

/* =========================================================================
   Standalone caption used at the end of sections — center, large air.
   (Variant on landing.css .pos-caption that sits across the full width.)
   ========================================================================= */
.section-caption {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--t-label);
  letter-spacing: var(--tr-label);
  text-transform: uppercase;
  color: var(--fg-2);
  text-align: center;
  margin-top: 48px;
}
.section-caption .accent { color: var(--accent); }


/* Section sub-heading — a quieter line that sits directly beneath the
   main h2 of a section-head. Used in 07/Access. Larger than the lede,
   lighter weight than h2. */
.section-head .section-subhead {
  font-family: var(--font-sans);
  font-weight: var(--w-light);
  font-size: clamp(20px, 1.7vw, 26px);
  line-height: 1.25;
  letter-spacing: -0.01em;
  color: var(--fg-2);
  margin: 14px 0 0;
  max-width: 30ch;
  text-wrap: balance;
}


/* =========================================================================
   Persistent topbar — always-visible nav (no reveal-on-scroll).
   Used by index-v2.html (after 50vh scroll), method.html, pricing.html.
   ========================================================================= */
.topbar--persistent {
  /* `--topbar-h` includes the iOS notch / status-bar safe area so the
     hero padding-top math below stays correct on devices with a notch.
     The topbar's height matches; `padding-top` pushes its children
     below the safe area so the wordmark + nav don't slide under the
     status bar. */
  --topbar-h: calc(48px + env(safe-area-inset-top, 0px));
  height: var(--topbar-h);
  padding-top: env(safe-area-inset-top, 0px);
  background: rgba(10, 10, 11, 0.62);
  border-bottom-color: var(--line-1);
  backdrop-filter: saturate(140%) blur(14px);
  -webkit-backdrop-filter: saturate(140%) blur(14px);
}
.topbar--persistent .shell {
  align-items: stretch;
}
.topbar--persistent .topbar__brand { align-self: center; }

/* Always show nav + CTA on the persistent topbar */
.topbar--persistent .topbar__nav {
  display: flex;
  align-self: center;
}
.topbar--persistent .topbar__nav a {
  position: relative;
  height: 48px;
  display: inline-flex;
  align-items: center;
}
/* Visual space between «Метод» and «Вектора» — a real space inside an
   inline-flex link collapses, so use a margin instead. */
.topbar--persistent .topbar__nav-suffix { margin-left: 0.32em; }
/* Active page indicator — thin accent underline + brighter foreground */
.topbar--persistent .topbar__nav a[aria-current="page"] {
  color: var(--fg-0);
}
.topbar--persistent .topbar__nav a[aria-current="page"]::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -1px;
  height: 2px;
  background: var(--accent);
}

/* CTA as a full-height topbar section, flush to the right viewport edge.
   Higher specificity (`body.vos-root`) so the landing.css `.is-scrolled`
   rules don't reset our positioning when the page scrolls. */
body.vos-root .topbar--persistent .topbar__cta {
  display: inline-flex;
  align-items: center;
  align-self: stretch;
  height: 48px;
  margin: 0 -48px 0 auto;       /* cancel shell padding on the right */
  padding: 0 48px;              /* match shell padding so text aligns */
  border: 0;
  border-left: 1px solid var(--line-1);
  border-radius: 0;
  background: transparent;
  color: var(--fg-0);
  font-family: var(--font-mono);
  font-size: var(--t-label);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  transition: background var(--dur-instant), color var(--dur-instant);
}
body.vos-root .topbar--persistent .topbar__cta:hover {
  background: var(--accent);
  color: var(--bg-0);
  border-color: var(--accent);
}

@media (max-width: 900px) {
  body.vos-root .topbar--persistent .topbar__cta {
    margin-right: -20px;
    padding: 0 20px;
  }
}
@media (max-width: 720px) {
  /* Mobile shape: VECTOROS · МАНИФЕСТ · МЕТОД · СТОИМОСТЬ · [→]
     · Brand stays at desktop size (22px wordmark) — the topbar is
       the brand surface, do not shrink it.
     · Nav is centred between brand and CTA via `margin: 0 auto`;
       any slack between groups goes to the nav's left/right margins
       in equal share.
     · CTA is a 3:2 icon button (72×48) hugging the right edge.
     · Base `.topbar .shell` gap is 32px which overflows narrow
       viewports; trimmed to 12px (auto margins around the nav do
       the rest of the spacing). */
  .topbar--persistent .shell {
    gap: 12px;
    padding: 0 16px;
  }
  .topbar--persistent .topbar__nav {
    display: flex;
    gap: 16px;
    margin: 0 auto;            /* centre between brand and CTA */
  }
  .topbar--persistent .topbar__nav a {
    height: 48px;
    font-size: 11px;
    letter-spacing: 0.06em;
  }
  .topbar--persistent .topbar__nav-suffix { display: none; }

  body.vos-root .topbar--persistent .topbar__cta {
    min-width: 72px;            /* 3:2 aspect against the 48px height */
    padding: 0 16px;
    margin-right: -16px;        /* hugs the right viewport edge */
    justify-content: center;
    line-height: 1;
    gap: 0;
  }
  .topbar--persistent .topbar__cta-label { display: none; }
  .topbar--persistent .topbar__cta-arrow {
    display: inline-block;
    font-family: var(--font-sans);
    font-size: 18px;
    line-height: 1;
    letter-spacing: 0;
  }
}
@media (max-width: 380px) {
  /* Smallest phones (iPhone SE / older Android): shrink nav text
     and gap a touch so the row still fits without truncation. */
  .topbar--persistent .topbar__nav { gap: 12px; }
  .topbar--persistent .topbar__nav a { font-size: 10.5px; }
}

/* Index-v2 reveal: logo always visible. Background, nav, and CTA fade in
   after the user scrolls past the threshold. One-way — once shown, stays. */
.topbar--reveal {
  background: transparent;
  border-bottom-color: transparent;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  transition: background var(--dur-med) var(--ease),
              border-color var(--dur-med) var(--ease),
              backdrop-filter var(--dur-med) var(--ease);
}
.topbar--reveal .topbar__nav,
.topbar--reveal .topbar__cta {
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--dur-med) var(--ease);
}
.topbar--reveal.is-visible {
  background: rgba(10, 10, 11, 0.62);
  border-bottom-color: var(--line-1);
  backdrop-filter: saturate(140%) blur(14px);
  -webkit-backdrop-filter: saturate(140%) blur(14px);
}
.topbar--reveal.is-visible .topbar__nav,
.topbar--reveal.is-visible .topbar__cta {
  opacity: 1;
  pointer-events: auto;
}

/* On-light mode — applied when the topbar physically overlaps the light
   manifesto section, so foreground glyphs invert from white to dark and
   the panel switches to a paper-white tint. Toggled by JS based on the
   intersection between bar and section bounding rects. */
.topbar,
.topbar .topbar__brand img,
.topbar .topbar__nav a,
body.vos-root .topbar .topbar__cta {
  transition:
    background var(--dur-med) var(--ease),
    border-color var(--dur-med) var(--ease),
    color var(--dur-med) var(--ease),
    filter var(--dur-med) var(--ease);
}
.topbar--on-light.is-visible {
  background: rgba(242, 242, 240, 0.88);
  border-bottom-color: rgba(10, 11, 13, 0.10);
}
.topbar--on-light .topbar__brand img {
  filter: invert(1);
}
.topbar--on-light .topbar__nav a,
body.vos-root .topbar--on-light .topbar__cta {
  color: #0A0B0D;
}
.topbar--on-light .topbar__nav a[aria-current="page"] { color: #0A0B0D; }
body.vos-root .topbar--on-light .topbar__cta {
  border-left-color: rgba(10, 11, 13, 0.18);
}
body.vos-root .topbar--on-light .topbar__cta:hover {
  background: var(--accent);
  color: #FFFFFF;
  border-color: var(--accent);
}

/* =========================================================================
   v2 overrides — price-card, quiet section, chat bubbles
   ========================================================================= */

/* Price card — equal columns and wider so left/right blocks balance */
.price-card {
  max-width: 880px;
  grid-template-columns: 1fr 1fr;
}
@media (max-width: 800px) {
  .price-card { grid-template-columns: 1fr; }
}

/* ---------------------------------------------------------------------
   v2 — stacked layout: price banner on top, features as a grid below.
   --------------------------------------------------------------------- */
.price-card--stacked {
  max-width: 1080px;
  grid-template-columns: 1fr;
  /* Drop the outer frame — the internal cell hairlines and the eyebrow tick
     already structure the block, so we don't stack a card border under the
     hero's bottom line. */
  border: 0;
  background: transparent;
  display: grid;
}
/* Remove the accent corner tick on the stacked variant. */
.price-card--stacked::before { content: none; display: none; }

.price-card--stacked .price-card__top {
  padding: 44px 48px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 40px;
  border-bottom: var(--border-subtle);
  flex-wrap: wrap;
}
.price-card--stacked .price-card__top-l {
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.price-card--stacked .price-card__eyebrow {
  font-family: var(--font-mono);
  font-size: var(--t-label);
  letter-spacing: var(--tr-label);
  text-transform: uppercase;
  color: var(--fg-3);
  display: inline-flex; gap: 10px; align-items: center;
}
.price-card--stacked .price-card__eyebrow::before {
  content: ""; width: 16px; height: 2px; background: var(--accent);
}
.price-card--stacked .price-readout--plain {
  font-size: 56px;
  line-height: 1;
  letter-spacing: -0.02em;
  font-weight: var(--w-light);
  display: flex;
  align-items: baseline;
  gap: 4px;
}
.price-card--stacked .price-readout__per {
  font-size: 18px;
  color: var(--fg-3);
  font-weight: 400;
  letter-spacing: 0;
}
.price-card--stacked .price-card__top-r { display: flex; }

@media (max-width: 700px) {
  .price-card--stacked .price-card__top {
    padding: 32px 24px;
    gap: 24px;
  }
  .price-card--stacked .price-readout--plain { font-size: 40px; }
}

/* Features grid — 3 cols × 2 rows of cells, hairline-divided. */
.price-card--stacked .price-card__features {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
}
.price-card--stacked .price-feature {
  padding: 28px 28px 32px;
  border-right: var(--border-subtle);
  border-bottom: var(--border-subtle);
  display: flex;
  flex-direction: column;
  gap: 14px;
  min-height: 170px;
}
.price-card--stacked .price-feature:nth-child(3n) { border-right: 0; }
.price-card--stacked .price-feature:nth-last-child(-n+3) { border-bottom: 0; }

.price-card--stacked .price-feature__head {
  display: grid;
  grid-template-columns: 18px 1fr auto;
  align-items: center;
  gap: 12px;
  font-family: var(--font-mono);
  font-size: var(--t-label);
  letter-spacing: var(--tr-label);
  text-transform: uppercase;
  color: var(--fg-3);
}
.price-card--stacked .price-feature__head .ico {
  width: 18px; height: 18px;
  color: var(--fg-2);
}
.price-card--stacked .price-feature__head .label { color: var(--fg-3); letter-spacing: var(--tr-label); }
.price-card--stacked .price-feature__head .num { color: var(--fg-3); }
.price-card--stacked .price-feature__head .label {
  color: var(--fg-3);
  letter-spacing: var(--tr-label);
}
.price-card--stacked .price-feature__head .num {
  color: var(--fg-3);
}
.price-card--stacked .price-feature__desc {
  font-size: 13px;
  line-height: 1.55;
  color: var(--fg-1);
  text-wrap: pretty;
  max-width: 34ch;
}

@media (max-width: 1000px) {
  .price-card--stacked .price-card__features { grid-template-columns: repeat(2, 1fr); }
  .price-card--stacked .price-feature { border-right: var(--border-subtle); border-bottom: var(--border-subtle); }
  .price-card--stacked .price-feature:nth-child(3n) { border-right: var(--border-subtle); }
  .price-card--stacked .price-feature:nth-child(2n) { border-right: 0; }
  .price-card--stacked .price-feature:nth-last-child(-n+3) { border-bottom: var(--border-subtle); }
  .price-card--stacked .price-feature:nth-last-child(-n+2) { border-bottom: 0; }
}
@media (max-width: 600px) {
  .price-card--stacked .price-card__features { grid-template-columns: 1fr; }
  .price-card--stacked .price-feature,
  .price-card--stacked .price-feature:nth-child(3n),
  .price-card--stacked .price-feature:nth-child(2n) { border-right: 0; border-bottom: var(--border-subtle); }
  .price-card--stacked .price-feature:last-child { border-bottom: 0; }
}

/* Replace the underscore-style dash before each include item with a small icon */
.price-includes .item {
  grid-template-columns: 22px 1fr;
  gap: 14px;
  align-items: center;
}
.price-includes .item::before { content: none; }
.price-includes .item .ico {
  width: 18px;
  height: 18px;
  color: var(--fg-2);
  display: block;
  flex-shrink: 0;
}

/* Quiet pause — sans, light & airy. Keep the larger reading size and
   muted opening from the editorial pass, but drop the serif italic so the
   voice stays consistent with the rest of the page. */
.quiet p {
  font-family: var(--font-sans);
  font-style: normal;
  font-weight: var(--w-light);
  font-size: clamp(22px, 2.1vw, 28px);
  line-height: 1.5;
  letter-spacing: -0.008em;
  color: var(--fg-1);
  max-width: 60ch;
  text-wrap: pretty;
}
.quiet p strong {
  display: block;
  margin-top: 28px;
  font-family: var(--font-sans);
  font-weight: var(--w-light);
  font-size: clamp(24px, 2.3vw, 30px);
  font-style: normal;
  color: var(--fg-1);
}

/* Chat bubbles — more conversational, less schematic.
   Cards are sized close to a vertical phone screen so they read as
   "Telegram chats", and content is revealed by the choreography in
   tg-animator.js (card fade-in, then per-message stream). */
.tg-card {
  background: var(--bg-1);
  aspect-ratio: 9 / 15;
  overflow: hidden;
  position: relative;
  /* Initial: invisible, revealed by .is-on */
  opacity: 0;
  transform: translateY(14px);
  transition: opacity .55s ease, transform .55s ease;
}
.tg-card.is-on {
  opacity: 1;
  transform: none;
}
/* Between 700–1100px the grid collapses to one column and the phone-shaped
   aspect ratio becomes absurdly tall — drop it for that range. */
@media (max-width: 1100px) and (min-width: 701px) {
  .tg-card { aspect-ratio: auto; }
}
.tg-card__head {
  background: transparent;
  border-bottom: var(--border-subtle);
}
.tg-thread {
  background:
    linear-gradient(var(--bg-0), var(--bg-0));
  gap: 8px;
  padding: 20px 16px 24px;
  overflow: hidden;
  position: relative;
}

/* Per-message reveal — slides up + fades in when .is-on is added. */
.tg-grid .tg-msg {
  opacity: 0;
  transform: translateY(10px);
  transition: opacity .45s ease, transform .45s ease;
}
.tg-grid .tg-msg.is-on {
  opacity: 1;
  transform: none;
}

/* Typing indicator — three dots that appear before a message lands. */
.tg-typing {
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 10px 14px;
  border: var(--border-subtle);
  background: var(--bg-1);
  border-radius: 14px 14px 14px 4px;
  opacity: 0;
  transform: translateY(10px);
  transition: opacity .25s ease, transform .25s ease;
  box-shadow: 0 1px 0 rgba(0,0,0,0.18);
}
.tg-typing.is-on { opacity: 1; transform: none; }
.tg-typing > i {
  width: 5px; height: 5px;
  border-radius: 50%;
  background: var(--fg-3);
  animation: tg-blink 1.1s infinite ease-in-out;
}
.tg-typing > i:nth-child(2) { animation-delay: .18s; }
.tg-typing > i:nth-child(3) { animation-delay: .36s; }
@keyframes tg-blink {
  0%, 60%, 100% { opacity: 0.3; transform: translateY(0); }
  30% { opacity: 1; transform: translateY(-2px); }
}

/* No-JS / reduced-motion fallback — show everything statically. */
.tg-grid.tg-static .tg-card,
.tg-grid.tg-static .tg-msg {
  opacity: 1;
  transform: none;
}
@media (prefers-reduced-motion: reduce) {
  .tg-card, .tg-grid .tg-msg, .tg-typing {
    transition: none !important;
    animation: none !important;
  }
}
.tg-msg.from-bot {
  background: var(--bg-1);
  border: var(--border-subtle);
  border-radius: 14px 14px 14px 4px;
  padding: 12px 14px;
  max-width: 88%;
  box-shadow: 0 1px 0 rgba(0,0,0,0.18);
  white-space: pre-line;
}
.tg-msg.from-bot + .tg-msg.from-bot {
  margin-top: 2px;
}
.tg-msg .readout {
  margin-top: 10px;
  padding-top: 10px;
  border-top: var(--border-subtle);
}


/* Position matrix — give the top-left "corner" cell the column-label
   that describes the vertical axis (рhythm: ситуативно/периодично/непрерывно). */
.pos-matrix .corner {
  font-family: var(--font-mono);
  font-size: var(--t-label);
  letter-spacing: var(--tr-label);
  text-transform: uppercase;
  color: var(--fg-3);
  font-weight: 500;
  border-bottom: var(--border-subtle);
  display: flex;
  align-items: flex-end;
}


/* =========================================================================
   Position chart — chart-style presentation. A 3×2 plot of methodologies
   framed by axis lines (left = order, bottom = rhythm). No cell borders,
   no row separators — the axes do the structural work, the plot points
   float. VectorOS occupies the previously-empty top-right node.
   ========================================================================= */
.pos-chart {
  margin: 0;
  display: grid;
  grid-template-columns: 168px 1fr;
  grid-template-rows: 1fr auto;
  column-gap: 36px;
  row-gap: 16px;
}

/* Y axis: two labels (top = II-order, bottom = I-order) connected by a
   thin vertical hairline that runs between them. */
.pos-chart__yaxis {
  grid-column: 1;
  grid-row: 1;
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: 18px 0 24px;
}
.pos-chart__yaxis::after {
  content: "";
  position: absolute;
  right: 0;
  top: 48px;
  bottom: 64px;
  width: 1px;
  background: var(--line-2);
}
.pos-chart__ylabel {
  font-family: var(--font-mono);
  font-size: var(--t-label);
  letter-spacing: var(--tr-label);
  text-transform: uppercase;
  color: var(--fg-2);
  font-weight: 500;
  display: flex;
  flex-direction: column;
  gap: 4px;
  text-align: right;
  padding-right: 16px;
}
.pos-chart__ylabel small {
  font-size: 11px;
  font-weight: 400;
  letter-spacing: 0.04em;
  text-transform: none;
  color: var(--fg-4);
}

/* Plot area: 3-column × 2-row grid, no borders, generous gaps. */
.pos-chart__plot {
  grid-column: 2;
  grid-row: 1;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: 1fr 1fr;
  column-gap: 36px;
  row-gap: 72px;
  padding: 18px 0 24px;
}
.pc-node {
  position: relative;
  padding-left: 22px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  align-self: start;
}
.pc-node::before {
  content: "";
  position: absolute;
  left: 0;
  top: 7px;
  width: 9px;
  height: 9px;
  background: var(--fg-2);
}
.pc-node__name {
  font-family: var(--font-sans);
  font-weight: 500;
  font-size: 17px;
  line-height: 1.3;
  color: var(--fg-1);
  letter-spacing: -0.005em;
  text-wrap: balance;
}
.pc-node p {
  margin: 0;
  font-size: 13.5px;
  line-height: 1.55;
  color: var(--fg-2);
  max-width: 30ch;
}
.pc-node p strong { color: var(--fg-1); font-weight: 500; }

/* ─────────────────────────────────────────────────────────────────────────
   VectorOS node — accent dot rendered as a circle, and the only accent-
   coloured name in the chart. Sits at row 1 col 3 naturally.

   Reveal sequence (added via .pc-node--us.is-revealing):
     · the cell starts EMPTY — no dot, no text
     · the dot fades + scales in (~300ms)
     · it blinks twice (a soft accent glow on/off)
     · then the name and copy fade in beneath it
   The .is-revealing class is added by an IntersectionObserver in the page
   when the chart scrolls into view. Once .is-revealed is added at the end
   of the sequence the elements stay visible (no looping).
   ───────────────────────────────────────────────────────────────────── */
.pc-node--us::before {
  background: var(--accent);
  border-radius: 50%;
  width: 11px;
  height: 11px;
  left: -1px;
  top: 6px;
}
.pc-node--us .pc-node__name {
  color: var(--fg-0);
}

/* When VectorOS begins its reveal, fade the surrounding nodes down to a
   quiet level and leave them there — the accent moment is the new
   resting state of the chart, not a flash. The fade is long and gentle
   so it reads as a settling, not a switch. */
.pos-chart.pc-anim-armed .pc-node:not(.pc-node--us) {
  transition: opacity 2200ms ease;
}
.pos-chart:has(.pc-node--us.is-revealing) .pc-node:not(.pc-node--us) {
  opacity: 0.28;
}

/* Initial hidden state — only applies once the observer has tagged the
   chart with .pc-anim-armed. If JS never runs, the node is visible by
   default so the chart still works without animation. */
.pos-chart.pc-anim-armed .pc-node--us::before,
.pos-chart.pc-anim-armed .pc-node--us .pc-node__name,
.pos-chart.pc-anim-armed .pc-node--us p {
  opacity: 0;
}
.pos-chart.pc-anim-armed .pc-node--us::before {
  transform: scale(0.4);
  box-shadow: 0 0 0 0 rgba(0, 0, 0, 0);
}

/* Play once the .is-revealing class is set. Three stages, on a single
   timeline, by staggered animation-delays. */
.pc-node--us.is-revealing::before {
  animation:
    pc-us-dot-in   460ms cubic-bezier(.2,.7,.3,1) 240ms forwards,
    pc-us-dot-blink 1180ms steps(1,end) 760ms 2;
}
.pc-node--us.is-revealing .pc-node__name {
  animation: pc-us-text-in 520ms ease 1860ms forwards;
}
.pc-node--us.is-revealing p {
  animation: pc-us-text-in 520ms ease 2040ms forwards;
  /* drop the revealing class once everything has settled; the JS adds
     .is-revealed at the same beat so the dim-others rule releases. */
}

@keyframes pc-us-dot-in {
  0%   { opacity: 0; transform: scale(0.4); }
  60%  { opacity: 1; transform: scale(1.25); }
  100% { opacity: 1; transform: scale(1); }
}
@keyframes pc-us-dot-blink {
  0%, 100% { opacity: 1; }
  40%      { opacity: 0.15; }
  80%      { opacity: 1; }
}
@keyframes pc-us-text-in {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
  .pos-chart.pc-anim-armed .pc-node--us::before,
  .pos-chart.pc-anim-armed .pc-node--us .pc-node__name,
  .pos-chart.pc-anim-armed .pc-node--us p {
    opacity: 1;
    transform: none;
    animation: none;
  }
}

/* X axis: hairline + three rhythm labels matching the plot columns. */
.pos-chart__xaxis {
  grid-column: 2;
  grid-row: 2;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  column-gap: 36px;
  padding-top: 16px;
  border-top: 1px solid var(--line-2);
}
.pos-chart__xlabel {
  font-family: var(--font-mono);
  font-size: var(--t-label);
  letter-spacing: var(--tr-label);
  text-transform: uppercase;
  color: var(--fg-2);
  font-weight: 500;
}

/* Tablet: drop the y-axis labels above the plot. */
@media (max-width: 1000px) {
  .pos-chart {
    grid-template-columns: 1fr;
  }
  .pos-chart__yaxis {
    grid-column: 1; grid-row: 1;
    flex-direction: row;
    justify-content: space-between;
    padding: 0 0 16px;
  }
  .pos-chart__yaxis::after { display: none; }
  .pos-chart__ylabel { text-align: left; padding-right: 0; }
  .pos-chart__plot, .pos-chart__xaxis { grid-column: 1; }
  .pos-chart__plot { grid-row: 2; }
  .pos-chart__xaxis { grid-row: 3; }
}

/* Mobile: lay the map out as a table in portrait. ORDER (I / II) becomes
   the two columns, splitting the screen in half; RHYTHM (Ситуативно →
   Непрерывно) becomes full-width row headers, each on its own row above
   the pair of nodes it groups. The horizontal dividers read as table
   rows. VectorOS keeps its accent cell (II · Непрерывно) and reveal.

   `display: contents` on the three sub-containers (yaxis / xaxis / plot)
   promotes their labels and nodes into ONE shared grid on .pos-chart, so
   row headers span the full width and the node columns stay 50 / 50.

   Row map:  1 order header · 2 Ситуативно · 3 nodes · 4 Периодично ·
             5 nodes · 6 Непрерывно · 7 nodes */
@media (max-width: 700px) {
  .pos-chart {
    display: grid;
    grid-template-columns: 1fr 1fr;
    column-gap: 18px;
    row-gap: 0;
    align-items: start;
  }
  .pos-chart__yaxis,
  .pos-chart__xaxis,
  .pos-chart__plot { display: contents; }
  .pos-chart__yaxis::after { content: none; }

  /* Order axis (II / I) → 2-column header in row 1, split 50/50. DOM order
     is [II, I]; placed so the header reads «I порядок | II порядок». */
  .pos-chart__ylabel {
    grid-row: 1;
    text-align: left;
    align-self: end;
    padding: 0 0 8px;
    border-bottom: 1px solid var(--line-2);
  }
  .pos-chart__ylabel:nth-child(1) { grid-column: 2; } /* II порядок → right col */
  .pos-chart__ylabel:nth-child(2) { grid-column: 1; } /* I порядок  → left col  */

  /* Rhythm axis → full-width row headers, each in its own row. */
  .pos-chart__xlabel {
    grid-column: 1 / -1;
    text-align: left;
    line-height: 1.2;
    padding: 22px 0 12px;
    border-top: 1px solid var(--line-2);
  }
  .pos-chart__xlabel:nth-child(1) { grid-row: 2; border-top: 0; padding-top: 18px; } /* Ситуативно (under header) */
  .pos-chart__xlabel:nth-child(2) { grid-row: 4; } /* Периодично */
  .pos-chart__xlabel:nth-child(3) { grid-row: 6; } /* Непрерывно */

  /* Nodes mapped to (rhythm-rows, order-column). DOM order of the plot is:
     1 Импульс · 2 Синхронизация · 3 VectorOS · 4 Хаос · 5 Механика · 6 Среда */
  .pc-node:nth-child(1) { grid-column: 2; grid-row: 3; } /* Импульс       — II · Ситуативно */
  .pc-node:nth-child(2) { grid-column: 2; grid-row: 5; } /* Синхронизация — II · Периодично */
  .pc-node:nth-child(3) { grid-column: 2; grid-row: 7; } /* VectorOS      — II · Непрерывно */
  .pc-node:nth-child(4) { grid-column: 1; grid-row: 3; } /* Хаос          — I  · Ситуативно */
  .pc-node:nth-child(5) { grid-column: 1; grid-row: 5; } /* Механика      — I  · Периодично */
  .pc-node:nth-child(6) { grid-column: 1; grid-row: 7; } /* Среда         — I  · Непрерывно */

  .pc-node { padding-left: 18px; padding-top: 4px; padding-bottom: 8px; }
  .pc-node p { max-width: none; }
}


/* =========================================================================
   Position map — 3 × 2 instrument grid of tool categories.
   Rows: rhythm (Ситуативно / Периодично / Непрерывно).
   Cols: order (Что вы делаете / Как вы работаете).
   VectorOS occupies the previously-empty "Непрерывно × Как вы работаете"
   cell, marked with an accent corner tick.
   ========================================================================= */
.map-table {
  margin: 88px 0 56px;
  display: grid;
  grid-template-columns: 200px 1fr 1fr;
  background: var(--line-2);
  gap: 1px;
  border: 1px solid var(--line-2);
}
.map-table .map-cell {
  background: var(--bg-0);
  padding: 28px 28px;
  display: flex;
  flex-direction: column;
  position: relative;
  min-height: 0;
}

/* Top-left corner — axis legend, in mono, tiny, with tertiary contrast. */
.map-cell--corner {
  padding: 18px 20px;
  justify-content: space-between;
}
.map-cell__corner-rhythm,
.map-cell__corner-order {
  font-family: var(--font-mono);
  font-size: var(--t-mono-s);
  letter-spacing: var(--tr-label);
  text-transform: uppercase;
  color: var(--fg-3);
}
.map-cell__corner-order { align-self: flex-end; }

/* Column headers — sit on top, mono title + sub-line. */
.map-cell--colhead {
  padding: 22px 28px 22px;
  gap: 4px;
  justify-content: center;
}
.map-cell__col-title {
  font-family: var(--font-sans);
  font-size: 16px;
  font-weight: var(--w-medium);
  color: var(--fg-0);
  letter-spacing: 0.005em;
}
.map-cell__col-sub {
  font-family: var(--font-mono);
  font-size: var(--t-mono-s);
  letter-spacing: var(--tr-label);
  text-transform: uppercase;
  color: var(--fg-3);
}

/* Row headers — left rail, mono ID + name. */
.map-cell--rowhead {
  flex-direction: column;
  justify-content: center;
  gap: 10px;
  padding: 32px 24px;
}
.map-cell__row-id {
  font-family: var(--font-mono);
  font-size: var(--t-mono-s);
  letter-spacing: var(--tr-label);
  text-transform: uppercase;
  color: var(--fg-3);
}
.map-cell__row-title {
  font-family: var(--font-sans);
  font-size: 22px;
  font-weight: var(--w-light);
  color: var(--fg-0);
  letter-spacing: -0.005em;
}

/* Data cells — top: mono inventory line. Bottom: light-weight slogan. */
.map-table article.map-cell {
  padding: 28px 28px 32px;
  gap: 18px;
  min-height: 168px;
  justify-content: space-between;
}
.map-cell__items {
  font-family: var(--font-mono);
  font-size: var(--t-mono-s);
  letter-spacing: var(--tr-label);
  text-transform: uppercase;
  color: var(--fg-2);
  line-height: var(--lh-mono);
}
.map-cell__slogan {
  margin: 0;
  font-family: var(--font-sans);
  font-size: 19px;
  line-height: 1.3;
  font-weight: var(--w-light);
  color: var(--fg-1);
  text-wrap: pretty;
}
.map-cell__slogan strong {
  color: var(--fg-0);
  font-weight: var(--w-medium);
}

/* VectorOS cell — accent corner tick, accent label, brightened slogan. */
.map-cell--us::before {
  content: "";
  position: absolute;
  top: 0; left: 0;
  width: 14px;
  height: 2px;
  background: var(--accent);
}
.map-cell--us .map-cell__items strong {
  color: var(--accent);
  font-weight: var(--w-semi);
  font-size: var(--t-mono-m);
  letter-spacing: 0.04em;
}
.map-cell--us .map-cell__slogan { color: var(--fg-0); }

/* Tablet: the corner legend goes away, columns stretch. */
@media (max-width: 900px) {
  .map-table { grid-template-columns: 140px 1fr 1fr; }
  .map-cell--corner .map-cell__corner-rhythm { display: none; }
  .map-cell--corner .map-cell__corner-order { align-self: flex-start; }
}

/* Mobile: collapse to single column. Each row-head becomes a section
   spanning full width; data cells stack underneath labelled by column. */
@media (max-width: 640px) {
  .map-table { grid-template-columns: 1fr; }
  .map-cell--corner { display: none; }
  .map-cell--colhead { display: none; }
  .map-cell--rowhead {
    flex-direction: row;
    align-items: baseline;
    justify-content: flex-start;
    gap: 16px;
    padding: 20px 24px;
  }
  .map-table article.map-cell { min-height: 0; padding: 24px; }
}

/* =========================================================================
   Effects stage — single auto-rotating panel that cycles through the three
   deltas. No paginators; a thin progress hairline at the bottom shows time
   remaining, and a small "01 — 03" readout in the top corner marks the
   position. Crossfades on each tick; pauses on hover.
   ========================================================================= */
.effects-stage {
  margin: 56px 0 0;
  position: relative;
  border-top: 1px solid var(--line-2);
  border-bottom: 1px solid var(--line-2);
  padding: 36px 0 56px;
  overflow: hidden;
}

.effects-stage__top {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 24px;
  margin-bottom: 56px;
}
.effects-stage__id {
  display: inline-flex;
  align-items: baseline;
  gap: 12px;
  font-family: var(--font-mono);
}
.effects-stage__delta {
  font-size: clamp(20px, 1.7vw, 26px);
  color: var(--fg-1);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0;
  line-height: 1;
}
.effects-stage__sep {
  color: var(--fg-4);
  font-size: clamp(18px, 1.4vw, 22px);
}
.effects-stage__tag {
  font-size: var(--t-mono-s);
  letter-spacing: var(--tr-label);
  color: var(--fg-3);
  text-transform: uppercase;
}
.effects-stage__count {
  font-family: var(--font-mono);
  font-size: var(--t-mono-s);
  letter-spacing: var(--tr-label);
  color: var(--fg-4);
  font-variant-numeric: tabular-nums;
}
.effects-stage__count em {
  font-style: normal;
  margin: 0 6px;
  color: var(--fg-4);
}

/* Body — two columns: readout left, copy right. */
.effects-stage__body {
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(0, 1.1fr);
  column-gap: 72px;
  align-items: center;
  transition: opacity 380ms ease, transform 380ms ease;
  opacity: 1;
  transform: translateY(0);
  will-change: opacity, transform;
  min-height: 220px;
}
.effects-stage.is-fading .effects-stage__body {
  opacity: 0;
  transform: translateY(-6px);
}
.effects-stage.is-fading .effects-stage__top .effects-stage__id,
.effects-stage.is-fading .effects-stage__count > span:first-child {
  opacity: 0.25;
  transition: opacity 380ms ease;
}

.effects-stage__states {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  column-gap: 32px;
}

/* the .state* rules are reused from the previous table layout, scaled up */
.effects-stage .state {
  display: flex;
  flex-direction: column;
  gap: 14px;
  min-width: 0;
}
.effects-stage .state__label {
  font-family: var(--font-mono);
  font-size: var(--t-mono-s);
  letter-spacing: var(--tr-label);
  color: var(--fg-3);
  text-transform: uppercase;
}
.effects-stage .state__value {
  font-family: var(--font-mono);
  font-size: clamp(20px, 1.9vw, 28px);
  line-height: 1.25;
  font-weight: var(--w-regular);
}
.effects-stage .state--before .state__value { color: var(--fg-3); }
.effects-stage .state--after  .state__value { color: var(--fg-0); }

.effects-stage .state__arrow {
  position: relative;
  width: clamp(52px, 6vw, 96px);
  height: 1px;
  background: var(--line-3);
  margin-top: 32px;
}
.effects-stage .state__arrow::after {
  content: "";
  position: absolute;
  right: 0;
  top: -4px;
  width: 9px;
  height: 9px;
  border-right: 1px solid var(--accent);
  border-top: 1px solid var(--accent);
  transform: rotate(45deg);
}

.effects-stage__copy h3 {
  font-family: var(--font-sans);
  font-weight: var(--w-light);
  font-size: clamp(26px, 2.4vw, 36px);
  line-height: 1.1;
  letter-spacing: -0.018em;
  color: var(--fg-0);
  margin: 0 0 18px;
  max-width: 22ch;
  text-wrap: balance;
}
.effects-stage__copy p {
  margin: 0;
  font-size: 15px;
  line-height: 1.6;
  color: var(--fg-2);
  max-width: 46ch;
}

/* Progress hairline — fills over DURATION ms then resets when the next
   panel mounts via the .is-running class restart trick in JS. */
.effects-stage__progress {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 1px;
  background: var(--line-2);
}
.effects-stage__progress > i {
  display: block;
  height: 100%;
  width: 0%;
  background: var(--accent);
  transform-origin: left center;
}
.effects-stage.is-running .effects-stage__progress > i {
  animation: effects-stage-progress 5400ms linear forwards;
}
.effects-stage.is-paused .effects-stage__progress > i {
  animation-play-state: paused;
}
@keyframes effects-stage-progress {
  from { width: 0%;   }
  to   { width: 100%; }
}

@media (max-width: 900px) {
  .effects-stage__body {
    grid-template-columns: 1fr;
    row-gap: 36px;
  }
  .effects-stage__states {
    grid-template-columns: 1fr;
    row-gap: 20px;
    column-gap: 0;
  }
  .effects-stage .state__arrow {
    width: 1px;
    height: 28px;
    margin: 0 0 0 4px;
  }
  .effects-stage .state__arrow::after {
    right: auto;
    top: auto;
    left: -4px;
    bottom: 0;
    transform: rotate(135deg);
  }
}

@media (prefers-reduced-motion: reduce) {
  .effects-stage__body,
  .effects-stage.is-fading .effects-stage__body { transition: none; opacity: 1; transform: none; }
  .effects-stage.is-running .effects-stage__progress > i { animation: none; width: 0%; }
}


/* =========================================================================
   Refs grid swap transitions (section 05 — Основания).
   refs-animator.js cycles 1–2 of the 8 visible cards every few seconds.
   Each swap is a push: the outgoing card slides up + fades, then the
   replacement slides up from below + fades back in. Cards have a fixed
   height (sized to fit the longest entry in the bibliography) so the
   surrounding grid never reflows mid-swap.
   ========================================================================= */
.refs-grid { grid-auto-rows: minmax(260px, auto); }
.refs-grid .ref-cell {
  min-height: 260px;
  height: 100%;
  display: flex;
  flex-direction: column;
  gap: 10px;
  overflow: hidden;
  transition: opacity 240ms linear, transform 240ms linear;
  opacity: 1;
  transform: translateY(0);
  will-change: opacity, transform;
}
.refs-grid .ref-cell__use { margin-top: auto; }
.refs-grid .ref-cell.ref-cell--swap-out {
  opacity: 0;
  transform: translateY(-14px);
}
.refs-grid .ref-cell.ref-cell--swap-in {
  opacity: 0;
  transform: translateY(14px);
}


/* Final-section BeamLocus: hide per-node labels — the circles speak for
   themselves in the closing visual. Locus label stays. */
.final--beam .bl-node-label { display: none; }


/* Final-section CTA accent treatment: reverted — the closing button
   stays white like the rest of the page's primary CTAs. Block kept for
   easy re-enable. */
.final--beam .cta--primary {
  /* default cta--primary styling applies */
}
.final--beam .cta--primary:hover {
  /* default hover applies */
}


/* Plain price readout: sans-serif, one size for digit and unit, large
   and quiet. Replaces the mono numeric + small unit treatment for the
   early-access tier. */
.price-readout--plain {
  font-family: var(--font-sans);
  font-weight: var(--w-light);
  font-size: clamp(56px, 6vw, 88px);
  line-height: 1;
  letter-spacing: -0.02em;
  color: var(--fg-1);
}
.price-readout--plain .unit { font-size: inherit; color: inherit; margin-left: 0; font-weight: inherit; }


/* =========================================================================
   Manifesto — LIGHT INVERSION
   Sits between Pricing and the final CTA. The page's only light surface,
   used as a tonal pause and editorial statement about the method.
   Surface is paper-white #F2F2F0 (the design system's --fg-1, here used
   as ground); type goes dark on it. Hairlines invert to dark on light.
   ========================================================================= */
/* =========================================================================
   Manifesto — LIGHT INVERSION
   Sits between Pricing and the final CTA. The page's only light surface,
   used as a tonal pause and editorial statement about the method. Plain
   paper-white ground (#F2F2F0), dark type; hairline dividers invert to
   dark-on-light. No background pattern, no grid — quiet by intention.
   ========================================================================= */
.manifesto {
  background: #F2F2F0;
  color: #0A0B0D;
  padding: 96px 0;
  position: relative;
  border-top: 0;
  border-bottom: 0;
}
.manifesto + section { border-top: 0; }
section:has(+ .manifesto) { border-bottom: 0; }
@media (max-width: 900px) { .manifesto { padding: 64px 0; } }

.manifesto .shell {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  column-gap: 24px;
  row-gap: 0;
  position: relative;
}

/* Title — Geist light, large display. Two-line construction; second
   line picks up the dark accent, first line sits muted. */
.manifesto__title {
  grid-column: 1 / span 11;
  margin: 0 0 48px;
  font-family: var(--font-sans);
  font-weight: var(--w-light);
  font-size: clamp(40px, 5.4vw, 76px);
  line-height: 1.04;
  letter-spacing: -0.025em;
  color: #0A0B0D;
  text-wrap: balance;
}
.manifesto__title-line1 { color: rgba(10, 11, 13, 0.42); }
.manifesto__title-line2 { color: #0A0B0D; }
@media (max-width: 700px) { .manifesto__title { margin-bottom: 32px; } }

/* Body column — sits in the right portion of the grid. The shifted
   column creates an editorial feel: the title leads, the body follows
   from a hanging position. */
.manifesto__body {
  grid-column: 3 / span 8;
  max-width: 64ch;
  display: flex;
  flex-direction: column;
  gap: 20px;
}
@media (max-width: 1000px) {
  .manifesto__body { grid-column: 1 / -1; }
}

.manifesto__body p {
  margin: 0;
  font-family: var(--font-sans);
  font-size: 17px;
  line-height: 1.55;
  letter-spacing: -0.003em;
  color: rgba(10, 11, 13, 0.82);
  text-wrap: pretty;
}
.manifesto__lede {
  font-size: 17px !important;
  line-height: 1.55 !important;
  color: #0A0B0D !important;
  font-weight: var(--w-regular);
  margin-bottom: 0 !important;
}

/* List — hairline-divided rows. Numbers hang in a left rail (mono) and
   the text aligns to a grid. */
.manifesto__list {
  list-style: none;
  margin: 4px 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  border-top: 1px solid rgba(10, 11, 13, 0.18);
}
.manifesto__list li {
  display: grid;
  grid-template-columns: 56px 1fr;
  column-gap: 24px;
  align-items: baseline;
  padding: 16px 0;
  border-bottom: 1px solid rgba(10, 11, 13, 0.18);
}
.manifesto__list-num {
  font-family: var(--font-mono);
  font-size: var(--t-label);
  letter-spacing: var(--tr-label);
  color: rgba(10, 11, 13, 0.45);
  font-variant-numeric: tabular-nums;
  padding-top: 2px;
}
.manifesto__list-text {
  font-family: var(--font-sans);
  font-size: 17px;
  line-height: 1.55;
  letter-spacing: -0.003em;
  color: rgba(10, 11, 13, 0.78);
  text-wrap: pretty;
}
.manifesto__list-lead {
  display: block;
  font-weight: var(--w-medium);
  color: #0A0B0D;
  margin: 0 0 6px;
}

/* Closing paragraph — body weight, full-dark color so it lands as a
   conclusion. */
.manifesto__close {
  color: #0A0B0D !important;
  margin-top: 4px !important;
}

/* CTA inside manifesto — uses the page's standard .cta primary, but
   inverted to dark-on-light so it sits correctly on the paper surface. */
.manifesto__cta {
  align-self: flex-start;
  margin-top: 20px;
  background: #0A0B0D;
  color: #F2F2F0;
  border-color: #0A0B0D;
}
.manifesto__cta:hover {
  background: #FF4F00;
  border-color: #FF4F00;
  color: #F2F2F0;
}
