/* docs/site-handoff/tokens.css */

/*
 * OctoJinn — дизайн-токены, извлечённые из финальных макетов (source/*.dc.html).
 * Значения точные (взяты из макетов). Имена переменных и роли даны по тому,
 * где цвет используется в макетах — при интеграции их можно переименовать.
 * Подключение шрифтов: fonts/fonts.css (или ссылка Google Fonts из макетов).
 */
:root {
  /* Бренд */
  --oj-navy:        #1C2C5A; /* основной: заголовки, главные кнопки, логотип-текст */
  --oj-ink:         #0F1233; /* текст и кнопки на жёлтом фоне (hero 404 и т.п.) */
  --oj-amber:       #F0B441; /* акцент: ромб логотипа, жёлтые секции */
  --oj-cyan:        #22C3DB; /* акцент: знак логотипа, активные состояния, focus-ring */
  --oj-blue:        #1B6B93; /* ссылки, вторичный акцент */
  --oj-cyan-tint:   #E3F5F8; /* фон активной карточки */

  /* Нейтральные */
  --oj-bg:          #F4F3EF; /* фон страницы */
  --oj-surface:     #FFFFFF; /* карточки, футер */
  --oj-cell:        #E7E5DF; /* плитки-заглушки в иллюстрациях */
  --oj-surface-2:   #ECEAE4;
  --oj-surface-3:   #EFEDE8;
  --oj-border:      #E0DDD6; /* разделители, обводки */
  --oj-border-2:    #DDDAD3;
  --oj-border-3:    #E4E1DA;
  --oj-border-4:    #D5D2CA;
  --oj-text:        #17181C; /* основной текст */
  --oj-text-2:      #3A3D47; /* второстепенный текст */
  --oj-muted:       #5C5F69; /* подписи, ссылки футера */
  --oj-subtle:      #A09D95; /* неактивное, плейсхолдеры декора */
  --oj-slate-200:   #C9CEDD;
  --oj-slate-150:   #C8D2E8;
  --oj-slate-300:   #B9BDC9;
  --oj-slate-500:   #7A7E8A;

  /* Статусы (форма демо, сравнение) */
  --oj-error:       #B3261E;
  --oj-error-bg:    #FBEAEA;
  --oj-error-line:  #F0CFCF;
  --oj-success:     #1E7A46;
  --oj-success-bg:  #EAF6EE;
  --oj-success-line:#CFE8D8;

  /* Шрифты */
  --oj-font-display: 'Manrope', sans-serif;          /* заголовки: 600 (крупные), 700 (карточки, подзаголовки) */
  --oj-font-body:    'Mulish', sans-serif;           /* текст: 400/600/700 */
  --oj-font-logo:    'Plus Jakarta Sans', sans-serif;/* ТОЛЬКО словесный знак OctoJınn, 700 */

  /* Радиусы (самые частые) */
  --oj-r-xs: 4px;   /* мелкие элементы, точки */
  --oj-r-sm: 10px;
  --oj-r-md: 14px;  /* кнопки 48px в шапке */
  --oj-r-lg: 16px;  /* кнопки 60px, поля формы 12px */
  --oj-r-xl: 28px;  /* большие карточки, плитки */

  /* Кнопки */
  --oj-btn-h-sm: 44px;
  --oj-btn-h-md: 48px;  /* padding 0 24px, radius 14px */
  --oj-btn-h-lg: 60px;  /* padding 0 36px, radius 16px */

  /* Сетка / контейнер (desktop 1440) */
  --oj-page-pad-desktop: 60px;
  --oj-header-h: 80px;
}

/* Базовые правила из макетов */
body { margin: 0; background: var(--oj-bg); color: var(--oj-text); font-family: var(--oj-font-body); -webkit-font-smoothing: antialiased; }
a { color: var(--oj-blue); }
a:hover { color: var(--oj-navy); }
a:focus-visible, button:focus-visible { outline: 2px solid var(--oj-cyan); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) { .oj-a { animation: none !important; } }

/* Словесный знак: «OctoJ<span class="oj-i">ı</span>nn» — ромб вместо точки над ı.
   Значения замерены для Plus Jakarta Sans 700 (fonts/). Для другого начертания — пересчитать. */
.oj-wordmark { font-family: var(--oj-font-logo); font-weight: 700; letter-spacing: -0.025em; line-height: 1; color: var(--oj-navy); white-space: nowrap; }
.oj-wordmark .oj-i { position: relative; display: inline-block; line-height: 1; }
.oj-wordmark .oj-i::after { content: ""; position: absolute; left: 0.0725em; bottom: 0.6805em; width: 0.14em; height: 0.14em; border-radius: 0.0295em; background: var(--oj-amber); transform: rotate(45deg); }


/* docs/site-handoff/fonts/fonts.css (paths rewritten to /fonts/) */

/* Самостоятельный хостинг шрифтов OctoJinn (замена ссылки на Google Fonts). Лицензия шрифтов: SIL OFL 1.1 */
@font-face{font-family:'Manrope';font-style:normal;font-weight:500;font-display:swap;src:url('/fonts/manrope-cyrillic-500-normal.woff2') format('woff2');unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}
@font-face{font-family:'Manrope';font-style:normal;font-weight:600;font-display:swap;src:url('/fonts/manrope-cyrillic-600-normal.woff2') format('woff2');unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}
@font-face{font-family:'Manrope';font-style:normal;font-weight:700;font-display:swap;src:url('/fonts/manrope-cyrillic-700-normal.woff2') format('woff2');unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}
@font-face{font-family:'Manrope';font-style:normal;font-weight:500;font-display:swap;src:url('/fonts/manrope-latin-500-normal.woff2') format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:'Manrope';font-style:normal;font-weight:600;font-display:swap;src:url('/fonts/manrope-latin-600-normal.woff2') format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:'Manrope';font-style:normal;font-weight:700;font-display:swap;src:url('/fonts/manrope-latin-700-normal.woff2') format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:'Mulish';font-style:normal;font-weight:400;font-display:swap;src:url('/fonts/mulish-cyrillic-400-normal.woff2') format('woff2');unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}
@font-face{font-family:'Mulish';font-style:normal;font-weight:600;font-display:swap;src:url('/fonts/mulish-cyrillic-600-normal.woff2') format('woff2');unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}
@font-face{font-family:'Mulish';font-style:normal;font-weight:700;font-display:swap;src:url('/fonts/mulish-cyrillic-700-normal.woff2') format('woff2');unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}
@font-face{font-family:'Mulish';font-style:normal;font-weight:400;font-display:swap;src:url('/fonts/mulish-latin-400-normal.woff2') format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:'Mulish';font-style:normal;font-weight:600;font-display:swap;src:url('/fonts/mulish-latin-600-normal.woff2') format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:'Mulish';font-style:normal;font-weight:700;font-display:swap;src:url('/fonts/mulish-latin-700-normal.woff2') format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:'Plus Jakarta Sans';font-style:normal;font-weight:700;font-display:swap;src:url('/fonts/plus-jakarta-sans-latin-700-normal.woff2') format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:'Plus Jakarta Sans';font-style:normal;font-weight:700;font-display:swap;src:url('/fonts/plus-jakarta-sans-latin-ext-700-normal.woff2') format('woff2');unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}


/* src/styles/fontFallbacks.css (generated — tools/generate-font-fallbacks.mjs) */

/* GENERATED — node tools/generate-font-fallbacks.mjs. Do not hand-edit:
   re-run it when a vendored webfont changes (../../AGENTS.md's path table).
   Metric-matched fallbacks for the layout spec's CLS = 0 target (§8/§9):
   `base.css` puts each of these second in its font stack, so the fallback
   sans-serif already occupies the box the webfont will, before it swaps in. */
@font-face {
  font-family: "Manrope Fallback";
  font-weight: 500;
  src: local("Arial"), local("Liberation Sans"), local("Helvetica");
  size-adjust: 136.7764%;
  ascent-override: 77.9374%;
  descent-override: 21.9336%;
  line-gap-override: 0%;
  font-display: swap;
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

@font-face {
  font-family: "Manrope Fallback";
  font-weight: 500;
  src: local("Arial"), local("Liberation Sans"), local("Helvetica");
  size-adjust: 97.6081%;
  ascent-override: 109.2122%;
  descent-override: 30.7351%;
  line-gap-override: 0%;
  font-display: swap;
  unicode-range:
    U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329,
    U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Manrope Fallback";
  font-weight: 600;
  src: local("Arial"), local("Liberation Sans"), local("Helvetica");
  size-adjust: 136.7764%;
  ascent-override: 77.9374%;
  descent-override: 21.9336%;
  line-gap-override: 0%;
  font-display: swap;
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

@font-face {
  font-family: "Manrope Fallback";
  font-weight: 600;
  src: local("Arial"), local("Liberation Sans"), local("Helvetica");
  size-adjust: 99.379%;
  ascent-override: 107.2661%;
  descent-override: 30.1875%;
  line-gap-override: 0%;
  font-display: swap;
  unicode-range:
    U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329,
    U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Manrope Fallback";
  font-weight: 700;
  src: local("Arial"), local("Liberation Sans"), local("Helvetica");
  size-adjust: 136.8806%;
  ascent-override: 77.8781%;
  descent-override: 21.9169%;
  line-gap-override: 0%;
  font-display: swap;
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

@font-face {
  font-family: "Manrope Fallback";
  font-weight: 700;
  src: local("Arial"), local("Liberation Sans"), local("Helvetica");
  size-adjust: 101.1499%;
  ascent-override: 105.3881%;
  descent-override: 29.6589%;
  line-gap-override: 0%;
  font-display: swap;
  unicode-range:
    U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329,
    U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Mulish Fallback";
  font-weight: 400;
  src: local("Arial"), local("Liberation Sans"), local("Helvetica");
  size-adjust: 104.0824%;
  ascent-override: 96.5581%;
  descent-override: 24.0194%;
  line-gap-override: 0%;
  font-display: swap;
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

@font-face {
  font-family: "Mulish Fallback";
  font-weight: 400;
  src: local("Arial"), local("Liberation Sans"), local("Helvetica");
  size-adjust: 104.0824%;
  ascent-override: 96.5581%;
  descent-override: 24.0194%;
  line-gap-override: 0%;
  font-display: swap;
  unicode-range:
    U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329,
    U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Mulish Fallback";
  font-weight: 600;
  src: local("Arial"), local("Liberation Sans"), local("Helvetica");
  size-adjust: 104.3067%;
  ascent-override: 96.3505%;
  descent-override: 23.9678%;
  line-gap-override: 0%;
  font-display: swap;
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

@font-face {
  font-family: "Mulish Fallback";
  font-weight: 600;
  src: local("Arial"), local("Liberation Sans"), local("Helvetica");
  size-adjust: 105.8769%;
  ascent-override: 94.9216%;
  descent-override: 23.6123%;
  line-gap-override: 0%;
  font-display: swap;
  unicode-range:
    U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329,
    U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Mulish Fallback";
  font-weight: 700;
  src: local("Arial"), local("Liberation Sans"), local("Helvetica");
  size-adjust: 104.531%;
  ascent-override: 96.1437%;
  descent-override: 23.9164%;
  line-gap-override: 0%;
  font-display: swap;
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

@font-face {
  font-family: "Mulish Fallback";
  font-weight: 700;
  src: local("Arial"), local("Liberation Sans"), local("Helvetica");
  size-adjust: 108.12%;
  ascent-override: 92.9522%;
  descent-override: 23.1224%;
  line-gap-override: 0%;
  font-display: swap;
  unicode-range:
    U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329,
    U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Plus Jakarta Sans Fallback";
  font-weight: 700;
  src: local("Arial"), local("Liberation Sans"), local("Helvetica");
  size-adjust: 100.8374%;
  ascent-override: 102.938%;
  descent-override: 22.0156%;
  line-gap-override: 0%;
  font-display: swap;
  unicode-range:
    U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329,
    U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}


/* src/styles/base.css */

/* Bundled right after docs/site-handoff/tokens.css (which already sets
   body/a/focus-visible/reduced-motion and `.oj-wordmark`, see
   ../../scripts/build/build.mjs) — this file only adds what that one
   deliberately leaves out: a box-sizing reset and default typography. */

/* Metric-matched fallbacks second in each stack (layout spec §8/§9, "CLS =
   0 на главной"; ../../scripts/lighthouse/'s own gate step): tokens.css's
   `--oj-font-*` are the design package's own, vendored read-only
   (../../AGENTS.md's path table) — overridden here, not there, so the
   fallback sans-serif already occupies the webfont's box while it loads
   (fontFallbacks.css, generated by ../../tools/generate-font-fallbacks.mjs).
   `sans-serif` stays last: a browser with neither the webfont nor Arial/
   Liberation Sans/Helvetica installed still gets *a* font, just an
   unmatched one. */
:root {
  --oj-font-display: "Manrope", "Manrope Fallback", sans-serif;
  --oj-font-body: "Mulish", "Mulish Fallback", sans-serif;
  --oj-font-logo: "Plus Jakarta Sans", "Plus Jakarta Sans Fallback", sans-serif;
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
  /* `DemoBlock.css`'s full-bleed breakout uses `calc(50% - 50vw)` margins;
     `100vw` includes the scrollbar gutter in some browsers, which would
     otherwise add a few px of horizontal scroll on every page (contract:
     no horizontal scroll 320–1920, layout spec §4/§9). */
  overflow-x: hidden;
  /* Same token as `body`'s own background (tokens.css) — task brief item 5:
     an in-app browser's chrome-collapse/overscroll paints whatever is
     behind the document using the root element's background, and left this
     unset it defaults to white, flashing behind the header for an instant.
     `Header.css`'s own safe-area padding and fill cover the rest. */
  background: var(--oj-bg);
}

h1,
h2,
h3,
h4,
p {
  margin: 0 0 16px;
  font-family: var(--oj-font-display);
  font-weight: 600;
  color: var(--oj-navy);
}

p {
  font-family: var(--oj-font-body);
  font-weight: 400;
  color: var(--oj-text);
}

h1 {
  font-size: 56px;
  line-height: 1.1;
}

h2 {
  font-size: 40px;
  line-height: 1.15;
}

h3 {
  font-size: 24px;
  line-height: 1.2;
}

/* `<main>` carries no box model of its own — every mockup's `<main>` is
   `display: flex; flex-direction: column` and nothing else
   (`Home2.dc.html`, `Privacy.dc.html`, `Compare.dc.html`, …: same three
   declarations on every one of them). Each `<section>` inside it owns its
   *own* full width, side padding and top spacing (and bottom, on the last
   section before the footer) — the layout spec §3 says so explicitly
   ("a section sets only its own top offset, so paddings never stack") and
   every page confirms it: legal pages pad `88px 60px 40px`, Compare
   `96px 60px 120px`, Integrations `72px 60px 56px`, About
   `88px 60px 96px`, Demo `88px 60px 80px`, the home hero
   `72px 60px 112px`, NotFound (a full-bleed amber band, like
   `../components/DemoBlock/DemoBlock.css`) `120px 60px`. A page's own
   `<section>` needs the same "full-bleed background, inner
   `max-width: 1320px` + side padding, `box-sizing: content-box`" shape
   `Header`/`Footer`/`DemoBlock` already use — copy that pattern, not
   `<main>`'s padding, which would double up with a section's own. */
main {
  display: flex;
  flex-direction: column;
}

@media (max-width: 767px) {
  h1 {
    font-size: 36px;
  }

  h2 {
    font-size: 28px;
  }
}

/* Everything a visitor can click shows a hand (the mockups' own
   `button{cursor:pointer}`, which the port lost). Links get it from the
   browser; buttons, tabs, selects and summaries do not. A draggable strip
   sets `grab` on its own container, which this does not touch. */
button:not(:disabled),
select:not(:disabled),
summary,
[role="tab"],
[role="button"] {
  cursor: pointer;
}

/* A tap on a control never selects its words and never flashes the
   browser's grey tap box (a quick second tap on a tab, a chip or the
   accordion used to select text on a phone); `manipulation` also drops the
   double-tap zoom that caused it. Controls only — buttons, tabs, the switch,
   navigation and the card-shaped links. A link inside a sentence keeps
   selection, so its text can still be copied. The pressed and focused looks
   stay each control's own. */
html {
  -webkit-tap-highlight-color: transparent;
}

button,
summary,
label,
[role="tab"],
[role="button"],
nav a,
.oj-header a,
.oj-btn,
.oj-different__card,
.oj-works-with__all {
  -webkit-user-select: none;
  user-select: none;
  touch-action: manipulation;
}

/* A strip the mouse can drag and wheel (`client/dragScroll.ts` adds
   `is-draggable` only while it overflows, `is-dragging` while held: no snap
   then, it snaps on release). A sideways scroll that reaches the strip's
   end stops there instead of swiping the browser back a page. */
/* No scrollbar on a draggable strip (the mockups' own `.oj-noscroll`): it
   scrolls by swipe or drag, the bar is only noise. The roles, connectors and
   compare strips hide theirs in their own CSS. */
[data-drag-scroll] {
  scrollbar-width: none;
  overscroll-behavior-x: contain;
}

[data-drag-scroll]::-webkit-scrollbar {
  display: none;
}

[data-drag-scroll].is-draggable {
  cursor: grab;
  user-select: none;
}

[data-drag-scroll].is-dragging {
  scroll-snap-type: none;
}

[data-drag-scroll].is-dragging,
[data-drag-scroll].is-dragging * {
  cursor: grabbing;
}

/* The page's side padding: 60 on desktop and at 1024 (tokens.css), 40 from
   1023 down to 768 (layout spec §3) — the header, the footer and every
   section read this one variable, so their text lines up at every width.
   Below 768 each section sets its own mobile inset. */
@media (max-width: 1023px) {
  :root {
    --oj-page-pad-desktop: 40px;
  }
}

/* Page to page: a cross-document view transition (Chrome/Edge, Safari 18.2+;
   elsewhere a plain navigation). The header stays put (`oj-header`), the
   nav's current-page rhombus slides from the old item to the new one like a
   moving lens (`oj-nav-mark`, Header.css), the page under them cross-fades
   quickly. Off under reduced motion. */
@view-transition {
  navigation: auto;
}

::view-transition-group(oj-nav-mark) {
  animation-duration: 360ms;
  animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1);
}

::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: 180ms;
}

@media (prefers-reduced-motion: reduce) {
  @view-transition {
    navigation: none;
  }
}

/* A label that turns bold when its tab is picked, without moving its
   neighbours: an invisible, zero-height bold copy under the text holds the
   bold width from the start. The `/ ""` keeps screen readers from reading
   the name twice. */
.oj-bold-stable {
  display: inline-flex;
  flex-direction: column;
}

.oj-bold-stable::after {
  /* the first line for browsers without alt text on `content` */
  content: attr(data-text);
  content: attr(data-text) / "";
  font-weight: 700;
  height: 0;
  overflow: hidden;
  visibility: hidden;
  pointer-events: none;
  user-select: none;
}

/* Read by assistive tech, never seen: the logo link's name in plain text
   (its visible wordmark spells the brand with a dotless "ı"). The link has
   no aria-label, so its name is its own text — Lighthouse's
   label-content-name-mismatch has nothing to compare. */
.oj-visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}


/* src/components/Button/Button.css */
/* Layout spec §3: primary/outline/secondary, heights 44/48/60. Hover states
   are not drawn in the mockups — darken 8% (outline: fill navy, white text),
   focus-visible a 2px cyan ring with 2px offset, disabled 0.5 opacity. */
.oj-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  border-radius: var(--oj-r-md);
  border: none;
  font-family: var(--oj-font-body);
  font-weight: 700;
  font-size: 16px;
  line-height: 1;
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
}

.oj-btn:focus-visible {
  outline: 2px solid var(--oj-cyan);
  outline-offset: 2px;
}

.oj-btn:disabled,
.oj-btn[aria-disabled="true"] {
  opacity: 0.5;
  cursor: not-allowed;
}

.oj-btn--sm {
  height: var(--oj-btn-h-sm);
  padding: 0 20px;
}

.oj-btn--md {
  height: var(--oj-btn-h-md);
  padding: 0 24px;
  border-radius: var(--oj-r-md);
}

.oj-btn--lg {
  height: var(--oj-btn-h-lg);
  padding: 0 36px;
  border-radius: var(--oj-r-lg);
  font-size: 17px;
}

.oj-btn--primary {
  background: var(--oj-navy);
  color: #fff;
}

/* The text colour is repeated on hover: base.css's `a:hover` (the mockups'
   own) outranks a single class, and turned a link-button's white label navy
   on navy. */
.oj-btn--primary:hover {
  background: color-mix(in srgb, var(--oj-navy) 92%, #000);
  color: #fff;
}

.oj-btn--outline {
  background: transparent;
  color: var(--oj-navy);
  border: 2px solid var(--oj-navy);
}

.oj-btn--outline:hover {
  background: var(--oj-navy);
  color: #fff;
}

.oj-btn--secondary {
  background: var(--oj-surface);
  color: var(--oj-navy);
  border: 1px solid var(--oj-border-2);
}

.oj-btn--secondary:hover {
  background: color-mix(in srgb, var(--oj-surface) 92%, #000);
  color: var(--oj-navy);
}


/* src/components/CookieBanner/CookieBanner.css */
/* Cookies spec §2, layout spec §4/§6: fixed to the bottom, above the header
   (Header.css z-index 20) and any sticky compare-table chrome. Geometry
   copied from docs/site-handoff/source/Cookies*.dc.html at each of their own
   widths (1440/1024 identical, 768, 390) rather than the prose breakpoint
   numbers, which the mockups themselves do not reproduce; the banner stays a
   fluid flex row/wrap between those widths like the rest of the site (layout
   spec §4). `[hidden]` is client/consent.ts's only way to show or hide it
   once cloned from the template — see CookieBanner.tsx for why it starts
   absent instead. */
.oj-cookie-banner {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  box-sizing: border-box;
  height: 144px;
  padding: 24px 60px;
  background: rgba(255, 255, 255, 0.82);
  -webkit-backdrop-filter: blur(16px) saturate(1.2);
  backdrop-filter: blur(16px) saturate(1.2);
  border-top: 1px solid rgba(28, 44, 90, 0.12);
  box-shadow: 0 -24px 48px -32px rgba(28, 44, 90, 0.35);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 16px 40px;
  z-index: 40;
}

.oj-cookie-banner[hidden] {
  display: none;
}

.oj-cookie-banner__body {
  flex: 1 1 320px;
  max-width: 860px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.oj-cookie-banner__title {
  font-family: var(--oj-font-display);
  font-weight: 700;
  font-size: 20px;
  letter-spacing: -0.02em;
  color: var(--oj-navy);
}

.oj-cookie-banner__text {
  margin: 0;
  font-family: var(--oj-font-body);
  font-size: 15px;
  line-height: 1.5;
  color: var(--oj-text);
}

.oj-cookie-banner__text a {
  color: var(--oj-blue);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.oj-cookie-banner__text a:hover {
  color: var(--oj-navy);
}

.oj-cookie-banner__actions {
  flex: 0 1 340px;
  display: flex;
  gap: 10px;
}

.oj-cookie-banner__decline,
.oj-cookie-banner__accept {
  flex: 1 1 140px;
  box-sizing: border-box;
  height: 48px;
  padding: 0 24px;
  border-radius: var(--oj-r-md);
  font-family: var(--oj-font-body);
  font-size: 16px;
  font-weight: 700;
  cursor: pointer;
}

.oj-cookie-banner__decline {
  border: 1px solid rgba(28, 44, 90, 0.25);
  background: rgba(255, 255, 255, 0.6);
  color: var(--oj-navy);
}

.oj-cookie-banner__accept {
  border: 0;
  background: var(--oj-navy);
  color: #fff;
}

/* Cookies768.dc.html: no fixed height, tighter padding/gap, the heading a
   size down. The two buttons still sit beside the text here — the fluid wrap
   below only kicks in once the row genuinely runs out of room. */
@media (max-width: 1023px) {
  .oj-cookie-banner {
    height: auto;
    padding: 24px 40px 28px;
    gap: 16px 24px;
  }

  .oj-cookie-banner__body {
    flex: 1 1 300px;
    max-width: 560px;
  }

  .oj-cookie-banner__title {
    font-size: 19px;
  }

  .oj-cookie-banner__actions {
    flex: 0 0 auto;
  }

  .oj-cookie-banner__decline,
  .oj-cookie-banner__accept {
    flex: 0 0 auto;
    min-width: 140px;
  }
}

/* CookiesMobile.dc.html (390): heading/text and the two full-width buttons
   stack, text starts at the top edge instead of centering on the row. */
@media (max-width: 599px) {
  .oj-cookie-banner {
    padding: 20px 20px 24px;
    align-items: flex-start;
  }

  .oj-cookie-banner__body {
    flex: 1 1 240px;
    max-width: 560px;
  }

  .oj-cookie-banner__title {
    font-size: 18px;
  }

  .oj-cookie-banner__text {
    font-size: 14px;
  }

  .oj-cookie-banner__actions {
    flex: 0 1 100%;
  }

  .oj-cookie-banner__decline,
  .oj-cookie-banner__accept {
    flex: 1 1 140px;
  }
}


/* src/components/DemoBlock/DemoBlock.css */
/* Layout spec §4 + `Home2.dc.html`/`Home1024.dc.html`/`HomeMobile.dc.html`:
   a full-bleed amber band, no radius — not a card. `.oj-demo-block` breaks
   out of `<main>`'s own max-width the same way `Header`/`Footer` sit outside
   it: a full-width box with only vertical padding, an inner row capped at
   1320px re-applying the shared side padding. The negative-margin breakout
   is why `base.css` sets `overflow-x: hidden` on `html` — `100vw` in the
   `calc()` below includes the scrollbar gutter some browsers give it, which
   would otherwise add a few px of horizontal scroll on every page. */
.oj-demo-block {
  background-color: var(--oj-amber);
  /* The mockup's own decorative pattern: a rounded-square grid fading in
     from the right, behind the number. Desktop/tablet only — `HomeMobile.
     dc.html`'s section has no background-image at all. */
  background-image:
    linear-gradient(90deg, var(--oj-amber) 42%, rgba(240, 180, 65, 0) 78%),
    url("data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20width%3D%27130%27%20height%3D%27130%27%3E%3Crect%20width%3D%27112%27%20height%3D%27112%27%20rx%3D%2732%27%20fill%3D%27rgba%2815%2C18%2C51%2C0.05%29%27%2F%3E%3C%2Fsvg%3E");
  background-size:
    auto,
    130px 130px;
  background-position:
    0 0,
    right -10px top 22px;
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
  padding: 96px 0;
}

.oj-demo-block__inner {
  /* content-box: see ../Header/Header.css for why — same container bug. */
  box-sizing: content-box;
  max-width: 1320px;
  margin: 0 auto;
  padding: 0 60px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 64px;
}

.oj-demo-block__text {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 24px;
  max-width: 760px;
}

.oj-demo-block__text h2 {
  margin: 0;
  font-family: var(--oj-font-display);
  font-weight: 600;
  font-size: 72px;
  line-height: 1.02;
  letter-spacing: -0.045em;
  color: var(--oj-ink);
}

.oj-demo-block__description {
  margin: 0;
  max-width: 640px;
  font-size: 22px;
  line-height: 1.5;
  color: var(--oj-ink);
}

.oj-demo-block__cta {
  margin-top: 12px;
  background: var(--oj-ink);
}

.oj-demo-block__cta:hover {
  background: color-mix(in srgb, var(--oj-ink) 92%, #000);
}

.oj-demo-block__minutes {
  margin: 0;
  flex: none;
  display: flex;
  align-items: baseline;
  gap: 16px;
  font-family: var(--oj-font-display);
  font-weight: 600;
  color: var(--oj-ink);
}

.oj-demo-block__value {
  font-size: 300px;
  line-height: 0.8;
  letter-spacing: -0.07em;
}

.oj-demo-block__label {
  font-size: 34px;
  letter-spacing: -0.03em;
}

@media (max-width: 1279px) {
  .oj-demo-block__inner {
    gap: 48px;
  }

  .oj-demo-block__text {
    max-width: 560px;
  }

  .oj-demo-block__text h2 {
    font-size: 64px;
  }

  .oj-demo-block__minutes {
    flex-direction: column;
    align-items: flex-start;
    gap: 14px;
  }

  .oj-demo-block__value {
    font-size: 200px;
    letter-spacing: -0.06em;
  }

  .oj-demo-block__label {
    font-size: 28px;
    padding-left: 8px;
  }
}

/* Layout spec §3's container table: side padding steps to 40px at the 768
   tablet tier (60px above it, 20px below 767) — this file only had the
   1279 and 767 steps, so at exactly 768 the "минут" column (`flex: none`)
   and the text column's own longest word together needed a few px more
   than the still-60px-padded row gave them (item 3). */
@media (max-width: 1023px) {
  .oj-demo-block__inner {
    padding-left: 40px;
    padding-right: 40px;
  }
}

@media (max-width: 767px) {
  .oj-demo-block {
    background-image: none;
    padding: 56px 0;
  }

  .oj-demo-block__inner {
    padding: 0 20px;
    flex-direction: column-reverse;
    align-items: stretch;
    gap: 18px;
  }

  .oj-demo-block__text {
    max-width: none;
    gap: 18px;
  }

  .oj-demo-block__text h2 {
    font-size: 36px;
    line-height: 1.06;
    letter-spacing: -0.04em;
  }

  .oj-demo-block__description {
    max-width: none;
    font-size: 18px;
  }

  .oj-demo-block__cta {
    margin-top: 8px;
    width: 100%;
    height: 56px;
  }

  .oj-demo-block__minutes {
    flex-direction: row;
    align-items: baseline;
    gap: 10px;
  }

  .oj-demo-block__value {
    font-size: 150px;
    letter-spacing: -0.07em;
  }

  .oj-demo-block__label {
    font-size: 24px;
    padding-left: 0;
  }
}


/* src/components/Footer/Footer.css */
/* Layout spec §6: mark + wordmark + a yellow rhombus + the slogan in one
   row, larger than plain body text; a divider; links left (wraps into two
   rows), copyright right. Padding 64/36 (mobile 40/28). */
.oj-footer {
  background: var(--oj-surface);
  border-top: 1px solid var(--oj-border);
}

.oj-footer__inner {
  /* content-box: see ../Header/Header.css for why — same container bug. */
  box-sizing: content-box;
  max-width: 1320px;
  margin: 0 auto;
  padding: 64px var(--oj-page-pad-desktop) 36px;
  display: flex;
  flex-direction: column;
  gap: 48px;
}

.oj-footer__brand {
  display: flex;
  align-items: center;
  gap: 24px;
}

/* the language switch sits at the far end of the brand row */
.oj-footer__lang {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 16px;
  font-size: 16px;
}

.oj-footer__lang a {
  color: var(--oj-muted);
  text-decoration: none;
}

.oj-footer__lang a:hover {
  color: var(--oj-navy);
  text-decoration: underline;
  text-underline-offset: 6px;
}

.oj-footer__lang [aria-current] {
  color: var(--oj-navy);
  font-weight: 700;
}

.oj-footer__logo {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  color: var(--oj-navy);
  text-decoration: none;
}

.oj-footer__logo svg {
  width: 36px;
  height: 36px;
}

.oj-footer__logo .oj-wordmark {
  font-size: 26px;
}

.oj-footer__slogan {
  margin: 0;
  display: flex;
  align-items: center;
  gap: 24px;
  font-family: var(--oj-font-display);
  font-weight: 600;
  font-size: 21px;
  letter-spacing: -0.03em;
  color: var(--oj-navy);
}

.oj-footer__slogan-mark {
  display: inline-block;
  width: 12px;
  height: 12px;
  border-radius: 2.6px;
  background: var(--oj-amber);
  transform: rotate(45deg);
  flex: none;
}

.oj-footer__bottom {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 32px;
  padding-top: 24px;
  border-top: 1px solid var(--oj-border-2);
}

.oj-footer__links {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 22px;
}

.oj-footer__links a {
  color: var(--oj-muted);
  text-decoration: none;
  font-size: 16px;
  /* Without this, a flex item's default min-width: auto lets a narrow
     container shrink a multi-word link below its content width and break
     mid-link (the mockup only ever wraps whole links to the next row). */
  white-space: nowrap;
}

.oj-footer__links a:hover {
  color: var(--oj-navy);
  text-decoration: underline;
  text-underline-offset: 6px;
}

.oj-footer__copyright {
  margin: 0;
  color: var(--oj-muted);
  font-size: 16px;
  white-space: nowrap;
}

/* A third tier `Compare768.dc.html` has and `Home1024.dc.html` does not: the
   brand row stays a row, but links + copyright stack instead of sharing a
   space-between row — at this width that row was squeezing the links down
   far enough to wrap every link onto its own line. 1023, not 767 or the
   shared 1279 breakpoint: same reasoning as the container padding fix in
   ../Header/Header.css, this is where these specific numbers change. */
@media (max-width: 1023px) {
  .oj-footer__inner {
    padding: 56px 40px 32px;
  }

  .oj-footer__bottom {
    flex-direction: column;
    align-items: flex-start;
    gap: 20px;
  }
}

@media (max-width: 767px) {
  .oj-footer__inner {
    padding: 40px 20px 28px;
    gap: 24px;
  }

  .oj-footer__brand {
    flex-direction: column;
    align-items: flex-start;
    gap: 24px;
  }

  .oj-footer__lang {
    margin-left: 0;
  }

  .oj-footer__logo svg {
    width: 32px;
    height: 32px;
  }

  .oj-footer__logo .oj-wordmark {
    font-size: 23px;
  }

  .oj-footer__slogan {
    gap: 12px;
    font-size: 17px;
    letter-spacing: -0.02em;
  }

  .oj-footer__slogan-mark {
    width: 11px;
    height: 11px;
    border-radius: 2.4px;
  }

  .oj-footer__bottom {
    flex-direction: column;
    align-items: flex-start;
    gap: 24px;
    padding-top: 22px;
  }

  .oj-footer__links {
    flex-direction: column;
    gap: 14px;
  }

  .oj-footer__links a {
    /* Column layout, one link per row: nothing left to protect from
       shrinking (that was only for the row layout above), and
       `HomeMobile.dc.html`'s longest link does wrap onto a second line. */
    white-space: normal;
  }

  .oj-footer__copyright {
    font-size: 14px;
    white-space: normal;
  }
}


/* src/components/Header/Header.css */
/* Layout spec §6: desktop/tablet 80px static bar; compact (<=899 — the spec
   says <=767, but four nav items no longer fit a bar below 900) 64px fixed
   bar with a burger that opens `.oj-header__menu` (client/menu.ts). Without
   JS the panel has no `hidden` attribute and sits open under the bar — see
   ../../client/menu.ts for how JS collapses it on load. */
.oj-header {
  border-bottom: 1px solid var(--oj-border);
  background: var(--oj-bg);
  position: relative;
  /* In-app browsers (Telegram/VK/WhatsApp WebViews, iOS — task brief item
     5): `viewport-fit=cover` (`layout/Document.tsx`) exposes this as
     non-zero only inside such a chrome; everywhere else it resolves to 0,
     so nothing moves. Padding, not margin: the header's own background
     (above) covers the inset instead of leaving it transparent, and the
     bar's logo/buttons keep their usual position inside `.oj-header__bar`,
     which carries its own padding unchanged. */
  padding-top: env(safe-area-inset-top);
}

.oj-header__bar {
  height: var(--oj-header-h);
  /* content-box, not the sitewide border-box reset (base.css): layout spec
     §3's container is "1320 content + N px side padding" — under
     border-box, `max-width: 1320px` would cap padding *and* content
     together, leaving only 1200px of content and, once centred, an extra
     unwanted margin (content starting at x=120 instead of 60 at 1440). With
     content-box, `max-width` bounds content alone and this box's rendered
     width becomes exactly 1320 + 2 * padding, self-centering past that. */
  box-sizing: content-box;
  max-width: 1320px;
  margin: 0 auto;
  padding: 0 var(--oj-page-pad-desktop);
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.oj-header__logo {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  color: var(--oj-navy);
  text-decoration: none;
}

.oj-header__logo svg {
  width: 28px;
  height: 28px;
}

.oj-header__logo .oj-wordmark {
  font-size: 20px;
}

.oj-header__nav {
  display: flex;
  align-items: center;
  gap: 36px;
}

.oj-header__nav a {
  color: var(--oj-navy);
  text-decoration: none;
  font-weight: 600;
  font-size: 17px;
  white-space: nowrap;
}

/* The current page's mark: the mockup's own rhombus (`Integrations.dc.html`),
   8px, radius 2, 14px above the label, centred. */
.oj-header__nav a.is-current {
  position: relative;
}

.oj-header__mark {
  position: absolute;
  left: 50%;
  top: -14px;
  width: 8px;
  height: 8px;
  margin-left: -4px;
  border-radius: 2px;
  background: var(--oj-amber);
  transform: rotate(45deg);
  /* slides between pages (base.css, `@view-transition`) */
  view-transition-name: oj-nav-mark;
}

/* the bar stays put while the page under it changes */
.oj-header {
  view-transition-name: oj-header;
}

.oj-header__nav a:hover {
  text-decoration: underline;
  text-underline-offset: 6px;
}

.oj-header__actions {
  display: flex;
  align-items: center;
  gap: 24px;
}

.oj-header__login {
  color: var(--oj-navy);
  text-decoration: none;
  font-weight: 600;
  font-size: 17px;
}

.oj-header__burger {
  display: none;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  border-radius: var(--oj-r-md);
  color: var(--oj-navy);
}

.oj-header__burger svg {
  width: 24px;
  height: 24px;
}

.oj-header__burger .oj-icon-close {
  display: none;
}

.oj-header__burger[aria-expanded="true"] .oj-icon-burger {
  display: none;
}

.oj-header__burger[aria-expanded="true"] .oj-icon-close {
  display: block;
}

.oj-header__menu {
  display: none;
  flex-direction: column;
  border-bottom: 1px solid var(--oj-border);
}

.oj-header__menu a {
  height: 56px;
  display: flex;
  align-items: center;
  padding: 0 20px;
  border-top: 1px solid var(--oj-border);
  color: var(--oj-navy);
  text-decoration: none;
  font-family: var(--oj-font-display);
  font-weight: 700;
  font-size: 19px;
  letter-spacing: -0.025em;
}

/* the same current-page rhombus, before the label in the mobile panel */
.oj-header__menu a.is-current::before {
  content: "";
  flex: none;
  width: 8px;
  height: 8px;
  margin-right: 12px;
  border-radius: 2px;
  background: var(--oj-amber);
  transform: rotate(45deg);
}

/* Layout spec §3's container table: 60px side padding holds all the way
   down to 1024 (content 904), only narrowing to 40 between there and 768.
   1023, not the shared 1279 "tablet" breakpoint, is deliberate: it is where
   this specific number changes, not where the header's own layout does. */
/* 1024-1279: items a little closer than the groups (logo, nav, actions) */
@media (max-width: 1279px) {
  .oj-header__nav {
    gap: 28px;
  }
}

@media (max-width: 1023px) {
  .oj-header__bar {
    padding: 0 40px;
  }

  /* Four nav items, not the artboard's two (DECISIONS.md 2а): a notch
     smaller and closer so the bar still fits in one line down to 900. */
  .oj-header__nav {
    gap: 20px;
  }

  .oj-header__nav a,
  .oj-header__login {
    font-size: 16px;
  }

  .oj-header__actions {
    gap: 20px;
  }
}

/* The compact bar's own height: the 64px bar plus its 1px bottom border,
   without the safe-area padding above it. `body` reserves it (and the
   safe area) at the top, since the fixed bar below takes no room. */
:root {
  --oj-header-compact-h: 65px;
}

@media (max-width: 899px) {
  /* Fixed, not sticky (in-app browsers, spec of 21.10): a WebView
     (Telegram/VK/WhatsApp on iOS) pins a sticky bar to the edge of its own
     content inset, below the strip where its collapsed address bar sits,
     and the page scrolled through that strip above the bar; a fixed bar is
     placed against the visible area itself. `body` takes the room the bar
     no longer holds in the flow, so the page below sits where it did. */
  .oj-header {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 20;
  }

  body {
    padding-top: calc(var(--oj-header-compact-h) + env(safe-area-inset-top));
  }

  /* an anchor or a focused field scrolled into view stops below the bar */
  html {
    scroll-padding-top: calc(var(--oj-header-compact-h) + env(safe-area-inset-top));
  }

  /* Task brief item 5: some in-app browsers momentarily mis-place the
     header while their own chrome collapses/rubber-bands, and the page's
     next section peeks through the gap above it for a frame. A
     same-background fill directly above the header's own box (it moves
     with the header, the fixed bar is its containing block) papers over
     that gap instead of showing content — `bottom: 100%` stacks it flush
     above, `100vh` is taller than any such gap gets. */
  .oj-header::before {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: 100%;
    height: 100vh;
    background: var(--oj-bg);
  }

  .oj-header__bar {
    height: 64px;
    /* HomeMobile.dc.html: 20px at the logo edge, 8px at the burger edge —
       the burger button is 48px square with a centred 24px icon, so its own
       12px of inner space already reads as most of a 20px margin. */
    padding: 0 8px 0 20px;
  }

  .oj-header__nav {
    display: none;
  }

  .oj-header__login {
    display: none;
  }

  .oj-header__actions {
    gap: 2px;
  }

  .oj-header__burger {
    display: inline-flex;
  }

  .oj-header__connect {
    /* HomeMobile.dc.html: 44px tall, 18px padding — smaller than the md
       button this reuses everywhere else. */
    height: 44px;
    padding: 0 18px;
    transition:
      opacity 200ms,
      transform 200ms;
  }

  .oj-header__connect[data-hidden="true"] {
    opacity: 0;
    transform: translateY(-4px);
    pointer-events: none;
  }

  .oj-header__menu {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    background: var(--oj-bg);
    box-shadow: 0 24px 40px -28px rgba(28, 44, 90, 0.45);
    transition:
      opacity 180ms,
      transform 180ms;
  }

  .oj-header__menu[hidden] {
    display: none;
  }

  .oj-header__menu:not([hidden]) {
    display: flex;
  }
}

/* 768-899: the compact bar keeps the page's 40px side padding (28 at the
   burger's edge — its 48px button holds 12 of its own), so the logo lines
   up with the content under it. */
@media (min-width: 768px) and (max-width: 899px) {
  .oj-header__bar {
    padding: 0 28px 0 40px;
  }
}

/* Below the 390 control width (fluid territory, layout spec §4: no
   horizontal scroll 320-1920), the burger (fixed 48px) plus the
   "Подключить" CTA at its 390-width padding no longer fit next to the logo
   at 320px (item 3) — the CTA's own padding is the one thing here with
   room to give without changing the 390 design itself. */
@media (max-width: 359px) {
  .oj-header__connect {
    padding: 0 12px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .oj-header__connect,
  .oj-header__menu {
    transition: none;
  }
}


/* src/components/LegalDocument/LegalDocument.css */
/* Geometry from Privacy.dc.html / PrivacyMobile.dc.html (Consent and Terms
   share the same structure per the mockups). No separate tablet rule: at
   1024 the two-column grid simply reflows inside its 60px page margins
   (Privacy1024.dc.html renders the same markup, only narrower) — the single
   breakpoint below is the shared 767px one (../../../AGENTS.md contract 9).
   `main` carries no padding of its own (../../styles/base.css) — this page's
   own top/side/bottom inset lives here: mockup's hero section is
   `88px 60px 40px` and its TOC+sections one is `0 60px 96px`; since both
   sit inside this single wrapper, one `padding: 88px 60px 96px` reproduces
   both edges at once (the 40px gap between them is `.oj-legal__hero`'s own
   `margin-bottom` below, not this wrapper). */
.oj-legal {
  padding: 40px 20px 56px;
}

.oj-legal__hero {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin: 0 auto 24px;
  max-width: 1000px;
}

.oj-legal__title {
  margin: 0;
  font-size: 32px;
  line-height: 1.12;
  letter-spacing: -0.035em;
  /* "конфиденциальности" alone, at 320px (below the 390 control width, so
     not in any mockup), is wider than the column and has no soft-wrap
     point of its own — without this the word overflows past the column
     the way ordinary text wrap never would (item 3). */
  overflow-wrap: break-word;
}

.oj-legal__date {
  margin: 0;
  font-size: 15px;
  color: var(--oj-muted);
}

.oj-legal__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 24px;
}

.oj-legal__toc {
  box-sizing: border-box;
  border: 1px solid var(--oj-border);
  border-radius: var(--oj-r-lg);
  background: var(--oj-surface);
  /* A closed `<details>` collapses its own box to the summary's height as
     part of its native rendering — the link list stays in normal flow
     underneath and, without this, would still paint past that collapsed
     box (`overflow: visible`'s default) instead of actually disappearing
     when a mobile reader taps `<summary>` to close it. */
  overflow: hidden;
}

.oj-legal__tocSummary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 18px;
  font-family: var(--oj-font-display);
  font-weight: 700;
  font-size: 16px;
  color: var(--oj-navy);
  list-style: none;
  cursor: pointer;
}

.oj-legal__tocSummary::-webkit-details-marker {
  display: none;
}

.oj-legal__tocChevron {
  flex: none;
  width: 16px;
  height: 16px;
}

.oj-legal__tocLabel {
  display: none;
}

.oj-legal__tocNav {
  flex-direction: column;
  gap: 2px;
  padding: 0 10px 14px;
}

/* `display` scoped to the open state, not unconditional: an unscoped
   `display: flex` here is an *author* declaration, which always beats the
   UA stylesheet's non-important `details:not([open]) > * { display: none }`
   regardless of specificity — it would keep the link list visible even
   after tapping `<summary>` to close it at mobile, the one place the
   native toggle still runs (≥768px hides the summary instead, below). */
details[open] > .oj-legal__tocNav {
  display: flex;
}

.oj-legal__tocNav a {
  font-size: 16px;
  line-height: 1.4;
  color: var(--oj-text-2);
  text-decoration: none;
  padding: 8px 10px;
  border-radius: var(--oj-r-sm);
}

.oj-legal__tocNav a:hover {
  background: var(--oj-surface-2);
}

.oj-legal__sections {
  display: flex;
  flex-direction: column;
  gap: 28px;
}

.oj-legal__section {
  display: flex;
  flex-direction: column;
  gap: 10px;
  scroll-margin-top: 16px;
}

.oj-legal__section h2 {
  margin: 0;
  font-family: var(--oj-font-display);
  font-weight: 700;
  font-size: 20px;
  letter-spacing: -0.02em;
  color: var(--oj-navy);
}

.oj-legal__section p {
  margin: 0;
  font-family: var(--oj-font-body);
  font-weight: 400;
  font-size: 16px;
  line-height: 1.55;
  color: var(--oj-text-2);
}

@media (min-width: 768px) {
  .oj-legal {
    padding: 88px var(--oj-page-pad-desktop) 96px;
  }

  .oj-legal__hero {
    gap: 16px;
    margin-bottom: 40px;
  }

  .oj-legal__title {
    font-size: 56px;
    line-height: 1.1;
    letter-spacing: -0.04em;
  }

  .oj-legal__date {
    font-size: 17px;
  }

  .oj-legal__grid {
    grid-template-columns: 250px 1fr;
    gap: 56px;
    align-items: start;
    max-width: 1000px;
    margin: 0 auto;
  }

  .oj-legal__toc {
    border: none;
    border-radius: 0;
    background: none;
    position: sticky;
    top: 24px;
    align-self: start;
  }

  .oj-legal__tocSummary {
    display: none;
  }

  .oj-legal__tocLabel {
    display: block;
    padding: 0 10px 8px;
    font-size: 14px;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--oj-muted);
  }

  .oj-legal__tocNav {
    padding: 0;
  }

  .oj-legal__sections {
    gap: 40px;
    max-width: 700px;
  }

  .oj-legal__section {
    gap: 12px;
    scroll-margin-top: 24px;
  }

  .oj-legal__section h2 {
    font-size: 26px;
  }

  .oj-legal__section p {
    font-size: 18px;
    line-height: 1.6;
  }
}


/* src/components/Wordmark/Wordmark.css */
/* The `.oj-wordmark`/`.oj-i` rules ship from docs/site-handoff/tokens.css
   itself (build.mjs concatenates it first into dist/styles.css, before this
   file) — this file only adds what tokens.css does not know about, plus one
   override: tokens.css hard-codes `.oj-wordmark`'s colour to navy, which is
   right everywhere the mockups use it (on `--oj-bg`/`--oj-surface`) but
   wrong the moment a page needs the word on a dark band. Same specificity,
   loaded later, so this wins; `Header.css`/`Footer.css` set navy explicitly
   on the link that wraps their own wordmark, so nothing changes there. */
.oj-wordmark {
  color: inherit;
}

.oj-logo-mark {
  display: block;
  flex: none;
}

/* The rhombus over the dotless ı, placed from the text's own baseline rather
   than tokens.css's box-bottom offset: the inline-block box's bottom depends
   on how each browser and OS read the font's ascent/descent (it sat lower
   in Safari), while the baseline does not. An empty inline-block sits with
   its bottom on the baseline; the margins pull it back over the stem and give
   the width back so "nn" does not move; the transform lifts it and turns it.
   Measured in Plus Jakarta Sans 700: the ı advances 0.203em (letter-spacing
   included), its stem is centred 0.1163em from its left edge, the J's top is
   0.75em above the baseline. So: centre over the stem, top corner level with
   the J — lifted a further 0.012em, the amount the rounded corner
   (radius 0.0295em) takes off the apex. */
.oj-wordmark .oj-i::after {
  position: static;
  display: inline-block;
  vertical-align: baseline;
  left: auto;
  bottom: auto;
  width: 0.14em;
  height: 0.14em;
  margin-left: -0.1567em;
  margin-right: 0.0167em;
  transform: translateY(-0.593em) rotate(45deg);
}


/* src/components/home/HomeAdvantages.css */
/* The "why OctoJinn" accordion (layout spec §4/§5, `Home2.dc.html` /
   `Home1024.dc.html` / `HomeMobile.dc.html`). Full-bleed section on the page
   background (no colour change of its own) + inner `max-width: 1320px` +
   side padding, the shape `../Header/Header.css` explains. Default (no
   `.is-closed` anywhere, i.e. no JS yet) renders every item as an open card:
   full text, always in the DOM — `client/advantages.ts` is the only thing
   that ever adds `.is-closed`, once it runs. */
.oj-advantages {
  background: var(--oj-bg);
}

.oj-advantages__inner {
  box-sizing: content-box;
  max-width: 1320px;
  margin: 0 auto;
  padding: 120px var(--oj-page-pad-desktop) 56px;
  display: flex;
  flex-direction: column;
  gap: 56px;
}

.oj-advantages__inner h2 {
  margin: 0;
  font-size: 64px;
  line-height: 1.04;
  letter-spacing: -0.045em;
}

/* The mobile-only shared animation window (`HomeAdvantages.tsx`): hidden
   above 767 (each open card gets its own window instead, below); at 767 it
   replaces every per-item window with one shared box showing the currently
   open item's scene (`client/advantages.ts` toggles `.is-active`). */
.oj-advantages__mobileWindow {
  display: none;
}

.oj-advantages__list {
  position: relative;
  /* its own stacking context, so the lens's `z-index: -1` lands behind the
     items but above the section's background, not beneath it */
  isolation: isolate;
  display: flex;
  flex-direction: column;
}

/* The sliding lens (owner's ask, not the mockup's): the open card's own
   look, carried by a separate element behind the items instead of the item
   itself, so `client/advantages.ts` can glide it from the old open item to
   the new one. Hidden by default — pre-JS every item keeps its own card
   look below and no lens ever appears; `.has-lens` (JS-added to the list)
   switches both at once. `z-index: -1` inside the list's own stacking
   context puts it behind the items. */
.oj-advantages__lens {
  display: none;
  position: absolute;
  top: 0;
  left: 0;
  z-index: -1;
  border-radius: 28px;
  background: var(--oj-surface);
  box-shadow: 0 30px 60px -44px rgba(28, 44, 90, 0.45);
}

.oj-advantages__list.has-lens .oj-advantages__lens {
  display: block;
}

.oj-advantages__list.has-lens .oj-advantages__item:not(.is-closed) {
  background: transparent;
  box-shadow: none;
}

.oj-advantages__item {
  border-radius: 28px;
}

/* The third column is never a grid item (the window below is positioned
   out of flow) — it exists only to cap the text column's width at exactly
   the mockup's, so a long title can never grow wide enough to run under the
   window. */
/* `min-height`: the window is positioned out of grid flow (below), so a
   short title+description no longer forces the card tall enough to hold it
   — pin the card to at least padding + the window's own height, matching
   the mockup's card height exactly (it gets there by making the window a
   normal, if oversized, grid item instead; same end result). */
.oj-advantages__item:not(.is-closed) {
  position: relative;
  display: grid;
  grid-template-columns: 96px 1fr 480px;
  align-items: start;
  align-content: start;
  column-gap: 8px;
  row-gap: 16px;
  margin: 6px 0;
  padding: 24px 24px 24px 28px;
  min-height: 268px;
  background: var(--oj-surface);
  box-shadow: 0 30px 60px -44px rgba(28, 44, 90, 0.45);
}

/* The row/panel wrappers exist for the closed layout and the collapse
   animation (below); once an item is open they get out of the way
   (`display: contents`) so num/title/desc/window become direct grid items
   of the item itself — the layout the mockup's own open card uses. */
.oj-advantages__item:not(.is-closed) .oj-advantages__row,
.oj-advantages__item:not(.is-closed) .oj-advantages__panelOuter,
.oj-advantages__item:not(.is-closed) .oj-advantages__panelInner,
.oj-advantages__item:not(.is-closed) .oj-advantages__panelBody {
  display: contents;
}

/* Closed row: `96px 1fr 32px`, gap 8 — the same number column and gap the
   open card above uses, so opening another item never moves this text.
   `position: relative`: the toggle's `::after` below stretches over the
   whole row (number, title, "+") so the entire row is the click target, as
   in the mockup — harmless when the row is `display: contents` (open). */
.oj-advantages__row {
  position: relative;
  box-sizing: border-box;
  width: 100%;
  display: grid;
  grid-template-columns: 96px 1fr 32px;
  align-items: center;
  column-gap: 8px;
  padding: 24px 28px;
}

/* Owner's decision: lines only between items — none above the first or
   below the last. */
.oj-advantages__item + .oj-advantages__item.is-closed .oj-advantages__row {
  border-top: 1px solid var(--oj-border);
}

/* Owner's decision (not the mockup's): no line above an open card (already
   true — an open row carries no border-top of its own) and none below it
   either — the closed row right after an open one skips its border-top too. */
.oj-advantages__item:not(.is-closed) + .oj-advantages__item.is-closed .oj-advantages__row {
  border-top: none;
}

.oj-advantages__num {
  font-family: var(--oj-font-display);
  font-weight: 600;
  font-size: 40px;
  line-height: 1;
  letter-spacing: -0.04em;
  color: var(--oj-slate-300);
}

.oj-advantages__item:not(.is-closed) .oj-advantages__num {
  grid-column: 1;
  grid-row: 1 / -1;
  align-self: start;
  padding-top: 2px;
  color: var(--oj-cyan);
}

.oj-advantages__heading {
  margin: 0;
  /* lets the button inside act as this row's own grid item (a11y: the
     heading tag stays, but it never intercepts layout) */
  display: contents;
}

.oj-advantages__toggle {
  box-sizing: border-box;
  width: 100%;
  border: 0;
  padding: 0;
  margin: 0;
  background: transparent;
  text-align: left;
  cursor: pointer;
  font-family: var(--oj-font-display);
  font-weight: 700;
  font-size: 27px;
  line-height: 1.15;
  letter-spacing: -0.025em;
  color: var(--oj-navy);
}

/* Owner's decision: the whole closed row is the click target, not just the
   title text — a transparent overlay stretched to the row's own bounds
   (`position: relative` above), the same trick as a "stretched link". */
.oj-advantages__item.is-closed .oj-advantages__toggle::after {
  content: "";
  position: absolute;
  inset: 0;
  cursor: pointer;
}

.oj-advantages__item:not(.is-closed) .oj-advantages__toggle {
  grid-column: 2;
  grid-row: 1;
  font-size: 42px;
  font-weight: 700;
  line-height: 1.08;
  letter-spacing: -0.035em;
}

.oj-advantages__plus {
  font-family: var(--oj-font-display);
  font-weight: 500;
  font-size: 30px;
  line-height: 1;
  color: var(--oj-blue);
}

.oj-advantages__item:not(.is-closed) .oj-advantages__plus {
  display: none;
}

/* The collapse: `grid-template-rows` 0fr <-> 1fr (layout spec §5 allows
   either an animated or an instant switch) — no JS means no `.is-closed`,
   so this rule never fires pre-JS and every panel stays at its natural
   (`1fr`) height. Only meaningful for a closed item now — an open one turns
   this wrapper transparent above. No `transition` of its own any more: the
   sliding-lens view transition (below) covers the smooth case, and without
   it the switch is meant to be instant, not a leftover 240ms fade. */
.oj-advantages__panelOuter {
  display: grid;
  grid-template-rows: 1fr;
}

.oj-advantages__item.is-closed .oj-advantages__panelOuter {
  grid-template-rows: 0fr;
}

.oj-advantages__panelInner {
  overflow: hidden;
  min-width: 0;
  display: grid;
  grid-template-columns: 96px 1fr;
  column-gap: 8px;
  /* no vertical padding here: a `0fr` row cannot shrink below its item's own
     padding, so the bottom space lives on the body instead */
  min-height: 0;
  padding: 0 28px;
}

/* The number column stays empty here — column 1 exists only so this text
   lines up under the row's own num/heading columns above, for the closed
   collapse. */
.oj-advantages__panelBody {
  grid-column: 2;
  min-width: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 24px 40px;
  padding-bottom: 28px;
}

.oj-advantages__desc {
  margin: 0;
  max-width: 520px;
  font-size: 22px;
  line-height: 1.45;
  color: var(--oj-text);
  flex: 1 1 320px;
}

.oj-advantages__item:not(.is-closed) .oj-advantages__desc {
  grid-column: 2;
  grid-row: 2;
}

/* Fixed-size animation window (contract 5, ../../../AGENTS.md: no CLS) —
   width fluid between breakpoints, but always a concrete box, never
   auto-sized to content. `aspect-ratio` gives the 1440 2:1 shape; 1024
   breaks that ratio on purpose (the mockup's own 300x200), so it is
   overridden explicitly below rather than derived. Positioned (contract:
   the open card's redesign) at the card's own top-right corner — `top`/
   `right` match the card's own padding exactly, so it sits at the top,
   beside the title, spanning the height, independent of how wide the text
   column happens to be. `position: relative` stays the base value (the
   scene inside centres on it) — the open-card rule below switches it to
   `absolute` without losing that. */
.oj-advantages__window {
  position: relative;
  flex: none;
  box-sizing: border-box;
  width: clamp(260px, 33vw, 440px);
  aspect-ratio: 2 / 1;
  border-radius: 22px;
  background: var(--oj-surface-2);
  overflow: hidden;
  --oj-scene-scale: 0.65;
}

.oj-advantages__item:not(.is-closed) .oj-advantages__window {
  position: absolute;
  top: 24px;
  right: 24px;
}

.oj-advantages__sceneWrap {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 500px;
  height: 340px;
  margin: -170px 0 0 -250px;
  transform: scale(var(--oj-scene-scale));
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Loops run only while their item is open and in the viewport
   (`client/advantages.ts`, layout spec §5 rule 4). Paused only on the
   script's explicit `data-running="false"`, never by the attribute's
   absence: without JavaScript nothing sets it, and a scene frozen on its
   first keyframe would be an empty box (§5 rule 2 — content visible
   without JS; audit 2026-09-30). `.oj-a`'s own
   `prefers-reduced-motion` kill switch (tokens.css) wins regardless.
   `!important`: each scene element carries its own `animation` in an inline
   `style` (React — durations/delays come from data,
   `HomeAdvantagesScene.tsx`), which always outranks a selector rule
   regardless of specificity — same reason `tokens.css`'s reduced-motion
   override uses it. */
.oj-advantages__window[data-running="false"] .oj-a {
  animation-play-state: paused !important;
}

/* The mobile shared window's own copy of the same gate — a separate class,
   a separate pause rule (`client/advantages.ts` drives `data-running` on
   this container the same way it drives it on a per-item window). */
.oj-advantages__mobileWindow[data-running="false"] .oj-a {
  animation-play-state: paused !important;
}

.oj-advantages__mobileScene {
  display: none;
}

/* No-JS start state (layout spec §5 rule 2, task brief item 3): the scene
   matching the initially open accordion item is visible by default — not
   set by a script, so a visitor with JavaScript off never sees an empty
   250px box. `client/advantages.ts` removes `data-default-open` once it
   runs, so `.is-active` alone decides visibility from then on and this rule
   never fights a later switch. */
.oj-advantages__mobileScene[data-default-open="true"],
.oj-advantages__mobileScene.is-active {
  display: block;
}

/* The sliding-lens same-document view transition (`client/advantages.ts`
   adds/removes `oj-vt-advantages` on `<html>` around the switch, only when
   motion is allowed and the API exists) — scoped to that class so it never
   touches the page-to-page transition (`../../styles/base.css`) or leaves
   rules active once the switch settles. `oj-adv-lens` and each item's own
   `oj-adv-item-N` (inline style, `HomeAdvantages.tsx`) share the same
   360ms/easing as the header's own sliding mark (`../Header/Header.css`) —
   the items between the old and new open one carry the same name-based
   groups, so the browser slides them instead of jumping. */

/* Defensive: the UA stylesheet's overlay (`::view-transition`, fixed and
   full-viewport) is not `pointer-events: none` by default. A click while a
   switch is still animating is a rare, sub-360ms window (a real click on
   another item lands well after) — this at least does not make it worse in
   an engine that already lets clicks reach the live page during one. */
html.oj-vt-advantages::view-transition {
  pointer-events: none;
}

/* While the switch animates, the browser hit-tests the whole page as the
   root element: a quick second tap (a double tap on a phone) landed on
   `<html>` and selected the nearest word of the page. No selection starts
   during those 360ms. */
html.oj-vt-advantages {
  -webkit-user-select: none;
  user-select: none;
}

/* Names exist only while a switch runs, so a page-to-page transition
   (`../../styles/base.css`) never captures the accordion piece by piece. */
html.oj-vt-advantages .oj-advantages__lens {
  view-transition-name: oj-adv-lens;
}

html.oj-vt-advantages .oj-advantages__item[data-index="0"] {
  view-transition-name: oj-adv-item-1;
}

html.oj-vt-advantages .oj-advantages__item[data-index="1"] {
  view-transition-name: oj-adv-item-2;
}

html.oj-vt-advantages .oj-advantages__item[data-index="2"] {
  view-transition-name: oj-adv-item-3;
}

html.oj-vt-advantages .oj-advantages__item[data-index="3"] {
  view-transition-name: oj-adv-item-4;
}

html.oj-vt-advantages .oj-advantages__item[data-index="4"] {
  view-transition-name: oj-adv-item-5;
}

html.oj-vt-advantages .oj-advantages__item[data-index="5"] {
  view-transition-name: oj-adv-item-6;
}

html.oj-vt-advantages .oj-advantages__item[data-index="6"] {
  view-transition-name: oj-adv-item-7;
}

html.oj-vt-advantages::view-transition-group(*) {
  animation-duration: 360ms;
  animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1);
}

/* Clip, don't stretch: a closed row and an open card have very different
   aspect ratios, and the browser's default "scale the snapshot to fit"
   morph would visibly distort the text while the box grows or shrinks. */
html.oj-vt-advantages::view-transition-old(*),
html.oj-vt-advantages::view-transition-new(*) {
  height: 100%;
  object-fit: none;
  object-position: top;
}

/* The closing and the opening item (`is-switching`, set by
   `client/advantages.ts`) lose their old look fast, so an item's big and
   small titles never sit on top of each other for the whole glide. Only
   those two: an unchanged item cross-fades with itself at equal speed and
   stays solid, where unequal fades would dim it. */
html.oj-vt-advantages .oj-advantages__item.is-switching {
  view-transition-class: oj-adv-switching;
}

html.oj-vt-advantages::view-transition-old(*.oj-adv-switching) {
  animation-duration: 140ms;
}

/* Keep it local to the accordion: the root snapshot's rect never actually
   changes (same viewport before and after), but by default it still
   cross-fades old-for-new across the *whole page* — switched off, and reset
   out of the clip-not-stretch rule above (it does not need it: nothing
   about the root's own box is animating). */
html.oj-vt-advantages::view-transition-old(root),
html.oj-vt-advantages::view-transition-new(root) {
  animation: none;
  mix-blend-mode: normal;
  height: auto;
  object-fit: cover;
  object-position: center;
}

@media (max-width: 1279px) {
  .oj-advantages__inner {
    padding: 96px var(--oj-page-pad-desktop) 48px;
    gap: 44px;
  }

  .oj-advantages__inner h2 {
    font-size: 48px;
  }

  .oj-advantages__item:not(.is-closed) {
    grid-template-columns: 96px 1fr 324px;
    row-gap: 14px;
    padding: 28px;
    min-height: 256px;
  }

  .oj-advantages__item:not(.is-closed) .oj-advantages__num {
    padding-top: 0;
  }

  .oj-advantages__item:not(.is-closed) .oj-advantages__toggle {
    font-size: 34px;
  }

  .oj-advantages__item.is-closed .oj-advantages__toggle {
    font-size: 24px;
  }

  .oj-advantages__desc {
    max-width: 420px;
    font-size: 19px;
  }

  .oj-advantages__panelBody {
    gap: 14px 24px;
  }

  .oj-advantages__window {
    width: 300px;
    height: 200px;
    aspect-ratio: auto;
    --oj-scene-scale: 0.58;
  }

  .oj-advantages__item:not(.is-closed) .oj-advantages__window {
    top: 28px;
    right: 28px;
  }
}

@media (max-width: 767px) {
  .oj-advantages__inner {
    padding: 72px 20px 36px;
    gap: 28px;
  }

  .oj-advantages__inner h2 {
    font-size: 34px;
    line-height: 1.06;
    letter-spacing: -0.04em;
  }

  .oj-advantages__mobileWindow {
    display: block;
    position: relative;
    box-sizing: border-box;
    width: 100%;
    height: 250px;
    border-radius: 24px;
    background: var(--oj-surface-2);
    overflow: hidden;
    --oj-scene-scale: 0.7;
  }

  .oj-advantages__row {
    grid-template-columns: 44px 1fr 24px;
    padding: 18px 16px;
  }

  .oj-advantages__item:not(.is-closed) {
    grid-template-columns: 44px 1fr 24px;
    row-gap: 10px;
    border-radius: 22px;
    padding: 20px 16px 22px;
    /* no window in the open card at this width (hidden below) — the card
       goes back to its natural, text-driven height */
    min-height: 0;
  }

  .oj-advantages__lens {
    border-radius: 22px;
  }

  .oj-advantages__num {
    font-size: 24px;
  }

  .oj-advantages__item:not(.is-closed) .oj-advantages__num {
    padding-top: 1px;
  }

  .oj-advantages__toggle {
    font-size: 19px;
  }

  /* the open title keeps the closed size on mobile (HomeMobile.dc.html: 19px),
     and needs the open rule's own specificity to say so */
  .oj-advantages__item:not(.is-closed) .oj-advantages__toggle {
    font-size: 19px;
    line-height: 1.15;
    letter-spacing: -0.025em;
  }

  .oj-advantages__plus {
    font-size: 24px;
  }

  .oj-advantages__panelInner {
    grid-template-columns: 44px 1fr;
    padding: 0 16px;
  }

  /* in a column the desktop flex-basis (320px) would become a height */
  .oj-advantages__desc {
    flex: none;
    font-size: 17px;
  }

  .oj-advantages__item:not(.is-closed) .oj-advantages__desc {
    max-width: 560px;
    line-height: 1.5;
    color: var(--oj-text-2);
  }

  .oj-advantages__panelBody {
    flex-direction: column;
    padding-bottom: 20px;
  }

  /* Per-item windows are hidden below 768 — the shared mobile window above
     takes over. */
  .oj-advantages__window {
    display: none;
  }
}


/* src/components/home/HomeAdvantagesScene.css */
/* The seven advantages scenes (`HomeAdvantagesScene.tsx`), keyframes copied
   verbatim from `Home2.dc.html`'s own `<style>` (timings are the source of
   truth, layout spec §5 rule "не на глаз"). Every animated element also
   carries the sitewide `.oj-a` class, so `prefers-reduced-motion: reduce`
   (tokens.css) already freezes all of them at their resting, non-animated
   position — which is why none of these need a separate "reduced" branch. */
@keyframes oj-draw {
  from {
    stroke-dashoffset: 900;
  }
  to {
    stroke-dashoffset: 0;
  }
}

@keyframes oj-in {
  from {
    opacity: 0;
    transform: translateY(8px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes oj-a5 {
  0%,
  8% {
    height: var(--h);
  }
  20% {
    height: var(--h2);
  }
  34% {
    height: var(--h);
  }
  50% {
    height: 36px;
    width: 36px;
    border-radius: 10px;
    background: var(--oj-amber);
  }
  60%,
  90% {
    height: 36px;
    width: 36px;
    border-radius: 10px;
    background: var(--oj-cyan);
  }
  100% {
    height: var(--h);
  }
}

@keyframes oj-fillx {
  0% {
    transform: scaleX(0);
  }
  75%,
  92% {
    transform: scaleX(1);
  }
  100% {
    transform: scaleX(0);
  }
}

@keyframes oj-pop2 {
  0%,
  30% {
    opacity: 0;
    transform: translateY(10px) scale(0.9);
  }
  40%,
  88% {
    opacity: 1;
    transform: none;
  }
  100% {
    opacity: 0;
    transform: none;
  }
}

@keyframes oj-sum {
  0% {
    transform: scaleX(0);
    background: var(--oj-amber);
  }
  55% {
    transform: scaleX(1.06);
    background: var(--oj-amber);
  }
  100% {
    transform: scaleX(1);
    background: var(--oj-cyan);
  }
}

@keyframes oj-absorb {
  0% {
    transform: translate(var(--x), var(--y)) scale(0.5);
    opacity: 0;
  }
  7%,
  38% {
    transform: translate(var(--x), var(--y)) scale(1);
    opacity: 1;
  }
  52% {
    transform: translate(0, 0) scale(0.3);
    opacity: 1;
  }
  56%,
  100% {
    transform: translate(0, 0) scale(0.2);
    opacity: 0;
  }
}

@keyframes oj-gulp {
  0%,
  100% {
    transform: rotate(45deg) scale(1);
  }
  50% {
    transform: rotate(45deg) scale(1.06);
  }
}

.oj-scene {
  display: flex;
  align-items: center;
  justify-content: center;
}

/* v0 — "connects to everything": five category chips (`Home2.dc.html`
   deliberately leaves out "Связь"/Communication, see ../../../AGENTS.md
   task notes). */
.oj-scene-v0__tags {
  width: 460px;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px;
}

.oj-scene-v0__tag {
  box-sizing: border-box;
  display: inline-flex;
  align-items: center;
  height: 44px;
  padding: 0 16px;
  border-radius: 14px;
  background: var(--oj-surface);
  border: 1px solid var(--oj-border-3);
  font-family: var(--oj-font-display);
  font-weight: 700;
  font-size: 16px;
  letter-spacing: -0.02em;
  color: var(--oj-navy);
  white-space: nowrap;
  animation: oj-in 0.4s ease-out var(--oj-scene-delay, 0s) backwards;
}

/* v1 — "learns any skill": an idle equalizer. */
.oj-scene--v1 {
  gap: 10px;
  height: 70px;
}

.oj-scene-v1__bar {
  display: block;
  width: 8px;
  height: var(--h);
  border-radius: 4px;
  background: var(--oj-navy);
  animation: oj-a5 5s ease-in-out infinite;
}

/* v2 — "several tasks in one message": a chat bubble + three filling rows. */
.oj-scene--v2 {
  width: 380px;
  flex-direction: column;
  align-items: stretch;
  gap: 18px;
}

.oj-scene-v2__bubble {
  align-self: flex-end;
  display: flex;
  flex-direction: column;
  gap: 7px;
  padding: 14px 18px;
  border-radius: 20px 20px 6px 20px;
  background: var(--oj-navy);
}

.oj-scene-v2__bubbleLine {
  display: block;
  height: 7px;
  border-radius: 4px;
  background: rgba(255, 255, 255, 0.75);
}

.oj-scene-v2__bubbleLine--w1 {
  width: 150px;
}

.oj-scene-v2__bubbleLine--w2 {
  width: 120px;
}

.oj-scene-v2__bubbleLine--w3 {
  width: 136px;
}

.oj-scene-v2__row {
  display: grid;
  grid-template-columns: 84px 1fr;
  align-items: center;
  gap: 12px;
}

.oj-scene-v2__label {
  font-size: 14px;
  font-weight: 700;
  color: var(--oj-navy);
}

.oj-scene-v2__track {
  display: block;
  height: 10px;
  border-radius: 5px;
  background: var(--oj-cell);
  overflow: hidden;
}

.oj-scene-v2__fill {
  display: block;
  height: 10px;
  border-radius: 5px;
  background: var(--oj-cyan);
  transform-origin: left center;
  animation: oj-fillx var(--oj-scene-duration, 3.2s) ease-out infinite;
}

/* v3 — "add to a task on the fly": a task card gaining a new line. */
.oj-scene--v3 {
  width: 380px;
  flex-direction: column;
  align-items: stretch;
  gap: 20px;
}

.oj-scene-v3__card {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 16px 18px;
  border-radius: 18px;
  background: var(--oj-surface);
}

.oj-scene-v3__cardLine {
  display: block;
  width: 190px;
  height: 8px;
  border-radius: 4px;
  background: var(--oj-border-2);
}

.oj-scene-v3__cardTrack {
  display: block;
  height: 10px;
  border-radius: 5px;
  background: var(--oj-cell);
  overflow: hidden;
}

.oj-scene-v3__cardFill {
  display: block;
  height: 10px;
  border-radius: 5px;
  background: var(--oj-cyan);
  transform-origin: left center;
  animation: oj-fillx 6s linear infinite;
}

.oj-scene-v3__bubble {
  align-self: flex-end;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 18px 12px 12px;
  border-radius: 20px 20px 6px 20px;
  background: var(--oj-navy);
  animation: oj-pop2 6s ease-out infinite;
}

.oj-scene-v3__plus {
  width: 26px;
  height: 26px;
  border-radius: 7.5px;
  background: var(--oj-amber);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--oj-font-display);
  font-weight: 700;
  font-size: 18px;
  line-height: 1;
  color: var(--oj-ink);
}

.oj-scene-v3__bubbleLine {
  display: block;
  width: 130px;
  height: 7px;
  border-radius: 4px;
  background: rgba(255, 255, 255, 0.75);
}

/* v4 — "the result is a ready file": PDF/XLSX cards + an arrow. */
.oj-scene--v4 {
  align-items: flex-end;
  gap: 16px;
}

.oj-scene-v4__doc {
  box-sizing: border-box;
  width: 150px;
  padding: 18px;
  border-radius: 20px;
  background: var(--oj-surface);
  display: flex;
  flex-direction: column;
  gap: 10px;
  animation: oj-in 0.5s ease-out backwards;
}

.oj-scene-v4__badge {
  align-self: flex-start;
  padding: 4px 9px;
  border-radius: 7px;
  font-size: 13px;
  font-weight: 700;
  color: var(--oj-surface);
}

.oj-scene-v4__badge--pdf {
  background: var(--oj-blue);
}

.oj-scene-v4__badge--xlsx {
  background: var(--oj-navy);
}

.oj-scene-v4__line {
  display: block;
  height: 7px;
  border-radius: 4px;
  background: var(--oj-border-2);
}

.oj-scene-v4__arrow {
  width: 52px;
  height: 52px;
  border-radius: 15px;
  background: var(--oj-cyan);
  display: flex;
  align-items: center;
  justify-content: center;
  animation: oj-in 0.5s ease-out backwards;
}

/* v5 — "crunches big data itself": a table settling into a total. */
.oj-scene--v5 {
  box-sizing: border-box;
  width: 380px;
  padding: 18px 24px 20px;
  flex-direction: column;
  align-items: stretch;
}

.oj-scene-v5__row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 34px;
  border-bottom: 1px solid var(--oj-surface-3);
  animation: oj-in 0.35s ease-out backwards;
}

.oj-scene-v5__cell {
  display: block;
  height: 8px;
  border-radius: 4px;
}

.oj-scene-v5__cell--label {
  background: var(--oj-border-2);
}

.oj-scene-v5__cell--value {
  background: var(--oj-slate-200);
}

.oj-scene-v5__sum {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: 14px;
  animation: oj-in 0.45s ease-out backwards;
}

.oj-scene-v5__sigma {
  font-family: var(--oj-font-display);
  font-weight: 700;
  font-size: 30px;
  line-height: 1;
  color: var(--oj-navy);
}

.oj-scene-v5__sumBar {
  display: block;
  width: 120px;
  height: 16px;
  border-radius: 8px;
  background: var(--oj-cyan);
  transform-origin: right center;
  animation: oj-sum 1.1s cubic-bezier(0.3, 1.3, 0.5, 1) 1s backwards;
}

/* v6 — "one service instead of many agents": icons absorbed into the
   diamond. */
.oj-scene--v6 {
  position: relative;
  width: 480px;
  height: 300px;
}

.oj-scene-v6__icon {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 60px;
  height: 60px;
  margin: -30px 0 0 -30px;
  box-sizing: border-box;
  border-radius: 17px;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  transform: translate(var(--x), var(--y));
  animation: oj-absorb 6.3s ease-in-out infinite backwards;
  animation-delay: var(--oj-scene-delay, 0s);
}

.oj-scene-v6__icon--bars {
  background: var(--oj-navy);
}

.oj-scene-v6__icon--lines,
.oj-scene-v6__icon--list {
  background: var(--oj-surface);
}

.oj-scene-v6__icon--grid3 {
  background: var(--oj-cyan);
}

.oj-scene-v6__icon--ring {
  background: var(--oj-blue);
}

.oj-scene-v6__icon--grid2 {
  background: var(--oj-cyan);
}

.oj-scene-v6__bars {
  display: flex;
  align-items: flex-end;
  gap: 4px;
  height: 30px;
}

.oj-scene-v6__bars span {
  display: block;
  width: 5px;
  border-radius: 3px;
  background: var(--oj-surface);
}

.oj-scene-v6__bars span:nth-child(1) {
  height: 12px;
}

.oj-scene-v6__bars span:nth-child(2) {
  height: 22px;
}

.oj-scene-v6__bars span:nth-child(3) {
  height: 30px;
}

.oj-scene-v6__bars span:nth-child(4) {
  height: 18px;
}

.oj-scene-v6__lines {
  width: 34px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.oj-scene-v6__lines span {
  display: block;
  height: 5px;
  border-radius: 3px;
  background: var(--oj-slate-200);
}

.oj-scene-v6__icon--lines .oj-scene-v6__lines span:first-child {
  width: 70%;
  background: var(--oj-navy);
}

.oj-scene-v6__icon--list .oj-scene-v6__lines span {
  height: 6px;
  background: var(--oj-cell);
  position: relative;
  overflow: hidden;
}

.oj-scene-v6__grid {
  display: grid;
  gap: 5px;
}

.oj-scene-v6__grid--3 {
  grid-template-columns: repeat(3, 8px);
}

.oj-scene-v6__grid--3 span {
  display: block;
  width: 8px;
  height: 8px;
  border-radius: 3px;
  background: var(--oj-surface);
}

.oj-scene-v6__grid--2 {
  grid-template-columns: repeat(2, 15px);
}

.oj-scene-v6__grid--2 span {
  display: block;
  width: 15px;
  height: 11px;
  border-radius: 3px;
  background: var(--oj-surface);
}

.oj-scene-v6__ring {
  display: block;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: conic-gradient(var(--oj-surface) 0 68%, rgba(255, 255, 255, 0.35) 68% 100%);
}

.oj-scene-v6__diamond {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 124px;
  height: 124px;
  margin: -62px 0 0 -62px;
  border-radius: 28px;
  background: var(--oj-amber);
  transform: rotate(45deg);
  box-shadow: 0 24px 40px -28px rgba(28, 44, 90, 0.55);
  z-index: 2;
  animation: oj-gulp 0.7s ease-in-out infinite;
}


/* src/components/home/HomeChannels.css */
/* B2C-Biz/Biz1024/BizMobile "Каналы": a full-bleed white band
   (HomeSecurity.css's shape — the security block right after it is white
   too, and takes only a short top padding of its own) with a capped inner
   column. The heading always breaks after "работы с ИИ," and wraps only
   between its four phrases, never inside one: two lines where they fit
   (the 1440 and 1024 artboards), the phone artboard's four on a phone. */
.oj-channels {
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
  background: var(--oj-surface);
  box-sizing: border-box;
  padding: 120px 0;
}

.oj-channels__inner {
  box-sizing: content-box;
  max-width: 1320px;
  margin: 0 auto;
  padding: 0 60px;
  display: flex;
  flex-direction: column;
  gap: 56px;
}

.oj-channels__heading {
  margin: 0;
  max-width: 980px;
  font-family: var(--oj-font-display);
  font-weight: 600;
  font-size: 64px;
  line-height: 1.02;
  letter-spacing: -0.045em;
  color: var(--oj-navy);
}

.oj-channels__headingLine {
  display: block;
}

.oj-channels__headingPart {
  white-space: nowrap;
}

.oj-channels__list {
  margin: 0;
  padding: 0;
  list-style: none;
  border-bottom: 1px solid var(--oj-border);
}

.oj-channels__row {
  display: flex;
  align-items: flex-start;
  gap: 18px;
  padding: 26px 0;
  border-top: 1px solid var(--oj-border);
}

.oj-channels__tile {
  flex: none;
  width: 36px;
  height: 36px;
  display: flex;
  align-items: center;
  color: var(--oj-blue);
}

.oj-channels__icon {
  display: block;
  width: 30px;
  height: 30px;
}

.oj-channels__body {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.oj-channels__head {
  min-height: 36px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
}

.oj-channels__title {
  margin: 0;
  font-family: var(--oj-font-display);
  font-weight: 700;
  font-size: 22px;
  line-height: 1.15;
  letter-spacing: -0.02em;
  color: var(--oj-navy);
}

.oj-channels__tag {
  flex: none;
  height: 30px;
  padding: 0 12px;
  display: inline-flex;
  align-items: center;
  border-radius: 999px;
  background: var(--oj-bg);
  font-size: 14px;
  font-weight: 700;
  color: var(--oj-blue);
  white-space: nowrap;
}

/* One wrapping line of names on a wide screen: the two groups dissolve into
   it, a 6px cyan square before every name but the first. */
.oj-channels__systems {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 14px;
}

.oj-channels__systemGroup {
  display: contents;
  margin: 0;
  padding: 0;
  list-style: none;
}

.oj-channels__system {
  display: inline-flex;
  align-items: center;
  gap: 14px;
  font-family: var(--oj-font-display);
  font-weight: 700;
  font-size: 18px;
  letter-spacing: -0.02em;
  color: var(--oj-navy);
  white-space: nowrap;
}

.oj-channels__system::before {
  content: "";
  flex: none;
  width: 6px;
  height: 6px;
  border-radius: 1.5px;
  background: var(--oj-cyan);
}

.oj-channels__systemGroup:first-child .oj-channels__system:first-child::before {
  display: none;
}

.oj-channels__note {
  margin: -24px 0 0;
  display: flex;
  align-items: baseline;
  gap: 14px;
  font-family: var(--oj-font-display);
  font-weight: 700;
  font-size: 22px;
  line-height: 1.3;
  letter-spacing: -0.02em;
  color: var(--oj-navy);
}

.oj-channels__rhombus {
  flex: none;
  width: 10px;
  height: 10px;
  border-radius: 2.4px;
  background: var(--oj-amber);
  transform: rotate(45deg) translateY(-2px);
}

@media (max-width: 1279px) {
  .oj-channels {
    padding: 96px 0;
  }

  .oj-channels__inner {
    gap: 48px;
  }

  .oj-channels__heading {
    max-width: 860px;
  }

  .oj-channels__note {
    margin-top: -16px;
  }
}

@media (max-width: 1023px) {
  .oj-channels__inner {
    padding: 0 40px;
  }
}

@media (max-width: 767px) {
  .oj-channels {
    padding: 72px 0;
  }

  .oj-channels__inner {
    padding: 0 20px;
    gap: 32px;
  }

  .oj-channels__heading {
    font-size: 34px;
    line-height: 1.04;
    letter-spacing: -0.04em;
  }

  .oj-channels__row {
    gap: 14px;
    padding: 20px 0;
  }

  .oj-channels__tile {
    width: 28px;
    height: 28px;
  }

  .oj-channels__icon {
    width: 26px;
    height: 26px;
  }

  .oj-channels__body {
    gap: 12px;
    padding-top: 2px;
  }

  .oj-channels__head {
    min-height: 0;
    align-items: flex-start;
    gap: 12px;
  }

  .oj-channels__title {
    font-size: 20px;
    line-height: 1.2;
  }

  .oj-channels__tag {
    margin-top: 3px;
    height: 26px;
    padding: 0 10px;
    font-size: 13px;
  }

  /* a line per group: the names keep the artboard's three-and-three */
  .oj-channels__systems {
    flex-direction: column;
    align-items: flex-start;
    gap: 8px;
  }

  /* a group of three may still break on the narrowest phones (320) */
  .oj-channels__systemGroup {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 10px;
  }

  .oj-channels__system {
    gap: 10px;
    font-size: 16px;
  }

  .oj-channels__systemGroup .oj-channels__system:first-child::before {
    display: none;
  }

  .oj-channels__note {
    margin-top: -8px;
    gap: 12px;
    font-size: 20px;
  }
}


/* src/components/home/HomeDifferent.css */
/* Layout spec §4/§3: full-bleed background (same shade as the page here, but
   the shape matches ../DemoBlock/DemoBlock.css and HomeSecurity.css right
   after it, whose white does need to reach the edges) + a capped inner
   column. Padding is the mockup's own literal value at each width
   (`Home2.dc.html` 120/60/120, `Home1024.dc.html` 96/60, `HomeMobile.dc.html`
   72/20) — not the general "96/120" the layout spec's prose gives for this
   block, which the pixels don't match (spec §1: the artboard wins). */
.oj-different {
  --oj-different-pad: 60px;
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
  background: var(--oj-bg);
  box-sizing: border-box;
  padding: 120px 0;
}

.oj-different__lines,
.oj-different__heading,
.oj-different__card {
  box-sizing: content-box;
  max-width: 1320px;
  margin-left: auto;
  margin-right: auto;
  padding-left: 60px;
  padding-right: 60px;
}

.oj-different__lines {
  display: flex;
  flex-direction: column;
}

.oj-different__line {
  margin: 0;
  font-family: var(--oj-font-display);
  font-weight: 600;
  font-size: 56px;
  line-height: 1.1;
  letter-spacing: -0.045em;
  color: var(--oj-slate-500);
}

.oj-different__heading {
  /* vertical only: the side margins are the shared `auto` above, which a bare
     `margin: 0` here used to cancel — the heading then sat at the viewport's
     left edge above 1440 while the lines and the card stayed centred */
  margin-top: 0;
  margin-bottom: 0;
  font-family: var(--oj-font-display);
  font-weight: 600;
  font-size: 56px;
  line-height: 1.1;
  letter-spacing: -0.045em;
  color: var(--oj-navy);
}

.oj-different__underline {
  color: inherit;
  white-space: nowrap;
  text-decoration: underline;
  text-decoration-color: var(--oj-cyan);
  text-decoration-thickness: 4px;
  text-underline-offset: 10px;
}

.oj-different__underline:hover {
  text-decoration-color: var(--oj-navy);
}

.oj-different__card {
  margin-top: 56px;
  box-sizing: border-box;
  /* the card's own padding (below) replaces the column's side padding, so its
     width is the column's, spelled out: the viewport less the page's side
     padding, capped at 1320 — otherwise below 1320 it ran edge to edge */
  width: min(1320px, calc(100% - 2 * var(--oj-different-pad)));
  padding: 32px 32px 32px 44px;
  border-radius: 28px;
  background: var(--oj-surface);
  border: 1px solid var(--oj-border-3);
  box-shadow: 0 40px 80px -48px rgba(28, 44, 90, 0.45);
  text-decoration: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 40px;
  transition: box-shadow 150ms;
}

.oj-different__card:hover {
  box-shadow: 0 44px 90px -40px rgba(28, 44, 90, 0.55);
}

.oj-different__cardText {
  font-family: var(--oj-font-display);
  font-weight: 700;
  font-size: 30px;
  line-height: 1.25;
  letter-spacing: -0.03em;
  color: var(--oj-navy);
}

.oj-different__cardCta {
  flex: none;
  height: 60px;
  padding: 0 30px;
  border-radius: 16px;
}

@media (max-width: 1279px) {
  .oj-different {
    padding: 96px 0;
  }

  .oj-different__lines,
  .oj-different__heading,
  .oj-different__card {
    padding-left: 60px;
    padding-right: 60px;
  }

  .oj-different__line,
  .oj-different__heading {
    font-size: 44px;
    line-height: 1.08;
    letter-spacing: -0.04em;
  }

  .oj-different__underline {
    text-decoration-thickness: 3px;
    text-underline-offset: 8px;
  }

  .oj-different__card {
    margin-top: 48px;
    padding: 28px 28px 28px 36px;
  }

  .oj-different__cardText {
    font-size: 26px;
  }
}

@media (max-width: 1023px) {
  .oj-different {
    --oj-different-pad: 40px;
  }
  .oj-different__lines,
  .oj-different__heading {
    padding-left: 40px;
    padding-right: 40px;
  }
}

@media (max-width: 767px) {
  .oj-different {
    --oj-different-pad: 20px;
    padding: 72px 0;
  }

  .oj-different__lines,
  .oj-different__heading,
  .oj-different__card {
    padding-left: 20px;
    padding-right: 20px;
  }

  .oj-different__line,
  .oj-different__heading {
    letter-spacing: -0.04em;
  }

  /* `HomeMobile.dc.html`: the grey lines and the heading are *not* quite the
     same size here, unlike 1440/1024 — the layout spec's own "26–28" range
     for this breakpoint is both values, not an approximation. */
  .oj-different__line {
    font-size: 26px;
    line-height: 1.18;
  }

  .oj-different__heading {
    font-size: 28px;
    line-height: 1.06;
  }

  .oj-different__underline {
    text-decoration-thickness: 3px;
    text-underline-offset: 6px;
  }

  .oj-different__card {
    margin-top: 32px;
    padding: 24px 20px 20px;
    flex-direction: column;
    align-items: stretch;
    gap: 20px;
  }

  .oj-different__cardText {
    font-size: 22px;
  }

  .oj-different__cardCta {
    width: 100%;
    height: 56px;
  }
}

/* Below 360 "ещё один ИИ-инструмент" is wider than the line, and kept whole
   it pushed the page sideways (no horizontal scroll from 320, layout spec
   §4); there it may break, its underline running on to the second line. */
@media (max-width: 359px) {
  .oj-different__underline {
    white-space: normal;
  }
}


/* src/components/home/HomeHero.css */
/* Layout spec §4/§6, `Home2.dc.html`/`Home1024.dc.html`/`HomeMobile.dc.html`.
   `.oj-hero` is its own container (content-box + max-width, see
   ../../styles/base.css's comment on why sections own this shape now that
   `<main>` carries no padding) — position: relative so the desktop tile
   ladder can sit at the same inset as the section's own padding. */
.oj-hero {
  position: relative;
  box-sizing: content-box;
  /* An explicit width, not `auto`: `.oj-hero` is a flex item of `main`
     (column direction) with `margin: 0 auto` for centering past 1320 —
     but per the flexbox spec, an item with an auto cross-axis margin never
     stretches to the container's size, `width: auto` falls back to
     shrink-to-fit instead, and shrink-to-fit's min-content floor is set by
     non-wrapping content deep inside (the tile ladder's mobile row, the
     example-chip strip, item 3) regardless of their own `overflow`. Giving
     `width` a definite value here (available space minus this rule's own
     side padding, capped by `max-width`) sidesteps shrink-to-fit entirely,
     so those strips stay inside their own `overflow-x: auto`/`hidden`
     instead of widening the whole page. Kept in sync with the padding
     this rule and its breakpoints declare below. */
  width: calc(100% - 120px);
  max-width: 1320px;
  margin: 0 auto;
  padding: 72px 60px 112px;
  display: flex;
  flex-direction: column;
}

/* B2C-Biz: above the tagline, in the top padding's band on desktop and
   tablet; in the flow, above the tile row, on a phone */
.oj-hero__badge {
  position: absolute;
  top: 20px;
  left: 60px;
  z-index: 2;
  margin: 0;
  box-sizing: border-box;
  height: 40px;
  padding: 0 16px 0 12px;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  border-radius: 999px;
  background: var(--oj-surface);
  font-family: var(--oj-font-display);
  font-weight: 700;
  font-size: 15px;
  letter-spacing: -0.01em;
  color: var(--oj-navy);
  white-space: nowrap;
}

.oj-hero__badgeIcon {
  display: block;
  flex: none;
  width: 18px;
  height: 18px;
}

.oj-hero__tagline {
  position: relative;
  margin: 0;
  max-width: 780px;
  font-family: var(--oj-font-display);
  font-weight: 600;
  font-size: 96px;
  line-height: 0.98;
  letter-spacing: -0.05em;
  color: var(--oj-navy);
}

.oj-hero__tagline-brand {
  font-size: 96px;
}

.oj-hero__taglineLine {
  display: block;
}

/* The real H1 (SEO spec 2.1, DECISIONS.md #6): same spot and size as the
   mockup's own lede paragraph — a heading tag, not a heading-sized font. */
.oj-hero__h1 {
  position: relative;
  margin: 44px 0 0;
  max-width: 540px;
  font-family: var(--oj-font-body);
  font-weight: 400;
  font-size: 24px;
  line-height: 1.45;
  color: var(--oj-text);
}

.oj-hero__ctaRow {
  position: relative;
  margin-top: 36px;
}

.oj-hero__cta {
  height: var(--oj-btn-h-lg);
  padding: 0 36px;
  border-radius: var(--oj-r-lg);
}

.oj-hero__demo {
  position: relative;
  margin-top: 96px;
  display: flex;
  flex-direction: column;
  gap: 24px;
}

.oj-hero__examples {
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.oj-hero__examplesTitle {
  margin: 0;
  font-family: var(--oj-font-display);
  font-weight: 600;
  font-size: 44px;
  line-height: 1.05;
  letter-spacing: -0.04em;
  color: var(--oj-navy);
}

/* Three equal columns as flex, not grid: WebKit (Safari) does not recompute
   a grid row's height when the window is resized, so a chip kept its old
   height and its text spilled out; flex tracks the width both ways. */
.oj-hero__chips {
  display: flex;
  align-items: stretch;
  gap: 12px;
}

/* Layout spec §5: a chip's own state carries no goal-worthy animation, so
   `data-goal`/`data-goal-scenario` (contract 6, ../../../AGENTS.md) sit
   right on the button — the delegated listener in
   ../../client/analytics.ts fires `hero_example_click` on a real click only,
   never on the automatic scenario loop (task brief, metrika spec §6 item 8). */
.oj-hero-chip {
  box-sizing: border-box;
  flex: 1 1 0;
  min-width: 0;
  min-height: 72px;
  padding: 16px 20px;
  border-radius: 18px;
  text-align: left;
  font-family: var(--oj-font-body);
  font-size: 17px;
  line-height: 1.35;
  display: flex;
  align-items: flex-start;
  gap: 12px;
  cursor: pointer;
  border: 2px solid var(--oj-border);
  background: var(--oj-surface);
  color: var(--oj-text-2);
  font-weight: 600;
}

.oj-hero-chip__icon {
  flex: none;
  margin-top: 4px;
  color: var(--oj-slate-300);
}

/* No bold on the active chip (the owner's call over the mockup): the chat
   loop moves the active chip on its own every few seconds, and a bolder,
   wider label rewrapped the row and made everything below it jump. */
.oj-hero-chip[aria-pressed="true"] {
  border-color: var(--oj-cyan);
  background: var(--oj-cyan-tint);
  color: var(--oj-navy);
}

.oj-hero-chip[aria-pressed="true"] .oj-hero-chip__icon {
  color: var(--oj-cyan);
}

/* ---- the decorative tile ladder (HomeHeroTiles.tsx), aria-hidden ---- */

.oj-hero-tiles--desktop,
.oj-hero-tiles--tablet {
  position: absolute;
  /* above the text blocks, whose full-width boxes would otherwise swallow
     a click on a tile (the Easter egg); the set's own empty area lets
     clicks through, only the tiles take them */
  z-index: 1;
  pointer-events: none;
  right: var(--oj-page-pad-desktop);
  top: 72px;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 16px;
}

.oj-hero-tiles--tablet,
.oj-hero-tiles--mobile {
  display: none;
}

/* `client/heroTiles.ts` drops a row's leftmost tiles that would come within
   40px of the text (layout spec §4). */
.oj-hero-tile.is-off {
  display: none;
}

.oj-hero-tiles__row {
  display: flex;
  justify-content: flex-end;
  gap: 16px;
  /* a row whose every tile is off keeps its height, so the rows below stay
     in the bands `client/heroTiles.ts` measured them in */
  min-height: 104px;
}

.oj-hero-tile {
  width: 104px;
  height: 104px;
  border-radius: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 5px;
  flex: none;
  overflow: hidden;
  background: var(--oj-surface-2);
}

.oj-hero-tile--cyan {
  background: var(--oj-cyan);
}

.oj-hero-tile--navy {
  background: var(--oj-navy);
}

.oj-hero-tile--blue {
  background: var(--oj-blue);
}

/* The rhombus (owner's call, as on `HomeMobile.dc.html`, over the spec's
   "no diamonds"): the tile itself turned 45° and shrunk to 74% of its cell,
   radius 22% — the phone artboard's 46px in 62. `--oj-turn` counts 45° steps;
   the Easter egg (`client/heroTiles.ts`) adds one per change, so a square
   always turns into a rhombus and back the same way round. The rhombus's
   own square colour is its tone class (navy for the one it starts with).
   The colour switches fast, so the turn never shows a muddy in-between. */
.oj-hero-tile {
  --oj-turn: 0;
  transform: rotate(calc(var(--oj-turn) * 45deg));
  transition:
    transform 520ms cubic-bezier(0.22, 1, 0.36, 1),
    background-color 220ms ease,
    border-radius 520ms ease;
  /* no hand cursor: an Easter egg is not announced (owner's call, the one
     exception to "everything clickable shows a hand") */
  cursor: default;
  pointer-events: auto;
  -webkit-user-select: none;
  user-select: none;
}

.oj-hero-tile.is-rhombus {
  --oj-turn: 1;
  transform: rotate(calc(var(--oj-turn) * 45deg)) scale(0.74);
  border-radius: 22%;
  background: var(--oj-amber);
}

.oj-hero-tile > * {
  transition: opacity 260ms ease;
}

.oj-hero-tile.is-rhombus > * {
  opacity: 0;
}

.oj-hero-tile--white {
  background: var(--oj-surface);
}

.oj-hero-tile__lines {
  width: 62px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.oj-hero-tile__line {
  display: block;
  width: 92%;
  height: 7px;
  border-radius: 4px;
  background: var(--oj-slate-200);
}

.oj-hero-tile__line--dark {
  width: 70%;
  background: var(--oj-navy);
}

.oj-hero-tile__line--short {
  width: 80%;
}

.oj-hero-tile__bar {
  display: block;
  width: 5px;
  height: var(--oj-bar-h);
  border-radius: 999px;
  background: #fff;
}

/* Below 1280 the tablet artboard's own set (2/1/3/4) replaces the desktop
   one. Without JS nothing measures the text, so each set holds a fixed
   approximation of the 40px rule for its range; `client/heroTiles.ts`
   marks the set `is-measured` and these give way to the exact count. */
@media (max-width: 1279px) {
  .oj-hero {
    padding-bottom: 96px;
  }

  .oj-hero-tiles--desktop {
    display: none;
  }

  .oj-hero-tiles--tablet {
    display: flex;
  }
}

@media (min-width: 1280px) and (max-width: 1439px) {
  .oj-hero-tiles--desktop:not(.is-measured)
    .oj-hero-tiles__row:nth-child(1)
    .oj-hero-tile:nth-child(1),
  .oj-hero-tiles--desktop:not(.is-measured)
    .oj-hero-tiles__row:nth-child(2)
    .oj-hero-tile:nth-child(1),
  .oj-hero-tiles--desktop:not(.is-measured)
    .oj-hero-tiles__row:nth-child(3)
    .oj-hero-tile:nth-child(1) {
    display: none;
  }
}

/* 1024-1279: "Команда говорит." reaches the top row's first tile */
@media (min-width: 1024px) and (max-width: 1279px) {
  .oj-hero-tiles--tablet:not(.is-measured)
    .oj-hero-tiles__row:nth-child(1)
    .oj-hero-tile:nth-child(1) {
    display: none;
  }
}

/* 768-1023: the fewest tiles the measured ladder keeps anywhere in the range */
@media (max-width: 1023px) {
  .oj-hero-tiles--tablet:not(.is-measured) .oj-hero-tiles__row:nth-child(-n + 3) .oj-hero-tile,
  .oj-hero-tiles--tablet:not(.is-measured)
    .oj-hero-tiles__row:nth-child(4)
    .oj-hero-tile:nth-child(-n + 3) {
    display: none;
  }
}

@media (max-width: 1023px) {
  .oj-hero {
    padding-left: 40px;
    padding-right: 40px;
    width: calc(100% - 80px);
  }

  .oj-hero__badge {
    left: 40px;
  }

  /* Below the 1024 artboard three columns only squeeze the chips into five-
     and six-line boxes; they become the mobile scheme's swipeable strip
     instead, a chip's width following the viewport smoothly (no step at
     any breakpoint), every chip the same height. */
  .oj-hero__chips {
    display: flex;
    align-items: stretch;
    gap: 8px;
    margin: 0 -40px;
    padding: 2px 40px;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scroll-padding-left: 40px;
  }

  .oj-hero-chip {
    width: auto;
    flex: 0 0 clamp(260px, 34vw, 300px);
    min-height: 44px;
    padding: 10px 16px;
    font-size: 16px;
    scroll-snap-align: start;
  }
}

@media (max-width: 767px) {
  .oj-hero {
    padding: 24px 20px 56px;
    width: calc(100% - 40px);
  }

  .oj-hero-tiles--tablet {
    display: none;
  }

  .oj-hero__badge {
    position: static;
    align-self: flex-start;
    margin-bottom: 16px;
    height: 36px;
    padding: 0 14px 0 11px;
    font-size: 14px;
  }

  .oj-hero__badgeIcon {
    width: 16px;
    height: 16px;
  }

  /* B2C-BizMobile: the rows stay inside the page's 20px margins and show
     only whole tiles, as many as fit — five at 390 (5 x 62 + 4 x 10 = 350,
     the content width), four at 320, ten at 767 (owner's reports, 22.10:
     the row used to run to the screen's edge and cut its last tile, then
     left an empty stretch on the right of a wider phone). */
  .oj-hero-tiles--mobile {
    position: relative;
    margin: 0 0 28px;
    display: flex;
    flex-direction: column;
    gap: 10px;
    overflow: hidden;
  }

  /* A tile that does not fit whole wraps to a second line, which the row
     clips: one tile's height, plus 13px above and below (taken back by the
     margin) so a tile turning for the Easter egg — 88px on the diagonal —
     is never cut. */
  .oj-hero-tiles--mobile .oj-hero-tiles__row {
    justify-content: flex-start;
    flex-wrap: wrap;
    gap: 40px 10px;
    box-sizing: content-box;
    height: 62px;
    min-height: 0;
    margin: -13px 0;
    padding: 13px 0;
    overflow: hidden;
  }

  .oj-hero-tiles--mobile .oj-hero-tile {
    width: 62px;
    height: 62px;
    border-radius: 18px;
    gap: 3px;
  }

  .oj-hero-tiles--mobile .oj-hero-tile.is-rhombus {
    border-radius: 22%;
  }

  .oj-hero-tiles--mobile .oj-hero-tile__lines {
    width: 38px;
    gap: 5px;
  }

  .oj-hero-tiles--mobile .oj-hero-tile__line {
    height: 5px;
  }

  .oj-hero-tiles--mobile .oj-hero-tile__bar {
    width: 3px;
    height: calc(var(--oj-bar-h) * 0.58);
  }

  /* B2C-BizMobile: 41px keeps "Команда говорит." on one line at 390 */
  .oj-hero__tagline,
  .oj-hero__tagline-brand {
    font-size: 41px;
  }

  .oj-hero__tagline {
    line-height: 1;
    letter-spacing: -0.045em;
  }

  .oj-hero__h1 {
    margin-top: 20px;
    max-width: none;
    font-size: 19px;
  }

  .oj-hero__ctaRow {
    margin-top: 24px;
  }

  .oj-hero__cta {
    width: 100%;
    height: 56px;
  }

  .oj-hero__demo {
    margin-top: 48px;
    gap: 14px;
  }

  .oj-hero__examplesTitle {
    font-size: 30px;
  }

  .oj-hero__chips {
    margin: 0 -20px;
    padding: 2px 20px;
    scroll-padding-left: 20px;
  }

  .oj-hero-chip {
    flex-basis: min(270px, 72vw);
  }
}

/* ---- the chat window (HomeHeroChat.tsx) ---- */

/* `overflow-anchor: none`: Chrome's scroll anchoring would otherwise pick a
   bubble as the page's anchor while the card sits at the top of the screen,
   and every time the conversation moves the bubble inside the clipped log,
   scroll the whole page after it — on a phone the page crept away by itself
   every few seconds (owner's report, 2026-09-29). The card never changes its
   own height, so nothing needs anchoring inside it. */
.oj-hero-chat {
  overflow-anchor: none;
  width: 100%;
  box-sizing: border-box;
  border-radius: 28px;
  background: var(--oj-surface);
  border: 1px solid var(--oj-border-3);
  box-shadow: 0 40px 80px -48px rgba(28, 44, 90, 0.45);
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

.oj-hero-chat__header {
  box-sizing: border-box;
  height: 60px;
  padding: 0 24px;
  display: flex;
  align-items: center;
  gap: 10px;
  border-bottom: 1px solid var(--oj-surface-3);
}

.oj-hero-chat__brand {
  font-size: 17px;
}

/* `hidden` must win over every `display` a chat part sets for itself — the
   answers of the other scenarios and the idle thinking row sit in the DOM
   hidden, and a class's own `display` would otherwise put them back on
   screen, where they push the live exchange out of the fixed-height log. */
.oj-hero-chat [hidden] {
  display: none !important;
}

.oj-hero-chat__log {
  box-sizing: border-box;
  position: relative;
  height: 396px;
  padding: 20px 24px;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  overflow: hidden;
}

/* The FLIP target (`HomeHeroChat.tsx`'s comment, `client/heroChat.ts`): its
   own height is intrinsic (the bubbles stack top-down inside it), `.oj-hero-
   chat__log` above bottom-anchors *this one child* and clips whatever
   scrolls past its own top. `position: relative` gives the thinking row a
   containing block while it is frozen `position: absolute` mid cross-fade
   (`freezeThinking` in heroChat.ts) so it can hold its exact spot without
   counting toward this element's height. */
.oj-hero-chat__track {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 14px;
  will-change: transform;
}

.oj-hero-chat__bubble {
  font-size: 17px;
  line-height: 1.45;
}

/* A bubble's entrance (task brief "smooth entries"): starts faded and offset
   below its resting spot, then rises into place while `client/heroChat.ts`
   glides `.oj-hero-chat__track` by the same delta — both transitions share
   the one forced-reflow tick `flipTrack` (heroChat.ts) triggers, so they run
   in lockstep. `--active` must be a second class, not the same one changing
   value, or there is nothing to transition *from*. `prefers-reduced-motion`
   never reaches this: `wireReducedMotion` (heroChat.ts) swaps exchanges
   outright and never adds either class. */
.oj-hero-chat__bubble--enter {
  opacity: 0;
  transform: translateY(14px);
}

.oj-hero-chat__bubble--enter-active {
  transition:
    opacity 280ms ease-out,
    transform 280ms ease-out;
  opacity: 1;
  transform: translateY(0);
}

/* The thinking row's own exit (task brief "the thinking row fades while the
   answer fades/rises in"): only opacity — position/top/left/width are frozen
   inline by `freezeThinking` (heroChat.ts) at the same instant, taking it out
   of `.oj-hero-chat__track`'s flow so the row's height collapses into the
   very same glide the answer's entrance triggers, instead of a second, later
   jump. 300ms below is kept in sync with `THINKING_FADE_MS` in heroChat.ts. */
.oj-hero-chat__thinking--leaving {
  transition: opacity 300ms ease-in;
  opacity: 0;
}

.oj-hero-chat__bubble--user {
  align-self: flex-end;
  max-width: 620px;
  padding: 12px 16px;
  border-radius: 20px 20px 6px 20px;
  background: var(--oj-navy);
  color: #fff;
}

.oj-hero-chat__bubble--bot {
  align-self: flex-start;
  box-sizing: border-box;
  max-width: 720px;
  padding: 12px 16px;
  border-radius: 6px 20px 20px 20px;
  background: var(--oj-bg);
  display: flex;
  flex-direction: column;
  gap: 10px;
  line-height: 1.5;
  color: var(--oj-text);
}

.oj-hero-chat__list {
  margin: 0;
  padding: 0 0 0 22px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.oj-hero-chat__link {
  color: var(--oj-blue);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.oj-hero-chat__note {
  font-style: italic;
  color: var(--oj-text-2);
}

.oj-hero-chat__underline {
  text-decoration: underline;
  text-underline-offset: 3px;
}

.oj-hero-chat__quote {
  position: relative;
  padding: 6px 28px 6px 10px;
  border-radius: 6px;
  border-left: 3px solid var(--oj-blue);
  background: rgba(27, 107, 147, 0.1);
}

.oj-hero-chat__thinking {
  align-self: flex-start;
  padding: 12px 16px;
  border-radius: 6px 20px 20px 20px;
  background: var(--oj-bg);
  font-size: 17px;
  color: var(--oj-text-2);
  display: flex;
  gap: 8px;
}

.oj-hero-chat__thinking span[data-js="hero-chat-counter"] {
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  color: var(--oj-blue);
}

/* `Home2.dc.html`'s own "thinking" pulse (layout spec §5's "первый экран"),
   copied verbatim — 1.2s ease-in-out, opacity 1 -> .35 and back. */
@keyframes oj-pulse {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0.35;
  }
}

.oj-hero-chat__thinkingLabel {
  animation: oj-pulse 1.2s ease-in-out infinite;
}

.oj-hero-chat__inputRow {
  box-sizing: border-box;
  padding: 14px 16px 16px;
  display: flex;
  align-items: center;
  gap: 8px;
}

.oj-hero-chat__input {
  box-sizing: border-box;
  flex-grow: 1;
  min-width: 0;
  height: 48px;
  padding: 0 18px;
  display: flex;
  align-items: center;
  border-radius: 16px;
  background: var(--oj-bg);
  font-size: 17px;
  color: var(--oj-text);
  white-space: nowrap;
  overflow: hidden;
}

.oj-hero-chat__placeholder {
  color: var(--oj-muted);
}

/* Shows the END of the typed line once it outgrows the field, not the start
   with "…" (owner's call, 2026-09-30). `is-clipped` is set by
   `client/heroChat.ts` only while the text overflows, so a short line keeps
   its first letters unfaded. The text sits flush right in a flex box, so
   what doesn't fit spills out of the LEFT edge; the direction stays
   left-to-right — `direction: rtl` would do the same but move a trailing «,
   comma or space to the start of the line while it is the last character
   typed. The fade on the left edge is a stylesheet rule (CSP, contract 10). */
.oj-hero-chat__typed {
  overflow: hidden;
}

.oj-hero-chat__typed.is-clipped {
  display: flex;
  justify-content: flex-end;
  white-space: nowrap;
  mask-image: linear-gradient(to right, transparent, #000 24px);
  -webkit-mask-image: linear-gradient(to right, transparent, #000 24px);
}

/* The typing caret (`Home2.dc.html`'s own `oj-caret`, copied verbatim) —
   `hidden` (not CSS opacity) outside the typing phase, per contract 5: the
   element simply isn't there rather than being invisibly animated. */
@keyframes oj-caret {
  0%,
  49% {
    opacity: 1;
  }
  50%,
  100% {
    opacity: 0;
  }
}

.oj-hero-chat__caret {
  display: inline-block;
  width: 2px;
  height: 18px;
  margin-left: 2px;
  border-radius: 1px;
  background: var(--oj-text);
  animation: oj-caret 1s steps(1) infinite;
  flex: none;
}

/* Off-screen the chat's loops stop (contract 5): `client/heroChat.ts` marks
   the root `data-running="false"` while it is out of the viewport. */
[data-js="hero-chat"][data-running="false"] .oj-hero-chat__caret,
[data-js="hero-chat"][data-running="false"] .oj-hero-chat__thinkingLabel {
  animation-play-state: paused;
}

.oj-hero-chat__iconBtn {
  width: 48px;
  height: 48px;
  border-radius: 16px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
}

.oj-hero-chat__iconBtn--send {
  background: var(--oj-cyan);
  color: var(--oj-ink);
}

.oj-hero-chat__iconBtn--voice {
  border: 1px solid var(--oj-border-3);
  background: var(--oj-surface);
  color: var(--oj-navy);
}

@media (max-width: 767px) {
  .oj-hero-chat__header {
    padding: 0 16px;
  }

  .oj-hero-chat__log {
    height: 500px;
    padding: 16px 14px;
  }

  .oj-hero-chat__bubble {
    font-size: 16px;
  }

  .oj-hero-chat__bubble--user {
    max-width: 90%;
  }

  .oj-hero-chat__bubble--bot {
    max-width: 94%;
  }

  .oj-hero-chat__input {
    font-size: 16px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .oj-hero-tile,
  .oj-hero-tile > * {
    transition: none;
  }
}


/* src/components/home/HomeHeroStats.css */
/* B2C-Biz/Biz1024/BizMobile "stats": a full-bleed band inside `.oj-hero`
   (which caps its own width), the figures in a capped inner column. The
   footnote takes `--oj-muted`, not the artboard's #6F727B: that grey on this
   band is ~4:1, under the 4.5:1 the Lighthouse accessibility target needs. */
.oj-hero-stats {
  position: relative;
  margin: 112px calc(50% - 50vw) 0;
  background: var(--oj-surface-2);
}

.oj-hero-stats__inner {
  box-sizing: content-box;
  max-width: 1320px;
  margin: 0 auto;
  padding: 96px 60px 88px;
  display: flex;
  flex-direction: column;
  gap: 56px;
}

.oj-hero-stats__list {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
}

.oj-hero-stats__item {
  flex: 1 1 0;
  min-width: 0;
  box-sizing: border-box;
  padding: 0 20px 0 40px;
  border-left: 1px solid #d6d3ca;
  display: flex;
  flex-direction: column;
}

.oj-hero-stats__item:first-child {
  padding-left: 0;
  border-left: 0;
}

.oj-hero-stats__label {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--oj-muted);
}

.oj-hero-stats__mark {
  flex: none;
  width: 10px;
  height: 10px;
  border-radius: 3px;
}

.oj-hero-stats__mark--cyan {
  background: var(--oj-cyan);
}

.oj-hero-stats__mark--navy {
  background: var(--oj-navy);
}

.oj-hero-stats__mark--amber {
  background: var(--oj-amber);
}

.oj-hero-stats__value {
  margin-top: 20px;
  font-family: var(--oj-font-display);
  font-weight: 600;
  font-size: 128px;
  line-height: 0.88;
  letter-spacing: -0.06em;
  color: var(--oj-navy);
  white-space: nowrap;
}

.oj-hero-stats__text {
  margin-top: 40px;
  font-family: var(--oj-font-display);
  font-weight: 700;
  font-size: 22px;
  line-height: 1.25;
  letter-spacing: -0.02em;
  color: var(--oj-navy);
}

.oj-hero-stats__note {
  margin: 0;
  font-size: 14px;
  line-height: 1.45;
  color: var(--oj-muted);
}

@media (max-width: 1279px) {
  .oj-hero-stats__inner {
    padding: 80px 60px 72px;
    gap: 44px;
  }

  .oj-hero-stats__item {
    padding: 0 14px 0 28px;
  }

  .oj-hero-stats__label {
    font-size: 12px;
  }

  .oj-hero-stats__mark {
    width: 9px;
    height: 9px;
  }

  .oj-hero-stats__value {
    margin-top: 16px;
    font-size: 88px;
  }

  .oj-hero-stats__text {
    margin-top: 32px;
    font-size: 19px;
  }

  .oj-hero-stats__note {
    font-size: 13px;
  }
}

@media (max-width: 1023px) {
  .oj-hero-stats__inner {
    padding-left: 40px;
    padding-right: 40px;
  }

  .oj-hero-stats__value {
    font-size: 72px;
  }
}

@media (max-width: 767px) {
  .oj-hero-stats {
    margin-top: 48px;
  }

  .oj-hero-stats__inner {
    padding: 56px 20px 48px;
    gap: 32px;
  }

  .oj-hero-stats__list {
    flex-direction: column;
    gap: 32px;
  }

  .oj-hero-stats__item,
  .oj-hero-stats__item:first-child {
    padding: 0;
    border-left: 0;
  }

  .oj-hero-stats__item + .oj-hero-stats__item {
    padding-top: 32px;
    border-top: 1px solid #d6d3ca;
  }

  .oj-hero-stats__mark {
    width: 10px;
    height: 10px;
  }

  .oj-hero-stats__value {
    margin-top: 14px;
    font-size: 88px;
    line-height: 0.9;
  }

  .oj-hero-stats__text {
    margin-top: 22px;
    font-size: 20px;
  }

  .oj-hero-stats__note {
    padding-top: 24px;
    border-top: 1px solid #d6d3ca;
  }
}


/* src/components/home/HomeRoles.css */
/* "What tasks you can hand over to OctoJinn" (layout spec §4/§5,
   `Home2.dc.html` / `Home1024.dc.html` / `HomeMobile.dc.html`). White
   full-bleed band, unlike `HomeAdvantages.css`'s page-background one — same
   full-bleed + inner `max-width: 1320px` shape as `../Header/Header.css`. */
.oj-roles {
  background: var(--oj-surface);
}

/* The cloud's floating background words (`HomeRolesCloud.tsx`'s
   `word.anim`, `homeRoles.json`) — keyframes copied verbatim from
   `Home2.dc.html`'s own `<style>`, one per `oj-f1`..`oj-f4` bucket. */
@keyframes oj-f1 {
  0%,
  100% {
    transform: translate(0, 0);
  }
  50% {
    transform: translate(7px, -9px);
  }
}

@keyframes oj-f2 {
  0%,
  100% {
    transform: translate(0, 0);
  }
  50% {
    transform: translate(-8px, 6px);
  }
}

@keyframes oj-f3 {
  0%,
  100% {
    transform: translate(0, 0);
  }
  50% {
    transform: translate(5px, 8px);
  }
}

@keyframes oj-f4 {
  0%,
  100% {
    transform: translate(0, 0);
  }
  50% {
    transform: translate(-6px, -7px);
  }
}

/* The running dashes along each role line (`RoleLines`' second path) — same
   source. */
@keyframes oj-run {
  from {
    stroke-dashoffset: 0;
  }
  to {
    stroke-dashoffset: -460;
  }
}

.oj-roles__inner {
  box-sizing: content-box;
  max-width: 1320px;
  margin: 0 auto;
  padding: 120px var(--oj-page-pad-desktop);
  display: flex;
  flex-direction: column;
  gap: 44px;
}

.oj-roles__inner h2 {
  margin: 0;
  max-width: 1000px;
  font-size: 64px;
  line-height: 1.02;
  letter-spacing: -0.045em;
}

/* The roles spread across the whole column (the owner's call: left-packed,
   the shorter English names bunched up): one row of eight while it fits, two
   even rows of four below 1280 — a wrapped flex row left a ragged second
   line. Mobile (below) is the swipeable strip. */
.oj-roles__tabs {
  display: grid;
  grid-template-columns: repeat(8, auto);
  justify-content: space-between;
  gap: 8px 24px;
}

.oj-roles__tab {
  position: relative;
  box-sizing: border-box;
  min-height: 48px;
  padding: 18px 0 0;
  border: 0;
  background: transparent;
  font-family: var(--oj-font-body);
  font-size: 19px;
  white-space: nowrap;
  font-weight: 600;
  color: var(--oj-navy);
}

.oj-roles__tab[aria-selected="true"] {
  font-weight: 700;
}

.oj-roles__marker {
  position: absolute;
  left: 50%;
  top: 2px;
  width: 9px;
  height: 9px;
  margin-left: -4.5px;
  border-radius: 2px;
  background: var(--oj-slate-200);
  transform: none;
  /* the picked role's marker turns into the amber rhombus: a quarter turn
     and a colour change, not a swap (off under reduced motion) */
  transition:
    transform 280ms cubic-bezier(0.22, 1, 0.36, 1),
    background-color 280ms ease;
}

@media (prefers-reduced-motion: reduce) {
  .oj-roles__marker {
    transition: none;
  }
}

.oj-roles__tab[aria-selected="true"] .oj-roles__marker {
  background: var(--oj-amber);
  transform: rotate(45deg);
}

.oj-roles__body {
  display: flex;
  align-items: flex-start;
}

.oj-roles__cloud {
  position: relative;
  width: 700px;
  height: 460px;
  flex: none;
}

.oj-roles__bgSvg,
.oj-roles__linesSvg {
  position: absolute;
  left: 0;
  top: 0;
  display: block;
  overflow: visible;
}

.oj-roles__bgSvg--400,
.oj-roles__linesSvg--400 {
  display: none;
}

/* The active role's lines fade in, the previous one fades out (opacity
   300ms, layout spec §5) — `opacity`, not `display`, so the crossfade can
   actually transition; both stay absolutely positioned, so this never
   affects the cloud's height. */
.oj-roles__linesSvg {
  opacity: 0;
  pointer-events: none;
  transition: opacity 300ms ease;
}

.oj-roles__linesSvg[data-active="true"] {
  opacity: 1;
}

/* Safety net (`client/roles.ts`'s `updateLinesFit`): a task long enough to
   wrap past the list's 68px row (`min-height` below lets it grow instead of
   overlapping the next one) leaves every line below it pointing at a row
   that has since moved — hide the active role's whole overlay rather than
   one stale line. Higher specificity than the rule above regardless of
   source order, so no `!important` needed. */
.oj-roles__cloud[data-lines-fit="false"] .oj-roles__linesSvg[data-active="true"] {
  opacity: 0;
}

/* Loops run only while the roles section is in the viewport
   (`client/roles.ts`, layout spec §5 rule 4). Paused only on the script's
   explicit `data-running="false"`: without JavaScript nothing sets it, and
   an animation frozen on its first keyframe would hide its element (§5
   rule 2 — content visible without JS; audit 2026-09-30). `!important`: every animated
   element carries its own `animation` in an inline `style` (React —
   duration/delay/easing come from data, `HomeRolesCloud.tsx`), and an
   inline declaration always outranks a selector rule regardless of
   specificity — same reason `tokens.css`'s reduced-motion override uses it. */
.oj-roles__cloud[data-running="false"] .oj-a {
  animation-play-state: paused !important;
}

/* The mockup only ever mounts the *active* role's overlay, so only its 6
   lines animate. Ours keeps all eight mounted (accessibility/no-JS), so the
   inactive ones need their own pause — otherwise every role's `oj-run`/
   `oj-draw`/`oj-in` would play at once the moment the cloud scrolls into
   view, not just the one actually on screen. */
.oj-roles__linesSvg[data-active="false"] .oj-a {
  animation-play-state: paused !important;
}

.oj-roles__panels {
  flex: 1 1 auto;
  min-width: 0;
}

.oj-roles__panel[hidden] {
  display: none;
}

.oj-roles__tasks {
  margin: 0;
  padding: 0;
  list-style: none;
}

.oj-roles__tasks li {
  box-sizing: border-box;
  /* Safety net: a row grows past this instead of clipping/overlapping the
     next one when its task wraps past two lines (`client/roles.ts` then
     hides the cloud's stale lines — see `.oj-roles__cloud[data-lines-fit]`
     above). Exact 68px still holds wherever the layout below keeps the
     two-column mode (1440, 1024 — spec §4 row height / line-centre math). */
  min-height: 68px;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 0 0 0 20px;
  border-top: 1px solid var(--oj-border);
}

.oj-roles__tasks li span:last-child {
  font-size: 20px;
  font-weight: 700;
  line-height: 1.3;
  color: var(--oj-text);
}

.oj-roles__taskBullet {
  display: none;
}

.oj-roles__more span {
  font-family: var(--oj-font-display);
  font-weight: 700;
  font-size: 24px;
  letter-spacing: -0.02em;
  color: var(--oj-navy);
}

@media (min-width: 1280px) {
  .oj-roles__body {
    gap: 0;
  }
}

@media (max-width: 1279px) {
  .oj-roles__tabs {
    grid-template-columns: repeat(4, auto);
  }

  .oj-roles__inner {
    padding: 96px var(--oj-page-pad-desktop);
    gap: 36px;
  }

  .oj-roles__inner h2 {
    font-size: 48px;
  }

  .oj-roles__cloud {
    width: 400px;
  }

  .oj-roles__bgSvg--700,
  .oj-roles__linesSvg--700 {
    display: none;
  }

  .oj-roles__bgSvg--400,
  .oj-roles__linesSvg--400 {
    display: block;
  }

  .oj-roles__linesSvg--400[data-active="false"] {
    display: none;
  }

  .oj-roles__body {
    gap: 24px;
  }
}

/* Below this, the two-column layout (cloud beside a ~296-320px list at
   768-1023, layout spec defect) makes the longest tasks wrap into 3 lines
   and overlap the next row: the list needs room for every role's longest
   task in two lines. Measured against the built site (both locales, all 8
   roles, `.oj-roles__panel li` `scrollHeight` vs `clientHeight`, sweeping
   the viewport 700-1100px): every role's tasks fit two lines from 980px
   except the single longest one (Russian secretariat reminder, 93
   characters), which the safety net above already covers at any width, so
   980 is not chased further. Below it: the mobile scheme already used at
   767 and narrower — same cloud-hidden, auto-height, swipeable-tabs
   layout, just starting earlier. */
@media (max-width: 979px) {
  .oj-roles__inner {
    padding: 72px 0;
    gap: 24px;
  }

  .oj-roles__inner h2 {
    padding: 0 20px;
    font-size: 34px;
    line-height: 1.06;
    letter-spacing: -0.04em;
  }

  /* No cloud on the mobile scheme (`HomeMobile.dc.html`): a draggable
     horizontal tab strip, then the list — `client/roles.ts` wires the drag. */
  .oj-roles__cloud {
    display: none;
  }

  .oj-roles__tabs {
    display: flex;
    flex-wrap: nowrap;
    gap: 24px;
    padding: 0 20px;
    overflow-x: auto;
    cursor: grab;
    user-select: none;
    scrollbar-width: none;
  }

  .oj-roles__tabs::-webkit-scrollbar {
    display: none;
  }

  .oj-roles__tab {
    flex: none;
    font-size: 17px;
  }

  .oj-roles__panels {
    padding: 0 20px;
  }

  .oj-roles__tasks li {
    height: auto;
    align-items: flex-start;
    gap: 12px;
    padding: 16px 0;
  }

  .oj-roles__tasks li span:last-child {
    font-size: 17px;
    line-height: 1.4;
  }

  .oj-roles__taskBullet {
    display: block;
    width: 11px;
    height: 11px;
    margin-top: 6px;
    border-radius: 3.2px;
    background: var(--oj-cyan);
    flex: none;
  }

  .oj-roles__more {
    min-height: 56px;
    padding: 0;
    border-top: none;
  }
}


/* src/components/home/HomeSecurity.css */
/* Layout spec §4, SEO spec 2.1 heading table. Full-bleed white background
   (../DemoBlock/DemoBlock.css's shape) + a capped inner column; on mobile
   cards 2–5 become the horizontal scroll-snap strip
   `../../client/homeSecurity.ts` tracks (`security_slide_change`). */
.oj-security {
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
  background: var(--oj-surface);
  box-sizing: border-box;
  /* a short top: the white channels block (HomeChannels.css) runs straight
     into this one, so its bottom padding already holds the gap */
  padding: 40px 0 120px;
}

.oj-security__title,
.oj-security__card1,
.oj-security__strip {
  box-sizing: content-box;
  max-width: 1320px;
  margin-left: auto;
  margin-right: auto;
  padding-left: 60px;
  padding-right: 60px;
}

/* The heading is the column (shared rule above: auto side margins, 1320
   cap); only its text is held to the mockup's 980, left-aligned — a bare
   `margin: 0` plus `max-width: 980px` here used to pin it to the viewport's
   left edge above 1440. */
.oj-security__title {
  margin-top: 0;
  margin-bottom: 0;
  font-family: var(--oj-font-display);
  font-weight: 600;
  font-size: 64px;
  line-height: 1.02;
  letter-spacing: -0.045em;
  color: var(--oj-navy);
}

.oj-security__titleText {
  display: block;
  max-width: 980px;
}

.oj-security__card1 {
  margin-top: 56px;
  box-sizing: border-box;
  padding: 48px 60px;
  border-radius: 36px;
  background: var(--oj-surface-2);
  display: flex;
  flex-direction: column;
  gap: 36px;
}

.oj-security__card1Head {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 16px;
  max-width: 600px;
}

.oj-security__progressRow {
  display: flex;
  align-items: center;
  gap: 12px;
}

.oj-security__progress {
  font-family: var(--oj-font-display);
  font-weight: 600;
  font-size: 17px;
  color: var(--oj-blue);
}

.oj-security__badge {
  padding: 7px 14px;
  border-radius: 999px;
  background: var(--oj-navy);
  font-size: 15px;
  font-weight: 700;
  color: #fff;
}

.oj-security__card1Heading {
  margin: 0;
  font-family: var(--oj-font-display);
  font-weight: 600;
  font-size: 38px;
  line-height: 1.06;
  letter-spacing: -0.035em;
  color: var(--oj-navy);
}

.oj-security__layers {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
}

.oj-security__layer {
  position: relative;
  box-sizing: border-box;
  padding: 24px 28px 30px;
  border-radius: 28px;
  background: var(--oj-surface);
  display: flex;
  flex-direction: column;
}

.oj-security__layerNum {
  font-family: var(--oj-font-display);
  font-weight: 600;
  font-size: 76px;
  line-height: 0.95;
  letter-spacing: -0.05em;
  color: var(--oj-cyan);
}

.oj-security__layerTitle {
  margin: 10px 0 0;
  font-family: var(--oj-font-display);
  font-weight: 700;
  font-size: 24px;
  letter-spacing: -0.02em;
  color: var(--oj-navy);
}

.oj-security__layerDesc {
  margin: 10px 0 0;
  font-size: 18px;
  line-height: 1.5;
  color: var(--oj-text-2);
}

.oj-security__layerOutcome {
  margin: 8px 0 0;
  font-size: 18px;
  font-weight: 700;
  line-height: 1.5;
  color: var(--oj-text);
}

.oj-security__strip {
  margin-top: 56px;
  padding-top: 0;
  padding-bottom: 0;
  list-style: none;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 40px;
}

.oj-security__slideCard {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding-top: 24px;
  border-top: 1px solid var(--oj-border);
}

.oj-security__slideHeading {
  margin: 0;
  font-family: var(--oj-font-display);
  font-weight: 700;
  font-size: 22px;
  line-height: 1.25;
  letter-spacing: -0.02em;
  color: var(--oj-navy);
}

.oj-security__slideDesc {
  margin: 0;
  font-size: 18px;
  line-height: 1.55;
  color: var(--oj-text-2);
}

@media (max-width: 1279px) {
  .oj-security {
    padding: 32px 0 96px;
  }
}

@media (max-width: 1023px) {
  .oj-security__title,
  .oj-security__card1,
  .oj-security__strip {
    padding-left: 40px;
    padding-right: 40px;
  }
}

@media (max-width: 767px) {
  .oj-security {
    padding: 24px 0 72px;
  }

  /* HomeMobile.dc.html: the heading's text starts at 20px, like every other
     section's; the card below sets its own 12px inset */
  .oj-security__title {
    padding-left: 20px;
    padding-right: 20px;
  }

  .oj-security__title {
    font-size: 34px;
    line-height: 1.06;
    letter-spacing: -0.04em;
  }

  .oj-security__card1 {
    margin-top: 28px;
    padding: 24px 12px 12px;
    border-radius: 28px;
    gap: 16px;
  }

  .oj-security__card1Head {
    padding: 0 8px;
    flex-direction: column;
    align-items: flex-start;
    gap: 12px;
  }

  .oj-security__progress {
    font-size: 16px;
  }

  .oj-security__card1Heading {
    margin-top: 0;
    max-width: none;
    font-size: 26px;
    line-height: 1.1;
    letter-spacing: -0.03em;
  }

  .oj-security__layers {
    display: flex;
    flex-direction: column;
    gap: 8px;
  }

  .oj-security__layer {
    padding: 18px 20px 20px;
    border-radius: 22px;
    display: grid;
    grid-template-columns: 52px 1fr;
    gap: 0 8px;
  }

  .oj-security__layerNum {
    grid-row: span 3;
    font-size: 56px;
  }

  .oj-security__layerTitle {
    margin: 4px 0 0;
    font-size: 21px;
  }

  .oj-security__layerDesc,
  .oj-security__layerOutcome {
    font-size: 17px;
    line-height: 1.45;
    margin-top: 6px;
  }

  /* `HomeMobile.dc.html`'s own strip cancels ITS section's 12px side padding
     with an equal negative margin, landing flush on the viewport edge; this
     section carries no side padding of its own (`.oj-security`, above —
     the inset instead lives on `.oj-security__title`/`__card1`), so the
     same -12px here would bleed 12px past the true edge on both sides
     (item 3) instead of cancelling anything. */
  .oj-security__strip {
    margin: 56px 0 0;
    padding: 0 20px;
    display: flex;
    align-items: stretch;
    gap: 10px;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scroll-padding-left: 20px;
  }

  .oj-security__slideCard {
    box-sizing: border-box;
    width: 276px;
    flex: none;
    scroll-snap-align: start;
    padding: 22px;
    border-radius: 22px;
    background: var(--oj-bg);
    border-top: none;
  }

  .oj-security__slideHeading {
    font-size: 20px;
    line-height: 1.2;
  }

  .oj-security__slideDesc {
    font-size: 17px;
    line-height: 1.5;
  }
}


/* src/components/home/HomeSeoText.css */
/* The SEO text block above the footer (SEO spec 2.1, `Home2.dc.html`). Task
   brief: the whole text — intro and all three subsections — is always in
   the HTML; collapse only ever changes what is *visible*
   (`../../client/seoText.ts` flips `data-expanded`), never what is
   rendered, unlike the mockup's own `sc-if` (which drops the subsections
   from the DOM entirely when closed). */
.oj-seo-text {
  box-sizing: content-box;
  max-width: 1320px;
  margin: 0 auto;
  padding: 64px 60px 56px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}

.oj-seo-text__title {
  margin: 0 0 8px;
  font-family: var(--oj-font-display);
  font-weight: 700;
  font-size: 22px;
  line-height: 1.3;
  letter-spacing: -0.02em;
  color: var(--oj-text-2);
}

.oj-seo-text__body {
  width: 100%;
}

.oj-seo-text__intro {
  margin: 0;
  font-size: 17px;
  line-height: 1.6;
  color: var(--oj-muted);
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  overflow: hidden;
}

.oj-seo-text__body[data-expanded="true"] .oj-seo-text__intro {
  display: block;
  -webkit-line-clamp: unset;
  overflow: visible;
}

.oj-seo-text__sections {
  margin-top: 24px;
  width: 100%;
  display: none;
}

.oj-seo-text__body[data-expanded="true"] .oj-seo-text__sections {
  display: block;
}

.oj-seo-text__section {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: 24px;
}

.oj-seo-text__section:last-child {
  margin-bottom: 0;
}

.oj-seo-text__sectionTitle {
  margin: 0;
  font-family: var(--oj-font-display);
  font-weight: 700;
  font-size: 18px;
  line-height: 1.35;
  color: var(--oj-text-2);
}

.oj-seo-text__sectionText {
  margin: 0;
  font-size: 17px;
  line-height: 1.6;
  color: var(--oj-muted);
}

.oj-seo-text__toggle {
  box-sizing: border-box;
  margin-top: 16px;
  min-height: 44px;
  padding: 0;
  border: 0;
  background: transparent;
  font-size: 17px;
  font-weight: 700;
  color: var(--oj-blue);
}

@media (max-width: 1023px) {
  .oj-seo-text {
    padding-left: 40px;
    padding-right: 40px;
  }
}

@media (max-width: 767px) {
  .oj-seo-text {
    padding: 40px 20px;
  }

  .oj-seo-text__title {
    font-size: 19px;
  }

  .oj-seo-text__intro,
  .oj-seo-text__sectionText {
    font-size: 16px;
  }

  .oj-seo-text__sections {
    margin-top: 20px;
  }

  .oj-seo-text__section {
    margin-bottom: 20px;
  }

  .oj-seo-text__sectionTitle {
    font-size: 17px;
  }

  .oj-seo-text__toggle {
    font-size: 16px;
  }
}


/* src/components/home/HomeWorksWith.css */
/* Layout spec §4: "above 1440 the strip stretches full width" — same
   full-bleed + capped inner shape ../DemoBlock/DemoBlock.css uses, here for
   the border lines rather than a background. */
.oj-works-with {
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
  border-top: 1px solid var(--oj-border);
  border-bottom: 1px solid var(--oj-border);
}

.oj-works-with__inner {
  box-sizing: content-box;
  max-width: 1320px;
  margin: 0 auto;
  padding: 12px 60px;
  display: grid;
  grid-template-columns: auto 9px minmax(0, 1fr) auto;
  align-items: center;
  gap: 20px;
}

.oj-works-with__title {
  margin: 0;
  font-family: var(--oj-font-display);
  font-weight: 700;
  font-size: 18px;
  letter-spacing: -0.02em;
  color: var(--oj-navy);
  white-space: nowrap;
}

/* A square, not the mockup's diamond, in the logo mark's cyan, not amber
   (owner's call): the mark is built of squares too. */
.oj-works-with__sep {
  width: 9px;
  height: 9px;
  /* centred on the line box, the square sat level with the capitals' middle,
     1.5px above the lowercase letters the eye reads; 3px on top moves its
     centre down by half that, a whole-pixel box keeps its edges sharp */
  margin-top: 3px;
  border-radius: 2px;
  background: var(--oj-cyan);
  flex: none;
}

.oj-works-with__slots {
  display: flex;
  align-items: center;
  gap: 14px;
  min-width: 0;
  /* Belt-and-braces only: `client/worksWithSlots.ts` measures every visible
     slot's natural (widest-name) width against this box and hides trailing
     slots (with their separator) before anything would reach this edge — a
     name is never clipped in normal operation (owner's rule). Kept as the
     no-JS fallback's own edge case, not the primary defence. */
  overflow: hidden;
}

/* A slot is as wide as the longest name in its own list — no absolute
   positioning: every `.oj-works-with__name` below sits in the same grid
   cell (`grid-row: 1; grid-column: 1`), so the column's automatic track
   width is the widest of them, and the rest stretch to match and centre
   their own (shorter) text inside it (owner's rule: a name is never
   clipped, ellipsised or shrunk — a slot drops instead, see
   `../../client/worksWithSlots.ts`). */
/* Never narrower than its widest name (the grid cell holds them all), and
   sharing whatever room is left equally with its neighbours — the strip
   stays evenly spread as the mockup has it, no gap piling up before
   «Все». */
.oj-works-with__slot {
  position: relative;
  box-sizing: border-box;
  display: grid;
  justify-items: center;
  flex: 1 0 auto;
  height: 56px;
  perspective: 400px;
}

.oj-works-with__name {
  grid-row: 1;
  grid-column: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  white-space: nowrap;
  font-family: var(--oj-font-display);
  font-weight: 700;
  font-size: 18px;
  letter-spacing: -0.02em;
  color: var(--oj-navy);
  backface-visibility: hidden;
  /* Base (pre-animation) state: only the first name shows — the same state
     `prefers-reduced-motion: reduce` leaves it in (`.oj-a`'s global rule,
     ../../vendor/site-handoff/tokens.css) and what a crawler/no-JS visitor
     sees, since `animation-name` alone never runs without the duration
     below. */
  opacity: 0;
  transform: rotateX(-90deg);
  animation-duration: 46s;
  animation-timing-function: ease-in-out;
  animation-iteration-count: infinite;
}

.oj-works-with__name:first-child {
  opacity: 1;
  transform: none;
}

/* Paused while the strip is out of the viewport (../../client/worksWithSlots.ts).
   `!important`: each name's `animation-name`/`animation-delay` is inline
   (React — `HomeWorksWith.tsx`), which always outranks a selector rule
   regardless of specificity — same reason `tokens.css`'s reduced-motion
   override uses it (`HomeRoles.css`, `HomeAdvantages.css` share the fix). */
.oj-works-with[data-playing="false"] .oj-a {
  animation-play-state: paused !important;
}

.oj-works-with__all {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 44px;
  padding-left: 12px;
  font-family: var(--oj-font-display);
  font-weight: 700;
  font-size: 18px;
  letter-spacing: -0.02em;
  color: var(--oj-navy);
  white-space: nowrap;
  text-decoration: none;
}

.oj-works-with__allText {
  border-bottom: 2px solid var(--oj-cyan);
  padding-bottom: 2px;
}

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

/* Layout spec §4: 5 slots at 1440, 4 from 1279, 3 at 1024, 2 at 767, 1 at
   599 — hiding a slot's own square separator with it so a missing slot
   never leaves a stray marker (task brief: "a missing slot is simply not
   rendered"). Children of `.oj-works-with__slots` alternate slot/separator
   (slot, separator, slot, separator, …), so `nth-child` counts both. */
@media (max-width: 1279px) {
  .oj-works-with__slots > :nth-child(n + 8) {
    display: none;
  }
}

@media (max-width: 1023px) {
  .oj-works-with__inner {
    padding-left: 40px;
    padding-right: 40px;
  }

  .oj-works-with__slots > :nth-child(n + 6) {
    display: none;
  }
}

@media (max-width: 767px) {
  .oj-works-with__inner {
    padding-left: 20px;
    padding-right: 20px;
    gap: 10px;
  }

  .oj-works-with__name {
    justify-content: flex-start;
  }

  .oj-works-with__slots > :nth-child(n + 4) {
    display: none;
  }
}

@media (max-width: 599px) {
  .oj-works-with__slots > :nth-child(n + 2) {
    display: none;
  }
}

/* `oj-slotbN` (0..10): the mockup's own 3D-flip keyframes
   (`Home2.dc.html`), copied verbatim — one keyframe per name position in an
   eleven-name slot, each visible for one eleventh of the 46s loop. */
@keyframes oj-slotb0 {
  0%,
  7.29% {
    opacity: 1;
    transform: none;
  }

  9.09%,
  98.5% {
    opacity: 0;
    transform: rotateX(-90deg);
  }

  100% {
    opacity: 1;
    transform: none;
  }
}

@keyframes oj-slotb1 {
  0%,
  9.09% {
    opacity: 0;
    transform: rotateX(90deg);
  }

  10.89%,
  16.38% {
    opacity: 1;
    transform: none;
  }

  18.18%,
  100% {
    opacity: 0;
    transform: rotateX(-90deg);
  }
}

@keyframes oj-slotb2 {
  0%,
  18.18% {
    opacity: 0;
    transform: rotateX(90deg);
  }

  19.98%,
  25.47% {
    opacity: 1;
    transform: none;
  }

  27.27%,
  100% {
    opacity: 0;
    transform: rotateX(-90deg);
  }
}

@keyframes oj-slotb3 {
  0%,
  27.27% {
    opacity: 0;
    transform: rotateX(90deg);
  }

  29.07%,
  34.56% {
    opacity: 1;
    transform: none;
  }

  36.36%,
  100% {
    opacity: 0;
    transform: rotateX(-90deg);
  }
}

@keyframes oj-slotb4 {
  0%,
  36.36% {
    opacity: 0;
    transform: rotateX(90deg);
  }

  38.16%,
  43.65% {
    opacity: 1;
    transform: none;
  }

  45.45%,
  100% {
    opacity: 0;
    transform: rotateX(-90deg);
  }
}

@keyframes oj-slotb5 {
  0%,
  45.45% {
    opacity: 0;
    transform: rotateX(90deg);
  }

  47.25%,
  52.75% {
    opacity: 1;
    transform: none;
  }

  54.55%,
  100% {
    opacity: 0;
    transform: rotateX(-90deg);
  }
}

@keyframes oj-slotb6 {
  0%,
  54.55% {
    opacity: 0;
    transform: rotateX(90deg);
  }

  56.35%,
  61.84% {
    opacity: 1;
    transform: none;
  }

  63.64%,
  100% {
    opacity: 0;
    transform: rotateX(-90deg);
  }
}

@keyframes oj-slotb7 {
  0%,
  63.64% {
    opacity: 0;
    transform: rotateX(90deg);
  }

  65.44%,
  70.93% {
    opacity: 1;
    transform: none;
  }

  72.73%,
  100% {
    opacity: 0;
    transform: rotateX(-90deg);
  }
}

@keyframes oj-slotb8 {
  0%,
  72.73% {
    opacity: 0;
    transform: rotateX(90deg);
  }

  74.53%,
  80.02% {
    opacity: 1;
    transform: none;
  }

  81.82%,
  100% {
    opacity: 0;
    transform: rotateX(-90deg);
  }
}

@keyframes oj-slotb9 {
  0%,
  81.82% {
    opacity: 0;
    transform: rotateX(90deg);
  }

  83.62%,
  89.11% {
    opacity: 1;
    transform: none;
  }

  90.91%,
  100% {
    opacity: 0;
    transform: rotateX(-90deg);
  }
}

@keyframes oj-slotb10 {
  0%,
  90.91% {
    opacity: 0;
    transform: rotateX(90deg);
  }

  92.71%,
  98.2% {
    opacity: 1;
    transform: none;
  }

  100% {
    opacity: 0;
    transform: rotateX(-90deg);
  }
}


/* src/pages/About.css */
/* About page (layout spec §4 "О компании"). `main` carries no padding of
   its own (../../styles/base.css) — each section below owns its own inset,
   the same "content-box, max-width: 1320px, side padding" shape
   Header/Footer/DemoBlock use, so it stays centered and capped at the same
   width as the chrome above and below it. The "why" band additionally
   breaks out to full viewport width for its background
   (docs/site-handoff/source/About.dc.html: the band spans edge to edge
   above the 1320px container, ТЗ §4). */
.oj-about-hero {
  /* This section is a flex item of `main` (base.css, column direction), not
     a sibling of it like Header/Footer — two consequences, unlike
     Header.css's own container:
     1. An auto cross-axis margin on a flex item wins over `align-items:
        normal`'s implicit stretch, so `margin: 0 auto` would shrink the box
        to its content's width instead of filling out to `max-width`
        (verified: it collapsed to the h1's own 780px) — `align-self:
        center` instead, which only matters once `max-width` caps growth
        past 1440px viewport.
     2. `width: 100%` together with `box-sizing: content-box` sets the
        *content* to 100% of the flex container and adds padding on top,
        overflowing it (verified: 60px of horizontal scroll at 1024px) — so
        this box is `border-box` and the cap is `1320 + 2 * 60`, not
        Header's content-box `1320`. */
  box-sizing: border-box;
  position: relative;
  width: 100%;
  max-width: 1440px;
  align-self: center;
  padding: 88px var(--oj-page-pad-desktop) 96px;
  display: flex;
  flex-direction: column;
  gap: 40px;
}

.oj-about-hero__mark {
  display: block;
  position: absolute;
  /* Measured from the section's own padding edge (About.dc.html /
     About1024.dc.html): 60px in from the right, i.e. flush with the content
     edge, not bleeding into the side gutter. */
  right: var(--oj-page-pad-desktop);
  top: 50%;
  width: 400px;
  height: 400px;
  margin-top: -200px;
}

.oj-about-hero h1 {
  margin: 0;
  max-width: 780px;
  font-size: 96px;
  line-height: 1;
  letter-spacing: -0.05em;
}

.oj-about-hero__slogan {
  margin: -4px 0 0;
  display: flex;
  align-items: center;
  gap: 14px;
  font-family: var(--oj-font-display);
  font-weight: 600;
  font-size: 36px;
  line-height: 1.15;
  letter-spacing: -0.035em;
  color: var(--oj-navy);
}

.oj-about-hero__slogan-mark {
  display: inline-block;
  flex: none;
  width: 14px;
  height: 14px;
  border-radius: 3px;
  background: var(--oj-amber);
  transform: rotate(45deg);
}

.oj-about-hero__lede {
  margin: 0;
  max-width: 640px;
  font-size: 24px;
  line-height: 1.55;
  color: var(--oj-text);
}

.oj-about-why {
  width: 100vw;
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
  background: var(--oj-navy);
}

.oj-about-why__inner {
  /* content-box: see ../../components/Header/Header.css for why — same
     container bug (border-box would cap padding *and* content together,
     doubling the inset to 120px instead of the mockup's 60). */
  box-sizing: content-box;
  max-width: 1320px;
  margin: 0 auto;
  padding: 96px var(--oj-page-pad-desktop);
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 80px;
  align-items: start;
}

.oj-about-why__inner h2 {
  margin: 0;
  font-size: 56px;
  line-height: 1.05;
  letter-spacing: -0.045em;
  color: #fff;
}

.oj-about-why__accent {
  white-space: nowrap;
  text-decoration: underline;
  text-decoration-color: var(--oj-cyan);
  text-decoration-thickness: 4px;
  text-underline-offset: 10px;
}

.oj-about-why__body {
  display: flex;
  flex-direction: column;
  gap: 32px;
}

/* the compare line takes the first paragraph's size at every width */
.oj-about-why__body1,
.oj-about-why__compare {
  margin: 0;
  font-size: 22px;
  line-height: 1.55;
  color: rgb(255 255 255 / 78%);
}

.oj-about-why__body2 {
  margin: 0;
  font-family: var(--oj-font-display);
  font-weight: 600;
  font-size: 32px;
  line-height: 1.25;
  letter-spacing: -0.03em;
  color: #fff;
}

/* `.oj-wordmark` (base.css, shared — not ours to edit) fixes its text to
   `--oj-navy` for its usual light-background spots (header, footer). On this
   band's dark navy background that text would be invisible; this selector's
   extra specificity overrides just the color, here, without touching the
   shared component. */
.oj-about-why__body2 .oj-wordmark,
.oj-about-why__compare .oj-wordmark {
  color: inherit;
}

.oj-about-why__compare a {
  color: #fff;
  text-decoration: underline;
  text-underline-offset: 4px;
}

.oj-about-team {
  /* border-box + width/align-self, not content-box + margin: auto — see
     `.oj-about-hero` above, same flex-item-of-`main` issue. */
  box-sizing: border-box;
  width: 100%;
  max-width: 1440px;
  align-self: center;
  padding: 96px var(--oj-page-pad-desktop);
  display: flex;
  flex-direction: column;
  gap: 56px;
}

.oj-about-team h2 {
  margin: 0;
  font-size: 56px;
  letter-spacing: -0.045em;
}

.oj-about-team__grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 40px;
}

.oj-about-team__card {
  box-sizing: border-box;
  padding: 36px;
  border-radius: var(--oj-r-xl);
  background: var(--oj-surface);
  display: grid;
  gap: 28px;
  align-items: start;
}

.oj-about-team__info {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.oj-about-team__heading {
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.oj-about-team__name {
  container: oj-founder-name / inline-size;
  font-family: var(--oj-font-display);
  font-weight: 700;
  font-size: 30px;
  letter-spacing: -0.025em;
  color: var(--oj-navy);
}

/* Both cards are always the same width, so one threshold breaks both names
   at once: the moment the longest name stops fitting its line, every family
   name moves to a line of its own. The threshold is that longest name's
   width in its own font size (em), measured: "Александр Нигматуллин"
   11.70em, "Alexander Nigmatullin" 10.17em — re-measure if a name changes. */
@container oj-founder-name (max-width: 11.75em) {
  :lang(ru) .oj-about-team__namePart {
    display: block;
  }
}

@container oj-founder-name (max-width: 10.2em) {
  :lang(en) .oj-about-team__namePart {
    display: block;
  }
}

.oj-about-team__role {
  font-family: var(--oj-font-body);
  font-size: 18px;
  font-weight: 600;
  color: var(--oj-blue);
}

.oj-about-team__bio {
  margin: 0;
  font-size: 19px;
  line-height: 1.5;
  color: var(--oj-text-2);
}

@media (max-width: 1279px) {
  .oj-about-hero__mark {
    width: 260px;
    height: 260px;
    margin-top: -130px;
  }

  .oj-about-hero h1 {
    max-width: 600px;
    font-size: 84px;
  }

  .oj-about-hero__slogan {
    font-size: 32px;
  }

  .oj-about-hero__slogan-mark {
    width: 12px;
    height: 12px;
    border-radius: 3px;
  }

  .oj-about-hero__lede {
    max-width: 600px;
    font-size: 22px;
  }

  .oj-about-why__inner {
    gap: 48px;
  }

  .oj-about-why__inner h2 {
    font-size: 46px;
  }

  .oj-about-why__accent {
    text-decoration-thickness: 3px;
    text-underline-offset: 8px;
  }

  .oj-about-why__body1,
  .oj-about-why__compare {
    font-size: 19px;
  }

  .oj-about-why__body2 {
    font-size: 26px;
  }

  .oj-about-team h2 {
    font-size: 46px;
  }

  .oj-about-team__grid {
    gap: 24px;
  }

  .oj-about-team__card {
    padding: 28px;
    border-radius: 24px;
    gap: 20px;
  }

  .oj-about-team__name {
    font-size: 24px;
  }

  .oj-about-team__role {
    font-size: 16px;
  }

  .oj-about-team__bio {
    font-size: 17px;
  }
}

/* Below the 1024 artboard the mark has no room beside the text: at 768-944
   it ran over the slogan and the paragraph (and, narrower, the H1 itself
   would not fit the space left of it). It goes, as on phones. */
@media (max-width: 1023px) {
  .oj-about-hero__mark {
    display: none;
  }
}

@media (max-width: 767px) {
  .oj-about-hero {
    padding: 40px 20px 40px;
    gap: 24px;
  }

  .oj-about-hero h1 {
    max-width: none;
    font-size: 42px;
    line-height: 1.03;
    letter-spacing: -0.045em;
  }

  .oj-about-hero__slogan {
    margin-top: -6px;
    font-size: 22px;
  }

  .oj-about-hero__slogan-mark {
    width: 10px;
    height: 10px;
    border-radius: 2px;
  }

  .oj-about-hero__lede {
    max-width: none;
    font-size: 18px;
    line-height: 1.5;
  }

  .oj-about-why__inner {
    padding: 48px 20px;
    grid-template-columns: 1fr;
    gap: 20px;
  }

  .oj-about-why__inner h2 {
    font-size: 32px;
    line-height: 1.08;
    letter-spacing: -0.035em;
  }

  .oj-about-why__accent {
    text-decoration-thickness: 3px;
    text-underline-offset: 6px;
  }

  .oj-about-why__body {
    gap: 20px;
  }

  .oj-about-why__body1,
  .oj-about-why__compare {
    font-size: 18px;
    line-height: 1.5;
  }

  .oj-about-why__body2 {
    font-size: 22px;
    line-height: 1.3;
    letter-spacing: -0.02em;
  }

  .oj-about-team {
    padding: 48px 20px 48px;
    gap: 24px;
  }

  .oj-about-team h2 {
    font-size: 30px;
    letter-spacing: -0.04em;
  }
}

@media (max-width: 599px) {
  /* one under the other, the cards still share one height: the taller's */
  .oj-about-team__grid {
    grid-template-columns: 1fr;
    grid-auto-rows: 1fr;
    gap: 16px;
  }

  .oj-about-team__card {
    padding: 24px;
    border-radius: 22px;
    gap: 16px;
  }

  .oj-about-team__info {
    gap: 4px;
  }
}


/* src/pages/Compare.css */
/* Layout spec §4/§5: Compare.dc.html (>=1280) / Compare1024.dc.html
   (1024-1279) grid tiers; Compare768.dc.html (768-1023) / CompareMobile.dc.html
   (<=767) horizontal-strip tiers. */

/* `<main>` carries no box model of its own (styles/base.css): this section
   owns the "full width, inner max-width 1320px + side padding,
   box-sizing: content-box" shape Header/Footer/DemoBlock use. Values are the
   section's own measured padding on each control-width artboard: 1440
   `96px 60px 120px`, 1024 `96px 60px`, 768 `80px 40px`, 390 `40px 20px 56px`. */
.oj-compare {
  /* `main` (styles/base.css) is `display: flex; flex-direction: column`;
     `.oj-compare` is its flex item, and — unlike Header/Footer/DemoBlock,
     which are plain block boxes outside any flex layout — a flex item's
     cross-axis stretch here does not shrink below the strip table's
     max-content width even with `min-width: 0` (tested: it doesn't).
     `width: 100%` forces the viewport-constrained size instead; `border-box`
     plus a max-width inflated by the 60+60 side padding keeps the content
     area at exactly 1320px once the viewport is wide enough to stop
     clamping — the same outcome `content-box` + `max-width: 1320px` gives a
     non-flex box, worked around because stretch ignores that here. */
  box-sizing: border-box;
  width: 100%;
  max-width: calc(1320px + 120px);
  min-width: 0;
  margin: 0 auto;
  padding: 96px 60px 120px;
  display: flex;
  flex-direction: column;
}

.oj-compare h1 {
  margin: 0;
  font-size: 88px;
}

.oj-compare__legend {
  margin: 40px 0 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 10px 28px;
}

.oj-compare__legend li {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 15px;
  color: var(--oj-text-2);
}

.oj-compare__icon {
  flex: none;
  display: block;
  width: 20px;
  height: 20px;
}

.oj-compare__hint {
  display: none;
  margin: 16px 0 0;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
  font-size: 16px;
  color: var(--oj-text-2);
}

.oj-compare__hint span:last-child {
  font-family: var(--oj-font-display);
  font-weight: 700;
  font-size: 15px;
  color: var(--oj-blue);
}

.oj-compare__scroll {
  min-width: 0;
  margin-top: 20px;
}

.oj-compare__table {
  width: 100%;
  /* separate, not collapse: each cell draws its own line, so the strip's
     sticky question column covers a scrolled cell's line too (Chromium
     paints collapsed borders above a sticky cell) */
  border-collapse: separate;
  border-spacing: 0;
  table-layout: fixed;
}

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

.oj-compare__table col {
  width: calc((100% - 210px) / 5);
}

.oj-compare__table col:first-child {
  width: 210px;
}

/* The header row stays part of the table (owner's call, over the layout
   spec's sticky header): it scrolls with the rows, down the page and
   sideways in the strip, never detached from them. */
.oj-compare__table thead th {
  background: var(--oj-bg);
  box-shadow: 0 1px 0 var(--oj-border);
  text-align: left;
  vertical-align: top;
}

.oj-compare__corner {
  background: var(--oj-bg);
}

.oj-compare__table thead th:not(.oj-compare__corner) {
  padding: 28px 18px 22px;
  border-radius: var(--oj-r-xl) var(--oj-r-xl) 0 0;
}

.oj-compare__table thead th.oj-compare__col--octojinn {
  background: var(--oj-navy);
}

.oj-compare__approach-name {
  display: block;
  font-family: var(--oj-font-display);
  font-weight: 700;
  font-size: 20px;
  letter-spacing: -0.02em;
  color: var(--oj-navy);
}

.oj-compare__col--octojinn .oj-compare__approach-name {
  font-size: 24px;
  letter-spacing: -0.03em;
  color: var(--oj-surface);
}

.oj-compare__approach-desc {
  display: block;
  margin-top: 6px;
  font-size: 15px;
  line-height: 1.45;
  color: var(--oj-muted);
}

.oj-compare__col--octojinn .oj-compare__approach-desc {
  color: var(--oj-slate-150);
}

.oj-compare__table th[scope="row"] {
  /* the question lines up with the cells' bold titles, not their icons: a
     cell's top padding + its 20px icon + the 10px gap (owner's call) */
  padding: 50px 18px 20px 0;
  border-top: 1px solid var(--oj-border);
  font-family: var(--oj-font-display);
  font-weight: 700;
  font-size: 18px;
  line-height: 1.35;
  color: var(--oj-navy);
  text-align: left;
  vertical-align: top;
}

.oj-compare__table td {
  padding: 20px 18px;
  border-top: 1px solid var(--oj-border);
  vertical-align: top;
}

.oj-compare__table td.oj-compare__col--octojinn {
  background: var(--oj-navy);
  border-top: 1px solid rgba(255, 255, 255, 0.14);
}

.oj-compare__table tbody tr:last-child td.oj-compare__col--octojinn {
  border-radius: 0 0 var(--oj-r-xl) var(--oj-r-xl);
}

.oj-compare__cell {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 10px;
}

.oj-compare__table td strong {
  font-size: 17px;
  line-height: 1.35;
  color: var(--oj-text);
}

/* `.oj-compare__table td` (0,1,2) beats a bare `.oj-compare__col--octojinn`
   (0,1,1) regardless of source order, so the dark default color above was
   winning over this one on the navy column — item 4. Matching the base
   selector's own `td` prefix restores the intended specificity order. */
.oj-compare__table td.oj-compare__col--octojinn strong {
  color: var(--oj-surface);
}

.oj-compare__table td span:not(.oj-compare__icon) {
  font-size: 15px;
  line-height: 1.5;
  color: var(--oj-muted);
}

.oj-compare__table td.oj-compare__col--octojinn span:not(.oj-compare__icon) {
  color: var(--oj-slate-150);
}

.oj-compare__footnote {
  margin: 36px 0 0;
  max-width: 520px;
  font-size: 15px;
  line-height: 1.5;
  color: var(--oj-muted);
}

/* 1024-1279: Compare1024.dc.html — narrower first column, smaller type. */
@media (max-width: 1279px) {
  .oj-compare {
    padding: 96px 60px;
  }

  .oj-compare__table col {
    width: calc((100% - 150px) / 5);
  }

  .oj-compare__table col:first-child {
    width: 150px;
  }

  .oj-compare__table thead th:not(.oj-compare__corner) {
    padding: 22px 12px 18px;
    border-radius: 22px 22px 0 0;
  }

  .oj-compare__col--octojinn .oj-compare__approach-name {
    font-size: 19px;
  }

  .oj-compare__approach-name {
    font-size: 17px;
  }

  .oj-compare__approach-desc {
    font-size: 14px;
    line-height: 1.4;
  }

  .oj-compare__table th[scope="row"] {
    padding: 46px 12px 16px 0;
    font-size: 16px;
  }

  .oj-compare__table td {
    padding: 16px 12px;
  }

  .oj-compare__icon {
    width: 20px;
    height: 20px;
  }

  .oj-compare__table td strong {
    font-size: 15px;
  }

  .oj-compare__table td span:not(.oj-compare__icon) {
    font-size: 14px;
    line-height: 1.45;
  }

  .oj-compare__table tbody tr:last-child td.oj-compare__col--octojinn {
    border-radius: 0 0 22px 22px;
  }
}

@media (min-width: 1024px) {
  .oj-compare__icon {
    width: 22px;
    height: 22px;
  }
}

/* 768-1023 and <=767: Compare768.dc.html / CompareMobile.dc.html — a
   horizontal strip. The question column (th[scope=row]) is sticky on the
   left; the header row and every approach column scroll with the rows. */
@media (max-width: 1023px) {
  .oj-compare {
    padding: 80px 40px;
  }

  .oj-compare h1 {
    font-size: 68px;
  }

  .oj-compare__hint {
    display: flex;
  }

  /* No `scroll-snap-type` (the layout spec asks for one): combined with the
     sticky question/OctoJinn columns inside a real `<table>`, Chrome's snap
     resolution repeatedly fought the actual scroll position in testing — an
     unwanted jump to mid-strip on first paint, and `scrollLeft` refusing to
     settle back at 0 after a drag or a plain `scrollTo({left: 0})`. Native
     momentum/touch scroll and the mouse-drag handler below still give the
     "slides to reveal the next system" feel without it; `overflow-anchor:
     none` guards against late web-font reflow nudging `scrollLeft` the same
     way snap did. */
  .oj-compare__scroll {
    --oj-compare-col2: 180px;
    --oj-compare-col: 220px;
    container-type: inline-size;
    overflow-x: auto;
    overflow-y: hidden;
    overflow-anchor: none;
    scrollbar-width: none;
    cursor: grab;
    /* Bleeds the strip to the viewport's right edge like the mockup; the
       left edge stays at the section's own inset, so the sticky OctoJinn
       column stops there and scrolled cells are clipped under it. */
    margin-right: -40px;
  }

  .oj-compare__scroll::-webkit-scrollbar {
    display: none;
  }

  /* An explicit sum, not `width: max-content`: with `table-layout: fixed`
     the declared column widths only hold when the table's own width is
     their sum. `--oj-compare-col2` is the OctoJinn column's (180 / 150). */
  .oj-compare__table {
    width: calc(160px + var(--oj-compare-col2) + 4 * var(--oj-compare-col));
    table-layout: fixed;
  }

  .oj-compare__table col {
    width: var(--oj-compare-col);
  }

  /* Room after the last column (owner's call): the strip scrolls on until
     the last column stands right against the stuck OctoJinn column, never
     under it, with empty page to its right — the strip's own width
     (`100cqw`) less the OctoJinn column and one approach column. */
  .oj-compare__track {
    width: max-content;
    padding-right: calc(100cqw - var(--oj-compare-col2) - var(--oj-compare-col));
  }

  .oj-compare__table col:first-child {
    width: 160px;
  }

  .oj-compare__table col:nth-child(2) {
    width: var(--oj-compare-col2);
  }

  /* Everything scrolls, the question column too; the OctoJinn column
     (header and body) stops at the strip's left edge once it gets there and
     the rest slide on under it (owner's call). */
  .oj-compare__table .oj-compare__col--octojinn {
    position: sticky;
    left: 0;
    z-index: 3;
  }

  .oj-compare__table thead th:not(.oj-compare__corner) {
    border-radius: 14px 14px 0 0;
    padding: 12px;
  }

  .oj-compare__col--octojinn .oj-compare__approach-name {
    font-size: 15px;
  }

  .oj-compare__approach-name {
    font-size: 15px;
    line-height: 1.25;
  }

  .oj-compare__approach-desc {
    display: none;
  }

  .oj-compare__table th[scope="row"] {
    padding: 46px 14px 16px 0;
    font-size: 15px;
  }

  .oj-compare__table td {
    padding: 16px 14px;
  }

  .oj-compare__table td strong {
    font-size: 15px;
  }

  .oj-compare__table td span:not(.oj-compare__icon) {
    font-size: 14px;
    line-height: 1.45;
  }

  .oj-compare__table tbody tr:last-child td.oj-compare__col--octojinn {
    border-radius: 0 0 14px 14px;
  }
}

@media (max-width: 767px) {
  .oj-compare {
    padding: 40px 20px 56px;
  }

  .oj-compare__scroll {
    --oj-compare-col2: 150px;
    --oj-compare-col: 200px;
    margin-right: -20px;
  }

  .oj-compare h1 {
    font-size: 44px;
  }

  .oj-compare__legend {
    margin-top: 24px;
  }

  .oj-compare__table {
    width: calc(122px + var(--oj-compare-col2) + 4 * var(--oj-compare-col));
  }

  .oj-compare__table col:first-child {
    width: 122px;
  }
}


/* src/pages/Connectors.css */
/* Layout spec: Integrations.dc.html (1440 & 1024 measure identically — one
   breakpoint at 767 is enough, see Connectors.tsx) / IntegrationsMobile.dc.html (390). */

/* `client/connectors.ts` toggles cards/empty-state/pagination through the
   native `hidden` IDL property. The UA stylesheet's `[hidden] { display:
   none }` and this file's own `display: flex/grid` rules below have equal
   selector specificity, so source order alone would decide the winner —
   fragile. This rule outranks both on purpose, everywhere under this page,
   so `hidden` always wins. */
[data-js="connectors"] [hidden] {
  display: none !important;
}

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

/* `<main>` carries no box model of its own (styles/base.css): each section
   owns the "full width, inner max-width 1320px + side padding,
   box-sizing: content-box" shape Header/Footer/DemoBlock use. Neither
   section here needs the full-bleed breakout those use (no section-wide
   background), so the padding sits directly on the section. Desktop values
   measured on both Integrations.dc.html and Integrations1024.dc.html (they
   match exactly); 768-1023 keeps the same vertical rhythm with the
   sitewide 40px side padding (layout spec §3's container table; no
   dedicated 768 artboard exists for this page). */
/* A flex item of `main` with auto side margins does not stretch — it
   shrinks to its content (the 1000px title), and then centres: at 1440 the
   title sat 160px right of the column. Full width, capped at the column plus
   its side padding, centred — the same shape as the catalog below. */
.oj-connectors-hero {
  box-sizing: border-box;
  width: 100%;
  max-width: calc(1320px + 2 * 60px);
  margin: 0 auto;
  padding: 72px 60px 56px;
  display: flex;
  flex-direction: column;
}

.oj-connectors-hero__title {
  margin: 0;
  max-width: 1000px;
  font-family: var(--oj-font-display);
  font-weight: 600;
  font-size: 88px;
  line-height: 1;
  letter-spacing: -0.05em;
  color: var(--oj-navy);
}

.oj-connectors-hero__text {
  margin: 36px 0 0;
  max-width: 900px;
  font-family: var(--oj-font-body);
  font-weight: 400;
  font-size: 24px;
  line-height: 1.5;
  color: var(--oj-text);
}

/* `main` (styles/base.css) is `display: flex; flex-direction: column`; this
   section is its flex item, and — like Compare.css's `.oj-compare` —
   stretch does not shrink it below the category tab strip's scrollable
   content width even with `min-width: 0` alone. `width: 100%` forces the
   viewport-constrained size; `border-box` plus a max-width inflated by the
   60+60 side padding keeps the content area at exactly 1320px past that
   (see Compare.css for the longer version of this workaround). */
.oj-connectors-catalog {
  box-sizing: border-box;
  width: 100%;
  max-width: calc(1320px + 120px);
  min-width: 0;
  margin: 0 auto;
  padding: 0 60px 96px;
  display: flex;
  flex-direction: column;
  gap: 28px;
}

@media (max-width: 1023px) {
  .oj-connectors-hero,
  .oj-connectors-catalog {
    padding-left: 40px;
    padding-right: 40px;
  }
}

.oj-connectors-catalog h1 {
  margin: 0 0 4px;
  font-family: var(--oj-font-display);
  font-weight: 600;
  font-size: 36px;
  line-height: 1.1;
  letter-spacing: -0.03em;
  color: var(--oj-navy);
}

.oj-connectors__search {
  box-sizing: border-box;
  display: flex;
  align-items: center;
  gap: 14px;
  height: 72px;
  padding: 0 24px;
  border-radius: var(--oj-r-xl);
  background: var(--oj-surface);
  box-shadow:
    0 0 0 2px var(--oj-cyan),
    0 0 0 7px rgba(34, 195, 219, 0.18);
}

.oj-connectors__search-icon {
  flex: none;
  display: block;
  color: var(--oj-navy);
}

.oj-connectors__search-input {
  flex-grow: 1;
  min-width: 0;
  height: 100%;
  border: 0;
  outline: 0;
  background: transparent;
  font-family: inherit;
  font-size: 22px;
  color: var(--oj-text);
}

.oj-connectors__tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.oj-connectors__tab {
  box-sizing: border-box;
  min-height: 48px;
  padding: 0 20px;
  border-radius: 15px;
  font-family: inherit;
  font-size: 17px;
  white-space: nowrap;
  border: 0;
  background: var(--oj-surface);
  color: var(--oj-navy);
  font-weight: 600;
}

/* every tab carries the same 1px border (transparent on the picked one), so
   picking a tab never changes its size; the bold width is held by
   `.oj-bold-stable` (base.css) */
.oj-connectors__tab {
  border: 1px solid var(--oj-border);
}

.oj-connectors__tab[aria-selected="true"] {
  background: var(--oj-navy);
  border-color: var(--oj-navy);
  color: var(--oj-surface);
  font-weight: 700;
}

@media (max-width: 1023px) {
  /* One row of categories that scrolls (strips spec of 21.10; mouse drag and
     wheel from client/dragScroll.ts, touch natively): it runs past the
     right margin to the screen's edge, so the category cut there shows
     there is more. 4px of padding all round, taken back by the margin, keep
     a focused tab's ring from being clipped by the strip. From 1024 up all
     categories show, wrapping onto a second line. */
  .oj-connectors__tabs {
    --oj-tabs-bleed: 40px;
    flex-wrap: nowrap;
    overflow-x: auto;
    overflow-y: hidden;
    scroll-snap-type: x mandatory;
    margin: -4px calc(-1 * var(--oj-tabs-bleed)) -4px -4px;
    padding: 4px var(--oj-tabs-bleed) 4px 4px;
    scroll-padding-left: 4px;
  }

  .oj-connectors__tab {
    flex: none;
    scroll-snap-align: start;
  }
}

/* Not a visible line under the tabs — `Integrations.dc.html`'s own script
   computes this text (`countText`) but never binds it to anything on
   screen; it exists there only as search-result feedback for assistive
   tech. `aria-live="polite"` on the element (`Connectors.tsx`) announces it
   as the query/tab changes. */
.oj-connectors__count {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.oj-connectors__window {
  padding: 24px;
  border-radius: var(--oj-r-xl);
  background: var(--oj-surface-2);
  display: flex;
  flex-direction: column;
  gap: 20px;
}

/* A page's height (five rows of cards) as a minimum, not a fixed height:
   the "no such system" message below takes the window's room in the flow,
   and on a narrow screen it can need more than a page of cards does. */
.oj-connectors__viewport {
  position: relative;
  min-height: 448px;
  user-select: none;
}

.oj-connectors__grid {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  grid-auto-rows: 80px;
  gap: 12px;
}

.oj-connectors__card {
  box-sizing: border-box;
  display: flex;
  align-items: center;
  gap: 16px;
  height: 80px;
  padding: 0 18px;
  border-radius: 20px;
  background: var(--oj-surface);
}

.oj-connectors__avatar {
  width: 48px;
  height: 48px;
  border-radius: var(--oj-r-md);
  background: var(--oj-bg);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--oj-font-display);
  font-weight: 700;
  font-size: 17px;
  letter-spacing: -0.03em;
  color: var(--oj-navy);
  flex: none;
}

.oj-connectors__meta {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.oj-connectors__name {
  font-size: 20px;
  font-weight: 700;
  line-height: 1.2;
  color: var(--oj-text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* 768-1023 (no artboard of its own): four columns left a card ~170px wide,
   names cut to a few letters; two columns, a page of 20 in ten rows, and
   while there is more than one page the grid keeps a full page's height so
   paging never moves the dots (as on phones). */
@media (min-width: 768px) and (max-width: 1023px) {
  .oj-connectors__grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .oj-connectors__viewport.is-paged .oj-connectors__grid {
    min-height: calc(10 * 80px + 9 * 12px);
  }
}

/* one line, like the name above it: the longer groups ("Логистика, доставка
   и маркетплейсы") wrapped onto three and ran out of the 80px card */
.oj-connectors__category {
  font-size: 16px;
  color: var(--oj-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* In the flow, not laid over the grid: with nothing found the grid is
   empty, and an absolute message left the window with no height of its own
   (on a phone the yellow block below ran over it). */
.oj-connectors__empty {
  box-sizing: border-box;
  padding: 48px 24px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 16px;
}

.oj-connectors__empty-title {
  margin: 0;
  font-family: var(--oj-font-display);
  font-weight: 700;
  font-size: 28px;
  letter-spacing: -0.025em;
  color: var(--oj-navy);
}

.oj-connectors__empty-text {
  margin: 0;
  max-width: 680px;
  font-size: 20px;
  line-height: 1.5;
  color: var(--oj-text-2);
}

.oj-connectors__pagination {
  height: 48px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 20px;
}

.oj-connectors__arrow {
  box-sizing: border-box;
  width: 48px;
  height: 48px;
  border-radius: var(--oj-r-md);
  border: 1px solid var(--oj-border-4);
  background: var(--oj-surface);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  flex: none;
  color: var(--oj-navy);
}

.oj-connectors__arrow:disabled {
  opacity: 0.35;
  cursor: default;
}

.oj-connectors__dots {
  display: flex;
  align-items: center;
  gap: 8px;
}

/* The visible dot stays 8px (28px active) — `position: relative` plus an
   invisible `::before` at `inset: -8px` grows the *clickable* area to the
   24 CSS px Lighthouse's `target-size` audit wants, without moving or
   resizing anything a visitor sees (production audit, 2026-09-29). A click
   on generated content still targets its own real element, so the button
   need not grow itself. */
.oj-connectors__dot {
  position: relative;
  display: block;
  width: 8px;
  height: 8px;
  padding: 0;
  border: 0;
  border-radius: var(--oj-r-xs);
  background: var(--oj-slate-200);
  cursor: pointer;
}

.oj-connectors__dot::before {
  content: "";
  position: absolute;
  inset: -8px;
}

.oj-connectors__dot--active {
  width: 28px;
  background: var(--oj-navy);
  cursor: default;
}

/* Layout spec §4: below 767 the catalogue becomes a single-column list
   (IntegrationsMobile.dc.html) instead of the 4-column grid — swipe/drag
   pagination stays. Seven systems a page here (owner's call, 21.10;
   `client/connectors.ts`), and while there is more than one page the list
   keeps seven cards' height, so a short last page does not move the dots. */
@media (max-width: 767px) {
  .oj-connectors-hero {
    padding: 36px 20px 40px;
  }

  /* IntegrationsMobile.dc.html: the section itself carries no side padding
     here — search/tabs/h1 sit flush against a 20px inset (this section's own
     padding), the window is a touch narrower (12px, via the negative margin
     below). */
  .oj-connectors-catalog {
    padding: 0 20px 64px;
  }

  .oj-connectors__tabs {
    --oj-tabs-bleed: 20px;
  }

  .oj-connectors-hero__title {
    font-size: 44px;
    letter-spacing: -0.045em;
  }

  .oj-connectors-hero__text {
    margin-top: 20px;
    max-width: none;
    font-size: 18px;
  }

  .oj-connectors-catalog h1 {
    font-size: 24px;
    letter-spacing: -0.03em;
  }

  .oj-connectors__search {
    height: 60px;
    padding: 0 18px;
    border-radius: var(--oj-r-lg);
    gap: 12px;
    box-shadow:
      0 0 0 2px var(--oj-cyan),
      0 0 0 6px rgba(34, 195, 219, 0.18);
  }

  .oj-connectors__search-input {
    font-size: 18px;
  }

  .oj-connectors__tab {
    min-height: 44px;
    padding: 0 18px;
    border-radius: var(--oj-r-md);
    font-size: 16px;
    flex: none;
  }

  .oj-connectors__window {
    margin: 0 -8px;
    padding: 12px;
    border-radius: 26px;
  }

  .oj-connectors__viewport {
    min-height: 0;
  }

  .oj-connectors__grid {
    display: flex;
    flex-direction: column;
    gap: 8px;
  }

  .oj-connectors__viewport.is-paged .oj-connectors__grid {
    min-height: calc(7 * 68px + 6 * 8px);
  }

  .oj-connectors__card {
    height: 68px;
    padding: 0 14px;
    border-radius: var(--oj-r-lg);
    gap: 14px;
  }

  .oj-connectors__avatar {
    width: 40px;
    height: 40px;
    border-radius: var(--oj-r-sm);
    font-size: 15px;
  }

  .oj-connectors__name {
    font-size: 18px;
  }

  .oj-connectors__category {
    font-size: 15px;
  }

  .oj-connectors__empty {
    padding: 24px 8px;
  }

  .oj-connectors__empty-title {
    font-size: 22px;
  }

  .oj-connectors__empty-text {
    font-size: 17px;
    max-width: 620px;
  }
}

@media (max-width: 599px) {
  .oj-connectors__grid {
    display: flex;
    flex-direction: column;
  }
}


/* src/pages/Demo.css */
/* Demo page (layout spec §4 "Первый экран демо-страницы" + §7 "Формы и
   данные", DemoMobile/Demo1024/Demo.dc.html). `main` carries no padding of
   its own (../../styles/base.css) — each section below owns its own inset,
   the same "content-box, max-width: 1320px, side padding" shape
   Header/Footer/DemoBlock use. The mockup's third "Сообщения формы" section
   is a design annotation showing both message states side by side, not a
   real page section — `FormCard` already renders both, hidden, inline. */
.oj-demo-hero {
  /* This section is a flex item of `main` (base.css, column direction), not
     a sibling of it like Header/Footer — two consequences, unlike
     Header.css's own container:
     1. An auto cross-axis margin on a flex item wins over `align-items:
        normal`'s implicit stretch, so `margin: 0 auto` would shrink the box
        to its content's width instead of filling out to `max-width` —
        `align-self: center` instead, which only matters once `max-width`
        caps growth past 1440px viewport.
     2. `width: 100%` together with `box-sizing: content-box` sets the
        *content* to 100% of the flex container and adds padding on top,
        overflowing it — so this box is `border-box` and the cap is
        `1320 + 2 * 60`, not Header's content-box `1320`. */
  box-sizing: border-box;
  width: 100%;
  max-width: 1440px;
  align-self: center;
  padding: 88px var(--oj-page-pad-desktop) 80px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 64px;
}

.oj-demo-hero h1 {
  margin: 0;
  max-width: 680px;
  font-size: 84px;
  line-height: 1.05;
  letter-spacing: -0.05em;
}

.oj-demo-hero__line {
  display: block;
}

.oj-demo-hero__minutes {
  margin: 0;
  flex: none;
  display: flex;
  align-items: baseline;
  gap: 16px;
  font-family: var(--oj-font-display);
  font-weight: 600;
  color: var(--oj-navy);
}

.oj-demo-hero__value {
  font-size: 220px;
  line-height: 0.8;
  letter-spacing: -0.07em;
}

.oj-demo-hero__label {
  font-size: 30px;
  letter-spacing: -0.03em;
}

.oj-demo-main {
  /* border-box + width/align-self, not content-box + margin: auto — see
     `.oj-demo-hero` above, same flex-item-of-`main` issue. */
  box-sizing: border-box;
  width: 100%;
  max-width: 1440px;
  align-self: center;
  padding: 0 var(--oj-page-pad-desktop) 96px;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 80px;
  align-items: start;
}

.oj-demo-steps {
  display: flex;
  flex-direction: column;
  gap: 40px;
}

.oj-demo-steps h2 {
  margin: 0;
  font-size: 32px;
  letter-spacing: -0.04em;
}

.oj-demo-steps__list {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 28px;
}

.oj-demo-steps__item {
  display: flex;
  align-items: flex-start;
  gap: 20px;
}

.oj-demo-steps__number {
  flex: none;
  width: 48px;
  height: 48px;
  border-radius: var(--oj-r-md);
  background: var(--oj-navy);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--oj-font-display);
  font-weight: 700;
  font-size: 20px;
}

.oj-demo-steps__body {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.oj-demo-steps__title {
  font-family: var(--oj-font-display);
  font-weight: 700;
  font-size: 22px;
  color: var(--oj-navy);
}

.oj-demo-steps__text {
  margin: 0;
  max-width: 460px;
  font-size: 18px;
  line-height: 1.5;
  color: var(--oj-text-2);
}

.oj-demo-form-card {
  box-sizing: border-box;
  padding: 40px;
  border-radius: var(--oj-r-xl);
  background: var(--oj-surface);
  display: flex;
  flex-direction: column;
  gap: 24px;
}

.oj-demo-form-card__hours {
  display: flex;
  align-items: center;
  gap: 8px;
  color: var(--oj-navy);
  font-size: 16px;
  font-weight: 600;
}

.oj-demo-form {
  display: flex;
  flex-direction: column;
  gap: 20px;
}

/* `client/demoForm.ts` sets `form.hidden = true` on submit success/error —
   without this, `.oj-demo-form`'s own `display: flex` (equal specificity to
   the UA's `[hidden]`, this stylesheet loading later) would keep the form
   visible. Same fix as `.oj-demo-form-result[hidden]` above. */
.oj-demo-form[hidden] {
  display: none;
}

.oj-field {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.oj-field label {
  font-size: 16px;
  font-weight: 600;
  color: var(--oj-navy);
}

.oj-field input,
.oj-field textarea {
  box-sizing: border-box;
  width: 100%;
  height: 52px;
  padding: 0 16px;
  border-radius: var(--oj-r-lg);
  border: 1px solid var(--oj-border);
  background: var(--oj-bg);
  font-family: var(--oj-font-body);
  font-size: 17px;
  color: var(--oj-text);
}

.oj-field textarea {
  height: 110px;
  padding: 12px 16px;
  resize: none;
}

.oj-field__error {
  font-size: 14px;
  line-height: 1.4;
  color: var(--oj-error);
}

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

.oj-demo-form__submit {
  width: 100%;
}

/* `.oj-field` in front outranks `.oj-field label`/`.oj-field input` (the text
   fields' look) */
.oj-field .oj-demo-consent__label {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  font-size: 15px;
  font-weight: 400;
  line-height: 1.45;
  color: var(--oj-text);
  cursor: pointer;
}

.oj-demo-consent__label a {
  color: inherit;
  text-decoration: underline;
}

.oj-field .oj-demo-consent__box {
  flex: none;
  box-sizing: border-box;
  width: 20px;
  height: 20px;
  margin: 1px 0 0;
  padding: 0;
  border-radius: 4px;
  accent-color: var(--oj-navy);
  cursor: pointer;
}

.oj-field .oj-demo-consent__box:focus-visible {
  outline: 2px solid var(--oj-ink);
  outline-offset: 2px;
}

.oj-demo-form-consent {
  margin: 0;
  font-size: 14px;
  line-height: 1.4;
  color: var(--oj-muted);
}

.oj-demo-form-consent a {
  color: inherit;
  text-decoration: underline;
}

.oj-demo-form-result {
  box-sizing: border-box;
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 16px 18px;
  border-radius: 14px;
}

.oj-demo-form-result p {
  margin: 0;
  font-size: 16px;
  line-height: 1.4;
  color: inherit;
}

/* `[hidden]` and `.oj-demo-form-result` are equal specificity, and this
   stylesheet loads after the UA one — without this rule, `display: flex`
   above would win over the UA's `[hidden] { display: none }` and the
   success/error block would render expanded even while `hidden`. The
   attribute selector combined with the class outranks the class alone, so
   this wins regardless of source order. */
.oj-demo-form-result[hidden] {
  display: none;
}

.oj-demo-form-result--success {
  background: var(--oj-success-bg);
  border: 1px solid var(--oj-success-line);
  color: var(--oj-success);
}

.oj-demo-form-result--error {
  background: var(--oj-error-bg);
  border: 1px solid var(--oj-error-line);
  color: var(--oj-error);
}

@media (max-width: 1279px) {
  .oj-demo-hero {
    gap: 40px;
  }

  .oj-demo-hero h1 {
    max-width: 620px;
    font-size: 76px;
  }

  .oj-demo-hero__minutes {
    flex-direction: column;
    align-items: flex-start;
    gap: 12px;
  }

  .oj-demo-hero__value {
    font-size: 160px;
    letter-spacing: -0.06em;
  }

  .oj-demo-hero__label {
    font-size: 24px;
  }
}

@media (max-width: 767px) {
  .oj-demo-hero {
    padding: 40px 20px 32px;
    flex-direction: column;
    align-items: flex-start;
    gap: 20px;
  }

  .oj-demo-hero h1 {
    max-width: none;
    font-size: 44px;
    line-height: 1.05;
    letter-spacing: -0.045em;
  }

  .oj-demo-hero__minutes {
    flex-direction: row;
    align-items: baseline;
    gap: 10px;
  }

  .oj-demo-hero__value {
    font-size: 96px;
    letter-spacing: -0.06em;
  }

  .oj-demo-hero__label {
    font-size: 18px;
  }

  .oj-demo-main {
    /* DemoMobile.dc.html splits steps and the form card into two sibling
       sections (steps: `0 20px 32px`; form: `0 20px 40px`) rather than one
       grid reflowing — `.oj-demo-main` keeps them as one flex column, so
       its own gap (32) and bottom padding (40, the form section's own)
       reproduce the same total spacing. */
    padding: 0 20px 40px;
    display: flex;
    flex-direction: column;
    gap: 32px;
  }

  .oj-demo-form-card {
    padding: 24px;
    border-radius: 24px;
    gap: 20px;
  }

  .oj-demo-form {
    gap: 16px;
  }
}


/* src/pages/NotFound.css */
/* Geometry from NotFound.dc.html / NotFound1024.dc.html / NotFoundMobile.dc.html.
   The hero is a full-bleed, edge-to-edge band like `../components/DemoBlock/
   DemoBlock.css` — same two-level shape: this element breaks out of `main`
   (which carries no padding of its own, ../../styles/base.css) to 100vw for
   the background and owns only the vertical inset; `.oj-notfound__inner`
   re-applies the shared "content-box, max-width: 1320px, side padding"
   container for the content and gets the row layout. */
.oj-notfound__hero {
  box-sizing: border-box;
  width: 100vw;
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
  padding: 120px 0;
  background-color: var(--oj-amber);
  background-image:
    linear-gradient(90deg, var(--oj-amber) 42%, rgba(240, 180, 65, 0) 78%),
    url("data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20width%3D%27130%27%20height%3D%27130%27%3E%3Crect%20width%3D%27112%27%20height%3D%27112%27%20rx%3D%2732%27%20fill%3D%27rgba%2815%2C18%2C51%2C0.05%29%27%2F%3E%3C%2Fsvg%3E");
  background-size:
    auto,
    130px 130px;
  background-position:
    0 0,
    right -10px top 22px;
}

.oj-notfound__inner {
  /* content-box: see ../components/Header/Header.css for why — same
     container bug. */
  box-sizing: content-box;
  max-width: 1320px;
  margin: 0 auto;
  padding: 0 var(--oj-page-pad-desktop);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 64px;
}

.oj-notfound__content {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 24px;
  max-width: 640px;
}

.oj-notfound__title {
  margin: 0;
  font-size: 72px;
  line-height: 1.02;
  letter-spacing: -0.045em;
  color: var(--oj-ink);
}

.oj-notfound__subtitle {
  margin: 0;
  max-width: 560px;
  font-size: 22px;
  line-height: 1.5;
  color: var(--oj-ink);
}

.oj-notfound__cta {
  margin-top: 12px;
  background: var(--oj-ink);
}

.oj-notfound__cta:hover {
  background: color-mix(in srgb, var(--oj-ink) 92%, #000);
}

.oj-notfound__links {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 8px 20px;
  font-size: 18px;
  line-height: 1.5;
  color: var(--oj-ink);
}

.oj-notfound__link {
  color: var(--oj-ink);
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 4px;
  text-decoration-thickness: 1px;
}

.oj-notfound__link:hover {
  text-decoration-thickness: 2px;
}

.oj-notfound__link:focus-visible {
  outline: 2px solid var(--oj-ink);
  outline-offset: 4px;
  border-radius: 4px;
}

.oj-notfound__digits {
  display: flex;
  align-items: center;
  gap: 22px;
  flex: none;
}

.oj-notfound__digit {
  font-family: var(--oj-font-display);
  font-weight: 600;
  font-size: 300px;
  line-height: 0.8;
  letter-spacing: -0.07em;
  color: var(--oj-ink);
}

.oj-notfound__tile {
  display: block;
  width: 168px;
  height: 214px;
  border-radius: 48px;
  background: rgba(15, 18, 51, 0.12);
  transform: rotate(8deg);
  flex: none;
}

@media (max-width: 1279px) {
  .oj-notfound__hero {
    padding: 96px 0;
  }

  .oj-notfound__inner {
    gap: 40px;
  }

  .oj-notfound__content {
    gap: 20px;
    max-width: 480px;
  }

  .oj-notfound__title {
    font-size: 56px;
    line-height: 1.04;
  }

  .oj-notfound__subtitle {
    max-width: 460px;
    font-size: 19px;
  }

  .oj-notfound__digits {
    gap: 15px;
  }

  .oj-notfound__digit {
    font-size: 200px;
  }

  .oj-notfound__tile {
    width: 112px;
    height: 143px;
    border-radius: 32px;
  }
}

@media (max-width: 767px) {
  .oj-notfound__hero {
    padding: 56px 0;
    background-image: none;
  }

  .oj-notfound__inner {
    padding: 0 20px;
    flex-direction: column;
    align-items: stretch;
    gap: 18px;
  }

  .oj-notfound__content {
    gap: 18px;
    max-width: none;
  }

  .oj-notfound__title {
    font-size: 36px;
    line-height: 1.06;
    letter-spacing: -0.04em;
  }

  .oj-notfound__subtitle {
    max-width: none;
    font-size: 18px;
  }

  .oj-notfound__links {
    font-size: 17px;
  }

  .oj-notfound__cta {
    height: 56px;
    margin-top: 8px;
    width: 100%;
  }

  .oj-notfound__digits {
    order: -1;
    gap: 11px;
  }

  .oj-notfound__digit {
    font-size: 150px;
  }

  .oj-notfound__tile {
    width: 84px;
    height: 107px;
    border-radius: 24px;
  }
}


/* the pages' own style attributes, moved here by scripts/build/inlineStyles.mjs */

.oj-s-038f68ff41.oj-s-038f68ff41.oj-s-038f68ff41{animation-name:oj-slotb9;animation-delay:0s}
.oj-s-0488ef4c06.oj-s-0488ef4c06.oj-s-0488ef4c06{animation:oj-f2 8s ease-in-out -7s infinite}
.oj-s-0523128c95.oj-s-0523128c95.oj-s-0523128c95{animation:oj-f3 7s ease-in-out -3s infinite}
.oj-s-06f52a30a3.oj-s-06f52a30a3.oj-s-06f52a30a3{animation:oj-f1 11s ease-in-out -7s infinite}
.oj-s-09c46fbb05.oj-s-09c46fbb05.oj-s-09c46fbb05{animation-name:oj-slotb6;animation-delay:-3.6s}
.oj-s-0bc4d30667.oj-s-0bc4d30667.oj-s-0bc4d30667{animation-name:oj-slotb6;animation-delay:-7.2s}
.oj-s-0decdc15ee.oj-s-0decdc15ee.oj-s-0decdc15ee{--oj-bar-h:44px}
.oj-s-0ea52991b7.oj-s-0ea52991b7.oj-s-0ea52991b7{animation-name:oj-slotb3;animation-delay:-7.2s}
.oj-s-12de02b473.oj-s-12de02b473.oj-s-12de02b473{width:52px}
.oj-s-14b2e3c619.oj-s-14b2e3c619.oj-s-14b2e3c619{animation-name:oj-slotb5;animation-delay:-7.2s}
.oj-s-15ac103ea7.oj-s-15ac103ea7.oj-s-15ac103ea7{--oj-scene-duration:5.6s}
.oj-s-15c12160a4.oj-s-15c12160a4.oj-s-15c12160a4{animation:oj-in 0.5s ease-out backwards;animation-delay:0.6s}
.oj-s-199c92261b.oj-s-199c92261b.oj-s-199c92261b{animation:oj-f1 9s ease-in-out -2s infinite}
.oj-s-19b88f8208.oj-s-19b88f8208.oj-s-19b88f8208{--oj-bar-h:29px}
.oj-s-1a4c19a2ad.oj-s-1a4c19a2ad.oj-s-1a4c19a2ad{animation-name:oj-slotb10;animation-delay:-7.2s}
.oj-s-1ba51881f3.oj-s-1ba51881f3.oj-s-1ba51881f3{width:70px}
.oj-s-1ba7b99389.oj-s-1ba7b99389.oj-s-1ba7b99389{animation:oj-run 3.8000000000000003s linear 1s infinite}
.oj-s-1c09cf61fc.oj-s-1c09cf61fc.oj-s-1c09cf61fc{animation-name:oj-slotb9;animation-delay:-5.4s}
.oj-s-1c6419e1d9.oj-s-1c6419e1d9.oj-s-1c6419e1d9{animation-name:oj-slotb0;animation-delay:-7.2s}
.oj-s-1f5dac3e0c.oj-s-1f5dac3e0c.oj-s-1f5dac3e0c{animation:oj-draw 1.4s ease-out backwards;animation-delay:0s}
.oj-s-1f9a2732f9.oj-s-1f9a2732f9.oj-s-1f9a2732f9{animation-name:oj-slotb3;animation-delay:0s}
.oj-s-1fdb42a9e7.oj-s-1fdb42a9e7.oj-s-1fdb42a9e7{animation-name:oj-slotb2;animation-delay:-5.4s}
.oj-s-207575de33.oj-s-207575de33.oj-s-207575de33{animation:oj-f2 12s ease-in-out -5s infinite}
.oj-s-222506b405.oj-s-222506b405.oj-s-222506b405{animation:oj-run 4.4s linear 2s infinite}
.oj-s-22c7bd7b93.oj-s-22c7bd7b93.oj-s-22c7bd7b93{animation-name:oj-slotb6;animation-delay:0s}
.oj-s-233d3ebceb.oj-s-233d3ebceb.oj-s-233d3ebceb{animation:oj-in 0.5s ease-out backwards;animation-delay:0s}
.oj-s-26f7511012.oj-s-26f7511012.oj-s-26f7511012{--oj-bar-h:50px}
.oj-s-2776745ac2.oj-s-2776745ac2.oj-s-2776745ac2{animation-name:oj-slotb1;animation-delay:-3.6s}
.oj-s-2cc80d5456.oj-s-2cc80d5456.oj-s-2cc80d5456{animation:oj-f3 7s ease-in-out -6s infinite}
.oj-s-2f0a184885.oj-s-2f0a184885.oj-s-2f0a184885{width:70%}
.oj-s-30cc571c1a.oj-s-30cc571c1a.oj-s-30cc571c1a{width:58px}
.oj-s-3106de3e37.oj-s-3106de3e37.oj-s-3106de3e37{animation-name:oj-slotb8;animation-delay:-3.6s}
.oj-s-31d4d6f912.oj-s-31d4d6f912.oj-s-31d4d6f912{width:84%}
.oj-s-334c545a67.oj-s-334c545a67.oj-s-334c545a67{animation:oj-f4 8s ease-in-out -4s infinite}
.oj-s-36398099a5.oj-s-36398099a5.oj-s-36398099a5{animation:oj-f3 9s ease-in-out -2s infinite}
.oj-s-390d99820b.oj-s-390d99820b.oj-s-390d99820b{animation-name:oj-slotb0;animation-delay:-5.4s}
.oj-s-3ab3aa168b.oj-s-3ab3aa168b.oj-s-3ab3aa168b{animation:oj-f2 8s ease-in-out -1s infinite}
.oj-s-3b1ddb233d.oj-s-3b1ddb233d.oj-s-3b1ddb233d{--oj-scene-delay:0.95s}
.oj-s-3b4d21864b.oj-s-3b4d21864b.oj-s-3b4d21864b{--h:16px;--h2:36px}
.oj-s-3d411c6891.oj-s-3d411c6891.oj-s-3d411c6891{animation-name:oj-slotb8;animation-delay:-5.4s}
.oj-s-3da2188717.oj-s-3da2188717.oj-s-3da2188717{--oj-bar-h:15px}
.oj-s-3e7ab93559.oj-s-3e7ab93559.oj-s-3e7ab93559{animation-name:oj-slotb1;animation-delay:-5.4s}
.oj-s-3ead67836f.oj-s-3ead67836f.oj-s-3ead67836f{--oj-scene-delay:0.45s}
.oj-s-4096f64efa.oj-s-4096f64efa.oj-s-4096f64efa{--x:175px;--y:92px;--oj-scene-delay:3.5s}
.oj-s-416d9c2dff.oj-s-416d9c2dff.oj-s-416d9c2dff{animation-name:oj-slotb5;animation-delay:-1.8s}
.oj-s-41c0c80405.oj-s-41c0c80405.oj-s-41c0c80405{animation-name:oj-slotb0;animation-delay:-1.8s}
.oj-s-4207510326.oj-s-4207510326.oj-s-4207510326{--oj-scene-duration:4.4s}
.oj-s-4534423290.oj-s-4534423290.oj-s-4534423290{--h:28px;--h2:56px}
.oj-s-457ca01d10.oj-s-457ca01d10.oj-s-457ca01d10{animation:oj-f2 8s ease-in-out -4s infinite}
.oj-s-45b4f3f6c9.oj-s-45b4f3f6c9.oj-s-45b4f3f6c9{animation:oj-f2 10s ease-in-out -3s infinite}
.oj-s-45f23f99cc.oj-s-45f23f99cc.oj-s-45f23f99cc{animation:oj-in 0.5s ease-out backwards;animation-delay:0.24s}
.oj-s-46c0baef25.oj-s-46c0baef25.oj-s-46c0baef25{animation:oj-f3 9s ease-in-out -8s infinite}
.oj-s-4b6cb9f45c.oj-s-4b6cb9f45c.oj-s-4b6cb9f45c{animation:oj-draw 1.4s ease-out backwards;animation-delay:0.24s}
.oj-s-4b8165c19e.oj-s-4b8165c19e.oj-s-4b8165c19e{animation:oj-f4 10s ease-in-out -6s infinite}
.oj-s-4ba85f8945.oj-s-4ba85f8945.oj-s-4ba85f8945{animation:oj-f1 9s ease-in-out -5s infinite}
.oj-s-4eb5a10ef0.oj-s-4eb5a10ef0.oj-s-4eb5a10ef0{--oj-bar-h:23px}
.oj-s-4f9d9cbb72.oj-s-4f9d9cbb72.oj-s-4f9d9cbb72{animation-name:oj-slotb6;animation-delay:-5.4s}
.oj-s-5392a78b53.oj-s-5392a78b53.oj-s-5392a78b53{--h:50px;--h2:22px}
.oj-s-540d170ec9.oj-s-540d170ec9.oj-s-540d170ec9{--h:44px;--h2:20px}
.oj-s-5471749f0c.oj-s-5471749f0c.oj-s-5471749f0c{--x:175px;--y:-92px;--oj-scene-delay:2.1s}
.oj-s-54a8705644.oj-s-54a8705644.oj-s-54a8705644{animation-name:oj-slotb0;animation-delay:-3.6s}
.oj-s-54f489ce16.oj-s-54f489ce16.oj-s-54f489ce16{animation:oj-f3 11s ease-in-out -1s infinite}
.oj-s-552c192063.oj-s-552c192063.oj-s-552c192063{--x:-190px;--y:0px;--oj-scene-delay:2.8s}
.oj-s-5555941388.oj-s-5555941388.oj-s-5555941388{animation:oj-f3 11s ease-in-out -7s infinite}
.oj-s-55d8ffef28.oj-s-55d8ffef28.oj-s-55d8ffef28{width:170px}
.oj-s-5682c3ee98.oj-s-5682c3ee98.oj-s-5682c3ee98{animation-name:oj-slotb4;animation-delay:0s}
.oj-s-59d2699e7c.oj-s-59d2699e7c.oj-s-59d2699e7c{--x:190px;--y:0px;--oj-scene-delay:0.7s}
.oj-s-5c09ee159e.oj-s-5c09ee159e.oj-s-5c09ee159e{animation-name:oj-slotb8;animation-delay:-7.2s}
.oj-s-5e4c41778c.oj-s-5e4c41778c.oj-s-5e4c41778c{animation:oj-f4 12s ease-in-out -5s infinite}
.oj-s-5ee47c9385.oj-s-5ee47c9385.oj-s-5ee47c9385{width:46px}
.oj-s-5f50bbb8df.oj-s-5f50bbb8df.oj-s-5f50bbb8df{animation-name:oj-slotb10;animation-delay:-1.8s}
.oj-s-5f74688441.oj-s-5f74688441.oj-s-5f74688441{animation-name:oj-slotb7;animation-delay:-7.2s}
.oj-s-5f8e1e4663.oj-s-5f8e1e4663.oj-s-5f8e1e4663{animation:oj-draw 1.4s ease-out backwards;animation-delay:0.48s}
.oj-s-5fc970ae35.oj-s-5fc970ae35.oj-s-5fc970ae35{animation-name:oj-slotb1;animation-delay:-7.2s}
.oj-s-626bbdac68.oj-s-626bbdac68.oj-s-626bbdac68{animation-name:oj-slotb7;animation-delay:-3.6s}
.oj-s-635b7a23e6.oj-s-635b7a23e6.oj-s-635b7a23e6{animation:oj-f4 12s ease-in-out -2s infinite}
.oj-s-641f6b25cc.oj-s-641f6b25cc.oj-s-641f6b25cc{animation-name:oj-slotb4;animation-delay:-7.2s}
.oj-s-65e8ccbfca.oj-s-65e8ccbfca.oj-s-65e8ccbfca{animation:oj-f4 8s ease-in-out -7s infinite}
.oj-s-662c8e4334.oj-s-662c8e4334.oj-s-662c8e4334{width:150px}
.oj-s-6889b9ab57.oj-s-6889b9ab57.oj-s-6889b9ab57{animation-name:oj-slotb3;animation-delay:-3.6s}
.oj-s-6b5d4e84fb.oj-s-6b5d4e84fb.oj-s-6b5d4e84fb{animation:oj-f2 10s ease-in-out -6s infinite}
.oj-s-6c5cdb2fe5.oj-s-6c5cdb2fe5.oj-s-6c5cdb2fe5{animation:oj-in 0.5s ease-out backwards;animation-delay:0.48s}
.oj-s-6e0dad4c7f.oj-s-6e0dad4c7f.oj-s-6e0dad4c7f{animation:oj-f3 9s ease-in-out -5s infinite}
.oj-s-701d9e1e4a.oj-s-701d9e1e4a.oj-s-701d9e1e4a{animation-name:oj-slotb2;animation-delay:-3.6s}
.oj-s-71ce290442.oj-s-71ce290442.oj-s-71ce290442{--oj-scene-delay:0.15s}
.oj-s-733ca69ab5.oj-s-733ca69ab5.oj-s-733ca69ab5{animation-name:oj-slotb9;animation-delay:-1.8s}
.oj-s-78c33857e6.oj-s-78c33857e6.oj-s-78c33857e6{animation:oj-in 0.5s ease-out backwards;animation-delay:0.36s}
.oj-s-7943ee17e0.oj-s-7943ee17e0.oj-s-7943ee17e0{animation-name:oj-slotb5;animation-delay:0s}
.oj-s-794e6a8a41.oj-s-794e6a8a41.oj-s-794e6a8a41{animation-name:oj-slotb2;animation-delay:0s}
.oj-s-79593404be.oj-s-79593404be.oj-s-79593404be{--oj-scene-duration:3.2s}
.oj-s-79aef40572.oj-s-79aef40572.oj-s-79aef40572{animation-name:oj-slotb9;animation-delay:-3.6s}
.oj-s-79f1da79e2.oj-s-79f1da79e2.oj-s-79f1da79e2{animation-name:oj-slotb3;animation-delay:-5.4s}
.oj-s-7dd91a58e1.oj-s-7dd91a58e1.oj-s-7dd91a58e1{animation:oj-draw 1.4s ease-out backwards;animation-delay:0.36s}
.oj-s-7ded2a0513.oj-s-7ded2a0513.oj-s-7ded2a0513{animation-name:oj-slotb2;animation-delay:-7.2s}
.oj-s-7df6d2cd72.oj-s-7df6d2cd72.oj-s-7df6d2cd72{--oj-bar-h:33px}
.oj-s-7eaecc77d0.oj-s-7eaecc77d0.oj-s-7eaecc77d0{width:50%}
.oj-s-818be7249e.oj-s-818be7249e.oj-s-818be7249e{animation:oj-draw 1.4s ease-out backwards;animation-delay:0.6s}
.oj-s-82a47a5324.oj-s-82a47a5324.oj-s-82a47a5324{animation-name:oj-slotb1;animation-delay:-1.8s}
.oj-s-8aefaaa5fd.oj-s-8aefaaa5fd.oj-s-8aefaaa5fd{animation:oj-in 0.5s ease-out backwards;animation-delay:0.12s}
.oj-s-8b1b8b6a12.oj-s-8b1b8b6a12.oj-s-8b1b8b6a12{animation-name:oj-slotb4;animation-delay:-5.4s}
.oj-s-8b4b7346d8.oj-s-8b4b7346d8.oj-s-8b4b7346d8{animation-name:oj-slotb7;animation-delay:0s}
.oj-s-91eaf75130.oj-s-91eaf75130.oj-s-91eaf75130{animation-name:oj-slotb7;animation-delay:-5.4s}
.oj-s-95685376bf.oj-s-95685376bf.oj-s-95685376bf{animation-name:oj-slotb8;animation-delay:0s}
.oj-s-96d766814c.oj-s-96d766814c.oj-s-96d766814c{animation:oj-run 4.1s linear 1.5s infinite}
.oj-s-9b0d43b6dc.oj-s-9b0d43b6dc.oj-s-9b0d43b6dc{animation-name:oj-slotb3;animation-delay:-1.8s}
.oj-s-9ccc6208cc.oj-s-9ccc6208cc.oj-s-9ccc6208cc{animation:oj-f1 7s ease-in-out 0s infinite}
.oj-s-9fac31459f.oj-s-9fac31459f.oj-s-9fac31459f{animation:oj-f3 11s ease-in-out -4s infinite}
.oj-s-a0c9fe3d79.oj-s-a0c9fe3d79.oj-s-a0c9fe3d79{animation-name:oj-slotb5;animation-delay:-5.4s}
.oj-s-a612519691.oj-s-a612519691.oj-s-a612519691{animation-name:oj-slotb8;animation-delay:-1.8s}
.oj-s-a7db3ce89b.oj-s-a7db3ce89b.oj-s-a7db3ce89b{--oj-bar-h:17px}
.oj-s-aad3b64677.oj-s-aad3b64677.oj-s-aad3b64677{animation:oj-f4 8s ease-in-out -1s infinite}
.oj-s-addd634407.oj-s-addd634407.oj-s-addd634407{--oj-scene-delay:0.24s}
.oj-s-b5a8cc694c.oj-s-b5a8cc694c.oj-s-b5a8cc694c{animation:oj-f1 9s ease-in-out -8s infinite}
.oj-s-b6ab0ca936.oj-s-b6ab0ca936.oj-s-b6ab0ca936{animation-name:oj-slotb10;animation-delay:-3.6s}
.oj-s-b773f9f704.oj-s-b773f9f704.oj-s-b773f9f704{animation:oj-run 4.7s linear 2.5s infinite}
.oj-s-b95ab77a54.oj-s-b95ab77a54.oj-s-b95ab77a54{animation:oj-f3 7s ease-in-out 0s infinite}
.oj-s-befd7b188f.oj-s-befd7b188f.oj-s-befd7b188f{animation:oj-f1 7s ease-in-out -6s infinite}
.oj-s-c11723f10c.oj-s-c11723f10c.oj-s-c11723f10c{animation-name:oj-slotb4;animation-delay:-3.6s}
.oj-s-c140cbab17.oj-s-c140cbab17.oj-s-c140cbab17{animation-name:oj-slotb6;animation-delay:-1.8s}
.oj-s-c3a673be09.oj-s-c3a673be09.oj-s-c3a673be09{--oj-scene-delay:0.16s}
.oj-s-c5486f5403.oj-s-c5486f5403.oj-s-c5486f5403{animation:oj-f4 12s ease-in-out -8s infinite}
.oj-s-c8fa645eb4.oj-s-c8fa645eb4.oj-s-c8fa645eb4{animation:oj-draw 1.4s ease-out backwards;animation-delay:0.12s}
.oj-s-c9cd1c78fc.oj-s-c9cd1c78fc.oj-s-c9cd1c78fc{animation:oj-run 3.5s linear 0.5s infinite}
.oj-s-ca602b6601.oj-s-ca602b6601.oj-s-ca602b6601{--x:-175px;--y:-92px;--oj-scene-delay:0s}
.oj-s-cb11c6ce49.oj-s-cb11c6ce49.oj-s-cb11c6ce49{animation:oj-f1 11s ease-in-out -1s infinite}
.oj-s-cd2b97c43d.oj-s-cd2b97c43d.oj-s-cd2b97c43d{width:140px}
.oj-s-cdafbaeecc.oj-s-cdafbaeecc.oj-s-cdafbaeecc{animation:oj-f1 7s ease-in-out -3s infinite}
.oj-s-cf3d8903f1.oj-s-cf3d8903f1.oj-s-cf3d8903f1{animation-name:oj-slotb4;animation-delay:-1.8s}
.oj-s-d076f764a2.oj-s-d076f764a2.oj-s-d076f764a2{--h:60px;--h2:30px}
.oj-s-d334b57bfc.oj-s-d334b57bfc.oj-s-d334b57bfc{width:120px}
.oj-s-d3db975bed.oj-s-d3db975bed.oj-s-d3db975bed{width:64px}
.oj-s-d4b431d35d.oj-s-d4b431d35d.oj-s-d4b431d35d{animation:oj-f2 10s ease-in-out 0s infinite}
.oj-s-d741e9f24e.oj-s-d741e9f24e.oj-s-d741e9f24e{--oj-scene-delay:0s}
.oj-s-d7bd9b26a3.oj-s-d7bd9b26a3.oj-s-d7bd9b26a3{animation-name:oj-slotb10;animation-delay:-5.4s}
.oj-s-d8757c4d45.oj-s-d8757c4d45.oj-s-d8757c4d45{animation:oj-f2 12s ease-in-out -2s infinite}
.oj-s-da0d0c5916.oj-s-da0d0c5916.oj-s-da0d0c5916{animation-name:oj-slotb7;animation-delay:-1.8s}
.oj-s-da5914331a.oj-s-da5914331a.oj-s-da5914331a{animation-name:oj-slotb9;animation-delay:-7.2s}
.oj-s-dc9eac3f89.oj-s-dc9eac3f89.oj-s-dc9eac3f89{width:190px}
.oj-s-e0deee27eb.oj-s-e0deee27eb.oj-s-e0deee27eb{animation:oj-f2 12s ease-in-out -8s infinite}
.oj-s-e2e567d7c0.oj-s-e2e567d7c0.oj-s-e2e567d7c0{--h:24px;--h2:48px}
.oj-s-e445f214c5.oj-s-e445f214c5.oj-s-e445f214c5{--oj-scene-delay:0.3s}
.oj-s-e581bd87fc.oj-s-e581bd87fc.oj-s-e581bd87fc{--oj-scene-delay:0.1s}
.oj-s-e7aebaa6e1.oj-s-e7aebaa6e1.oj-s-e7aebaa6e1{--oj-scene-delay:0.32s}
.oj-s-e829533e75.oj-s-e829533e75.oj-s-e829533e75{animation-name:oj-slotb5;animation-delay:-3.6s}
.oj-s-e8b011ec4a.oj-s-e8b011ec4a.oj-s-e8b011ec4a{--oj-scene-delay:0.08s}
.oj-s-e96a83fb36.oj-s-e96a83fb36.oj-s-e96a83fb36{animation-name:oj-slotb2;animation-delay:-1.8s}
.oj-s-ed5b3ff292.oj-s-ed5b3ff292.oj-s-ed5b3ff292{--x:-175px;--y:92px;--oj-scene-delay:1.4s}
.oj-s-ed725f6c7a.oj-s-ed725f6c7a.oj-s-ed725f6c7a{animation-name:oj-slotb1;animation-delay:0s}
.oj-s-f5008936cd.oj-s-f5008936cd.oj-s-f5008936cd{animation:oj-f4 10s ease-in-out -3s infinite}
.oj-s-f62899c8eb.oj-s-f62899c8eb.oj-s-f62899c8eb{animation:oj-run 3.2s linear 0s infinite}
.oj-s-f6f5c2097b.oj-s-f6f5c2097b.oj-s-f6f5c2097b{--h:18px;--h2:40px}
.oj-s-f8492bed99.oj-s-f8492bed99.oj-s-f8492bed99{animation-name:oj-slotb10;animation-delay:0s}
.oj-s-f8519b3bb7.oj-s-f8519b3bb7.oj-s-f8519b3bb7{--oj-scene-delay:0.6s}
.oj-s-fc4006fd40.oj-s-fc4006fd40.oj-s-fc4006fd40{animation:oj-f4 10s ease-in-out 0s infinite}
.oj-s-fc9c1b2112.oj-s-fc9c1b2112.oj-s-fc9c1b2112{width:90%}
.oj-s-fd97d34385.oj-s-fd97d34385.oj-s-fd97d34385{animation:oj-f1 11s ease-in-out -4s infinite}
.oj-s-ff37302ce2.oj-s-ff37302ce2.oj-s-ff37302ce2{animation-name:oj-slotb0;animation-delay:0s}