/* The look of zabsoft.com, dark only (spec, «Визуальная система»; approved home mockup v11). There is no light theme and no
   theme switch: the snakes on the grid are not seen on a light background.
   No purple, violet or blue on the site (the owner, 23 Oct 2026): the accents are the brand's turquoise (--teal, the logo's link)
   and a lighter mint (--mint) for labels, links and highlights where the mockup had periwinkle; the grid's lines are a
   faint teal-grey, as faint as the periwinkle ones were. tests/lint/colours.test.mjs keeps blue and violet out of the built CSS,
   the social pictures' template and the snakes, and every accent readable on --bg. */

/* Headings: ZabSoft Display. Letters unique to Cyrillic come from the -cyr half; the rest of the face is declared last, so it wins. */
@font-face { font-family:'ZabSoft Display'; src:url('/_astro/zabsoft-display-cyr.Dc9zebRF.woff2') format('woff2'); font-weight:400; font-style:normal; font-display:swap; unicode-range:U+0400-045F, U+0490-0491, U+2116; }
@font-face { font-family:'ZabSoft Display'; src:url('/_astro/zabsoft-display.xnP2PZYs.woff2') format('woff2'); font-weight:400; font-style:normal; font-display:swap; }
/* Text: IBM Plex Sans 400 and 600; labels: JetBrains Mono 400. The files are @fontsource's (5.3.0), Latin and Cyrillic with
   their -ext halves and the same unicode-range, but only as woff2: @fontsource's own CSS adds a .woff copy of each, which every
   browser of today skips and the cloud does not serve (src/web/landing.ts types .woff2 only). */
@font-face { font-family:'IBM Plex Sans'; src:url('/_astro/ibm-plex-sans-cyrillic-ext-400-normal.g30qAdWV.woff2') format('woff2'); font-weight:400; font-style:normal; font-display:swap; unicode-range:U+0460-052F,U+1C80-1C8A,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F; }
@font-face { font-family:'IBM Plex Sans'; src:url('/_astro/ibm-plex-sans-cyrillic-400-normal.DZqxrq2p.woff2') format('woff2'); font-weight:400; font-style:normal; font-display:swap; unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116; }
@font-face { font-family:'IBM Plex Sans'; src:url('/_astro/ibm-plex-sans-latin-ext-400-normal.C5H60-Va.woff2') format('woff2'); font-weight:400; font-style:normal; font-display:swap; unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF; }
@font-face { font-family:'IBM Plex Sans'; src:url('/_astro/ibm-plex-sans-latin-400-normal.CDDApCn2.woff2') format('woff2'); font-weight:400; font-style:normal; 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:'IBM Plex Sans'; src:url('/_astro/ibm-plex-sans-cyrillic-ext-600-normal.DUMzJB7m.woff2') format('woff2'); font-weight:600; font-style:normal; font-display:swap; unicode-range:U+0460-052F,U+1C80-1C8A,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F; }
@font-face { font-family:'IBM Plex Sans'; src:url('/_astro/ibm-plex-sans-cyrillic-600-normal.71GNu3SW.woff2') format('woff2'); font-weight:600; font-style:normal; font-display:swap; unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116; }
@font-face { font-family:'IBM Plex Sans'; src:url('/_astro/ibm-plex-sans-latin-ext-600-normal.DOrvGEcy.woff2') format('woff2'); font-weight:600; font-style:normal; font-display:swap; unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF; }
@font-face { font-family:'IBM Plex Sans'; src:url('/_astro/ibm-plex-sans-latin-600-normal.CuJfVYMP.woff2') format('woff2'); font-weight:600; font-style:normal; 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:'JetBrains Mono'; src:url('/_astro/jetbrains-mono-cyrillic-ext-400-normal.C_uLvvQ5.woff2') format('woff2'); font-weight:400; font-style:normal; font-display:swap; unicode-range:U+0460-052F,U+1C80-1C8A,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F; }
@font-face { font-family:'JetBrains Mono'; src:url('/_astro/jetbrains-mono-cyrillic-400-normal.BEIGL1Tu.woff2') format('woff2'); font-weight:400; font-style:normal; font-display:swap; unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116; }
@font-face { font-family:'JetBrains Mono'; src:url('/_astro/jetbrains-mono-latin-ext-400-normal.Bc8Ftmh3.woff2') format('woff2'); font-weight:400; font-style:normal; font-display:swap; unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF; }
@font-face { font-family:'JetBrains Mono'; src:url('/_astro/jetbrains-mono-latin-400-normal.V6pRDFza.woff2') format('woff2'); font-weight:400; font-style:normal; 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; }

:root { color-scheme:dark;
  --bg:#05070f; --ink:#e9edf7; --mint:#7ee8c9; --teal:#00d6b4; --line:rgba(120,160,155,.075);
  --glass:linear-gradient(135deg, rgba(255,255,255,.075), rgba(255,255,255,.02)); --edge:rgba(255,255,255,.13);
  /* The surfaces that stand on their own: the phone's menu, the drawn windows of ChatGPT and Claude, a picture's box until it
     loads. A near-black a step lighter than the page, neutral as the page is: no navy (the owner, 23 Oct 2026). */
  --panel:#0b0d11;
  --display:'ZabSoft Display', 'Arial Black', sans-serif; --mono:'JetBrains Mono', monospace; }
* { box-sizing:border-box; }
html, body { margin:0; background:var(--bg); color:var(--ink); font-family:'IBM Plex Sans', sans-serif; font-size:16px; line-height:1.5; }
a { color:inherit; text-decoration:none; }
button { font:inherit; color:inherit; }
:focus-visible { outline:2px solid var(--mint); outline-offset:3px; border-radius:6px; }

/* The background: lines of a 44 px grid, fixed under the content. */
.grid { position:fixed; inset:0; z-index:0; pointer-events:none; background-image:linear-gradient(var(--line) 1px, transparent 1px), linear-gradient(90deg, var(--line) 1px, transparent 1px); background-size:44px 44px; }
/* The snakes run on a canvas over the grid (scripts/background.js). It is empty until the script draws, and stays empty under "reduce motion".
   The script sets its width and height to the window's (not 100vw / 100vh: on a phone 100vh is taller than the window now). */
canvas.snakes { position:fixed; inset:0; pointer-events:none; z-index:0; }
main, header, footer { position:relative; z-index:1; }
/* Blocks that drift with the scroll and the pointer: the script sets their translate. The layers are made ready only while motion is allowed. */
@media (prefers-reduced-motion: no-preference) {
  [data-speed], [data-depth] { will-change:translate; }
}
/* The header's menu opens over the page. */
header { z-index:5; }

/* Layout */
.wrap { width:min(1200px, 100%); margin:0 auto; padding:0 clamp(18px, 4vw, 56px); }
section.wrap { padding-top:91px; padding-bottom:91px; }
.mono { font-family:var(--mono); font-size:12px; letter-spacing:.1em; text-transform:uppercase; opacity:.7; }
h1, h2, h3 { font-family:var(--display); font-weight:400; margin:0; }
h1 { font-size:clamp(40px, 5.2vw, 70px); line-height:1.0; }
h2 { font-size:clamp(30px, 3.6vw, 48px); line-height:1.04; margin:10px 0 21px; }
h3 { font-size:20px; line-height:1.15; margin-bottom:8px; }
/* A word longer than the line («менеджерам» in a post's title on a 320 px phone) breaks inside the heading instead of pushing the
   page sideways, but on a phone only (640 px and narrower). On a phone a long word of a heading (ten letters or more) is hyphenated
   by the page's language (lang on <html>), the shorter ones wrap whole as before; a word that has no place for a hyphen breaks
   anywhere. A browser that cannot keep hyphens to the long words (no hyphenate-limit-chars) hyphenates none, and breaks only what
   does not fit. Wider screens never break a word of a heading: it wraps between words, and a heading that would not fit gets a
   smaller size (tests/e2e/headings.spec.mjs reads every word of every heading from 641 to 1440 px). overflow-wrap is inherited, so
   the wider screens' "normal" is set on the headings themselves: a card (.kpost) or a post's text (.md) that breaks anywhere would
   pass that on to the headings in it. */
h1, h2, h3 { overflow-wrap:normal; }
@media (max-width:640px) {
  h1, h2, h3 { overflow-wrap:anywhere; }
  @supports (hyphenate-limit-chars:10 4 4) {
    h1, h2, h3 { -webkit-hyphens:auto; hyphens:auto; hyphenate-limit-chars:10 4 4; }
  }
}
p { margin:0; opacity:.86; }
.glass { background:var(--glass); border:1px solid var(--edge); border-radius:20px; }
.btn { display:inline-block; padding:14px 22px; border-radius:12px; background:var(--ink); color:var(--bg); font-weight:600; transition:box-shadow .3s; }
.btn:hover { box-shadow:0 0 30px rgba(126,232,201,.4); }
/* The main button of a first screen is turquoise with dark text, as on the approved first screen, and so is the same call further
   down a page (components/TryFree.astro), the home page's closing call (components/Closing.astro) and the sign-up of a post's call
   to connect (components/Cta.astro); every other .btn and the header's button stay light. */
.hero .btn, .try .btn, .closing .btn, .incta .btn { background:var(--teal); color:var(--bg); }
.hero .btn:hover, .try .btn:hover, .closing .btn:hover, .incta .btn:hover { box-shadow:0 0 30px rgba(0,214,180,.45); }
.ghost { display:inline-block; padding:13px 20px; border-radius:12px; border:1px solid rgba(233,237,247,.3); transition:background .3s; }
.ghost:hover { background:rgba(255,255,255,.06); }
.chip { display:inline-block; padding:6px 12px; border-radius:999px; border:1px solid rgba(255,255,255,.18); font-size:13px; margin:0 6px 8px 0; }
.actions { display:flex; flex-wrap:wrap; align-items:center; gap:10px; }

/* Header (mockup, lines 38–41). The bar is one row at every width: its links need about 990 px in Russian (890 in English), and
   1010 px on the cloud's pages for a signed-in reader, whose «Войти» the cloud turns into «Кабинет» (src/web/site-frame.ts of the
   repository), so from 1040 px down they fold into the menu, and the button stays (tests/lint/fit.test.mjs measures the row at the
   widths around it, signed out and signed in). */
header .bar { display:flex; align-items:center; justify-content:space-between; gap:16px; padding:22px 0; }
/* The logo is the brand package's inline drawing: the letters take the link's colour, the second link of the chain the accent.
   Its height is 26 px (24 to 32 allowed), 22 px on a phone; never under 20: the gaps of the chain run together. */
.logo { display:block; color:var(--ink); --apiunicon-accent:var(--teal); }
.logo svg { display:block; height:26px; width:auto; }
header nav { display:flex; align-items:center; }
nav a { margin-left:24px; opacity:.8; font-size:15px; transition:opacity .2s; }
nav a:hover { opacity:1; }
nav a.cta { opacity:1; padding:9px 16px; border-radius:10px; background:var(--ink); color:var(--bg); font-weight:600; white-space:nowrap; }
nav a.lang { font-family:var(--mono); font-size:13px; letter-spacing:.1em; }
.menu { display:none; position:relative; margin-left:12px; }
.menu summary { list-style:none; display:flex; flex-direction:column; justify-content:center; gap:5px; width:40px; height:40px; padding:0 11px; border-radius:10px; border:1px solid rgba(255,255,255,.18); cursor:pointer; }
.menu summary::-webkit-details-marker { display:none; }
.menu summary i { display:block; height:2px; border-radius:1px; background:var(--ink); transition:transform .3s; }
.menu[open] summary i:first-child { transform:translateY(3.5px) rotate(45deg); }
.menu[open] summary i:last-child { transform:translateY(-3.5px) rotate(-45deg); }
.menu .drop { position:absolute; right:0; top:calc(100% + 10px); z-index:10; min-width:230px; display:flex; flex-direction:column; padding:8px;
  background:var(--panel); border:1px solid var(--edge); border-radius:16px; }
.menu .drop a { margin:0; padding:11px 14px; border-radius:10px; opacity:.9; }
.menu .drop a:hover { background:rgba(255,255,255,.06); opacity:1; }
/* The button's second place, the last line of the menu: shown only where the bar has no room for the button (below). */
.menu .drop a.start { display:none; }
/* The directions under "What to connect" in the phone's menu: the six of the home page and the line about any other service,
   indented under the link, as a plain list. */
.menu .drop .sub { list-style:none; display:flex; flex-direction:column; margin:0 0 6px 14px; padding:0 0 0 6px; border-left:1px solid rgba(255,255,255,.1); }
.menu .drop .sub a { display:block; padding:7px 12px; font-size:14px; }
.menu .drop .sub a.any { margin-top:2px; opacity:.75; }
.menu .drop .sub a.any:hover { opacity:1; }

/* The panel of the six directions under "What to connect", where the links are in the bar (components/Header.astro). It hangs from
   the foot of the bar at its right edge, as wide as the bar allows up to 720 px, so it stays in the window at every width where the
   links are in the bar (wider than 1040 px) and covers none of the bar. CSS opens it on hover and on focus inside; it closes a
   moment after the pointer leaves (visibility waits .3 s), so the pointer can travel from the link to it.
   Escape shuts it (scripts/menu.js sets data-shut) until the pointer or the focus comes back. The outer box reaches 20 px up into
   the bar's own padding, under the links and the button, so the way down to the tiles is short. */
header .bar { position:relative; }
.dirs { display:inline; }
.dirs > a::after { content:''; display:inline-block; width:5px; height:5px; margin:0 1px 3px 8px; border-right:1.5px solid currentColor; border-bottom:1.5px solid currentColor; rotate:45deg; opacity:.7; }
.mega { position:absolute; right:0; top:calc(100% - 20px); z-index:10; width:min(720px, 100%); padding-top:20px;
  visibility:hidden; opacity:0; transition:opacity .2s .1s, visibility 0s linear .3s; }
.dirs:hover .mega, .dirs:focus-within .mega { visibility:visible; opacity:1; transition-delay:0s; }
.dirs[data-shut] .mega { visibility:hidden; opacity:0; transition:none; }
/* Where motion is welcome, the panel also slides down a little as it opens. Only the panel itself moves: the outer box and its
   20 px reach into the bar stay put, so that reach ends 2 px under the foot of the bar's tallest item (the button) at every moment,
   and every link of the bar keeps the pointer while the panel is open (tests/e2e/header.spec.mjs). */
@media (prefers-reduced-motion: no-preference) {
  .mega-in { translate:0 -6px; transition:translate .2s .1s; }
  .dirs:hover .mega-in, .dirs:focus-within .mega-in { translate:0 0; transition-delay:0s; }
}
.mega-in { padding:12px; background:rgba(5,7,15,.94); border:1px solid var(--edge); border-radius:20px; backdrop-filter:blur(18px); -webkit-backdrop-filter:blur(18px); }
/* The tiles are small cards of the home page's directions grid (.sol): the same glass, edge and radius, closer padding, the name in
   the heading face at 17 px and the services in the muted grey; on hover the edge and the name turn green, as a card's would, with
   no glow. */
.tiles { list-style:none; margin:0; padding:0; display:grid; grid-template-columns:repeat(3, 1fr); grid-auto-rows:1fr; gap:10px; }
nav .tiles a { display:flex; flex-direction:column; gap:6px; height:100%; margin:0; padding:18px 20px; opacity:1; transition:border-color .2s; }
nav .tiles a:hover { border-color:rgba(0,214,180,.55); }
.tiles b { font-family:var(--display); font-weight:400; font-size:17px; line-height:1.2; transition:color .2s; }
.tiles a:hover b { color:var(--teal); }
.tiles span { font-size:13px; line-height:1.45; opacity:.6; }
.tiles span i { font-style:normal; white-space:nowrap; }
/* The owner's line under the tiles: muted, its arrow green on hover. */
nav .mega a.any { display:block; margin:12px 0 0; padding:14px 20px 4px; border-top:1px solid rgba(255,255,255,.08); opacity:.65; transition:opacity .2s; }
nav .mega a.any:hover { opacity:1; }
.any .arr { display:inline-block; transition:color .2s; }
a.any:hover .arr { color:var(--teal); }

@media (max-width:1040px) {
  header nav .links { display:none; }
  .menu { display:block; }
}
@media (max-width:760px) {
  .logo svg { height:22px; }
  nav a.cta { margin-left:0; padding:9px 12px; font-size:14px; }
}
/* Logo (22 px), button and the menu's square do not fit in one row of a phone this narrow, in Russian least of all, so the header
   keeps the logo and the menu and the button goes into the menu. The hero keeps its own turquoise button. */
@media (max-width:440px) {
  nav a.cta { display:none; }
  .menu { margin-left:0; }
  .menu .drop a.start { display:block; margin-top:6px; text-align:center; background:var(--ink); color:var(--bg); font-weight:600; opacity:1; }
  .menu .drop a.start:hover { background:var(--ink); }
}

/* First screen: the text on the left; the example chat on the right, under the text on a phone. The hint stands 22 px above the foot
   of the first screen and is 58 px tall; 112 px under the content keeps it 32 px clear of the content where the window is shorter
   than the content (1280 x 800, 1024 x 768): the chat sinks toward it by up to 24 px as the page scrolls (lib/parallax.js). */
.hero { display:grid; grid-template-columns:1.05fr .95fr; gap:72px; align-items:center; padding-top:40px; padding-bottom:112px; min-height:calc(100vh - 82px); min-height:calc(100svh - 82px); position:relative; }
.hero h1 { margin-top:14px; }
.hero h1 .accent { color:var(--teal); }
.hero .lede { font-size:19px; margin:22px 0 30px; max-width:580px; }
.hero .note { margin-top:14px; font-size:14px; opacity:.6; }
/* The pill above the label that leads to the source code (components/Hero.astro): the GitHub mark and its words, and, once
   scripts/github.js has the count, a thin rule and the star with the number in turquoise. As small as a chip, never on two lines.
   The part for the count is hidden until then and takes no room, so nothing around the pill moves when it appears. */
.gh { display:inline-flex; align-items:center; gap:8px; max-width:100%; margin-bottom:22px; padding:6px 14px 6px 11px; border-radius:999px; border:1px solid rgba(255,255,255,.14); background:rgba(255,255,255,.035); font-size:13px; line-height:1.4; white-space:nowrap; transition:border-color .3s, background .3s; }
.gh:hover { border-color:rgba(255,255,255,.3); background:rgba(255,255,255,.06); }
.gh svg { flex:none; width:16px; height:16px; fill:currentColor; }
.gh-stars { display:inline-flex; align-items:center; gap:5px; padding-left:10px; border-left:1px solid rgba(255,255,255,.18); color:var(--teal); }
.gh-stars[hidden] { display:none; }
.gh-stars svg { width:13px; height:13px; stroke:currentColor; stroke-width:1.2; stroke-linejoin:round; }
.gh-stars b { font-weight:400; font-variant-numeric:tabular-nums; }
/* On the narrowest phones the pill gives up some of its spacing, so that a count of five digits still fits; and should anything make it
   wider than its column (a larger text size), its words shrink to an ellipsis rather than stand over the edge of the window. */
.gh > span:not(.gh-stars) { min-width:0; overflow:hidden; text-overflow:ellipsis; }
@media (max-width:360px) {
  .gh { gap:6px; padding-left:9px; padding-right:12px; }
  .gh-stars { gap:4px; padding-left:8px; }
}
@media (max-width:900px) {
  .hero { grid-template-columns:1fr; gap:40px; padding-bottom:72px; }
}
/* The chat window's row of connected services (mockup, lines 46–47): turquoise on translucent turquoise. The window is
   components/ChatWindow.astro, which writes <div class="linked"><span>● Wildberries</span>…</div>. */
.linked { display:flex; gap:8px; flex-wrap:wrap; margin-bottom:14px; }
.linked span { font-size:12px; padding:4px 10px; border-radius:999px; background:rgba(0,214,180,.12); color:var(--teal); }
/* The hint under the first screen: its line runs down and fades (mockup, lines 102–104). Under "reduce motion" the line stands still. */
.scroll-hint { position:absolute; left:50%; bottom:22px; translate:-50% 0; display:flex; flex-direction:column; align-items:center; gap:8px; opacity:.55; font-family:var(--mono); font-size:11px; letter-spacing:.12em; text-transform:uppercase; }
.scroll-hint i { width:1px; height:34px; background:linear-gradient(var(--ink), transparent); animation:hint 2.2s ease-in-out infinite; transform-origin:top; }
@keyframes hint { 0% { transform:scaleY(0); opacity:0; } 40% { transform:scaleY(1); opacity:1; } 100% { transform:scaleY(1); opacity:0; } }
@media (prefers-reduced-motion: reduce) {
  .scroll-hint i { animation:none; }
}
/* One column is taller than the window, so the hint under it would stand over the chat as the chat drifts down: it goes. So it does
   in a short window (a laptop's 1280 x 720 or a phone held sideways): the first screen is taller than the window there too. */
@media (max-width:900px), (max-height:720px) {
  .scroll-hint { display:none; }
}

/* Read out to screen readers only. */
.sr { position:absolute; width:1px; height:1px; margin:-1px; padding:0; overflow:hidden; clip-path:inset(50%); white-space:nowrap; border:0; }
q { quotes:"«" "»"; }
:lang(en) q { quotes:"\201C" "\201D"; }

/* The example chat of a first screen (components/ChatWindow.astro; mockup v11, lines 45–52, sellers mockup, lines 46–52). The
   line under the window says it is an example. */
.chatbox { margin:0; min-width:0; }
.chat { padding:22px; }
.chat > .mono { margin-bottom:12px; }
.msg { padding:12px 16px; border-radius:14px; margin-bottom:12px; font-size:15px; overflow-wrap:anywhere; }
.msg:last-child { margin-bottom:0; }
.msg.me { background:rgba(126,232,201,.12); margin-left:56px; }
.msg.ai { background:rgba(255,255,255,.05); margin-right:20px; }
.msg ul { margin:8px 0; padding-left:18px; }
.msg table { width:100%; border-collapse:collapse; margin:10px 0; font-size:14px; }
.msg th, .msg td { text-align:left; padding:5px 6px; border-bottom:1px solid rgba(255,255,255,.08); }
.msg th { font-weight:600; opacity:.7; font-size:12px; }
/* The action the AI offers in an example chat: turquoise, as on the approved first screen. */
.msg .ok { margin-top:8px; opacity:1; color:var(--teal); }
.chatbox figcaption { margin-top:12px; text-align:right; opacity:.5; }
@media (max-width:440px) {
  .chat { padding:18px; }
  .msg.me { margin-left:28px; }
  .msg.ai { margin-right:0; }
}

/* A grid of cards: 36 px under its heading (it collapses with the h2's 21 px), cards of one size that move together. A grid drifts
   no more than 24 px (lib/parallax.js), so it never comes within 12 px of its heading. */
.steps, .asks, .posts, .sol { display:grid; margin-top:36px; grid-auto-rows:1fr; align-items:stretch; }

/* The three steps (mockup v11, lines 54–56 and 106–107). */
.steps { grid-template-columns:repeat(3, 1fr); gap:20px; }
.step { padding:34px; height:100%; }
.step .n { font-family:var(--display); font-size:44px; color:var(--mint); line-height:1; margin-bottom:16px; }

/* Where to add APIUniCon: the switch and the two halves (mockup v11, lines 76–95 and 108–112). The build writes both halves shown
   and the switch hidden; scripts/tabs.js shows the switch and hides the other half. */
.tabs { display:flex; flex-wrap:wrap; gap:8px; margin-top:45px; }
.tabs[hidden] { display:none; }
.tab { padding:10px 18px; border-radius:12px; border:1px solid rgba(255,255,255,.18); background:none; cursor:pointer; font-weight:600; transition:background .3s, color .3s; }
.tab:hover { background:rgba(255,255,255,.06); }
.tab[aria-selected="true"] { background:var(--ink); color:var(--bg); border-color:transparent; }
.setup { display:grid; grid-template-columns:1fr 1fr; gap:20px; margin-top:20px; align-items:stretch; }
.setup[hidden] { display:none; }
/* Without the script both halves stand one under the other, and the first one under the steps, as far as the switch would be. */
.steps + .setupbox > .tabs[hidden] + .setup { margin-top:45px; }
.howto { padding:36px; min-width:0; }
.howto > .mono { margin-bottom:14px; }
.howto ol { margin:0; padding-left:22px; }
.howto li { margin-bottom:16px; }
.howto b.ui, .tcard b.ui { font-weight:600; padding:1px 7px; border-radius:6px; background:rgba(126,232,201,.14); white-space:nowrap; }
.howto code, .win code { font-family:var(--mono); font-size:13px; overflow-wrap:anywhere; }
.howto code { padding:1px 6px; border-radius:6px; background:rgba(0,0,0,.4); }
.hint { margin-top:10px; font-size:13px; opacity:.6; }
.plannote { margin:8px 0 2px; font-size:13px; line-height:1.5; opacity:.75; }
.shot { padding:26px; display:flex; flex-direction:column; justify-content:center; min-width:0; }
/* The drawn window of ChatGPT or Claude: its fields, the address lit in turquoise, its button. */
.win { border-radius:14px; background:var(--panel); border:1px solid rgba(255,255,255,.12); overflow:hidden; }
.win .top { display:flex; gap:6px; padding:10px 12px; border-bottom:1px solid rgba(255,255,255,.08); }
.win .top i { width:10px; height:10px; border-radius:50%; background:rgba(255,255,255,.18); display:block; }
.win .form { padding:18px; display:flex; flex-direction:column; gap:12px; font-size:14px; }
.win .field .name { display:block; font-size:12px; opacity:.6; margin-bottom:4px; }
.win .field div { padding:9px 12px; border-radius:9px; border:1px solid rgba(255,255,255,.16); background:rgba(255,255,255,.03); }
.win .field.lit div { outline:2px solid var(--teal); outline-offset:2px; }
.win .fakebtn { align-self:flex-end; padding:9px 16px; border-radius:10px; background:var(--ink); color:var(--bg); font-weight:600; }
.more-link { margin-top:25px; }

/* What to ask: four cards, the question at the foot of each (sellers mockup, lines 60–62). */
.asks { grid-template-columns:repeat(4, 1fr); gap:18px; }
.ask { padding:32px; height:100%; display:flex; flex-direction:column; gap:12px; }
.ask h3 { margin:0; }
.ask q { display:block; margin-top:auto; font-size:15px; opacity:.85; }
/* What the AI can do, with the person's "yes" (sellers mockup, line 63): the words on the left, the actions on the right. Under the
   grid by as much as the grid stands under its heading, so the grid's drift never reaches it. */
.act { margin-top:36px; padding:36px; display:grid; grid-template-columns:1fr 1fr; gap:24px 48px; align-items:center; }
.act h3 { margin:12px 0 8px; font-size:24px; }
.act ul { margin:0; padding:0; list-style:none; display:grid; gap:10px; }
.act li { position:relative; padding-left:22px; }
.act li::before { content:''; position:absolute; left:2px; top:.62em; width:8px; height:8px; border-radius:50%; background:var(--mint); }
/* Under the promise of actions (the home page's first block, a solution's .act, a post's call to connect): which plans may change
   data, small and quiet. .incta p (blog.css) would make it a paragraph of the call, so it is named here too. */
p.access, .incta p.access { margin-top:14px; font-size:14px; opacity:.65; }

/* The services of a direction, with their notes, beside the line "almost any service" (sellers mockup, lines 64 and 129–142). */
.split2 { display:grid; grid-template-columns:1fr 1fr; gap:24px 48px; align-items:start; }
.split2 > div > p { max-width:520px; }
.svc { margin:0; padding:12px 32px; list-style:none; }
.svc li { display:flex; flex-direction:column; gap:2px; padding:16px 0; border-bottom:1px solid rgba(255,255,255,.08); }
.svc li:last-child { border-bottom:0; }
.svc b { font-weight:600; }
.svc .note { font-size:15px; opacity:.75; }

/* The six directions on the home page: three cards a row, each one a link, the question and "Learn more" at its foot (mockup v11,
   lines 58–62 and 113–114; the mockup's six-column grid with cards two wide is these three columns). Six cards make the tallest grid
   of the home page, one that reaches its full drift while its heading is in view: it stands 44 px under the heading, 20 clear. */
.sol { grid-template-columns:repeat(3, 1fr); gap:18px; margin-top:44px; }
.sol a { padding:32px; gap:16px; height:100%; display:flex; flex-direction:column; transition:transform .5s cubic-bezier(.2,.8,.2,1); }
.sol a:hover { transform:translateY(-4px); }
.sol q { display:block; font-size:15px; opacity:.85; }
.sol .more { margin-top:auto; color:var(--mint); font-size:14px; font-weight:600; }

/* The three blocks under them: two side by side, the third under both with its button at the right (mockup v11, lines 63–64 and 115–116,
   233–242). */
.two { display:grid; grid-template-columns:1fr 1fr; gap:20px; }
.card { padding:36px; }
.card h3 { margin-top:12px; }
.card.wide { margin-top:20px; display:flex; justify-content:space-between; align-items:center; gap:24px; }
.card.wide > div { min-width:0; }
.card.wide .ghost { flex:none; }

/* A post's picture (components/PostImage.astro): a box of 16:9 that the picture covers, so the box keeps its place while the picture
   loads and the picture is cut, never stretched; the near-black of the menus shows until it comes. Each place frames it with the
   thin edge of the cards: the blog's cards and lead card and a post's page in blog.css, the row of posts below. */
.pimg { position:relative; overflow:hidden; width:100%; aspect-ratio:16/9; background:var(--panel); }
.pimg img { position:absolute; inset:0; display:block; width:100%; height:100%; object-fit:cover; }

/* Posts of a direction in one row (mockup v11, lines 65–67 and 117–118). */
.posts { grid-template-columns:repeat(3, 1fr); gap:18px; }
/* The card is a.post: a post's own page is <article class="post">, which takes none of this (no padding, no lift on hover). Its
   picture, small, is the first thing inside its padding, then the services and the title; the reading time keeps to the foot. */
a.post { padding:32px; min-height:220px; height:100%; display:flex; flex-direction:column; gap:16px; transition:transform .5s cubic-bezier(.2,.8,.2,1); }
a.post:hover { transform:translateY(-4px); }
a.post .pimg { flex:none; border-radius:12px; border:1px solid var(--edge); margin-bottom:4px; }
a.post h3 { font-size:21px; margin:0; }
a.post > :last-child { margin-top:auto; }

/* Questions and answers that open on a click (<details>), on every page that has them. */
section.wrap > .faq { margin-top:28px; }
.faq details { border-bottom:1px solid rgba(255,255,255,.12); }
.faq summary { position:relative; list-style:none; cursor:pointer; padding:18px 44px 18px 0; font-weight:600; font-size:18px; }
.faq summary::-webkit-details-marker { display:none; }
.faq summary::after { content:'+'; position:absolute; right:6px; top:12px; font-size:26px; font-weight:300; transition:transform .4s cubic-bezier(.2,.8,.2,1); }
.faq details[open] summary::after { transform:rotate(45deg); }
.faq details p { padding:0 0 20px; max-width:820px; }
.faq details a { color:var(--mint); text-decoration:underline; text-underline-offset:3px; }

/* The call to try the service further down a page (components/TryFree.astro): a card of glass, its line (and heading, where it has
   one) on the left, the turquoise button on the right; on a phone the button goes under the line. The sections around it give the
   room above and below it; the last one of a page keeps 51 px, which the footer's 40 px of margin make the 91 px of a section. */
section.try { padding-top:0; padding-bottom:0; }
main > section.try:last-child { padding-bottom:51px; }
.tryfree { display:flex; justify-content:space-between; align-items:center; gap:20px 32px; padding:32px 36px; }
.tryfree > div { min-width:0; }
.tryfree b { display:block; margin-bottom:8px; font-family:var(--display); font-weight:400; font-size:24px; line-height:1.15; }
.tryfree p { font-size:17px; }
.tryfree .btn { flex:none; }

/* The home page's closing call (components/Closing.astro): one panel across the content, roomier than a card and solid, so it stands
   apart from the glass cards above it: the near-black of the drawn windows under the glass's sheen, the thin edge and the radius of
   the cards. The words and the button on the left, the field where the questions are typed on the right; one column under 900 px,
   the field under the words. The questions above give the room over it; at the foot of the page it keeps 51 px, which the footer's
   40 px of margin make the 91 px of a section. */
section.closing { padding-top:0; padding-bottom:51px; }
.cpanel { position:relative; display:grid; grid-template-columns:minmax(0, 1.3fr) minmax(0, 1fr); align-items:center; gap:48px 64px;
  padding:clamp(28px, 5vw, 72px); background:var(--glass), var(--panel); }
.cpanel > :not(canvas) { position:relative; min-width:0; }
/* The snake round the edge: a canvas over the panel's border box (scripts/closing.js draws on the middle of the border), in the
   brand's turquoise, which the script reads from the canvas's colour. Empty without the script. */
canvas.rim { position:absolute; left:-1px; top:-1px; width:calc(100% + 2px); height:calc(100% + 2px); pointer-events:none; color:var(--teal); }
.ctext > .mono { color:var(--mint); opacity:1; }
/* The heading's lines are balanced: «Спросите / свой бизнес / прямо сейчас», not a word left alone on the last line. */
.cpanel h2 { font-size:clamp(34px, 4vw, 56px); line-height:1.02; margin:14px 0 20px; text-wrap:balance; }
.clede { font-size:19px; max-width:560px; }
/* The three steps: the time in the labels' face, in mint, in a column of its own; hairlines between them. */
.ctime { list-style:none; margin:30px 0 34px; padding:0; display:grid; grid-template-columns:max-content 1fr; column-gap:24px; }
.ctime li { display:grid; grid-column:1 / -1; grid-template-columns:subgrid; align-items:baseline; padding:13px 0; border-top:1px solid rgba(255,255,255,.09); }
.ctime li:last-child { border-bottom:1px solid rgba(255,255,255,.09); }
.ctime .t { font-family:var(--mono); font-size:13px; letter-spacing:.06em; color:var(--mint); white-space:nowrap; }
.ctime li > span:last-child { font-size:17px; }
/* The button, larger than the usual one, and the quiet link beside it. */
.cgo { display:flex; flex-wrap:wrap; align-items:center; gap:16px 28px; }
.closing .btn { padding:18px 32px; border-radius:14px; font-size:17px; }
.chow { font-weight:600; opacity:.72; transition:opacity .2s; }
.chow:hover { opacity:1; }
/* The reassurances: small, in a row that wraps, each with a green tick. */
.csure { list-style:none; margin:24px 0 0; padding:0; display:flex; flex-wrap:wrap; gap:8px 22px; font-size:14px; }
.csure li { display:flex; align-items:center; gap:7px; opacity:.85; }
.csure svg { flex:none; width:16px; height:16px; fill:none; stroke:var(--teal); stroke-width:1.9; stroke-linecap:round; stroke-linejoin:round; }
/* The window of the chat, in the glass of the site's example chats, with its field: every question stands in the same cell,
   invisible but one (.ctyped), so the field is as tall as the longest question at this width and does not move while they are
   typed. The green send arrow stands under the words at the right, as in the composer of ChatGPT or Claude on a computer, so the
   words have the field's whole width; on a phone it stands beside them, as in a phone's chat. The caret shows only while the
   script types. */
.cask { padding:24px 26px 22px; border-radius:20px; background:var(--glass); border:1px solid var(--edge); }
.cask > .mono { margin-bottom:12px; }
.cfield { display:flex; flex-direction:column; gap:10px; padding:22px 16px 16px 24px; border-radius:20px; background:var(--panel); border:1px solid rgba(255,255,255,.14); }
.clines { min-width:0; display:grid; padding-right:8px; font-size:clamp(18px, 1.55vw, 22px); line-height:1.4; }
.clines > * { grid-area:1 / 1; }
.cq { visibility:hidden; }
.caret { display:none; position:relative; }
.cpanel.typing .caret { display:inline; }
.caret::after { content:''; position:absolute; left:2px; top:.1em; width:2px; height:1.15em; border-radius:1px; background:var(--teal); }
.csend { flex:none; align-self:flex-end; display:grid; place-items:center; width:40px; height:40px; border-radius:50%; background:var(--teal); color:var(--bg); }
.csend svg { width:18px; height:18px; fill:none; stroke:currentColor; stroke-width:2; stroke-linecap:round; stroke-linejoin:round; }
/* Under the field: the direction of the question, and six marks, the one of the question lit. */
.cdir { display:flex; align-items:center; justify-content:space-between; gap:16px; margin-top:14px; font-family:var(--mono); font-size:12px; letter-spacing:.1em; text-transform:uppercase; }
.cname { min-width:0; color:var(--mint); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.ticks { flex:none; display:flex; gap:5px; }
.ticks i { display:block; width:16px; height:2px; border-radius:1px; background:rgba(255,255,255,.16); transition:background .3s; }
.ticks i.on { background:var(--teal); }
@media (prefers-reduced-motion: no-preference) {
  .cpanel.typing .cfield[data-phase="hold"] .caret::after, .cpanel.typing .cfield[data-phase="gap"] .caret::after { animation:caret 1.05s steps(1) infinite; }
}
@keyframes caret { 50% { opacity:0; } }
@media (max-width:900px) {
  .cpanel { grid-template-columns:minmax(0, 1fr); gap:44px; }
}
@media (max-width:640px) {
  .cpanel { padding:36px 22px 28px; }
  .cpanel h2 { margin-bottom:16px; }
  .clede { font-size:17px; }
  .ctime { margin:24px 0 28px; column-gap:18px; }
  .ctime li > span:last-child { font-size:16px; }
  .cask { padding:16px 14px 14px; border-radius:16px; }
  .clines { flex:1; padding-right:0; font-size:17px; line-height:1.38; }
  .cfield { flex-direction:row; align-items:flex-end; gap:12px; padding:16px 12px 12px 18px; border-radius:16px; }
  .csend { width:34px; height:34px; }
  .csend svg { width:16px; height:16px; }
  .ticks i { width:12px; }
}

@media (prefers-reduced-motion: reduce) {
  a.post, .sol a, .faq summary::after { transition:none; }
  a.post:hover, .sol a:hover { transform:none; }
}
@media (max-width:1100px) {
  .asks { grid-template-columns:repeat(2, 1fr); }
}
@media (max-width:900px) {
  .steps, .posts, .setup, .act, .split2, .two { grid-template-columns:1fr; }
  .sol { grid-template-columns:repeat(2, 1fr); }
  .card.wide { flex-direction:column; align-items:flex-start; }
}
@media (max-width:640px) {
  .asks, .sol { grid-template-columns:1fr; }
  .tryfree { flex-direction:column; align-items:flex-start; padding:28px 24px; }
  .step, .ask, a.post, .howto, .act, .sol a, .card { padding:28px 24px; }
  .shot { padding:18px; }
  .svc { padding:8px 24px; }
  /* A long name of a button wraps on a phone instead of sticking out of its card. */
  .howto b.ui, .tcard b.ui { white-space:normal; }
}

/* The setup page (/setup): its heading, the full steps right under it (the home page's three cards are not above them, so no room
   is left for them), then three sections, the call to try it and the block for developers. */
section.shead { padding-top:40px; padding-bottom:0; }
.shead h1 { margin-top:14px; max-width:940px; }
.shead .lede { font-size:19px; margin:22px 0 0; max-width:720px; }
section.sbody { padding-top:36px; padding-bottom:0; }
/* The block for developers ends the page, under the call to try it: as the last block of a page it keeps 51 px, which the footer's
   40 px of margin make the 91 px of a section. */
main > section.ssec:last-child { padding-bottom:51px; }
.setupbox.full .tabs { margin-top:0; }
.setupbox.full .tabs[hidden] + .setup { margin-top:0; }
/* The day the buttons were checked and the note for Claude's free plan, small under the steps. */
.snote { margin-top:20px; max-width:760px; font-size:14px; opacity:.7; }
.snote + .snote { margin-top:8px; }
.snote a, .ssec p a:not(.ghost) { color:var(--mint); text-decoration:underline; text-underline-offset:3px; }
.ssec > p, .ssec .split2 > div > p { max-width:760px; }
.ssec p + p { margin-top:14px; }
.ssec code { font-family:var(--mono); font-size:13px; padding:1px 6px; border-radius:6px; background:rgba(0,0,0,.4); overflow-wrap:anywhere; }
/* What to write first: the line, as it is typed in ChatGPT and in Claude. */
.say { padding:32px; min-width:0; }
.say p { font-size:17px; opacity:1; overflow-wrap:anywhere; }
.ssec .say p + .mono { margin-top:22px; }
.say .mono + p { margin-top:10px; }
/* Where the key is: one card for every post of the language. */
.klist { list-style:none; margin:28px 0 0; padding:0; display:grid; grid-template-columns:repeat(3, 1fr); gap:18px; }
.kpost { display:flex; flex-direction:column; gap:10px; height:100%; padding:26px 28px; overflow-wrap:anywhere; transition:transform .5s cubic-bezier(.2,.8,.2,1); }
.kpost:hover { transform:translateY(-4px); }
.kpost b { font-family:var(--display); font-weight:400; font-size:19px; line-height:1.2; }
/* If it failed: five cases, the last (write to us) across the row. */
.tlist { display:grid; grid-template-columns:1fr 1fr; gap:18px; margin-top:36px; }
.tcard { padding:32px; min-width:0; }
.tcard:last-child { grid-column:1 / -1; }
.tcard h3 { margin-bottom:10px; }
/* The Claude Code command: one line that wraps instead of sticking out of the card. */
.cmd { margin:18px 0; padding:20px 24px; }
.ssec .cmd code { display:block; padding:0; background:none; font-size:14px; white-space:pre-wrap; }
@media (prefers-reduced-motion: reduce) {
  .kpost { transition:none; }
  .kpost:hover { transform:none; }
}
@media (max-width:900px) {
  .klist { grid-template-columns:repeat(2, 1fr); }
}
@media (max-width:640px) {
  .klist, .tlist { grid-template-columns:1fr; }
  .tcard, .say { padding:28px 24px; }
}

/* The not-found page */
.lost { min-height:calc(100vh - 82px - 160px); min-height:calc(100svh - 82px - 160px); display:flex; flex-direction:column; justify-content:center; }
.lost h1 { margin-top:14px; }
.lost .lede { font-size:19px; margin:22px 0 30px; max-width:580px; }

/* Footer (mockup, lines 70–73) */
footer.wrap { padding-top:40px; padding-bottom:60px; border-top:1px solid rgba(255,255,255,.08); margin-top:40px; }
footer .bar { display:flex; flex-wrap:wrap; justify-content:space-between; align-items:center; gap:14px 24px; font-size:14px; opacity:.75; }
footer .legal { display:flex; flex-direction:column; gap:4px; }
footer .legal a:hover { color:var(--mint); }
/* The company that runs the domain (COMPANY, lib/site.js): no part of it breaks inside but the address, and that only between the
   pieces its commas part (each a span); the line breaks after a dot, never before one. The phone after the address stays whole. */
footer .company span { white-space:nowrap; }
footer .company > .address { white-space:normal; }
.by { display:flex; align-items:center; gap:10px; }
.by b { font-family:var(--display); font-weight:400; font-size:18px; }
/* The app's open pages, /pricing, /terms, /privacy and /refund, and its sign-in pages, as the cloud draws them in this site's frame
   (src/web/site-frame.ts of the repository): it takes the header, the footer, the background, the stylesheet and the script of the
   home page of a build, and puts the page in <main class="wrap apppage"> (.doc on the three texts, .auth on the sign-in pages).
   Every rule here is scoped under .apppage, so none reaches the site's own pages (tests/lint/app-pages.test.mjs), and reads the class
   names the cloud writes (src/web/site-pages.ts, legal.ts, auth-pages.ts). The site never builds these pages;
   scripts/render-app-pages.ts of the repository writes them into dist/ for a local look. */

.apppage { padding-top:56px; padding-bottom:51px; }
.apppage .lede { font-size:19px; margin:22px 0 0; max-width:720px; }
.apppage .muted { opacity:.6; }

/* ===== Pricing ===== */
/* The year / month switch: two chips, as the blog's filter draws them, the chosen one light. The radio buttons stay in the page for
   the keyboard and screen readers, out of sight; CSS alone shows the chosen prices, so the switch works without a script. */
.apppage .billing { position:relative; margin-top:36px; }
.apppage .billing > input { position:absolute; top:0; left:0; width:1px; height:1px; margin:0; opacity:0; pointer-events:none; }
.apppage .billing > label { display:inline-block; margin:0 6px 0 0; padding:8px 16px; border-radius:999px; border:1px solid rgba(255,255,255,.18);
  font-size:14px; font-weight:600; cursor:pointer; transition:background .3s, color .3s, border-color .3s; }
.apppage .billing > label:hover { border-color:rgba(255,255,255,.4); }
.apppage .billing > input:checked + label { background:var(--ink); border-color:var(--ink); color:var(--bg); }
.apppage .billing > input:focus-visible + label { outline:2px solid var(--mint); outline-offset:3px; }
.apppage #billing-year:checked ~ .plans .monthly, .apppage #billing-month:checked ~ .plans .yearly { display:none; }
/* apiunicon.online's currency switch, dollars or lari, after the year / month one with a wider gap between the two: the same chips and
   the same working without a script. Each card has its prices in both currencies, each in its block (.usd, .gel), which hands its
   price and line to the card's grid as the yearly and monthly blocks do; the switch hides the other currency's. */
.apppage .billing > #currency-usd + label { margin-left:12px; }
.apppage .plans .usd, .apppage .plans .gel { display:contents; }
.apppage #currency-usd:checked ~ .plans .gel, .apppage #currency-gel:checked ~ .plans .usd { display:none; }

/* Three plans of one size in a row, cards of glass as the site's; the call of each at its foot, the free plan's turquoise as the
   site's main button, the others' a ghost. Their parts line up across the row: each card is a subgrid of the row's five lines (the
   name, the price, the line under the price, the list, the call), so the lists, their bullets and the calls stand at one height
   whichever prices the switch shows, though only some cards have a line under their price (the free plan's "no card", a paid plan's
   yearly row of discount, struck year and yearly price). A paid plan's yearly and monthly blocks hand their price and line to the
   card's grid (display:contents); the switch still hides one of them. One under another from 1040 px down, where the header folds
   too: three cards narrower than that no longer hold a Russian yearly row (the discount, the struck year, the yearly price) or a
   price with its "/ мес" on one line. */
.apppage .plans { display:grid; grid-template-columns:repeat(3, 1fr); grid-template-rows:repeat(5, auto); column-gap:20px; row-gap:0; margin-top:28px; }
.apppage .plans .card { display:grid; grid-row:span 5; grid-template-rows:subgrid; min-width:0; padding:36px; background:var(--glass); border:1px solid var(--edge); border-radius:20px; }
.apppage .plans .yearly, .apppage .plans .monthly { display:contents; }
.apppage .plans .card > h2 { grid-row:1; }
.apppage .plans .price { grid-row:2; }
.apppage .plans .price + .muted, .apppage .plans .deal { grid-row:3; }
.apppage .plans .card > ul { grid-row:4; }
.apppage .plans .card > .button, .apppage .plans .card > .yearly > .button, .apppage .plans .card > .monthly > .button { grid-row:5; }
.apppage .plans h2 { font-size:28px; line-height:1.1; margin:0 0 22px; }
.apppage .price { font-family:var(--display); font-size:44px; line-height:1.05; opacity:1; }
.apppage .price small { font-family:'IBM Plex Sans', sans-serif; font-size:15px; opacity:.6; }
.apppage .price + .muted { margin-top:10px; font-size:14px; }
/* Under a yearly price, one row from the left: the discount, a turquoise label as the site's accents; the year at the monthly price,
   struck through; the yearly price. It wraps on a narrow card rather than leave the card. */
/* The row is a <p>, which the site draws at .86, and a struck price at .5 on top of that was .43 in all: 3.8:1 on the card, under AA.
   The row stands at full strength, as the price above it does, and the dimming is each part's own: the struck year .65 (6.9:1 on
   the card's lightest corner), the yearly price .8 (tests/lint/colours.test.mjs reads them from the built stylesheet). */
.apppage .deal { display:flex; flex-wrap:wrap; align-items:center; gap:6px 10px; margin-top:10px; font-size:14px; line-height:1.4; opacity:1; }
.apppage .deal .off { padding:3px 8px; border-radius:999px; border:1px solid rgba(0,214,180,.45); background:rgba(0,214,180,.12);
  color:var(--teal); font-family:var(--mono); font-size:12px; font-weight:700; letter-spacing:.04em; white-space:nowrap; }
.apppage .deal s { opacity:.65; text-decoration-thickness:1px; white-space:nowrap; }
.apppage .deal .year { opacity:.8; white-space:nowrap; }
.apppage .plans ul { list-style:none; display:grid; align-content:start; gap:12px; margin:26px 0 30px; padding:26px 0 0; border-top:1px solid rgba(255,255,255,.08); }
.apppage .plans li { position:relative; padding-left:22px; font-size:15px; line-height:1.45; opacity:.86; }
.apppage .plans li::before { content:''; position:absolute; left:2px; top:.55em; width:8px; height:8px; border-radius:50%; background:var(--mint); }
.apppage .plans .button { margin-top:auto; align-self:flex-start; justify-self:start; }
.apppage .button { display:inline-block; padding:14px 22px; border-radius:12px; background:var(--teal); color:var(--bg); font-weight:600; transition:box-shadow .3s; }
.apppage .button:hover { box-shadow:0 0 30px rgba(0,214,180,.45); }
.apppage .button.secondary { padding:13px 20px; border:1px solid rgba(233,237,247,.3); background:none; color:var(--ink); transition:background .3s; }
.apppage .button.secondary:hover { background:rgba(255,255,255,.06); box-shadow:none; }
/* The line about payment under the plans. */
.apppage .billing + .muted { margin-top:28px; font-size:15px; }

/* ===== The terms and the privacy policy ===== */
/* A column of long text as a post's body (blog.css, .pbody): 720 px at most, the headings in the site's face, the edition in the
   labels' face, mint links and markers, tables as a post's. The title is not part of the column: it spans the content's width, so
   that «конфиденциальности» (12.2 em, the longest word of the two titles) stands whole on a line of its own and the title wraps
   between its words, «Политика / конфиденциальности», instead of the word being cut. The size follows the window as the site's
   h1 does, 38 px to 64 px: the word is 61 % of the window at 5 vw and 779 px at 64 px, and the content is 92 % of a 641 px window
   and 1088 px of a wide one, so it fits at every width above the phone (tests/e2e/headings.spec.mjs). */
.apppage.doc > * { max-width:720px; }
.apppage.doc > h1 { max-width:none; }
.apppage.doc h1 { font-size:clamp(38px, 5vw, 64px); line-height:1.02; }
.apppage.doc h1 + .muted { margin-top:18px; font-family:var(--mono); font-size:12px; letter-spacing:.06em; text-transform:uppercase; }
.apppage .section-gap { margin-top:48px; }
.apppage.doc h2 { font-size:clamp(24px, 2.4vw, 30px); line-height:1.15; margin:0 0 16px; }
.apppage.doc h3 { font-size:20px; margin:28px 0 10px; }
.apppage.doc p, .apppage.doc li { font-size:17px; line-height:1.7; opacity:.88; overflow-wrap:break-word; }
.apppage.doc p + p { margin-top:14px; }
.apppage.doc a { color:var(--mint); text-decoration:underline; text-decoration-thickness:1px; text-underline-offset:3px; }
.apppage.doc a:hover { color:var(--ink); }
.apppage.doc ul, .apppage.doc ol { margin:14px 0 0; padding-left:24px; }
.apppage.doc li + li { margin-top:8px; }
.apppage.doc li::marker { color:var(--mint); }
.apppage.doc table { width:100%; margin-top:18px; border-collapse:collapse; font-size:15px; line-height:1.5; }
.apppage.doc th, .apppage.doc td { text-align:left; vertical-align:top; padding:12px 14px; border-bottom:1px solid rgba(255,255,255,.1); }
.apppage.doc th { font-family:var(--mono); font-size:12px; font-weight:400; letter-spacing:.08em; text-transform:uppercase; opacity:.7; }

/* ===== Sign-in ===== */
/* The sign-in, sign-up, password, second-factor and OAuth pages (the cloud's sign-in look, src/web/http.ts): the site's whole frame,
   snakes and all, and the page in one card of glass (.glass, site.css) in the middle of the window. Inside it the site's dark fields,
   the turquoise main button, quiet links under the form; what went wrong in a muted red and what is done in the green of the accents,
   the tinted chips of the site, no glow. The forms and boxes the cloud writes as cards (form.card, section.card) are parts of this
   one card, not cards of their own. */
.apppage.auth { display:flex; flex-direction:column; align-items:center; justify-content:center; min-height:calc(100vh - 82px - 200px); min-height:calc(100svh - 82px - 200px); }
.apppage .authcard { width:min(480px, 100%); padding:40px 36px 36px; }
/* The consent's question is the longest heading («Разрешить Claude работать с вашими подключениями APIUniCon?»): a size that keeps it
   to four lines in the card, its lines balanced. */
.apppage .authcard h1 { font-size:clamp(28px, 2.6vw, 36px); line-height:1.1; text-wrap:balance; }
.apppage .authcard h2 { font-size:18px; line-height:1.2; margin:0 0 10px; }
.apppage .authcard .lede { margin:14px 0 0; font-size:16px; line-height:1.55; opacity:.75; }
.apppage .authcard p + p { margin-top:12px; }
.apppage .authcard .card { padding:0; background:none; border:0; border-radius:0; }
.apppage .authcard form, .apppage .authcard .card { margin:24px 0 0; }
.apppage .authcard section.card + form.card { padding-top:22px; border-top:1px solid rgba(255,255,255,.1); }
.apppage .authcard code { padding:3px 8px; border-radius:6px; background:rgba(0,0,0,.4); font-family:var(--mono); font-size:14px; letter-spacing:.06em; overflow-wrap:anywhere; }
.apppage .authcard label { display:block; margin-top:16px; font-size:14px; font-weight:600; }
.apppage .authcard form > label:first-of-type { margin-top:0; }
.apppage .authcard input:not([type="hidden"]) { display:block; width:100%; margin-top:8px; padding:12px 14px; border:1px solid rgba(255,255,255,.16); border-radius:12px;
  background:rgba(255,255,255,.03); color:var(--ink); font:inherit; font-weight:400; transition:border-color .2s; }
.apppage .authcard input:focus-visible { outline:none; border-color:var(--teal); box-shadow:0 0 0 3px rgba(0,214,180,.2); border-radius:12px; }
.apppage .authcard button { display:block; width:100%; margin-top:24px; padding:14px 22px; border:0; border-radius:12px; background:var(--teal); color:var(--bg);
  font-weight:600; cursor:pointer; transition:box-shadow .3s, background .3s; }
.apppage .authcard button:hover { box-shadow:0 0 30px rgba(0,214,180,.45); }
.apppage .authcard button.secondary { border:1px solid rgba(233,237,247,.3); background:none; color:var(--ink); }
.apppage .authcard button.secondary:hover { background:rgba(255,255,255,.06); box-shadow:none; }
/* Allow and deny of the OAuth consent: two buttons side by side. */
.apppage .authcard div.actions { margin-top:28px; flex-wrap:nowrap; gap:12px; }
.apppage .authcard div.actions form { flex:1; margin:0; }
.apppage .authcard div.actions button { margin-top:0; }
/* Under the form: the quiet links ("Forgot your password?", "Sign up"), as the site's own quiet links, mint on hover. */
.apppage .authcard form + p { margin-top:22px; }
.apppage .authcard p.actions { justify-content:space-between; gap:8px 20px; font-size:14px; }
.apppage .authcard p > a { opacity:.72; transition:opacity .2s, color .2s; }
.apppage .authcard p > a:hover { opacity:1; color:var(--mint); }
.apppage .authcard .warning, .apppage .authcard .notice { margin-top:20px; padding:12px 14px; border:1px solid; border-radius:12px; font-size:15px; line-height:1.45; opacity:1; }
.apppage .authcard .warning { border-color:rgba(240,128,120,.42); background:rgba(240,128,120,.09); color:#f4b4ac; }
.apppage .authcard .notice { border-color:rgba(0,214,180,.42); background:rgba(0,214,180,.08); color:var(--ink); }

@media (prefers-reduced-motion: reduce) {
  .apppage .billing > label, .apppage .button, .apppage .authcard input, .apppage .authcard button, .apppage .authcard p > a { transition:none; }
}
/* Three a row in a narrower window: the cards give their padding to the Russian yearly row, the longest line of a card. */
@media (max-width:1200px) {
  .apppage .plans .card { padding:32px; }
}
@media (max-width:1040px) {
  .apppage .plans { grid-template-columns:1fr; grid-template-rows:none; row-gap:20px; }
  .apppage .plans .card { display:flex; flex-direction:column; grid-row:auto; }
}
@media (max-width:640px) {
  .apppage { padding-top:36px; }
  .apppage .authcard { padding:32px 22px 28px; }
  .apppage .lede { font-size:17px; }
  .apppage .plans .card { padding:28px 24px; }
  .apppage .price { font-size:38px; }
  .apppage.doc p, .apppage.doc li { font-size:16px; }
  /* A table wider than the phone scrolls in its own box, never the page. */
  .apppage.doc table { display:block; overflow-x:auto; }
}
/* The cabinet: the account, the connections and adapters, the administration and the core's key-entry and confirmation pages, as
   the cloud draws them (src/web/layout.ts of the repository) in <body class="cabinet">, with the site's stylesheet, logo and company
   line. Simpler than the site, in its colours and faces (the owner, 24 Oct 2026): the page's near-black, panels of the near-black of
   the menus, the site's thin edges and 20 px corners, the headings in ZabSoft Display, the text in IBM Plex Sans, the labels in
   JetBrains Mono, turquoise for the main buttons, the links and where the reader is. A static faint grid under the content (the
   site's .grid, which no script moves here), and nothing that moves: no snakes, no parallax, no animation.
   Every rule is scoped under .cabinet, so none reaches the site's pages (tests/lint/cabinet.test.mjs); the class names are the ones
   the cloud and the core write (card, row, choice-card, confirm, domain, warning, notice, …). */

/* ===== The frame ===== */
/* The header: the site's logo, then the cabinet's links and the language switch, then the sign-out. On a phone the sign-out stays
   beside the logo and the links go under both, from the left. */
.cabinet header .bar { flex-wrap:wrap; gap:14px 28px; }
.cabinet header nav { flex-wrap:wrap; justify-content:flex-end; gap:8px 22px; margin-left:auto; }
.cabinet nav a { margin-left:0; }
.cabinet nav a[aria-current="page"] { opacity:1; color:var(--teal); }
.cabinet header .bar > form { margin:0; }

/* The page: a column as wide as reading allows, under the logo, as the site's long texts stand. */
.cabinet main { padding-top:44px; padding-bottom:51px; }
.cabinet main > * { max-width:880px; }
.cabinet h1 { font-size:clamp(34px, 4.2vw, 52px); line-height:1.04; margin:0 0 24px; overflow-wrap:anywhere; }
.cabinet h1 + .lede { margin-top:-10px; }
.cabinet h2 { font-size:22px; line-height:1.2; margin:0 0 16px; }
.cabinet h2 small { font-family:'IBM Plex Sans', sans-serif; font-size:14px; }
.cabinet h3 { font-size:17px; line-height:1.25; margin:22px 0 8px; }
.cabinet main p { margin:0 0 14px; }
.cabinet main p:last-child { margin-bottom:0; }
.cabinet .lede { font-size:18px; line-height:1.5; opacity:.72; }
.cabinet main > .lede { margin-bottom:32px; }
.cabinet .muted { opacity:.6; }
.cabinet .section-gap { margin-top:30px; }
.cabinet main a:not(.button) { color:var(--mint); text-decoration:underline; text-decoration-thickness:1px; text-underline-offset:3px; }
.cabinet main a:not(.button):hover { color:var(--ink); }
.cabinet main a[aria-current="page"] { color:var(--teal); text-decoration:none; }
.cabinet .eyebrow { display:block; margin:0 0 14px; color:var(--mint); font-family:var(--mono); font-size:12px; letter-spacing:.12em; text-transform:uppercase; }
.cabinet [hidden] { display:none; }

/* ===== Panels ===== */
/* A card is a panel: the near-black of the site's menus and drawn windows, solid, so the grid does not show through. */
.cabinet .card { margin:0 0 18px; padding:30px 32px; background:var(--panel); border:1px solid var(--edge); border-radius:20px; }
.cabinet .card > :first-child { margin-top:0; }
/* A form between the cards (block an account, delete a connection) keeps the cards' rhythm. */
.cabinet main > form:not(.card) { margin-bottom:18px; }
.cabinet .row { display:flex; justify-content:space-between; align-items:baseline; gap:6px 24px; padding:13px 0; border-top:1px solid rgba(255,255,255,.08); }
.cabinet .row:last-child { padding-bottom:0; }
/* A card that opens with its rows has no line over the first: the card's edge is there. */
.cabinet .card > .row:first-child { padding-top:0; border-top:0; }
.cabinet .row + :not(.row) { margin-top:16px; }
.cabinet .row strong { font-weight:600; text-align:right; }
.cabinet .row form { margin:0; }
.cabinet .actions { gap:10px 24px; }
.cabinet .actions form { margin:0; }
.cabinet .actions button { margin-top:0; }

/* ===== Messages ===== */
/* What went wrong in a muted red, what is done in the green of the accents: the tinted chips of the site (its turquoise service
   chips), no glow. */
.cabinet .warning, .cabinet .notice { margin:0 0 18px; padding:13px 16px; border:1px solid; border-radius:12px; font-size:15px; line-height:1.5; opacity:1; }
.cabinet .warning { border-color:rgba(240,128,120,.42); background:rgba(240,128,120,.09); color:#f4b4ac; }
.cabinet .notice { border-color:rgba(0,214,180,.42); background:rgba(0,214,180,.08); color:var(--ink); }
.cabinet .warning ul { margin:8px 0 0; }

/* ===== Forms ===== */
/* The fields of the site's drawn windows: a faint fill, a thin edge, 12 px corners; turquoise around the one being typed in. */
.cabinet label { display:block; margin:18px 0 0; font-size:14px; font-weight:600; }
.cabinet input:not([type="checkbox"]):not([type="radio"]):not([type="hidden"]), .cabinet select, .cabinet textarea {
  display:block; width:100%; margin-top:8px; padding:12px 14px; border:1px solid rgba(255,255,255,.16); border-radius:12px;
  background:rgba(255,255,255,.03); color:var(--ink); font:inherit; font-weight:400; transition:border-color .2s; }
.cabinet input:focus-visible, .cabinet select:focus-visible, .cabinet textarea:focus-visible { outline:none; border-color:var(--teal); box-shadow:0 0 0 3px rgba(0,214,180,.2); border-radius:12px; }
.cabinet select option { background:var(--panel); color:var(--ink); }
.cabinet textarea { min-height:96px; resize:vertical; }
.cabinet input[type="checkbox"] { flex:none; width:18px; height:18px; margin:2px 0 0; accent-color:var(--teal); }
/* The main button turquoise with dark words, as the site's; the second one a ghost; the quiet one small (sign out, disconnect). */
.cabinet button, .cabinet .button { display:inline-block; margin-top:22px; padding:13px 22px; border:0; border-radius:12px; background:var(--teal);
  color:var(--bg); font-size:15px; font-weight:600; line-height:1.25; text-decoration:none; cursor:pointer; transition:box-shadow .3s, background .3s; }
.cabinet button:hover, .cabinet .button:hover { box-shadow:0 0 30px rgba(0,214,180,.45); }
.cabinet .secondary { padding:12px 21px; border:1px solid rgba(233,237,247,.3); background:none; color:var(--ink); }
.cabinet .secondary:hover { background:rgba(255,255,255,.06); box-shadow:none; }
.cabinet .quiet { margin:0; padding:7px 14px; border:1px solid rgba(255,255,255,.18); border-radius:10px; background:none; color:var(--ink); font-size:14px; font-weight:400; opacity:.85; }
.cabinet .quiet:hover { background:rgba(255,255,255,.06); box-shadow:none; opacity:1; }

/* ===== Key entry and confirmation ===== */
/* The addresses keys go to stand out: each a card of its own with its host in mint, the chosen ones edged in turquoise. */
.cabinet .choices { display:grid; gap:10px; }
.cabinet .choice-card { display:flex; align-items:flex-start; gap:12px; margin:0; padding:14px 16px; border:1px solid rgba(255,255,255,.14); border-radius:14px;
  background:rgba(255,255,255,.025); font-weight:400; cursor:pointer; }
.cabinet .choice-card:has(input:checked) { border-color:rgba(0,214,180,.55); background:rgba(0,214,180,.06); }
.cabinet .choice-card strong { display:block; font-weight:600; }
.cabinet .choice-card .domain { display:block; margin-top:2px; }
.cabinet .choices + * { margin-top:18px; }
.cabinet .confirm { display:flex; align-items:flex-start; gap:12px; margin:0 0 6px; font-weight:400; }
.cabinet .domain { font-family:var(--mono); font-size:14px; color:var(--mint); overflow-wrap:anywhere; }
.cabinet .technical-detail { display:block; margin-top:4px; font-family:var(--mono); font-size:12px; font-weight:400; opacity:.55; overflow-wrap:anywhere; }
.cabinet code { padding:2px 7px; border-radius:6px; background:rgba(255,255,255,.07); font-family:var(--mono); font-size:13px; overflow-wrap:anywhere; }

/* ===== Changes to the person's data ===== */
/* The connection a link of the assistant points to (/connections?connection=<id>#connection-<id>) edged in turquoise, as a chosen
   address of the key entry is; the anchor is lost across the sign-in, the address is not. */
.cabinet .card[aria-current="true"], .cabinet .card:target { border-color:rgba(0,214,180,.55); }
.cabinet .card div.actions:not(:last-child) { margin-bottom:16px; }
/* What a change sends, on the core's confirmation page (/confirm/change/…) and in the change log: a name over its value. A block of
   JSON is never cut short and never scrolls inside itself, so nothing that is sent sits hidden above the button; its long lines
   wrap instead. */
.cabinet dl { margin:6px 0 14px; }
.cabinet dt { margin-top:12px; font-weight:600; overflow-wrap:anywhere; }
.cabinet dt:first-child { margin-top:0; }
.cabinet dd { margin:4px 0 0; overflow-wrap:anywhere; }
.cabinet pre { max-height:none; overflow:visible; margin:6px 0 0; padding:12px 14px; border:1px solid rgba(255,255,255,.14); border-radius:12px; background:rgba(255,255,255,.03); font-family:var(--mono); font-size:13px; line-height:1.5; white-space:pre-wrap; overflow-wrap:anywhere; }
/* The assistant's own words on the confirmation page, set apart from what is sent. */
.cabinet blockquote { margin:22px 0 8px; padding:14px 18px; border-left:2px solid var(--mint); border-radius:0 12px 12px 0; background:rgba(255,255,255,.025); }
.cabinet details { margin-top:8px; }
.cabinet summary { cursor:pointer; color:var(--mint); font-size:13px; }
/* The log: seven columns, so it may take the frame's whole width rather than the reading column, in a box of its own
   (<div class="changes">, src/web/changes-pages.ts) that scrolls sideways whenever the frame is narrower than the columns need, at
   every width, so the page itself never does. What others wrote (the connection's name, the action, the assistant's words) breaks
   anywhere it must, so one unbroken run of 500 characters wraps inside its column instead of widening the table; our own words
   break only between words. Each column keeps a readable width, so a long run squeezes none of them to a letter. */
.cabinet main > .changes { max-width:none; overflow-x:auto; }
.cabinet .changes td { overflow-wrap:break-word; }
.cabinet .changes td:nth-child(2), .cabinet .changes td:nth-child(3), .cabinet .changes td:nth-child(6) { overflow-wrap:anywhere; }
.cabinet .changes td:first-child { min-width:8em; }
.cabinet .changes td:nth-child(2) { min-width:7em; }
.cabinet .changes td:nth-child(3) { min-width:8em; }
.cabinet .changes td:nth-child(4) { min-width:16em; }
.cabinet .changes td:nth-child(6) { min-width:12em; }

/* ===== Lists and tables ===== */
.cabinet main ul, .cabinet main ol { margin:10px 0 14px; padding-left:22px; }
.cabinet main li + li { margin-top:6px; }
.cabinet main li::marker { color:var(--mint); }
.cabinet table { width:100%; margin:6px 0 14px; border-collapse:collapse; font-size:14px; line-height:1.45; }
.cabinet th, .cabinet td { padding:11px 14px 11px 0; border-bottom:1px solid rgba(255,255,255,.08); text-align:left; vertical-align:top; }
.cabinet th { font-family:var(--mono); font-size:11px; font-weight:400; letter-spacing:.08em; text-transform:uppercase; opacity:.6; }

@media (prefers-reduced-motion: reduce) {
  .cabinet button, .cabinet .button, .cabinet input, .cabinet select, .cabinet textarea { transition:none; }
}
/* A phone: the links under the logo, from the left; a row's label over its value; a table scrolls in its own box, never the page.
   The log has its box already, so its table stays a table. */
@media (max-width:760px) {
  .cabinet header nav { order:1; flex-basis:100%; justify-content:flex-start; gap:8px 18px; margin-left:0; }
  .cabinet table { display:block; overflow-x:auto; }
  .cabinet .changes table { display:table; }
}
@media (max-width:640px) {
  .cabinet main { padding-top:28px; }
  /* a host of the key entry on one line where it can be: statistics-api.wildberries.ru fits a 375 px phone at 13 px */
  .cabinet .domain { font-size:13px; }
  .cabinet .lede { font-size:17px; }
  .cabinet main > .lede { margin-bottom:26px; }
  .cabinet .card { padding:24px 20px; }
  .cabinet .row { flex-direction:column; align-items:flex-start; }
  .cabinet .row strong { text-align:left; }
}
