/* ============================================================
   BASE (shared, do not edit from a section)
   Tokens, type, shell, nav, pin frame, HUD.
   ============================================================ */
:root{
  --ink:#121216;
  --muted:#6E7280;
  --faint:#A3A7B0;
  --line:#E6E7EB;
  --ground:#E4E4E4;      /* behind the page card */
  --page:#FDFDFD;        /* page white */
  --band:#F4F5F7;        /* light band a white panel sits on */
  --panel:#FFFFFF;
  --coral:#EF4A33;
  --coral-deep:#E23D26;
  --violet:#905DF9;
  --violet-deep:#6E3BE6;
  --violet-soft:#F0EAFF;
  --yellow:#F9E14C;
  --cyan:#5CC8F5;
  --gold:#F5B400;
  --r-xl:32px; --r-lg:28px; --r-md:20px; --r-sm:14px;
  --shadow-soft:0 1px 2px rgba(18,18,22,.03), 0 12px 32px rgba(18,18,22,.06);
  --shadow-lift:0 4px 10px rgba(18,18,22,.05), 0 30px 64px rgba(18,18,22,.13);
  --ease:cubic-bezier(.16,1,.3,1);
  --ease-pop:cubic-bezier(.2,.9,.25,1.12);
  --maxw:1180px;
  --nav-h:56px;
}
*{box-sizing:border-box;margin:0;padding:0}
html{scroll-behavior:auto}
body{
  font-family:"Gilroy","Aeonik","TT Hoves",-apple-system,"SF Pro Display","Helvetica Neue",Arial,sans-serif;
  background:var(--page); color:var(--ink);
  -webkit-font-smoothing:antialiased; font-size:16px; line-height:1.5; overflow-x:hidden;
}
img,svg{display:block;max-width:100%}
button{font-family:inherit}

/* type */
h1,h2,h3{font-weight:800;letter-spacing:-.03em;line-height:1.02}
h1{font-size:clamp(46px,5.6vw,80px)}
h2{font-size:clamp(34px,3.9vw,56px)}
h3{font-size:19px;letter-spacing:-.012em;line-height:1.25}
.sub{font-size:clamp(15px,1.2vw,17px);color:var(--muted);font-weight:500;max-width:36ch;margin:18px auto 0;line-height:1.55}
/* .eyebrow: ONE shared rule, in live-chrome.css (dot + :lang(en) caps) */

/* shell */
.wrap{width:100%;max-width:var(--maxw);margin:0 auto;padding:0 32px}
.center{text-align:center;width:100%}
/* a pinned frame: put .pin inside a tall wrapper (height 200-400vh) and register MOTION.scene(wrapperId, fn) */
.pin{position:sticky;top:0;height:100vh;display:grid;place-items:center;overflow:hidden}
/* NOT DONE, and the measurement is why: unpinning .pin under reduced motion only
   works if every deck also has a rest LAYOUT, and none of them has one yet. With
   .pin unpinned and each scene held at its last frame, the hero loses its h1, sub
   and both CTAs (the copy is translated -311px at p=1 and clipped), the steps deck
   shows "3 / 3" over an empty stage, and the conversations rail is gone. That has
   to be authored section by section; the engine cannot pick the frame for them. */

/* pills */
.btn{border:0;cursor:pointer;font-weight:700;font-size:14px;padding:11px 18px;border-radius:100px;letter-spacing:-.01em;
  transition:transform .25s var(--ease),box-shadow .25s var(--ease),background .2s ease}
.btn-ghost{background:#fff;border:1px solid var(--line);color:var(--ink)}
.btn-ghost:hover{background:#F7F8F9}
.btn-dark{background:#1A1A1A;color:#fff}
.btn-dark:hover{transform:translateY(-1px);box-shadow:0 8px 20px rgba(18,18,22,.22)}
.btn-coral{background:var(--coral);color:#fff;padding:15px 30px;font-size:15px}
.btn-coral:hover{transform:translateY(-1px);box-shadow:0 10px 26px rgba(239,74,51,.32)}
.btn-violet{background:var(--violet);color:#fff;padding:13px 26px;font-size:14px}
.btn-violet:hover{transform:translateY(-1px);box-shadow:0 10px 26px rgba(144,93,249,.32)}

/* nav (fixed glass pill) */
.nav{position:fixed;top:22px;left:50%;transform:translateX(-50%);z-index:60;display:flex;align-items:center;gap:26px;
  padding:7px 7px 7px 22px;background:rgba(255,255,255,.78);backdrop-filter:blur(18px) saturate(1.6);-webkit-backdrop-filter:blur(18px) saturate(1.6);
  border:1px solid rgba(255,255,255,.75);border-radius:100px;box-shadow:0 1px 2px rgba(18,18,22,.04),0 10px 30px rgba(18,18,22,.08)}
.nav .brand{font-weight:800;font-size:17px;letter-spacing:-.02em;display:flex;align-items:center;gap:6px}
.nav .links{display:flex;gap:22px}
.nav a{color:var(--muted);text-decoration:none;font-size:14px;font-weight:600;transition:color .2s ease}
.nav a:hover{color:var(--ink)}
.nav .actions{display:flex;gap:8px;align-items:center}
@media (max-width:760px){.nav .links{display:none}}

/* HUD */
#motionHud{position:fixed;right:14px;bottom:14px;z-index:200;display:none;background:rgba(18,18,22,.9);color:#fff;border-radius:12px;padding:12px 14px;
  font:600 12px/1.6 ui-monospace,SFMono-Regular,Menlo,monospace;letter-spacing:.02em;backdrop-filter:blur(10px)}
#motionHud.on{display:block}
#motionHud b{color:#B9A5FF;font-weight:700}
#motionPerf{position:fixed;left:14px;bottom:14px;z-index:200;display:none;background:rgba(18,18,22,.9);color:#fff;border-radius:12px;padding:12px 14px;
  font:600 12px/1.6 ui-monospace,SFMono-Regular,Menlo,monospace;letter-spacing:.02em;backdrop-filter:blur(10px);min-width:250px}
#motionPerf.on{display:block}
#motionPerf b{color:#B9A5FF;font-weight:700}
#motionPerf small{color:#A3A7B0;font-weight:500}

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:1ms;animation-iteration-count:1;transition-duration:1ms;scroll-behavior:auto}
}


/* ===== theme: suppo-theme.css ===== */
/* ============================================================
   SUPPO THEME (overrides base tokens; loaded after base.css)
   Brand tokens from suppo.ge v2. Fonts self-hosted from fonts.
   ============================================================ */
@font-face{font-family:"Gilroy";src:url("fonts/gilroy-400.woff2") format("woff2");font-weight:400;font-display:swap}
@font-face{font-family:"Gilroy";src:url("fonts/gilroy-500.woff2") format("woff2");font-weight:500;font-display:swap}
@font-face{font-family:"Gilroy";src:url("fonts/gilroy-600.woff2") format("woff2");font-weight:600;font-display:swap}
@font-face{font-family:"Gilroy";src:url("fonts/gilroy-700.woff2") format("woff2");font-weight:700;font-display:swap}
@font-face{font-family:"Gilroy";src:url("fonts/gilroy-800.woff2") format("woff2");font-weight:800;font-display:swap}
@font-face{font-family:"FiraGO";src:url("fonts/firago-400.woff2") format("woff2");font-weight:400;font-display:swap}
@font-face{font-family:"FiraGO";src:url("fonts/firago-500.woff2") format("woff2");font-weight:500;font-display:swap}
@font-face{font-family:"FiraGO";src:url("fonts/firago-600.woff2") format("woff2");font-weight:600;font-display:swap}
@font-face{font-family:"FiraGO";src:url("fonts/firago-700.woff2") format("woff2");font-weight:700;font-display:swap}

:root{
  --ink:#0A0A0B;
  --muted:#5B5B63;
  --faint:#7A7A82;
  --line:rgba(10,10,11,.08);
  --ground:#F3F3F4;
  --page:#FAFAFA;
  --band:#F3F3F5;
  --panel:#FFFFFF;
  --card-2:#FCFCFE;
  --live:#00D26A;
  --live-press:#00B95E;
  --mint:#5DFFC3;
  --grad:linear-gradient(92deg,#00C267 0%,#1FA8E8 100%);   /* Figma 85:1951: two stops, no violet, for TEXT gradients */
  /* keep the skeleton's accent names alive so shared components still work */
  --coral:var(--live);
  --coral-deep:var(--live-press);
  --violet:#1FA8E8;
  --violet-deep:#1592CC;
  --violet-soft:#E9F7F0;
  --shadow-soft:0 20px 31px rgba(10,10,11,.04), 0 5px 17px rgba(10,10,11,.05);
  --shadow-lift:0 40px 80px rgba(23,24,24,.12), 0 8px 20px rgba(10,10,11,.06);
}
body{ font-family:"Gilroy","FiraGO",-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif; background:var(--page); color:var(--ink); }

/* Georgian runs: FiraGO carries the glyphs; loosen tracking, Georgian has no case so never text-transform it */
:lang(ka) h1,:lang(ka) h2,:lang(ka) h3{ letter-spacing:-.012em; }
html[lang="ka"] h1{ font-size:clamp(42px,5.2vw,74px); }
html[lang="ka"] h2{ font-size:clamp(32px,3.6vw,52px); }

/* aurora accent inside headlines */
em.hl{ font-style:normal; background:var(--grad); -webkit-background-clip:text; background-clip:text; color:transparent; }

/* primary CTA in brand green with ink text */
.btn-coral,.btn-live{ background:var(--live); color:var(--ink); }
.btn-coral:hover,.btn-live:hover{ background:var(--live-press); box-shadow:0 10px 26px rgba(0,210,106,.32); }
.btn-dark{ background:#0A0A0B; }

/* the nav is position:fixed at left:50%, so its shrink-to-fit width is only half the viewport:
   force a single line or the pill wraps to two rows in both languages */
.nav{ white-space:nowrap; flex-wrap:nowrap; gap:22px; }
.nav .links{ gap:18px; }
.nav .actions .btn{ white-space:nowrap; }

/* language toggle in the nav */
.lang{ display:inline-flex; align-items:center; border:1px solid var(--line); border-radius:100px; padding:3px; gap:2px; background:#fff; }
.lang button{ border:0; background:transparent; cursor:pointer; font-weight:700; font-size:12px; letter-spacing:.04em; padding:6px 9px; border-radius:100px; color:var(--faint); }
.lang button.on{ background:var(--ink); color:#fff; }


/* ===== theme: live-chrome.css ===== */
/* ============================================================================
   LIVE CHROME  (shared; loaded after base.css + suppo-theme.css)

   Founder decision 2026-09-04: the scroll page wears the LIVE site's chrome,
   not the light glass pill. This file is the .nav / .brand / .lang / .btn--* /
   .footer / .mesh / .dot-live layer of ~/suppo-landing/styles.css, lifted and
   re-tokenised onto the scroll page's own token names.

   Two hard constraints shaped it:
   1. The scroll page's base.css already owns .nav, .btn, .wrap. Every rule here
      that collides is written as a FULL reset of the property it inherits, so
      loading order alone decides the winner and nothing depends on specificity
      tricks. The old pill button family (.btn-ghost/.btn-dark/.btn-coral) is
      left untouched, because other sections still use it: the live buttons come
      in as .btn--live / .btn--ink / .btn--ghost / .btn--sm / .btn--lg.
   2. build-legal.py lifts the header.nav element and the footer.footer element
      out of the built page verbatim (it matches the opening tags with a regex),
      so the class names below must stay exactly the ones the live stylesheet
      uses, and no comment on this page may spell those opening tags out again
      or the lift would start inside the comment instead of the real markup.
   ========================================================================= */

:root{
  /* names the lifted rules use, mapped onto the scroll page's palette */
  --wrap:var(--maxw);
  --paper:#FFFFFF;
  --paper-2:#FAFAFA;
  --paper-3:#F1F1F2;
  --ink-2:#1C1C1F;
  --ink-hover:#1C1C1F;
  --muted-2:#69696F;      /* 12px labels only: 4.7:1 on paper-2 */
  --line-solid:#E5E5E7;   /* the scroll page's --line is an rgba; borders that
                             sit on colour need the opaque one */
  --line-strong:#D0D0D4;
  --live-hover:#00BE60;
  --live-text:#067A45;
  --accent-ink:#062A17;   /* ink that reads on the green pill: 12.6:1 */
  --pill-ink:#18181B;
  --green-ink:#067A45;    /* brand green dark enough for TEXT on white (hoisted
                             out of #pricingWrap: the tags need it page-wide) */

  /* ---- radii: four steps, and every corner on the page is one of them ----
     --r-card   a card or panel standing on a band
     --r-inner  a surface nested inside a card
     --r-chrome a small chrome object (chip, well, field, icon tile)
     --r-pill   anything that reads as a pill */
  --r-card:32px;
  --r-inner:24px;
  --r-chrome:16px;
  --r-pill:999px;

  /* ---- quiet surfaces inside a card ---- */
  --tile:#F1F1F4;
  --tile-deep:#E7E7EC;

  /* ---- the only two hairlines on the page ----
     --line       rgba, for a border drawn over an unknown ground (suppo-theme)
     --line-solid opaque, for a border that sits on a known colour (above) */

  /* the demo card is the one object that stands off the page, not on it */
  --shadow-dark:0 40px 80px rgba(10,10,11,.16), 0 8px 20px rgba(10,10,11,.08);

  /* --faint is NON-TEXT ONLY (rules, dashes, disabled marks). Every 12-13px
     label takes --muted-2. Darkened from #7A7A82 so the few places it does
     touch a glyph are not the page's worst contrast. */
  --faint:#6B6B73;

  /* ---- aurora ----
     --grad is a TEXT gradient (em.hl clips it): both stops must clear 3:1 on
     the --band it is read on. --grad-fill keeps the bright pair for the places
     the aurora is a background, not a letterform. */
  --grad:linear-gradient(92deg,#008A49 0%,#1177A8 100%);
  --grad-fill:linear-gradient(92deg,#00C267 0%,#1FA8E8 100%);
  --t-fast:140ms;
  --t-med:220ms;
  --nav-ease:cubic-bezier(.16,1,.3,1);
  /* aurora mesh, the live site's chosen theme (styles.css "ANIMATED MESH THEMES") */
  --m1:#5DFFC3; --m2:#3EC5FF; --m3:#8A7CFF; --m4:#C6FFF0; --m5:#6FE3FF;
  --mesh-a:.78;
}

/* The aurora inside a headline. A FIXED 520px slice, not `100%`, so a one-word
   accent and a four-word one sample the same colours at the same rate instead of
   each stretching the whole ramp across itself. background-color is the END stop:
   with background-clip:text an uncovered run would otherwise clip to transparent
   (invisible), and this way an accent longer than the slice simply holds the last
   colour. Measured on the built page: the longest run is the demo headline at
   644px, so 124px of it rides flat #1177A8. */
em.hl{
  background-image:var(--grad);
  background-size:520px 100%;
  background-repeat:no-repeat;
  background-color:#1177A8;
}

/* the island and the footer sit on the live site's 1180 grid with its own
   24px gutter, not base.css's 32px, so the row lines up with the live page */
.nav > .wrap,
.footer > .wrap{padding-left:24px;padding-right:24px}

/* Every nav and footer link on this page is an in-page anchor, and the island
   is FIXED over the top 72px of the viewport: without this the target of
   "Pricing" or "FAQ" lands underneath the pill. The live stylesheet solves it
   the same way (one global scroll-margin on the id'd landmarks). Sections that
   want more room already say so with an id selector, which outranks this. */
section[id]{scroll-margin-top:96px}

/* --- live button family --------------------------------------------------
   Scoped to the modifier so base.css's .btn geometry survives for every
   section that still uses .btn-coral / .btn-dark / .btn-ghost. */
.btn--live,.btn--ink,.btn--ghost{
  display:inline-flex;align-items:center;justify-content:center;gap:9px;
  border:0;cursor:pointer;border-radius:var(--r-pill);
  font-family:inherit;font-size:15px;font-weight:700;line-height:1.1;
  padding:14px 26px 11px;min-height:44px;white-space:nowrap;text-decoration:none;
  transition:background var(--t-fast) ease,border-color var(--t-fast) ease,
             color var(--t-fast) ease,transform var(--t-fast) ease;
}
.btn--live{background:var(--live);color:var(--accent-ink)}
.btn--live:hover{background:var(--live-hover)}
.btn--live:active{background:var(--live-press)}
.btn--ink{background:var(--ink);color:#fff}
.btn--ink:hover{background:var(--ink-hover)}
.btn--ghost{border:1px solid var(--line-strong);color:var(--ink);background:var(--paper)}
.btn--ghost:hover{border-color:var(--ink);background:var(--paper-3)}
.btn--sm{padding:10px 18px 7px;font-size:13.5px;min-height:36px;letter-spacing:.04em}
/* the live site's one uppercase rule for small labels, and the ONE correct route
   to Georgian caps on this font stack. Two halves, and neither replaces the other:

   text-transform:uppercase raises the LATIN only. Chromium implements the CSS
   Georgian exception, so it leaves Mkhedruli exactly as written (and downcases
   real Mtavruli, which is one of the two reasons never to reach for it there).

   font-feature-settings:"case" 1 is what produces MTAVRULI. FiraGO ships a `case`
   variant for all 43 Mkhedruli letters, so the feature substitutes true Mtavruli
   letterforms on ordinary Mkhedruli text, and lifts Latin punctuation and brackets
   to cap height in the same pass. Verified in headless Chrome on this page: the
   same string measures 192.48px lowercase and 203.05px with the feature on, and
   the ascenders and descenders are gone from the rendering.

   The two things you must never do instead: text-transform on Georgian (above),
   and baking U+1C90.. Mtavruli characters into the markup. FiraGO carries ZERO
   Mtavruli code points, so baked characters fall out of it into a system font and
   change typeface mid line. The hero headline and the two hero CTA labels take
   their caps from this same feature, in sections-suppo/hero/section.css. */
.nav__cta,.nav__cta-m,.brand__name{font-feature-settings:"case" 1}
/* the hard rule: text-transform NEVER reaches Georgian. Scoping it to :lang(en)
   is what guarantees that, and "case" 1 above is what makes the Mtavruli. */
.nav__cta:lang(en),.nav__cta-m:lang(en),.brand__name:lang(en){text-transform:uppercase}
/* --lg is the closing beat's size and nothing else's */
.btn--lg{padding:17px 32px 14px;font-size:16px;min-height:51px}

/* --- nav: the island -----------------------------------------------------
   One ink pill floating 14px off the top edge, the only dark object on the
   light page. The header strip is transparent and pointer-transparent; only
   the pill is a thing. It wakes up narrow (960px) and stretches to the grid
   on the first scroll. */
.nav{
  position:fixed;top:0;left:0;right:0;bottom:auto;transform:none;z-index:60;
  display:block;gap:0;white-space:normal;flex-wrap:nowrap;
  padding:14px 0;pointer-events:none;
  background:none;border:0;border-radius:0;box-shadow:none;
  backdrop-filter:none;-webkit-backdrop-filter:none;
}
/* The nav CTA is the first button a visitor sees, on every screen of every page,
   and base.css's `.nav a` (0,1,1) was beating `.btn--live` (0,1,0) on THREE
   properties at once: colour (var(--muted) grey, 3.34:1 on the green), weight
   (600) and size (14px). These selectors are 0,2,0 and 0,2,1, so they win, and
   they restore exactly the pill it was designed as: accent ink on green
   (#062A17 on #00D26A = 7.72:1) at .btn--sm geometry, which is also what stops
   it being the only 30px green pill on a page of 44px ones. */
.nav .btn--live,
.nav a.btn--live,
.nav .nav__cta,
.nav .nav__cta-m{color:var(--accent-ink);font-weight:700;font-size:13.5px;min-height:36px}
.nav .nav__cta-m{font-size:15px;min-height:44px}

.nav__row{
  max-width:960px;margin:0 auto;
  --nav-dur:1100ms;
  transition:max-width var(--nav-dur) var(--nav-ease),background-color 800ms var(--nav-ease),
             border-color 800ms var(--nav-ease),color 800ms var(--nav-ease),
             backdrop-filter 800ms var(--nav-ease),-webkit-backdrop-filter 800ms var(--nav-ease);
  pointer-events:auto;position:relative;display:flex;align-items:center;gap:14px;height:58px;
  padding:0 10px 0 22px;border-radius:var(--r-pill);color:#fff;
  background:rgba(24,24,27,.96);border:1px solid rgba(255,255,255,.07);
  backdrop-filter:saturate(160%) blur(14px);-webkit-backdrop-filter:saturate(160%) blur(14px);
}
.nav.is-stuck .nav__row{max-width:calc(var(--wrap) - 48px)}
/* at the very top the island has no body yet: ink type straight on the hero */
.nav:not(.is-stuck):not(.is-open) .nav__row{
  background:rgba(24,24,27,0);border-color:rgba(255,255,255,0);color:var(--ink);
  backdrop-filter:none;-webkit-backdrop-filter:none;
}
.nav:not(.is-stuck):not(.is-open) .brand__mark{color:var(--ink)}
.nav:not(.is-stuck):not(.is-open) .nav__links a{color:rgba(10,10,11,.66)}
.nav:not(.is-stuck):not(.is-open) .nav__links a:hover{color:var(--ink)}
.nav:not(.is-stuck):not(.is-open) .lang{background:rgba(10,10,11,.07)}
.nav:not(.is-stuck):not(.is-open) .lang:hover{background:rgba(10,10,11,.12)}
.nav:not(.is-stuck):not(.is-open) .nav__burger{border-color:rgba(10,10,11,.22)}
.nav:not(.is-stuck):not(.is-open) .nav__burger span{background:var(--ink)}
.nav .brand__mark,.nav__links a,.lang,.nav__burger,.nav__burger span{
  transition:background-color 800ms var(--nav-ease),color 800ms var(--nav-ease),
             border-color 800ms var(--nav-ease),opacity var(--t-fast) ease;
}

.brand{display:flex;align-items:center;gap:12px;flex:none;color:inherit;text-decoration:none}
.nav .brand{font-size:17px;letter-spacing:normal;color:inherit}
/* the mark = the founder's headset vector, inline so it takes currentColor for
   the ink parts and var(--live) for the green bar and the mic dot */
.brand__mark{width:38px;height:35px;display:block;flex:none;color:var(--ink)}
.brand__mark .mark{width:100%;height:100%;display:block;overflow:visible}
.brand__mark .m-bar{transform-box:fill-box;transform-origin:center}
.brand__name{font-weight:800;font-size:17px;letter-spacing:.15em}
.nav .brand__mark{color:#fff}
/* the three bars of the mark breathe like a level meter, exactly as the live
   header does it: scaleY on three fill-box rects, nothing else. The island is
   fixed, so this loop can never be paused off screen the way a section loop is;
   it stays affordable because it is three transforms inside a 38x35 box and it
   is the page's only always-on animation. */
.brand__mark .m-bar{animation:navBar 1.8s var(--nav-ease) infinite}
.brand__mark .m-bar:nth-of-type(1){animation-delay:0ms}
.brand__mark .m-bar--mid{animation-name:navBarMid;animation-delay:220ms}
.brand__mark .m-bar:nth-of-type(3){animation-delay:440ms}
@keyframes navBar{0%,100%{transform:scaleY(1)}50%{transform:scaleY(1.45)}}
@keyframes navBarMid{0%,100%{transform:scaleY(1)}50%{transform:scaleY(.78)}}

.nav__links{display:flex;align-items:center;gap:28px;margin:0 auto;list-style:none}
.nav__links a{font-size:14.5px;font-weight:500;letter-spacing:normal;text-decoration:none;color:rgba(255,255,255,.72)}
.nav__links a:hover{color:#fff}
.nav__right{margin-left:0;display:flex;align-items:center;gap:10px}

/* language = ONE button in the darker well: the globe and the code of the language
   you are reading (KA, EN, DE ...). It opens .langMenu, the searchable list of the
   97 languages Suppo answers in, which i18n/loader.js builds into the island. Same
   height and the same well as the flag pair it replaces, so the island's silhouette
   does not move. */
.lang{display:inline-flex;align-items:center;gap:6px;border:0;cursor:pointer;
  border-radius:var(--r-pill);padding:0 11px 0 9px;min-height:30px;background:#33333A;
  color:inherit;font-family:inherit;font-size:12px;font-weight:700;letter-spacing:.06em;line-height:1}
.lang:hover{background:#3E3E46}
.lang[aria-expanded="true"]{background:var(--pill-ink)}
.lang__globe{width:15px;height:15px;display:block;flex:none;opacity:.85}
.lang__code{display:block;padding-top:1px;min-width:2ch;text-align:center}
/* phone: the button is a real tap target (the island has the height) */
@media (max-width:680px){
  .lang{min-width:44px;min-height:44px;padding:0 10px 0 9px}
  /* the burger is the ONLY way to open the menu on a phone: it gets the full
     44 in both axes, not 38 */
  .nav__burger{width:44px;height:44px}
}

/* --- the language menu ---------------------------------------------------
   A second ink card under the island, like the phone menu: search on top,
   the list grouped A..Z by English name, native name first. Rows are 44px.
   [hidden] is restated because .langMenu sets display:flex. */
.langMenu{position:absolute;top:calc(100% + 8px);inset-inline-end:0;width:312px;
  max-height:min(72vh,540px);display:flex;flex-direction:column;overflow:hidden;z-index:2;
  background:var(--pill-ink);color:#fff;border:1px solid rgba(255,255,255,.07);border-radius:22px;
  box-shadow:0 18px 48px rgba(10,10,11,.28)}
.langMenu[hidden]{display:none}
.langMenu__search{display:flex;align-items:center;gap:10px;min-height:56px;padding:6px 14px 6px 18px;
  border-bottom:1px solid rgba(255,255,255,.08);color:rgba(255,255,255,.6)}
.langMenu__search:focus-within{color:#fff}
.langMenu__searchIcon{width:16px;height:16px;flex:none}
.langMenu__input{flex:1 1 auto;min-width:0;min-height:44px;border:0;background:none;color:#fff;
  font-family:inherit;font-size:15px;font-weight:500;outline:none;-webkit-appearance:none;appearance:none}
.langMenu__input::placeholder{color:rgba(255,255,255,.45)}
.langMenu__input::-webkit-search-cancel-button{-webkit-appearance:none;appearance:none}
.langMenu__list{list-style:none;margin:0;padding:6px 8px 10px;overflow-y:auto;overscroll-behavior:contain;
  scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.18) transparent}
.langMenu__group{font-size:12px;font-weight:700;letter-spacing:.08em;color:rgba(255,255,255,.4);
  padding:12px 12px 4px;text-transform:uppercase}
.langMenu__group[hidden]{display:none}
.langMenu__item{display:flex;align-items:center;gap:10px;min-height:44px;padding:0 12px;
  border-radius:12px;cursor:pointer;font-size:14.5px;font-weight:500;color:rgba(255,255,255,.88)}
.langMenu__item[hidden]{display:none}
.langMenu__item.is-active{background:rgba(255,255,255,.09);color:#fff}
.langMenu__item.on{color:#fff;font-weight:700}
.langMenu__native{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.langMenu__en{flex:none;font-size:12px;font-weight:500;color:rgba(255,255,255,.5);white-space:nowrap}
.langMenu__check{width:16px;height:16px;flex:none;opacity:0;color:var(--live)}
.langMenu__item.on .langMenu__check{opacity:1}
.langMenu__none{padding:14px 12px;font-size:14px;color:rgba(255,255,255,.55)}
.langMenu__none[hidden]{display:none}
.langMenu__item:focus-visible{outline:2px solid #fff;outline-offset:-2px}

/* --- scripts Gilroy and FiraGO do not carry --------------------------------
   The loader stamps html[data-script] from i18n/languages.json. Gilroy and FiraGO
   stay first (Latin, Cyrillic, Greek and Georgian glyphs), then the system faces
   that hold the script, Noto first where it is installed. Negative tracking is
   lifted for these scripts: joined and stacked glyphs collide under it. */
html[data-script="arabic"] body{font-family:"Gilroy","FiraGO","Noto Sans Arabic","Noto Naskh Arabic","Geeza Pro","Segoe UI",Tahoma,sans-serif}
html[data-script="hebrew"] body{font-family:"Gilroy","FiraGO","Noto Sans Hebrew","Arial Hebrew","Segoe UI",Tahoma,sans-serif}
html[data-script="devanagari"] body{font-family:"Gilroy","FiraGO","Noto Sans Devanagari","Kohinoor Devanagari","Devanagari Sangam MN","Nirmala UI",sans-serif}
html[data-script="bengali"] body{font-family:"Gilroy","FiraGO","Noto Sans Bengali","Kohinoor Bangla","Bangla Sangam MN","Nirmala UI",sans-serif}
html[data-script="gujarati"] body{font-family:"Gilroy","FiraGO","Noto Sans Gujarati","Kohinoor Gujarati","Gujarati Sangam MN","Nirmala UI",sans-serif}
html[data-script="gurmukhi"] body{font-family:"Gilroy","FiraGO","Noto Sans Gurmukhi","Gurmukhi MN","Nirmala UI",sans-serif}
html[data-script="tamil"] body{font-family:"Gilroy","FiraGO","Noto Sans Tamil","Tamil Sangam MN","Nirmala UI",sans-serif}
html[data-script="telugu"] body{font-family:"Gilroy","FiraGO","Noto Sans Telugu","Kohinoor Telugu","Telugu Sangam MN","Nirmala UI",sans-serif}
html[data-script="kannada"] body{font-family:"Gilroy","FiraGO","Noto Sans Kannada","Kannada Sangam MN","Nirmala UI",sans-serif}
html[data-script="malayalam"] body{font-family:"Gilroy","FiraGO","Noto Sans Malayalam","Malayalam Sangam MN","Nirmala UI",sans-serif}
html[data-script="oriya"] body{font-family:"Gilroy","FiraGO","Noto Sans Oriya","Oriya Sangam MN","Nirmala UI",sans-serif}
html[data-script="sinhala"] body{font-family:"Gilroy","FiraGO","Noto Sans Sinhala","Sinhala Sangam MN","Nirmala UI",sans-serif}
html[data-script="thai"] body{font-family:"Gilroy","FiraGO","Noto Sans Thai",Thonburi,"Leelawadee UI",sans-serif}
html[data-script="lao"] body{font-family:"Gilroy","FiraGO","Noto Sans Lao","Lao Sangam MN","Leelawadee UI",sans-serif}
html[data-script="khmer"] body{font-family:"Gilroy","FiraGO","Noto Sans Khmer","Khmer Sangam MN","Leelawadee UI",sans-serif}
html[data-script="myanmar"] body{font-family:"Gilroy","FiraGO","Noto Sans Myanmar","Myanmar Sangam MN","Myanmar Text",sans-serif}
html[data-script="ethiopic"] body{font-family:"Gilroy","FiraGO","Noto Sans Ethiopic",Kefa,Ebrima,sans-serif}
html[data-script="armenian"] body{font-family:"Gilroy","FiraGO","Noto Sans Armenian",Mshtakan,Sylfaen,sans-serif}
html[data-script="zh"] body{font-family:"Gilroy","FiraGO","Noto Sans SC","PingFang SC","Hiragino Sans GB","Microsoft YaHei",sans-serif}
html[data-script="ja"] body{font-family:"Gilroy","FiraGO","Noto Sans JP","Hiragino Sans","Hiragino Kaku Gothic ProN","Yu Gothic",Meiryo,sans-serif}
html[data-script="ko"] body{font-family:"Gilroy","FiraGO","Noto Sans KR","Apple SD Gothic Neo","Malgun Gothic",sans-serif}
html[data-script]:not([data-script=""]) h1,html[data-script]:not([data-script=""]) h2,html[data-script]:not([data-script=""]) h3{letter-spacing:0}

/* --- right-to-left (ar, fa, ur, ps, sd, ku, iw) -------------------------------
   Flex mirrors itself; only the island's asymmetric padding and the menu's edge
   are written with physical sides and get their mirror here. */
html[dir="rtl"] .nav__row{padding:0 22px 0 10px}
html[dir="rtl"] .lang{padding:0 9px 0 11px}
html[dir="rtl"] .nav__right{margin-left:0}
html[dir="rtl"] .footer__sig{margin-left:0;margin-right:auto}

/* --- legal pages in a third language ----------------------------------------
   The documents exist in KA and EN only (section[lang="ka"] / section[lang="en"]
   are toggled by html[lang]); any other language reads the EN document. */
html:not([lang="ka"]):not([lang="en"]) .lg-doc section[lang="en"],
html:not([lang="ka"]):not([lang="en"]) .lg-hub section[lang="en"],
html:not([lang="ka"]):not([lang="en"]) .lg-toc nav[lang="en"]{display:block}

.nav__burger{display:none;width:38px;height:38px;padding:0;background:none;cursor:pointer;
  border-radius:var(--r-pill);border:1px solid rgba(255,255,255,.18)}
.nav__burger span{display:block;width:15px;height:1.5px;background:#fff;margin:3px auto;border-radius:2px;
  transition:transform var(--t-med) var(--nav-ease),opacity var(--t-fast) ease}
.nav__cta-m{display:none}
/* one CTA, two labels: the long one everywhere, the one-word one on a phone */
.nav__cta-short{display:none}
/* mobile menu: a second ink card hanging under the island */
.nav.is-open .nav__links{
  display:flex;position:absolute;top:calc(100% + 8px);left:0;right:0;
  flex-direction:column;align-items:stretch;gap:0;margin:0;padding:8px 22px 16px;
  background:var(--pill-ink);border:1px solid rgba(255,255,255,.07);border-radius:22px;
}
.nav.is-open .nav__links a{padding:13px 0;font-size:16px;color:#fff;border-bottom:1px solid rgba(255,255,255,.08)}
.nav.is-open .nav__links a:last-child{border-bottom:0}
/* the green CTA lives in the island at every width now, so the menu's last row
   is always the one BEFORE the hidden CTA link, and that is the row that must
   lose the divider */
.nav.is-open .nav__links a:nth-last-child(2){border-bottom:0}
.nav.is-open .nav__burger span:nth-child(1){transform:translateY(4.5px) rotate(45deg)}
.nav.is-open .nav__burger span:nth-child(2){opacity:0}
.nav.is-open .nav__burger span:nth-child(3){transform:translateY(-4.5px) rotate(-45deg)}

/* --- focus, once, for the whole page ---------------------------------------
   Tab stops 1-12 had no author ring at all and the designed green one measured
   1.82:1. One ink ring, 3px clear of the object; inside the ink island it flips
   to white (17.4:1 on rgba(24,24,27,.96)). No green rings anywhere. */
.nav a:focus-visible,
.brand:focus-visible,
.lang:focus-visible,
.nav__burger:focus-visible,
.btn--live:focus-visible,
.btn--ink:focus-visible,
.btn--ghost:focus-visible{outline:2px solid var(--ink);outline-offset:3px}
/* inside the ink island the ring flips to white (17.4:1 on rgba(24,24,27,.96)).
   It is scoped to the two states where the island HAS a body: at the very top
   the pill is transparent over the light hero, and a white ring there would be
   the invisible one. .nav.is-stuck a:focus-visible is 0,3,1, which is what it
   takes to outrank .nav a:focus-visible above. */
.nav.is-stuck :focus-visible,
.nav.is-open :focus-visible,
.nav.is-stuck a:focus-visible,
.nav.is-open a:focus-visible{outline-color:#fff}

/* --- the skip link (task 16) ----------------------------------------------
   Off screen until it takes focus, then the first thing on the page. */
.skipLink{position:absolute;top:0;inset-inline-start:0;width:1px;height:1px;overflow:hidden;
  clip-path:inset(50%);white-space:nowrap;font-size:14px;font-weight:700;
  letter-spacing:-.01em;text-decoration:none;color:var(--ink)}
/* clipped to a pixel, not parked at left:-9999px: under dir="rtl" the page scrolls
   leftward and the parked link became 10,000px of horizontal scroll */
.skipLink:focus{width:auto;height:auto;clip-path:none;inset-inline-start:16px;top:16px;z-index:70;
  background:var(--ink);color:#fff;padding:12px 18px;border-radius:var(--r-pill)}
/* the ring goes INSIDE this one: the pill is ink on a near-white page, so an
   outer ring would either merge with the pill or with the ground */
.skipLink:focus-visible{outline:2px solid #fff;outline-offset:-4px}

/* --- the eyebrow, once (task 6) -------------------------------------------
   Five sections hand-rolled this label. One rule now: 12px/700, .14em, the
   page's --muted-2 label ink, and a 6px live dot as the ::before. Caps are the
   same two-half recipe as the nav CTA above: text-transform ONLY under
   :lang(en), "case" 1 for the Georgian Mtavruli. */
.eyebrow{
  display:inline-flex;align-items:center;gap:8px;
  font-size:12px;font-weight:700;letter-spacing:.14em;line-height:1.3;
  color:var(--muted-2);text-transform:none;font-feature-settings:"case" 1;
}
.eyebrow::before{
  content:"";width:6px;height:6px;flex:none;border-radius:var(--r-pill);
  background:var(--live);
}
.eyebrow:lang(en){text-transform:uppercase}

/* --- tags, once (task 7) ---------------------------------------------------
   SOON is one object everywhere. Each of the three stands alone; they also
   compose (`class="tag tag--live"`) because the modifiers come after .tag. */
.tag,.tag--live,.tag--promo{
  display:inline-flex;align-items:center;gap:6px;
  border-radius:var(--r-pill);font-size:12px;line-height:1.25;
  white-space:nowrap;letter-spacing:.01em;
}
.tag{font-weight:600;color:var(--muted-2);padding:3px 9px;
  background:transparent;border:1px solid var(--line)}
.tag--live{font-weight:700;color:var(--green-ink);padding:3px 9px 3px 7px;
  background:rgba(0,185,94,.11);border:0}
.tag--live::before{content:"";width:6px;height:6px;flex:none;
  border-radius:var(--r-pill);background:var(--live)}
.tag--promo{font-weight:700;color:var(--ink);padding:3px 9px;
  background:var(--live);border:0}
/* the same objects on an ink panel */
.tag--onDark{background:rgba(255,255,255,.05);border:1px solid rgba(255,255,255,.10);
  color:rgba(255,255,255,.78)}
.tag--live.tag--onDark{color:var(--mint)}

/* --- the live dot --------------------------------------------------------- */
.dot-live{
  width:7px;height:7px;border-radius:var(--r-pill);background:var(--live);
  flex:none;position:relative;display:inline-block;
}
/* the ring the live site puts around it: one expanding, fading circle, transform
   and opacity only. It ships PAUSED, because the only place this dot lives is
   the closing screen and a loop must not run while its section is off screen.
   The owning section is what starts it (see the footer's .f-awake). */
.dot-live::after{
  content:"";position:absolute;inset:0;border-radius:var(--r-pill);
  border:1px solid var(--live);
  animation:dotRing 2.4s var(--nav-ease) infinite;
  animation-play-state:paused;
}
@keyframes dotRing{
  0%  {transform:scale(1);opacity:.5}
  70% {opacity:0}
  100%{transform:scale(2.4);opacity:0}
}

/* --- footer --------------------------------------------------------------
   The live footer verbatim: a paper-2 band under one hairline, a 1.6fr + 3
   column grid, a bottom rule carrying the entity line and the live signature,
   and the ghost wordmark cropped by the bottom edge. */
.footer{
  border-top:1px solid var(--line-solid);
  padding:64px 0 40px;
  background:var(--paper-2);
}
.footer__grid{display:grid;grid-template-columns:1.6fr repeat(3,1fr);gap:40px;align-items:start}
.footer h3{
  font-size:12px;letter-spacing:.14em;color:var(--muted-2);font-weight:700;line-height:1.4;
  /* the shared .eyebrow's recipe exactly: "case" 1 renders the Georgian as
     Mtavruli out of FiraGO's case variants, text-transform is scoped to English
     below, and the letterspacing carries the "label" reading in both. */
  font-feature-settings:"case" 1;
}
.footer h3:lang(en){text-transform:uppercase}
.footer ul{margin-top:16px;display:flex;flex-direction:column;gap:11px;list-style:none;padding:0}
.footer a{font-size:14px;color:var(--muted);text-decoration:none;transition:color var(--t-fast) ease}
.footer a:hover{color:var(--ink)}
.footer .meta{font-size:13px;line-height:1.55;color:var(--muted)}
.footer .brand__name{color:var(--ink)}
.footer__bottom{
  margin-top:56px;padding-top:24px;border-top:1px solid var(--line-solid);
  display:flex;gap:16px;align-items:center;flex-wrap:wrap;font-size:13px;color:var(--muted);
}
.footer__sig{margin-left:auto;display:flex;align-items:center;gap:8px}
/* the ghost wordmark: the name, oversized, cropped by the band's bottom edge,
   a watermark rather than a heading. Decoration, so aria-hidden and inert. */
/* The footer's intro column, socials and blurb are chrome, not scroll choreography, so they
   live here rather than in the scroll section: the legal pages lift this footer element out of
   the built page and have no #footerWrap around it, and without these the social marks rendered
   as three bare glyphs in a vertical stack and the blurb ran the full column width. The section
   file keeps its own scoped copies for the wipe (they are more specific and still win there). */
.fIntro .brand{display:inline-flex}
.fBlurb{margin-top:16px;max-width:30ch}
.fSocial{display:flex;gap:8px;margin-top:20px}
.fBtn{
  width:38px;height:38px;border-radius:var(--r-pill);
  border:1px solid var(--line-solid);background:var(--paper);color:var(--ink);
  display:grid;place-items:center;
  transition:border-color var(--t-fast) ease,background var(--t-fast) ease;
}
.fBtn:hover{border-color:var(--ink);background:var(--paper-3)}
   /* = live's live/line mix */

/* --- animated mesh field --------------------------------------------------
   Colour lives in the GROUNDS between the surfaces as slow blurred drifting
   blobs, never on the reading surface. Shared so the integrations and closing
   beats can both stand on it. Markup:
     <div class="mesh" aria-hidden="true"><i></i>x5<div class="mesh__clear"></div></div>
   inside a positioned parent carrying .band--mesh. */
.band--mesh{position:relative;isolation:isolate;overflow:hidden}
.band--mesh > .mesh{z-index:-1}
.mesh{position:absolute;inset:0;overflow:hidden;pointer-events:none;contain:strict}
.mesh i{
  position:absolute;display:block;border-radius:50%;
  width:42vw;height:42vw;min-width:380px;min-height:380px;max-width:820px;max-height:820px;
  filter:blur(56px);opacity:var(--mesh-a);will-change:transform;transform:translateZ(0);backface-visibility:hidden;
  background:radial-gradient(circle at 50% 50%,var(--c) 0%,transparent 66%);
}
.mesh i:nth-child(1){--c:var(--m1);left:-12%;top:-18%}
.mesh i:nth-child(2){--c:var(--m2);right:-14%;top:-22%}
.mesh i:nth-child(3){--c:var(--m3);left:18%;bottom:-30%}
.mesh i:nth-child(4){--c:var(--m4);right:10%;bottom:-26%}
.mesh i:nth-child(5){--c:var(--m5);left:38%;top:-30%;width:34vw;height:34vw}
/* the clearing behind the type, painted as one STATIC layer above the blobs:
   a moving mask costs a re-rasterise every frame, this costs nothing */
.mesh__clear{
  position:absolute;inset:0;pointer-events:none;z-index:1;
  background:
    radial-gradient(58% 44% at 50% 38%,var(--paper) 0%,rgba(255,255,255,.72) 42%,rgba(255,255,255,0) 76%),
    linear-gradient(rgba(255,255,255,0) 52%,rgba(255,255,255,.55) 80%,var(--paper) 100%);
}
.mesh--close .mesh__clear{
  background:radial-gradient(58% 58% at 50% 50%,rgba(255,255,255,.62) 0%,rgba(255,255,255,0) 72%);
}
.mesh--band i{opacity:.62}
.mesh--band .mesh__clear{background:radial-gradient(50% 40% at 28% 18%,rgba(255,255,255,.55) 0%,rgba(255,255,255,0) 70%)}

/* --- narrower viewports --------------------------------------------------- */
@media (max-width:1080px){
  .footer__grid{grid-template-columns:1fr 1fr;gap:32px}
}
@media (max-width:900px){
  .nav__links{display:none}
  .nav__burger{display:block}
  .nav__row{padding:0 8px 0 16px}
  .nav__right{margin-left:auto}
  html[dir="rtl"] .nav__right{margin-left:0;margin-right:auto}
  html[dir="rtl"] .nav__row{padding:0 16px 0 8px}
  /* phones choke on a backdrop blur under a moving page: colour stays, blur goes */
  .nav__row{backdrop-filter:none;-webkit-backdrop-filter:none;
    transition:max-width var(--nav-dur) var(--nav-ease),background-color 800ms var(--nav-ease),
               border-color 800ms var(--nav-ease),color 800ms var(--nav-ease)}
  .nav.is-stuck .nav__row,.nav.is-open .nav__row{background:rgba(24,24,27,.98)}
  .mesh i{filter:none;opacity:calc(var(--mesh-a) * .72);width:92vw;height:92vw;min-width:0;min-height:0;
    background:radial-gradient(circle at 50% 50%,var(--c) 0%,transparent 62%)}
  .mesh i:nth-child(5){display:none}
}
@media (max-width:640px){
  .nav{padding:10px 0}
  .nav__row{height:54px;padding:0 8px 0 14px}
  .nav > .wrap,.footer > .wrap{padding-left:18px;padding-right:18px}
  /* At 390 the island CAN carry a pill and a burger, once two things shrink:
     the CTA drops to its one-word label (.nav__cta-short in the markup) and the
     language control shows only the language you are NOT reading, as two
     letters instead of a flag. Measured at 390: brand 110 + lang 46 + CTA 74 +
     burger 44 + three 10px gaps = 304 inside a 332px row. Hiding the CTA cost
     6.9 screens of scrolling with no visible primary action; this holds it to
     1 (the island is fixed). No floating bar and no scroll listener. */
  .nav__cta{display:inline-flex;min-height:40px;padding:10px 16px 7px}
  .nav .nav__cta{min-height:40px}
  .nav__cta-long{display:none}
  .nav__cta-short{display:inline}
  .lang{padding:0 10px 0 9px;min-width:44px;min-height:44px;background:rgba(255,255,255,.06)}
  .nav:not(.is-stuck):not(.is-open) .lang{background:rgba(10,10,11,.06)}
  /* the menu becomes a sheet pinned under the island, edge to edge */
  .langMenu{position:fixed;top:74px;inset-inline:10px;width:auto;max-height:calc(100vh - 90px);max-height:calc(100dvh - 90px)}
  .langMenu__search{padding:4px 12px 4px 16px}
  .langMenu__input{font-size:16px}
  html[dir="rtl"] .nav__row{padding:0 14px 0 8px}
  /* the island carries the CTA again, so the menu's copy of it would be a second
     green pill for the same action, stacked directly under the first. It goes,
     and the row above it becomes the menu's last row. */
  .nav.is-open .nav__links a:nth-last-child(2){border-bottom:0}
  .footer{padding:52px 0 32px}
  .footer__grid{grid-template-columns:1fr;gap:30px}
  .footer__bottom{margin-top:38px}
  .footer__sig{margin-left:0}
}

/* --- reduced motion ---------------------------------------------------------
   base.css's blanket rule is specificity 0,0,0 now that the !important is gone,
   so the two loops declared in THIS file (the level-meter bars in the mark, the
   ring around the live dot) stop themselves. */
@media (prefers-reduced-motion:reduce){
  .brand__mark .m-bar{animation:none}
  .dot-live::after{animation:none}
  .nav__row{transition:none}
}

/* ===== hero ===== */
/* ---------- SUPPO HERO  (Figma node 85-3916, the frame the founder picked) -------
   Composition, 1:1 with the frame: aurora ground, a badge pill, a two line INK
   headline, the sub, two pills, the trial line, and the console panel rising out
   of the fold, with the grey logo band under it.

   Geometry. The Figma frame is 1920 wide with a 1564 content column; our grid is
   1440 with an 1180 column, so every measurement below is the frame's number x
   0.7545 (1180/1564): headline block 1000 -> 755, logo marks 25 -> 24.

   One number is the founder's call rather than the raw conversion: the mat is
   920px, 64% of the 1440 frame, centred, because the frame's own 1300 converts to
   981 and read too wide beside the headline.

   ROUND 5 (2026-09-05), on the founder's note about this illustration, "make this
   illustration MUCH more detailed": the panel inside the mat is now the real
   portal rather than a sketch of one, and every string in it is 12px or larger.
   The two rules pull against each other, so the density comes from choosing what
   a working panel shows at that size (see the block that starts THE PANEL below),
   never from shrinking type until more of it fits.

   Rules kept: no blur anywhere (the mesh is plain radial gradients, not the live
   site's filter:blur(56px) stack), box-shadow only on the panel, the two CTAs and
   the badge, every idle loop a CSS keyframe on transform/opacity, parked off screen.
--------------------------------------------------------------------------------- */

#heroWrap{
  position:relative;
  height:170vh;
  background:var(--page);

  /* the three vertical numbers are viewport-relative so the panel is cut by the
     fold on a 813px frame (the Figma's own height) and still cut on a 1100px one,
     instead of leaving a void under it on tall screens */
  /* ROUND 6: the two vertical gaps around the copy block are the only place the
     taller panel can take its room from, so they are written as a LINE in the
     viewport height rather than a fraction of it: at 1060 they are the frame's own
     137 and 92, at 813 they close to 92 and 43 and hand the panel 36px it did not
     have. The copy block's own margins are untouched at every height. */
  --pad-top:clamp(90px,calc(19.03vh - 64.7px),150px);
  --panel-w:920px;
  --panel-h:clamp(280px,40vh,430px);
  --gap-panel:clamp(40px,calc(21.05vh - 131.16px),110px);

  /* ---- ROUND 6 SPACING TOKENS -----------------------------------------------
     The founder's note on this panel was "increase paddings and spacing around
     elements, everything feels super duper tight". Every number below is his ask
     at the top of the range and the largest that still fits at the bottom, and it
     is written as ONE fluid clamp per token rather than two profiles either side
     of a media query: a breakpoint here would make the panel jump 70px of content
     on a one pixel resize. The maxima are reached at a 1060 fold, the minima at
     813, and every value in between is a straight line, so nothing ever jumps.
     Type sizes are NOT in this list. Nothing here shrinks any of them. ---------- */
  /* ROUND 6b (2026-09-06): the ladder is re-anchored on the two folds this page is
     verified at rather than on a 1060 that no headless window ever reports. Every
     line below now reaches the founder's number at vh 973 (the 2000x1060 window)
     and sits one or two px under it at vh 813 (the 1440x900 window), which is the
     shortest fold the panel is drawn for. Nothing here is a breakpoint: each token
     is one straight line between those two folds, so a resize never jumps. */
  --mat-pad:clamp(11px,calc(.81vh + 4.42px),13px);      /* mat around the window  */
  --bar-h:clamp(42px,calc(2.5vh + 21.68px),46px);       /* window chrome row  ~44 */
  --head-h:clamp(43px,calc(2.5vh + 22.68px),47px);      /* conversations header   */
  --stats-p:clamp(12px,calc(3.125vh - 13.41px),18px);   /* stats strip, vertical  */
  --col-p:clamp(14px,calc(1.25vh + 3.84px),16px);       /* rail + list, vertical  */
  --col-px:clamp(11px,calc(.625vh + 5.92px),13px);      /* list, horizontal       */
  --chat-p:clamp(15px,calc(2.5vh - 5.33px),20px);       /* chat pane, vertical    */
  --nav-h:clamp(40px,calc(1.25vh + 29.84px),42px);      /* rail route row         */
  --nav-gap:clamp(5px,calc(.625vh - .08px),7px);
  --row-h:clamp(58px,calc(2.5vh + 37.68px),62px);       /* conversation row box   */
  --row-gap:clamp(6px,calc(.625vh + .92px),7px);
  --row-step:calc(var(--row-h) + var(--row-gap));  /* the arrival loop's pitch    */
  --chip-p:clamp(12px,calc(1.25vh + 1.84px),14px);      /* under the filter chips */
  --bub-gap:clamp(10px,calc(1.25vh - .16px),12px);      /* between two bubbles    */
  --bub-p:clamp(10px,calc(1.25vh - .16px),12px);        /* inside a bubble        */
  --rcpt-p:clamp(12px,calc(1.875vh - 3.24px),16px);     /* inside the receipt     */
  --gap-s:clamp(6px,calc(.81vh - .58px),8px);           /* two lines of one block */
  --gap-m:clamp(12px,calc(2.02vh - 4.42px),16px);       /* one block to the next  */
  --odo-h:20px;     /* the rolling unread count, one digit tall */
  --logo-h:24px;
  /* the panel's own three colours: the tile grey he likes, and the green tint
     that marks everything Suppo did (the open route, the live call, its own
     turns, the written booking) */
  --tile:#F1F1F4;
  --tint:rgba(0,210,106,.10);
  --tint-line:rgba(0,210,106,.22);

  /* every idle loop ends its declaration with animation-play-state:var(--ps).
     Parking them by specificity does not work: each loop rule sets the `animation`
     SHORTHAND, which resets play-state to running, and those rules carry more
     classes than any #heroWrap.rest selector could without becoming unreadable.
     One inherited custom property parks all of them from one place instead. */
  --ps:running;
}
#heroWrap.rest{--ps:paused}
#heroWrap .pin{
  align-items:stretch;
  justify-items:stretch;
  background:var(--page);
}

/* ---------- aurora ground ---------------------------------------------------- */
#heroWrap .hMesh{position:absolute;inset:0;overflow:hidden;pointer-events:none;z-index:0;contain:strict}
#heroWrap .hMesh i{
  position:absolute;display:block;border-radius:50%;
  background:radial-gradient(closest-side circle,var(--c) 0%,rgba(255,255,255,0) 100%);
  opacity:var(--o,.55);
  will-change:transform;
}
#heroWrap .hb1{--c:#5DFFC3;--o:.62;left:-24%;top:-30%;width:124%;max-width:1120px;height:1020px}
#heroWrap .hb2{--c:#3EC5FF;--o:.60;right:0;top:-34%;width:124%;max-width:1220px;height:1120px}
#heroWrap .hb3{--c:#8A7CFF;--o:.34;left:-16%;bottom:-46%;width:116%;max-width:1040px;height:940px}
#heroWrap .hb4{--c:#6FE3FF;--o:.42;right:0;top:12%;width:62%;max-width:900px;height:840px}
/* the clearing: colour lives at the edges, paper under the type and under the panel */
#heroWrap .hMesh__clear{
  position:absolute;inset:0;z-index:1;pointer-events:none;
  background:
    radial-gradient(56% 40% at 50% 30%,var(--page) 0%,rgba(250,250,250,.74) 44%,rgba(250,250,250,0) 78%),
    linear-gradient(rgba(250,250,250,0) 36%,rgba(250,250,250,.62) 62%,var(--page) 84%);
}

/* ---------- stage ------------------------------------------------------------ */
/* height:100vh, not 100%: .pin is a grid and a grid row sizes to its content, so
   height:100% would let the stage grow to 864 and the band (top:100%) would hang
   51px too low. A fixed 100vh keeps the box exactly the frame and lets the panel
   spill past the fold, where .pin's overflow:hidden clips it. */
#heroWrap .heroStage{
  position:relative;z-index:1;
  /* min-width:0 : .pin is a grid and a grid item's automatic minimum is its
     MIN-CONTENT, so at 390 the console's min-content pushed the whole stage to
     399 and every width:100% child with it. Nothing on desktop is near its
     min-content, so this only ever bites on a phone. */
  width:100%;min-width:0;height:100vh;max-height:100vh;
  display:flex;flex-direction:column;align-items:center;
  padding-top:var(--pad-top);
}

#heroWrap .heroCopy{
  width:100%;max-width:var(--maxw);
  padding:0 32px;
  text-align:center;
  flex:none;
  will-change:transform,opacity;
}

/* the one line the mock leaves in the accessibility tree. .heroShot itself is
   aria-hidden, so this span is its sibling and not its child, or nothing would
   read it. Off screen for sighted readers, in the tree for the rest. */
#heroWrap .srOnly{
  position:absolute;width:1px;height:1px;margin:-1px;padding:0;
  overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0;
}

/* ---------- badge ------------------------------------------------------------ */
#heroWrap .hBadge{
  display:inline-flex;align-items:center;gap:9px;
  height:34px;padding:0 17px;border-radius:100px;
  background:var(--panel);border:1px solid var(--line-solid);
  box-shadow:0 1px 2px rgba(10,10,11,.04),0 6px 18px rgba(10,10,11,.05);
  font-size:12.5px;font-weight:600;letter-spacing:-.004em;color:var(--ink);
  opacity:0;transform:translateY(10px) scale(.94);
  transition:opacity .5s var(--ease) .12s,transform .6s var(--ease-pop) .12s;
}

/* ---------- headline: both lines INK, per-word slide-up --------------------- */
#heroWrap .heroTitle{
  margin-top:16px;
  font-size:50px;line-height:1.04;letter-spacing:-.014em;font-weight:700;
  color:var(--ink);
}
/* MTAVRULI, the only route that exists on this font stack. FiraGO ships a `case`
   variant for all 43 Mkhedruli letters and carries ZERO Mtavruli code points, so
   the caps in the frame are the OpenType `case` feature applied to ordinary
   Mkhedruli text: no text-transform (Chromium's Georgian exception refuses to
   raise Mkhedruli, and downcases real Mtavruli) and no baked U+1C90.. characters
   (they would fall out of FiraGO into a system font and change typeface mid line).
   Caps run about 5.5% wider than the lower case, which is why the size drops from
   55 to 50 and the tracking tightens: the two lines land at the frame's width.
   Scoped to :lang(ka), so the English headline keeps its sentence case and the EN
   toggle swaps only the words. */
#heroWrap .heroTitle:lang(ka) .wd{font-feature-settings:"case" 1}
#heroWrap .heroTitle:lang(en){font-size:59px;line-height:1.04;letter-spacing:-.034em;font-weight:800}
#heroWrap .heroTitle .ln{display:block}
#heroWrap .heroTitle .sp{display:inline-block;width:.26em}
#heroWrap .heroTitle .wd{
  display:inline-block;white-space:nowrap;
  opacity:0;transform:translateY(26px);
  transition:opacity .55s var(--ease) var(--d,0s),transform .7s var(--ease) var(--d,0s);
}
#heroWrap .heroStage .heroTitle .wd.shown{opacity:1;transform:none;transition:none}

/* ---------- sub, pills, trial line ------------------------------------------ */
#heroWrap .heroSub{
  max-width:640px;margin:14px auto 0;
  font-size:16px;line-height:1.55;font-weight:500;color:var(--muted);
  opacity:0;transform:translateY(16px);
  transition:opacity .6s var(--ease) .96s,transform .7s var(--ease) .96s;
}
#heroWrap .heroCta{
  margin-top:26px;display:flex;justify-content:center;align-items:center;gap:12px;
  opacity:0;transform:translateY(18px);
  transition:opacity .6s var(--ease) 1.06s,transform .7s var(--ease) 1.06s;
}
#heroWrap .hBtn{
  display:inline-flex;align-items:center;justify-content:center;text-decoration:none;
  height:44px;padding:0 26px;border-radius:100px;
  font-size:15px;font-weight:700;letter-spacing:-.006em;line-height:1;
}
/* both hero labels are Mtavruli in the frame, by the same `case` route as the
   headline; the tracking compensates for the wider caps inside a fixed pill */
#heroWrap .heroCta:lang(ka) .hBtn{font-feature-settings:"case" 1;letter-spacing:.008em}
#heroWrap .hBtn--live{
  background:var(--live);color:var(--ink);border:0;
  box-shadow:0 1px 2px rgba(0,150,76,.16),0 10px 24px rgba(0,210,106,.26);
}
#heroWrap .hBtn--live:hover{background:var(--live-press)}
#heroWrap .hBtn--ghost{
  background:var(--panel);border:1px solid var(--line-solid);color:var(--ink);
  box-shadow:0 1px 2px rgba(10,10,11,.04);
}
#heroWrap .hBtn--ghost:hover{border-color:var(--ink)}

#heroWrap .heroNote{
  margin-top:20px;display:flex;align-items:center;justify-content:center;gap:9px;
  font-size:13px;font-weight:500;color:var(--muted);
  opacity:0;transform:translateY(14px);
  transition:opacity .6s var(--ease) 1.16s,transform .7s var(--ease) 1.16s;
}
#heroWrap .num{font-variant-numeric:tabular-nums}

/* ---------- the group that parallaxes: panel + logo band -------------------- */
/* .heroLower carries ONLY the scrubbed transform, with no transition on it: an
   intro transition left in place here would swallow every scrub write for its
   1.2s delay and the panel would lag a third of the timeline behind the copy.
   The intro rise lives one level down, on .heroShot. */
#heroWrap .heroLower{
  width:100%;flex:1 1 auto;min-height:0;
  display:flex;flex-direction:column;align-items:center;
  margin-top:var(--gap-panel);
  will-change:transform,opacity;
}
#heroWrap .heroShot{
  width:100%;max-width:var(--maxw);padding:0 32px;flex:none;
  opacity:0;transform:translateY(60px);
  transition:opacity .7s var(--ease) 1.2s,transform .9s var(--ease) 1.2s;
}

/* on desktop the frame is a plain block: the mat keeps its own max-width and its
   own centring, and the frame measures exactly the mat. On a phone (see PHONE at
   the bottom) it becomes the overflow:hidden window the scaled stage is cropped by. */
#heroWrap .shotFrame{width:100%}
#heroWrap .shotMat{
  width:100%;max-width:var(--panel-w);height:var(--panel-h);
  margin:0 auto;
  padding:var(--mat-pad);
  border-radius:var(--r-chrome,16px);
  background:#EDEDF0;
  box-shadow:0 2px 6px rgba(10,10,11,.05),0 34px 70px rgba(10,10,11,.14);
}
#heroWrap .app{
  width:100%;height:100%;
  border-radius:10px;
  background:var(--panel);
  border:1px solid var(--line-solid);
  display:flex;flex-direction:column;overflow:hidden;
}

/* ================================================================================
   THE PANEL. Round 5, the founder's note on this illustration: "make this
   illustration MUCH more detailed". The frame size, the mat and the panel's place
   in the composition are untouched; what changed is what is INSIDE it, which is
   now the real portal (portal.suppo.ge, structure and labels read straight off
   the panel's own source): window chrome, a header with search and a language pill, a
   nav rail with six routes and two unread counts, a conversation list of seven
   threads on five channels with one call LIVE, a chat pane with five turns and a
   delivered tick, the booking receipt and a stats strip.

   Every string in it is 12px or larger. That is the whole reason the panel is
   built the way it is: at 12px a 902px wide console holds a rail, a list and a
   conversation and no more, so the density comes from CHOOSING what a real panel
   shows, not from shrinking type until more fits. Anything that does not fit at a
   given viewport height is clipped by the column that owns it, exactly the way a
   window clips: the list loses its last rows, the chat loses its oldest turns, and
   the two things the picture is about (the live call and the written booking) are
   the last to go.
   ============================================================================== */

/* ---------- window chrome --------------------------------------------------- */
#heroWrap .appBar{
  position:relative;flex:none;height:var(--bar-h);
  display:flex;align-items:center;gap:14px;
  padding:0 22px;border-bottom:1px solid var(--line-solid);background:var(--paper-2);
}
#heroWrap .appDots{display:inline-flex;gap:6px;font-style:normal;flex:none}
#heroWrap .appDots b{width:8px;height:8px;border-radius:50%;display:block}
#heroWrap .appDots b:nth-child(1){background:#F5B400}
#heroWrap .appDots b:nth-child(2){background:var(--live)}
#heroWrap .appDots b:nth-child(3){background:#3EC5FF}
#heroWrap .appTitle{
  flex:none;font-size:12px;font-weight:700;letter-spacing:-.004em;
  color:var(--ink);white-space:nowrap;
}
/* the address bar, centred on the window and not on the space left over by the
   title, which is what a real browser does and what makes the chrome read */
/* the mock is marked as a mock, the same way the demo panel marks its own
   sample transcript. Values are the shared .tag primitive's. */
#heroWrap .apSample{
  flex:none;font-size:12px;font-weight:600;color:var(--muted-2);
  border:1px solid var(--line);border-radius:999px;padding:3px 9px;
  white-space:nowrap;
}
#heroWrap .appUrl{
  position:absolute;left:50%;transform:translateX(-50%);
  height:26px;line-height:26px;padding:0 16px;border-radius:100px;
  background:var(--tile);color:var(--muted-2);
  font-size:12px;font-weight:600;white-space:nowrap;
}
#heroWrap .appLive{
  margin-left:auto;flex:none;display:inline-flex;align-items:center;gap:9px;
  font-size:12px;line-height:1.3;font-weight:600;color:var(--live-text);white-space:nowrap;
}

/* ---------- panel header: title, count, search, KA/EN ----------------------- */
#heroWrap .appHead{
  flex:none;height:var(--head-h);display:flex;align-items:center;gap:12px;
  padding:0 22px;border-bottom:1px solid var(--line-solid);
}
#heroWrap .ahTtl{flex:none;font-size:13px;font-weight:700;letter-spacing:-.008em;color:var(--ink);white-space:nowrap}
#heroWrap .ahN{
  flex:none;height:24px;line-height:24px;padding:0 10px;border-radius:100px;
  background:var(--tile);color:var(--muted-2);font-size:12px;font-weight:700;
}
#heroWrap .ahSearch{
  flex:1 1 auto;min-width:0;max-width:290px;margin-left:6px;
  display:flex;align-items:center;gap:9px;height:34px;padding:0 14px;
  border-radius:10px;background:var(--tile);color:var(--faint);
}
#heroWrap .ahSearch svg{width:14px;height:14px;flex:none}
#heroWrap .ahSearch span{font-size:12px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
#heroWrap .ahLang{
  flex:none;margin-left:auto;display:inline-flex;align-items:center;gap:3px;
  padding:3px;border-radius:100px;background:var(--tile);
}
#heroWrap .ahLang b{
  font-size:12px;font-weight:700;letter-spacing:.03em;line-height:22px;
  padding:0 10px;border-radius:100px;color:var(--faint);
}
#heroWrap .ahLang b.is-on{background:var(--ink);color:#fff}

/* ---------- body grid: rail | list | conversation --------------------------- */
#heroWrap .appBody{
  flex:1 1 auto;min-height:0;
  /* ROUND 6: the rail takes 1.2% off the list. Its own padding went 7 -> 12 with
     the spacing pass, and at 167px the quota card's label started truncating; the
     wider column gives the card back the 153px of inner width it had before, and
     the list takes 1.2% of its own so the third filter chip clears the divider at
     the founder's 8px gaps: the chips row measures 312px and the column now holds
     314. Both come out of the conversation, which is the widest column and the one
     with room to give. */
  display:grid;grid-template-columns:20.8% 1px 37.2% 1px 1fr;
}
#heroWrap .appBody::before,
#heroWrap .appBody::after{content:"";display:block;background:var(--line-solid)}
#heroWrap .appBody::before{grid-column:2;grid-row:1}
#heroWrap .appBody::after{grid-column:4;grid-row:1}

/* ---------- the nav rail ---------------------------------------------------- */
#heroWrap .appSide{
  grid-column:1;grid-row:1;min-width:0;overflow:hidden;
  display:flex;flex-direction:column;gap:var(--nav-gap);
  padding:var(--col-p) var(--col-px) var(--col-p) 12px;background:var(--paper-2);
}
#heroWrap .sideWs{display:flex;align-items:center;gap:10px;padding:0 4px;margin-bottom:var(--gap-s);min-width:0}
#heroWrap .sideWs i{
  flex:none;width:24px;height:24px;border-radius:7px;
  background:var(--live);color:var(--accent-ink);
  font-style:normal;font-size:12px;font-weight:800;line-height:24px;text-align:center;
}
#heroWrap .sideWs b{
  font-size:12px;font-weight:700;color:var(--ink);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
#heroWrap .appNav{
  flex:none;display:flex;align-items:center;gap:10px;height:var(--nav-h);padding:0 12px;
  border-radius:10px;font-size:12px;font-weight:600;color:var(--muted);
  white-space:nowrap;overflow:hidden;
}
#heroWrap .appNav span{overflow:hidden;text-overflow:ellipsis}
#heroWrap .appNav svg{width:16px;height:16px;flex:none;color:var(--faint)}
#heroWrap .appNav.is-on{background:var(--tint);color:var(--ink);font-weight:700}
#heroWrap .appNav.is-on svg{color:var(--live-text)}
/* two counts, two weights: the open route's unread is the green one, the other
   route's backlog is a quiet grey, so the rail has one focus and not two */
#heroWrap .navN,#heroWrap .navOdo{
  flex:none;margin-left:auto;height:var(--odo-h);min-width:var(--odo-h);padding:0 6px;
  border-radius:100px;font-size:12px;font-weight:700;text-align:center;
}
#heroWrap .navN{line-height:var(--odo-h);background:var(--tile);color:var(--muted-2)}
#heroWrap .navOdo{
  display:inline-block;overflow:hidden;
  background:var(--live);color:var(--accent-ink);
}
#heroWrap .navOdo i{display:block;font-style:normal}
#heroWrap .navOdo .num{display:block;height:var(--odo-h);line-height:var(--odo-h);font-size:12px}
/* the plan's quota, the way the real rail carries it. The rail's own 16px padding
   is the air below and beside it; padding-top puts the same 16 above. */
#heroWrap .sideQ{margin-top:auto;display:flex;flex-direction:column;gap:var(--gap-s);padding:var(--gap-m) 0 0}
#heroWrap .sideQR{display:flex;align-items:baseline;justify-content:space-between;gap:8px}
#heroWrap .sideQR span{font-size:12px;font-weight:500;color:var(--faint);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
#heroWrap .sideQR b{flex:none;font-size:12px;font-weight:700;color:var(--ink)}
#heroWrap .sideQB{display:block;height:5px;border-radius:100px;background:var(--tile);overflow:hidden}
#heroWrap .sideQB i{display:block;height:100%;width:32%;border-radius:100px;background:var(--live)}

/* ---------- the conversation list ------------------------------------------- */
#heroWrap .appList{
  grid-column:3;grid-row:1;position:relative;min-width:0;overflow:hidden;
  display:flex;flex-direction:column;padding:var(--col-p) var(--col-px) 0;
}
#heroWrap .apChips{flex:none;display:flex;gap:8px;padding:0 3px var(--chip-p)}
#heroWrap .apChip{
  height:26px;line-height:26px;padding:0 10px;border-radius:100px;
  background:var(--tile);color:var(--muted-2);
  font-size:12px;font-weight:600;white-space:nowrap;
}
#heroWrap .apChip.is-on{background:var(--ink);color:#fff}
#heroWrap .apRows{position:relative;flex:1 1 auto;min-height:0;overflow:hidden}
#heroWrap .apStack{display:flex;flex-direction:column;gap:var(--row-gap)}
#heroWrap .apRow{
  display:flex;align-items:center;gap:12px;
  height:var(--row-h);padding:0 14px;border-radius:12px;min-width:0;
}
#heroWrap .apRow.is-on{background:var(--tint)}
#heroWrap .apIco{flex:none;width:17px;height:17px;color:var(--muted)}
#heroWrap .apIco svg{width:17px;height:17px;display:block}
#heroWrap .apTxt{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;gap:var(--gap-s)}
#heroWrap .apTxt b{
  font-size:12.5px;font-weight:700;letter-spacing:-.006em;color:var(--ink);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
#heroWrap .apLine{
  font-size:12px;font-weight:500;color:var(--muted);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
#heroWrap .apSide{flex:none;display:flex;flex-direction:column;align-items:flex-end;gap:6px}
#heroWrap .apTime{font-size:12px;font-weight:500;color:var(--faint);white-space:nowrap}
#heroWrap .apPip{
  height:19px;min-width:19px;line-height:19px;padding:0 6px;border-radius:100px;
  background:var(--live);color:var(--accent-ink);
  font-size:12px;font-weight:700;text-align:center;
}
#heroWrap .apMark{flex:none;width:16px;height:16px;color:var(--live-text)}
#heroWrap .apMark svg{width:16px;height:16px;display:block}
#heroWrap .apTag{
  height:22px;line-height:22px;padding:0 10px;border-radius:100px;
  background:var(--live);color:var(--accent-ink);
  font-size:12px;font-weight:700;white-space:nowrap;
}
/* the running call's meter: ONE svg holding the same twenty bars twice, in a
   window exactly one repeat wide, so translateX(-50%) is a seamless scroll and a
   live audio meter costs a single keyframe animation */
#heroWrap .apWave{position:relative;display:block;width:100px;height:12px;overflow:hidden}
#heroWrap .apWave__s{
  position:absolute;left:0;top:0;width:200%;max-width:none;height:12px;
  fill:var(--live-text);opacity:.5;
}
/* the row that arrives on the loop sits over the list and takes no space */
#heroWrap .apRow--new{
  position:absolute;left:0;right:0;top:0;
  background:var(--tint);opacity:0;transform:translateY(-10px);
}
/* the rail refuses to be cut mid-row and so does the list: a 24px fade left the
   last row's NAME crisp and then guillotined it, which reads as a bug. The fade is
   one whole row tall, so whatever the window cuts is already dissolving before the
   edge and the column reads as a list that continues. */
#heroWrap .apFade{
  position:absolute;left:0;right:0;bottom:0;height:var(--row-h);pointer-events:none;
  background:linear-gradient(
    rgba(255,255,255,0) 0%,
    rgba(255,255,255,.55) 34%,
    rgba(255,255,255,.88) 62%,
    var(--panel) 88%);
}

/* ---------- the conversation ------------------------------------------------ */
#heroWrap .appChat{
  grid-column:5;grid-row:1;min-width:0;overflow:hidden;
  display:flex;flex-direction:column;padding:var(--chat-p) 22px;
}
#heroWrap .chHead{
  flex:none;display:flex;align-items:center;gap:12px;
  padding-bottom:var(--gap-m);border-bottom:1px solid var(--line-solid);
}
#heroWrap .chAva{
  flex:none;width:30px;height:30px;border-radius:50%;
  background:var(--tile);color:var(--ink);
  font-size:12px;font-weight:700;line-height:30px;text-align:center;
}
#heroWrap .chWho{display:flex;flex-direction:column;gap:3px;min-width:0}
#heroWrap .chWho b{font-size:12.5px;line-height:1.25;font-weight:700;color:var(--ink);white-space:nowrap}
#heroWrap .chWho span{font-size:12px;line-height:1.25;font-weight:500;color:var(--faint);white-space:nowrap}
#heroWrap .chMeta{margin-left:auto;flex:none;display:flex;align-items:center;gap:18px}
#heroWrap .chMeta__i{
  display:inline-flex;align-items:center;gap:7px;
  font-size:12px;font-weight:600;color:var(--muted-2);white-space:nowrap;
}
#heroWrap .chMeta__i svg{width:14px;height:14px;flex:none;color:var(--faint)}
/* flex-end: when the window is short the thread loses its OLDEST turns off the
   top, which is what a chat pane does, instead of losing the newest off the bottom */
#heroWrap .chBody{
  flex:1 1 auto;min-height:0;overflow:hidden;
  display:flex;flex-direction:column;justify-content:flex-end;gap:var(--bub-gap);
  padding:var(--gap-m) 0 0;
}
#heroWrap .chT{flex:none;display:flex;align-items:flex-end;gap:9px}
#heroWrap .chT--c{justify-content:flex-start}
#heroWrap .chT--s{flex-direction:row-reverse;justify-content:flex-start}
#heroWrap .chB{
  max-width:94%;display:flex;align-items:flex-end;gap:14px;
  padding:var(--bub-p) 14px;border-radius:13px;background:var(--tile);
}
#heroWrap .chT--c .chB{border-bottom-left-radius:5px}
#heroWrap .chT--s .chB{
  padding:calc(var(--bub-p) - 1px) 13px;border-bottom-right-radius:5px;
  background:var(--tint);border:1px solid var(--tint-line);
}
#heroWrap .chTx{font-size:12px;line-height:1.45;font-weight:500;color:var(--ink)}
#heroWrap .chM{
  flex:none;display:inline-flex;align-items:center;gap:6px;
  font-size:12px;font-weight:500;color:var(--faint);
}
#heroWrap .chT--s .chM{color:var(--live-text)}
#heroWrap .chTick{width:15px;height:9px;flex:none}
/* the avatar was a solid ink disc with an 11px white mark inside it: the heaviest
   object in a white pane, and at that size the headset read as a smudge. It is a
   light chip now, the mark drawn in ink at its own weight with its green dot, so
   the pane's only strong colour stays the answer itself. */
#heroWrap .chAv{
  flex:none;width:22px;height:22px;border-radius:50%;
  background:var(--panel);border:1px solid var(--line-solid);
  color:var(--ink);display:grid;place-items:center;
}
#heroWrap .chAv svg{width:14px;height:14px;display:block}
/* one slot, two states: Suppo is composing, then the answer is standing there.
   The answer keeps the slot open at opacity 0, so nothing reflows when it lands. */
#heroWrap .chLand{position:relative;flex:none}
#heroWrap .chT--land{opacity:1}
#heroWrap .chTypeRow{
  position:absolute;right:0;top:50%;transform:translateY(-50%);
  display:flex;flex-direction:row-reverse;align-items:center;gap:9px;opacity:0;
}
#heroWrap .apTyping{
  display:inline-flex;align-items:center;gap:5px;
  height:28px;padding:0 13px;border-radius:100px;
  background:var(--tint);border:1px solid var(--tint-line);
}
#heroWrap .apTyping i{display:block;width:4px;height:4px;border-radius:50%;background:var(--live-text);opacity:.55}

/* ---------- the booking receipt --------------------------------------------- */
#heroWrap .apRcpt{
  flex:none;display:flex;align-items:flex-start;gap:12px;
  margin-top:var(--gap-m);padding:var(--rcpt-p) 15px;border-radius:12px;
  background:var(--tint);border:1px solid var(--tint-line);
}
#heroWrap .apRcptI{
  flex:none;width:22px;height:22px;border-radius:50%;
  background:var(--live);color:var(--accent-ink);display:grid;place-items:center;
}
#heroWrap .apRcptI svg{width:13px;height:13px;display:block}
#heroWrap .apRcptT{display:flex;flex-direction:column;gap:var(--gap-s);min-width:0}
#heroWrap .apRcptR{display:flex;align-items:center;gap:10px;min-width:0}
#heroWrap .apRcptL{font-size:12px;line-height:1.3;font-weight:700;letter-spacing:.02em;color:var(--live-text);white-space:nowrap}
#heroWrap .apRcptC{
  flex:none;padding:3px 10px;border-radius:100px;background:rgba(0,210,106,.16);
  font-size:12px;font-weight:600;color:var(--live-text);white-space:nowrap;
}
#heroWrap .apRcptV{font-size:12.5px;line-height:1.3;font-weight:700;color:var(--ink);white-space:nowrap}
#heroWrap .apRcptM{font-size:12px;line-height:1.3;font-weight:500;color:var(--muted);white-space:nowrap}
#heroWrap .apRcptV i,#heroWrap .apRcptM i{font-style:normal;color:var(--faint);margin:0 5px}

/* ---------- the stats strip -------------------------------------------------- */
#heroWrap .appStats{
  flex:none;display:flex;align-items:center;gap:24px;padding:var(--stats-p) 22px;
  border-top:1px solid var(--line-solid);background:var(--paper-2);
}
#heroWrap .stIt{display:inline-flex;align-items:baseline;gap:8px;min-width:0;white-space:nowrap}
#heroWrap .stIt b{flex:none;font-size:14px;font-weight:800;letter-spacing:-.012em;color:var(--ink)}
#heroWrap .stIt b.stG{color:var(--live-text)}
#heroWrap .stIt span{font-size:12px;font-weight:500;color:var(--muted-2);overflow:hidden;text-overflow:ellipsis}
#heroWrap .stPlan{
  margin-left:auto;flex:none;display:inline-flex;align-items:center;gap:7px;
  font-size:12px;font-weight:600;color:var(--muted-2);white-space:nowrap;
}
#heroWrap .stPlan b{font-weight:700;color:var(--ink)}
#heroWrap .stPlan i{font-style:normal;color:var(--faint)}

/* ---------- the logo band the page continues on ----------------------------- */
/* it hangs one viewport below the fold and is pulled up by the scrub; top:100%
   of the stage IS the fold, so the resting position needs no measurement */
#heroWrap .heroLogos{
  position:absolute;left:0;right:0;top:100%;height:64vh;
  background:var(--band);border-top:1px solid var(--line-solid);
  display:flex;justify-content:center;
  opacity:0;
  transition:opacity .8s var(--ease) 1.55s;
  will-change:transform;
}
#heroWrap .heroLogos__row{
  width:100%;max-width:var(--maxw);padding:20px 32px 0;
  align-self:flex-start;
  display:flex;align-items:center;justify-content:space-between;gap:18px 34px;flex-wrap:wrap;
}
#heroWrap .heroLogos img{height:var(--logo-h);width:auto;opacity:.4}
/* every mark except WooCommerce's arrives with its viewBox already cropped to the
   ink. WooCommerce's is a square 24x24 holding a 5:1 wordmark, so height:24 draws
   the letters 4.8px tall. The window shows that middle fifth at the full mark
   height: the img is blown up 5x and shifted so its ink band fills the box. */
#heroWrap .heroLogos .lgWoo{
  position:relative;display:block;flex:none;
  width:calc(var(--logo-h) * 5);height:var(--logo-h);overflow:hidden;
}
#heroWrap .heroLogos .lgWoo img{
  position:absolute;left:0;top:calc(var(--logo-h) * -2);
  width:calc(var(--logo-h) * 5);height:calc(var(--logo-h) * 5);max-width:none;
}

/* ---------- INTRO end states (MOTION.play adds .playing) --------------------- */
#heroWrap .heroStage.playing .hBadge,
#heroWrap .heroStage.playing .heroSub,
#heroWrap .heroStage.playing .heroCta,
#heroWrap .heroStage.playing .heroNote,
#heroWrap .heroStage.playing .heroShot{opacity:1;transform:none}
#heroWrap .heroStage.playing .heroLogos{opacity:1}
#heroWrap .heroStage.playing .heroTitle .wd{opacity:1;transform:none}

/* ================================================================================
   IDLE LOOPS. Keyframes only, transform and opacity only, armed by .loop once the
   intro tail has landed and parked by #heroWrap.rest, which an IntersectionObserver
   writes when the section leaves the screen or the tab is hidden.

   The panel tells ONE story on a 14 second cycle, staggered so the eye always has
   exactly one thing to follow and every arrival then stands still long enough to
   be read:

     0.0 .. 1.0s   rest. The panel is a still and reads as one picture.
     1.0 .. 1.7s   a new WhatsApp thread drops in at the top of the list, the rows
                   under it step down by exactly one row height, and the open
                   route's unread count rolls 3 -> 4 with it.
     4.3 .. 6.6s   Suppo is composing in the conversation, in the slot the answer
                   already occupies at opacity 0, so nothing reflows.
     6.6 .. 13.0s  the answer lands and STAYS, for six and a half seconds.
     13.0 .. 14s   the reset, all of it at once and at the lowest contrast of the
                   cycle, so the loop never reads as a flicker.

   Fifteen animations run on screen at once (four mesh blobs, four panel beats,
   three typing dots, the call meter, two live rings), all of them cheap: no
   filter, no shadow on a moving layer, no layout property.
   ============================================================================== */
@media (prefers-reduced-motion:no-preference){

  /* the ground breathes */
  #heroWrap.loop .hb1{animation:hMeshA 34s ease-in-out infinite alternate;animation-play-state:var(--ps)}
  #heroWrap.loop .hb2{animation:hMeshB 40s ease-in-out infinite alternate;animation-play-state:var(--ps)}
  #heroWrap.loop .hb3{animation:hMeshC 46s ease-in-out infinite alternate;animation-play-state:var(--ps)}
  #heroWrap.loop .hb4{animation:hMeshD 38s ease-in-out infinite alternate;animation-play-state:var(--ps)}
  @keyframes hMeshA{from{transform:translate3d(0,0,0) scale(1)}to{transform:translate3d(-84px,58px,0) scale(.93)}}
  @keyframes hMeshB{from{transform:translate3d(0,0,0) scale(1)}to{transform:translate3d(-76px,64px,0) scale(.94)}}
  @keyframes hMeshC{from{transform:translate3d(0,0,0) scale(1)}to{transform:translate3d(-92px,-62px,0) scale(.9)}}
  @keyframes hMeshD{from{transform:translate3d(0,0,0) scale(1)}to{transform:translate3d(-70px,-48px,0) scale(.97)}}

  /* beat 1: the thread arrives and the count rolls with it */
  #heroWrap .heroStage.loop .apRow--new{animation:hApNew 14s var(--ease) infinite;animation-play-state:var(--ps)}
  #heroWrap .heroStage.loop .apStack{animation:hApStack 14s var(--ease) infinite;animation-play-state:var(--ps)}
  #heroWrap .heroStage.loop .navOdo i{animation:hOdo 14s var(--ease) infinite;animation-play-state:var(--ps)}
  @keyframes hApNew{
    0%,7%    {opacity:0;transform:translateY(-10px)}
    12%,92%  {opacity:1;transform:translateY(0)}
    97%,100% {opacity:0;transform:translateY(-10px)}
  }
  /* the stack steps down by one PITCH, the row box plus the air under it, so the
     arriving row lands in the gap it opened and not on the row below */
  @keyframes hApStack{
    0%,7%    {transform:translateY(0)}
    12%,92%  {transform:translateY(var(--row-step))}
    97%,100% {transform:translateY(0)}
  }
  @keyframes hOdo{
    0%,8%    {transform:translateY(0)}
    13%,92%  {transform:translateY(calc(var(--odo-h) * -1))}
    97%,100% {transform:translateY(0)}
  }

  /* beat 2: Suppo composes, then the answer lands and stays */
  #heroWrap .heroStage.loop .chTypeRow{animation:hType 14s linear infinite;animation-play-state:var(--ps)}
  #heroWrap .heroStage.loop .apTyping i{animation:hTypeDot 1.15s ease-in-out infinite;animation-play-state:var(--ps)}
  #heroWrap .heroStage.loop .apTyping i:nth-child(2){animation-delay:.15s}
  #heroWrap .heroStage.loop .apTyping i:nth-child(3){animation-delay:.3s}
  #heroWrap .heroStage.loop .chT--land{animation:hLand 14s var(--ease) infinite;animation-play-state:var(--ps)}
  @keyframes hType{0%,24%{opacity:0}28%,44%{opacity:1}47%,100%{opacity:0}}
  @keyframes hTypeDot{0%,100%{transform:translateY(0);opacity:.4}50%{transform:translateY(-3px);opacity:1}}
  /* the answer is the resting state of this slot: it stands from 7.3s of one
     cycle to 2.9s of the next, nine and a half seconds, and the slot is only
     empty for the beat where Suppo is visibly composing the next one */
  @keyframes hLand{
    0%,21%   {opacity:1;transform:translateY(0)}
    25%,45%  {opacity:0;transform:translateY(8px)}
    52%,100% {opacity:1;transform:translateY(0)}
  }

  /* the running call's meter: one repeat of the bar pattern per 4.4s, seamless
     because the svg holds the pattern twice and the shift is exactly half of it */
  #heroWrap .heroStage.loop .apWave__s{animation:hWave 4.4s linear infinite;animation-play-state:var(--ps)}
  @keyframes hWave{from{transform:translateX(0)}to{transform:translateX(-50%)}}

  /* the live rings: the panel's "the line is live" dot and the trial line dot */
  #heroWrap .heroStage.loop .appLive .dot-live::after,
  #heroWrap .heroStage.loop .heroNote .dot-live::after{animation-play-state:var(--ps)}
}

/* nothing animates: the panel is its resting state, the whole conversation
   standing still with the answer already given */
@media (prefers-reduced-motion:reduce){
  #heroWrap .chTypeRow{display:none}
}

/* ================================================================================
   SHORT WINDOWS. Every PADDING in the panel is a fluid clamp (see the token block
   at the top), so nothing here tightens anything. What lives here is the other
   half of the founder's instruction: when the fold is too low to hold the panel
   at its full spacing, the panel SHOWS LESS rather than squeezing what it shows.
   Three ladders, each running from the tail of its own column, each cutting on a
   whole element so the window never slices a row, a route or a glyph in half:

     the rail  drops routes from the bottom of the list, then the quota card
     the chat  drops its OLDEST turns, which is what a chat pane does anyway
     the list  is the one column that does NOT drop: it dissolves into its own
               bottom edge (.apFade), so it just shows fewer rows on its own.

   The thresholds are measured, not guessed: at each one the column's content is
   at least 8px shorter than the box that holds it at that fold.
   ============================================================================== */

/* the rail: workspace(1), Home(2), Conversations(3), Bookings(4), Knowledge(5),
   Channels(6), Settings(7), quota card(8). A rail with air under its last route is
   what every real app looks like; a rail with a route sliced in half is a bug. */
@media (max-height:1210px) and (min-width:681px){
  #heroWrap .appNav--tail{display:none}                    /* Settings  */
}
@media (max-height:1035px) and (min-width:681px){
  #heroWrap .appSide > span:nth-of-type(6){display:none}   /* Channels  */
}
@media (max-height:1000px) and (min-width:681px){
  #heroWrap .sideQ{display:none}                           /* the quota */
}
@media (max-height:865px) and (min-width:681px){
  #heroWrap .appSide > span:nth-of-type(5){display:none}   /* Knowledge */
}
@media (max-height:780px) and (min-width:681px){
  #heroWrap .appSide > span:nth-of-type(4){display:none}   /* Bookings  */
}

/* the chat: the thread keeps its NEWEST turns, the answer that the loop plays and
   the receipt it wrote. .chBody is justify-content:flex-end for the same reason. */
@media (max-height:1130px) and (min-width:681px){
  #heroWrap .chBody > div:nth-of-type(1){display:none}
}
@media (max-height:935px) and (min-width:681px){
  #heroWrap .chBody > div:nth-of-type(2){display:none}
}
@media (max-height:865px) and (min-width:681px){
  #heroWrap .chBody > div:nth-of-type(3){display:none}
}
/* below the 813 fold this panel is drawn for, the pane has room for the answer and
   the receipt and nothing else, so the contact head goes rather than the bottom of
   the answer being sliced: the name and the number are on the row beside it anyway */
@media (max-height:812px) and (min-width:681px){
  #heroWrap .chHead{display:none}
}

/* two lines that repeat what the row beside them already says: the caller's number
   under their name in the chat head, and again on the third line of the receipt */
@media (max-height:1000px) and (min-width:681px){
  #heroWrap .chWho span{display:none}
  #heroWrap .apRcptM{display:none}
}

/* ================================================================================
   RESPONSIVE
   ============================================================================== */
/* between 1000 and 1240 the panel is 790 wide and the list column cannot hold the
   third filter chip whole at any padding: it was sliced by the divider here before
   this pass too. A filter bar that shows two whole chips is a filter bar; one that
   shows a chip cut in half is a bug, so the third one goes at these widths. */
@media (min-width:1001px) and (max-width:1240px){
  #heroWrap .apChip:nth-child(3){display:none}
}
/* the same cut, for the same reason, in the band under 1000 where the rail is gone
   and the list is 40% of a full width panel: it holds the three chips again only
   once the viewport is past about 900. */
@media (min-width:681px) and (max-width:900px){
  #heroWrap .apChip:nth-child(3){display:none}
}

@media (max-width:1240px){
  /* the mat stays the same 64% of the frame all the way down to the point where
     the grid gutter is closer than that, which is where it becomes the column */
  #heroWrap{--panel-w:790px;--panel-h:clamp(270px,38vh,400px)}
  #heroWrap .heroTitle{font-size:42px}
  #heroWrap .heroTitle:lang(en){font-size:50px}
  #heroWrap .appBody{grid-template-columns:21% 1px 35.6% 1px 1fr}
  #heroWrap .ahSearch{max-width:190px}
  #heroWrap .appStats{gap:18px;padding:15px 18px}
  #heroWrap .apWave{width:88px}
}

@media (max-width:1000px) and (min-width:681px){
  #heroWrap{--panel-w:100%;--panel-h:clamp(270px,38vh,410px)}
  /* the rail is the first thing a narrow panel can lose: the list and the
     conversation are the picture, the nav rail is not */
  #heroWrap .appBody{grid-template-columns:0 0 40% 1px 1fr}
  #heroWrap .appSide{display:none}
  #heroWrap .appBody::before{display:none}
  #heroWrap .ahSearch{display:none}
  #heroWrap .heroTitle{font-size:36px}
  #heroWrap .heroTitle:lang(en){font-size:44px}
  #heroWrap .heroSub{max-width:600px;font-size:15px}
  #heroWrap .heroLogos__row{justify-content:center;gap:16px 28px}
}

@media (max-width:820px) and (min-width:681px){
  #heroWrap{height:200vh;--pad-top:clamp(88px,11vh,132px);--panel-h:clamp(260px,36vh,380px)}
  #heroWrap .heroCopy,#heroWrap .heroShot{padding:0 24px}
  #heroWrap .heroLogos__row{padding:20px 24px 0}
  #heroWrap .heroTitle{font-size:35px}
  #heroWrap .heroTitle:lang(en){font-size:41px}
  #heroWrap .chB{max-width:88%}
  #heroWrap .appStats{gap:14px}
  #heroWrap .stPlan{display:none}
}

/* ================================================================================
   PHONE (<= 680)

   Founder, 2026-09-06, with phone screenshots: "on mobile all of this layout is
   not optimized ... [the hero panel] should be the SAME dashboard, not responsive".

   So nothing below re-flows the console. Every rule that used to restack it (the
   list stacked over the chat, the hidden rail, the height ladder that drops routes
   and turns) is scoped to min-width:681px above, and the phone gets the DESKTOP
   composition: one fixed stage, three columns, the same rows, the same thread, the
   same receipt, the same stats strip, scaled down as ONE PIECE inside an
   overflow:hidden frame the width of the phone column minus its 20px gutters, the
   way a product shot crops a screen.

   Three numbers drive it and nothing else:
     --stage-k      how far the whole console is scaled down (0.66)
     --stage-base   what its WIDTH is still derived from (0.48)
     --stage-h      the console's own height in its own coordinates

   ROUND 7 (2026-09-06). At k .48 the panel's own 12px labels rendered at 5.8px on
   a 390 phone: the page's only product proof was decoration on the device the
   founder checks. k is .66 now and the panel's smallest type is 17px, so those
   labels land at 11.2px, above the 11px floor this pass was given.

   The width is deliberately NOT re-derived from the new k. The console keeps the
   exact composition it had at .48 - the same 729 wide stage at 390, the same three
   columns, the same rows, the same thread - and the frame CROPS it instead of
   shrinking it: at 530 wide the list column could not spell a caller's name at
   17px and the picture would have become a different layout, which is the one
   thing the founder ruled out. The crop is taken off the LEFT, because everything
   this panel has to prove (the list, the transcript, the written booking) sits on
   its right: the rail goes first, exactly as it does at the 1000px breakpoint.
   translateX is (base - k) of the mat's own width, so the mat's right edge lands
   ON the frame's at any device width and nothing ever bleeds past it.

   Type is the phone scale from the top of the page: H1 32, sub 15, CTAs 46 tall.
   The idle loops are untouched and run here exactly as they do on a desktop.
   ============================================================================== */
@media (max-width:680px){
  #heroWrap{
    height:200vh;
    --pad-top:clamp(88px,12vh,132px);
    --gap-panel:clamp(14px,2vh,30px);
    --logo-h:20px;
    --stage-k:.66;
    --stage-base:.48;
    /* the console's own height follows the fold the way the desktop mat does, but
       on a short leash at both ends: under 590 the rail cannot hold its six routes
       and its quota card, and past 610 the rail and the conversation start showing
       air rather than more of themselves. A picture with air in it is worse than a
       picture with air around it. */
    --stage-h:clamp(590px,70vh,610px);
  }

  /* ---- copy column: 20px gutters, the phone type scale ---- */
  #heroWrap .heroCopy,#heroWrap .heroShot{padding:0 20px}
  #heroWrap .hBadge{height:32px;padding:0 14px;font-size:12px}
  #heroWrap .heroTitle{font-size:32px;margin-top:14px}
  #heroWrap .heroTitle:lang(en){font-size:33px}
  #heroWrap .heroSub{font-size:15px;line-height:1.5;margin-top:12px;max-width:350px}
  #heroWrap .heroCta{margin-top:22px;gap:10px}
  #heroWrap .hBtn{height:46px;padding:0 22px;font-size:15px}
  /* the line wraps at 390: hang the dot off the FIRST line, not the middle */
  #heroWrap .heroNote{margin-top:16px;font-size:12.5px;line-height:1.45;text-align:left;align-items:flex-start;gap:8px}
  #heroWrap .heroNote .dot-live{margin-top:5px}

  /* ---- the frame: the window the console is cropped by ---- */
  /* the panel is centred in whatever the copy leaves, so the fold never ends on a
     strip of empty paper under it */
  #heroWrap .heroLower{justify-content:center}
  #heroWrap .shotFrame{
    width:100%;height:calc(var(--stage-h) * var(--stage-k));
    overflow:hidden;border-radius:22px;
    box-shadow:0 2px 6px rgba(10,10,11,.05),0 22px 44px rgba(10,10,11,.13);
  }
  /* the stage: a desktop console in its own coordinates, scaled as one piece.
     The radius is the frame's own 22 divided by the scale, so after the transform
     the mat's corners land exactly on the frame's. The shadow moved up to the
     frame, which is the only box the crop does not clip. */
  #heroWrap .shotMat{
    width:calc(100% / var(--stage-base));max-width:none;height:var(--stage-h);
    margin:0;border-radius:calc(22px / var(--stage-k));box-shadow:none;
    transform:translateX(calc((var(--stage-base) - var(--stage-k)) * 100%)) scale(var(--stage-k));
    transform-origin:0 0;
  }

  /* ---- the panel's own type, raised so the crop is legible ----
     Every label in the console is 12 to 14px in the stage's own coordinates,
     which at .66 renders 7.9 to 9.2px. The whole set moves up by one ratio
     (x1.4167) so the smallest of them lands at 11.2px on the glass, and the boxes
     that are sized to hold a line of it move up by the same ratio, so nothing is
     clipped and no proportion in the composition changes. */
  #heroWrap .appTitle,
  #heroWrap .apSample,
  #heroWrap .appUrl,
  #heroWrap .appLive,
  #heroWrap .ahN,
  #heroWrap .ahSearch span,
  #heroWrap .ahLang b,
  #heroWrap .sideWs i,
  #heroWrap .sideWs b,
  #heroWrap .appNav,
  #heroWrap .navN,
  #heroWrap .navOdo .num,
  #heroWrap .sideQR span,
  #heroWrap .sideQR b,
  #heroWrap .apChip,
  #heroWrap .apLine,
  #heroWrap .apTime,
  #heroWrap .apPip,
  #heroWrap .apTag,
  #heroWrap .chAva,
  #heroWrap .chWho span,
  #heroWrap .chMeta__i,
  #heroWrap .chTx,
  #heroWrap .chM,
  #heroWrap .apRcptL,
  #heroWrap .apRcptC,
  #heroWrap .apRcptM,
  #heroWrap .stIt span,
  #heroWrap .stPlan{font-size:17px}
  #heroWrap .apTxt b,
  #heroWrap .chWho b,
  #heroWrap .apRcptV{font-size:17.5px}
  #heroWrap .ahTtl{font-size:18px}
  #heroWrap .stIt b{font-size:19px}

  /* the boxes a line of that type has to sit inside */
  #heroWrap{--odo-h:25px}
  #heroWrap .ahN{height:29px;line-height:29px;padding:0 12px}
  #heroWrap .ahLang b{line-height:26px;padding:0 12px}
  #heroWrap .ahSearch{height:40px;border-radius:12px}
  #heroWrap .sideWs i{width:29px;height:29px;line-height:29px;border-radius:9px}
  #heroWrap .apChip{height:31px;line-height:31px;padding:0 12px}
  #heroWrap .apPip{height:24px;min-width:24px;line-height:24px;padding:0 8px}
  #heroWrap .apTag{height:27px;line-height:27px;padding:0 10px}
  /* the running call's meter follows its column instead of holding a fixed 100px
     open in a row that is now 240 stage px wide */
  #heroWrap .apWave{width:100%}
  #heroWrap .chAva{width:36px;height:36px;line-height:36px}
  #heroWrap .apRcptC{padding:4px 12px}

  /* the glyphs beside that type, at the same ratio, so no icon reads as a speck */
  #heroWrap .ahSearch svg{width:17px;height:17px}
  #heroWrap .appNav svg{width:19px;height:19px}
  #heroWrap .apIco,#heroWrap .apIco svg{width:20px;height:20px}
  #heroWrap .apMark,#heroWrap .apMark svg{width:19px;height:19px}
  #heroWrap .chMeta__i svg{width:17px;height:17px}
  #heroWrap .chAv{width:26px;height:26px}
  #heroWrap .chAv svg{width:17px;height:17px}
  #heroWrap .chTick{width:18px;height:11px}
  #heroWrap .apRcptI{width:26px;height:26px}
  #heroWrap .apRcptI svg{width:16px;height:16px}
  #heroWrap .apWave{height:14px}

  /* ---- the three cuts the stage makes for itself ----
     The height ladder above is a function of the VIEWPORT height, which on a phone
     says nothing about this console: the stage is 560 to 610 tall whatever the
     device is. What follows is its own ladder, measured on that stage, and every
     cut takes a whole element, so the window never slices a row or a chip in half. */
  /* the stage is 729 wide at 390 and 812 at 430, so its columns sit one notch
     narrower than the 790 desktop panel: the rail takes the 3% it needs to spell
     "პარამეტრები" whole, and the list gives it, exactly the way the desktop grid
     re-cuts itself at 1240. Same three columns, same order, same content. */
  /* the rail's share is now the CROP's share: at 390 the window opens 199 stage px
     in, and 27.2% puts the rail's own right edge (and its divider) 5px past that,
     so the panel's left edge is a divider line and not the middle of a row. The
     list keeps the 34% it had and is now whole inside the window instead of
     losing its own left padding to the crop; the 3.2% comes out of the
     conversation, which is the widest column and the one with room to give. */
  #heroWrap .appBody{grid-template-columns:27.2% 1px 34% 1px 1fr}
  /* Tried and rejected: giving EN a 27% rail so "Conversations" spells whole.
     It buys the rail label with the caller's number ("+995 599 12...") and three
     thread names, which are the tokens that carry the truth of the picture. The
     rail label keeps its ellipsis, the same way a real narrow window does. */
  #heroWrap .apChip:nth-child(3){display:none}   /* the list column is 248 wide */
  /* the receipt's third line repeats what the head of the conversation beside it
     already says, and it is the line the desktop drops first on a short fold too.
     The caller's number stays: at this width the list row cannot spell it whole,
     so the chat head is the one place the picture still carries it in full. */
  #heroWrap .apRcptM{display:none}
  /* the head of a 294 wide conversation holds the name and the length of the call;
     the channel is already the glyph on its row in the list beside it */
  #heroWrap .chMeta__i:first-child{display:none}
  /* the thread keeps its NEWEST turns, exactly as the desktop pane does when the
     fold is short: the answer the loop plays, the question it answers and the
     receipt it wrote. Anything older would be sliced by the top of the pane. */
  #heroWrap .chBody > div:nth-of-type(1){display:none}
  /* the receipt is the one block that must never lose a token, so at this column
     width its label and its SMS pill take a line each instead of the pill being cut */
  #heroWrap .apRcptR{flex-wrap:wrap;gap:6px 10px}
  /* and its value line breaks rather than losing the time off the right edge. It
     has to be a wrapping FLEX row, not white-space:normal: the four tokens are
     written with no whitespace between them, so a text flow has nowhere to break
     and the line just ran off the pane. Flex items wrap without needing a space. */
  #heroWrap .apRcptV{display:flex;flex-wrap:wrap;align-items:baseline;white-space:normal}
  /* but the price itself never breaks: only the separators between the tokens do */
  #heroWrap .apRcptV span{white-space:nowrap}
  /* the conversation is the narrowest column on this stage, so it spends its own
     gutter on the booking rather than on air: 16 instead of 22 puts the Georgian
     receipt back on one line and gives every bubble six more characters. */
  #heroWrap .appChat{padding:var(--chat-p) 16px}
  #heroWrap .apRcpt{padding:var(--rcpt-p) 13px}

  /* a narrow column needs a wider clearing or the sub reads on colour */
  #heroWrap .hMesh__clear{
    background:
      radial-gradient(82% 40% at 50% 26%,var(--page) 0%,rgba(250,250,250,.82) 48%,rgba(250,250,250,0) 82%),
      linear-gradient(rgba(250,250,250,0) 30%,rgba(250,250,250,.7) 58%,var(--page) 82%);
  }
  #heroWrap .heroLogos{height:58vh}
  #heroWrap .heroLogos__row{padding:18px 20px 0;gap:14px 22px;justify-content:center}
}

/* a phone with a 667 fold cannot hold the copy and the whole console at once. The
   console keeps its size and the fold cuts its lower edge, which is what the desktop
   composition does at every height; centring it there would push its top edge into
   the trial line instead. */
@media (max-width:680px) and (max-height:740px){
  #heroWrap .heroLower{justify-content:flex-start}
}

/* the smallest phones still in service. The console is not rebuilt here either:
   its stage follows the frame, so at 360 it is 667 wide and every bubble in the
   conversation runs a line longer. The pane drops one more of its OLDEST turns for
   that line, the same cut the desktop ladder makes, and the headline takes the
   only other thing that runs out of room at this width. */
@media (max-width:374px){
  #heroWrap .heroTitle{font-size:29px}
  #heroWrap .heroTitle:lang(en){font-size:30px}
  #heroWrap .hBtn{padding:0 18px}
  #heroWrap .chBody > div:nth-of-type(2){display:none}
}

/* ===== conversations ===== */
/* CONVERSATIONS  "ერთი თანამშრომელი ყველა არხზე"
   ---------------------------------------------------------------------------
   Founder (2026-09-05 14:03, with a screenshot of the ring): "I actually like
   it a lot, but it is not the modern, cool UI style that Suppo has. Animation
   is pretty fine. Also the animation scrolls super fast, so we need to show ALL
   connectors open with illustration states (cards) visible, not open-and-close,
   the eye cannot see. Maybe the layout could be: headline comes in, and when
   you scroll down the orb expands and takes the whole horizontal width for the
   illustration to appear, and the header should be on top of it vertically."

   The ring became one open diagram, and then the diagram was re-cut for the
   only thing the ellipse could not deliver: a connector you can actually FOLLOW
   from the orb to the card.

   WHY TWO WINGS AND NOT A RING
     Eight 280px cards on an ellipse put two of them almost directly above the
     orb and two almost directly below it, because a pinned 813px frame only
     gives the illustration ~560px of height. Those four connectors then have to
     dive under their own card to reach the badge: measured on the ring build,
     Facebook's and Viber's lines were 24px stubs and Instagram's and
     Messenger's were ~60px of a 136px path. Two columns of four fix that by
     construction: every badge sits on the edge that faces the orb, so every
     curve runs 85 to 90 per cent in the open and only its last 22px pass under
     the card, dying exactly beneath its own glyph.

   GEOMETRY (desktop, one 1180 column, pinned frame 813)
     orb        240px in the centre, aurora blobs, wide halo, one thin ring
     cards      280 x 130, badge 26, radius 16; four rows a side
     columns    +-412px, the two outer rows pulled in to .955 of that so the
                eight cards trace a soft bow around the orb instead of a table
     rows       pitch = min(ch + 22, (stage height - 6) / 4), rows at
                +-1.5 and +-0.5 pitch about the stage centre
     connectors orb rim -> badge centre, one quadratic curve under the cards:
                a 5px glow at .13 and a 1.6px gradient hairline that runs from
                the orb's aurora colour at the rim to the channel's brand colour
                at the badge. One slow light dot rides each curve inward.
   Tablet (640 to 1059): two columns of three cards flanking the orb, Facebook
   and Viber fold to badges stacked with the orb. Phone (< 640): the section
   UNPINS and runs in flow, head, orb with two short connectors, then the eight
   cards as a two column grid with every thread still live (see the phone block
   at the bottom of this file).

   BUDGETS: will-change 12 (4 orb blobs + 8 cards), filter 0, backdrop-filter 0,
   box-shadow 9 (8 cards + the orb), running animations 19 on screen and 0 off
   screen (every loop is gated on .cv-awake, written by an IntersectionObserver).
   ------------------------------------------------------------------------- */

#conversationsWrap{
  /* positioned so #channels, the anchor the footer's Channels link lands on,
     resolves against THIS section and not the initial containing block */
  position:relative;
  height:300vh;background:var(--band);
  --orb:288px;
  --cw:300px;          /* card width  */
  --ch:134px;          /* card height */
  --badge:24px;
  --a1:#00D26A; --a2:#1FA8E8; --a3:#7C6BF2; --a4:#5DFFC3;
  /* the greys and radii come from the shared layer now: the card border is
     var(--line), the quiet surface inside it var(--tile), the corner
     var(--r-chrome). The old local --hair, a seventh grey for a job that
     already had one, is gone. */
}
#conversationsWrap .pin{background:var(--band);display:block}
#conversationsWrap .cv-sprite{position:absolute;width:0;height:0;overflow:hidden}

#conversationsWrap .cv-frame{
  position:relative;width:100%;height:100%;
  max-width:1180px;margin:0 auto;padding:96px 0 92px;
  display:flex;flex-direction:column;align-items:center;justify-content:center;
}
/* THE PAGE'S BAND RHYTHM, and the one frame that cannot always pay for it.
   96 / 92 is what every band on this page breathes. This band is a PINNED
   viewport, so nobody ever sees that padding as space between two bands: it is
   188px taken straight out of the illustration, and the four row wing needs
   570px of stage or measure() folds two channels to badges. Above 944px of
   viewport the rhythm and the wing both fit. Below it the frame keeps only the
   inset that clears the nav island, because padding no eye can see is not worth
   two closed conversations. The threshold is measured, not guessed: 96 + 92
   padding + a 127px head + a 52px pill leave the stage 570px at exactly 943px
   of viewport, and 944 keeps a pixel of slack on the crossing. */
@media (max-height:944px){
  #conversationsWrap .cv-frame{padding:72px 0 14px}
}

/* ---- the mesh ground -------------------------------------------------
   Three aurora blobs behind the illustration. Placed with transform, never
   animated, never blurred: a radial gradient is already soft, and a blur pass
   on a 700px box is the single most expensive thing this page could do. */
#conversationsWrap .cv-mesh{position:absolute;inset:0;overflow:hidden;pointer-events:none;z-index:0}
#conversationsWrap .cv-mesh i{position:absolute;display:block;border-radius:50%}
#conversationsWrap .cv-mesh1{
  left:0;top:44%;width:min(840px,58vw);height:min(600px,68vh);transform:translateY(-50%);
  background:radial-gradient(closest-side,rgba(0,210,106,.15),rgba(0,210,106,0) 100%);
}
#conversationsWrap .cv-mesh2{
  right:0;top:50%;width:min(820px,57vw);height:min(580px,66vh);transform:translateY(-50%);
  background:radial-gradient(closest-side,rgba(31,168,232,.14),rgba(31,168,232,0) 100%);
}
#conversationsWrap .cv-mesh3{
  left:50%;top:20%;width:min(760px,54vw);height:min(460px,52vh);transform:translate(-50%,-50%);
  background:radial-gradient(closest-side,rgba(124,107,242,.11),rgba(124,107,242,0) 100%);
}

/* ---- head ------------------------------------------------------------- */
/* the head takes the full 1180 column. At the page's H2 scale (56 EN / 54 KA)
   the Georgian headline measures ~1103px, and a 940 cap broke it onto a second
   line: 62px of a PINNED frame, which the four row wing needs more than the
   headline needs a narrower measure. The sub keeps its own 640 measure. */
#conversationsWrap .cv-head{
  position:relative;z-index:2;flex:none;width:100%;max-width:1180px;text-align:center;margin-bottom:6px;
}
#conversationsWrap .cv-h2{
  margin:0;font-size:clamp(36px,3.889vw,56px);font-weight:800;
  line-height:1.04;letter-spacing:-.03em;color:var(--ink);
}
#conversationsWrap:lang(ka) .cv-h2{font-size:clamp(35px,3.75vw,54px);font-weight:800;line-height:1.14;letter-spacing:-.012em}
#conversationsWrap .cv-w{display:inline-block;opacity:0;transform:translate3d(0,26px,0)}
/* one animation per word, not one transition per property per word: the
   headline enter has to fit inside the section's 24 running animations */
#conversationsWrap .cv-head.in .cv-w{animation:cv-word .58s var(--ease) var(--d,0s) both}
@keyframes cv-word{from{opacity:0;transform:translate3d(0,26px,0)}to{opacity:1;transform:none}}
#conversationsWrap .cv-sub{
  margin:10px auto 0;max-width:640px;
  font-size:16px;line-height:1.55;font-weight:500;color:var(--muted);letter-spacing:-.002em;
}

/* ---- the stage -------------------------------------------------------- */
#conversationsWrap .cv-stage{position:relative;z-index:1;flex:1 1 auto;width:100%;min-height:0;max-height:632px}

/* ---- connectors -------------------------------------------------------
   Two paths per channel on top of each other: a wide soft glow and a 1.6px
   gradient hairline. The gradient is in user space and its two ends are the
   rim point and the badge point, so the stroke really does travel from the
   orb's aurora to the channel's brand colour. */
#conversationsWrap .cv-lines{position:absolute;inset:0;overflow:visible;pointer-events:none;z-index:1}
#conversationsWrap .cv-lines path{fill:none;stroke-linecap:round;stroke-dasharray:1;stroke-dashoffset:1}
#conversationsWrap .cv-glow path{stroke-width:5;opacity:.13}
#conversationsWrap .cv-line path{stroke-width:1.6}

/* ---- the travelling light dots ---------------------------------------
   One per curve, riding from the badge back into the orb: the message the
   channel is handing to the one brain. Pure keyframes on offset-distance, so
   the hold is alive without a single scroll-driven write. */
#conversationsWrap .cv-dots{position:absolute;inset:0;pointer-events:none;z-index:2}
#conversationsWrap .cv-dots i{
  position:absolute;left:0;top:0;width:11px;height:11px;border-radius:50%;
  offset-rotate:0deg;offset-anchor:50% 50%;opacity:0;
  background:radial-gradient(circle closest-side,var(--dc,#00D26A) 0 34%,color-mix(in srgb,var(--dc,#00D26A) 34%,transparent) 52%,rgba(255,255,255,0) 100%);
  animation:cv-travel 5.4s cubic-bezier(.45,0,.55,1) infinite;animation-play-state:paused;
  visibility:hidden;
}
#conversationsWrap.cv-open .cv-dots i{visibility:visible}
#conversationsWrap.cv-awake.cv-open .cv-dots i{animation-play-state:running}
@keyframes cv-travel{
  0%  {offset-distance:100%;opacity:0}
  12% {opacity:1}
  74% {opacity:1}
  92%,100%{offset-distance:0%;opacity:0}
}
#conversationsWrap .cv-dots i:nth-child(2){animation-delay:-.68s}
#conversationsWrap .cv-dots i:nth-child(3){animation-delay:-1.36s}
#conversationsWrap .cv-dots i:nth-child(4){animation-delay:-2.04s}
#conversationsWrap .cv-dots i:nth-child(5){animation-delay:-2.72s}
#conversationsWrap .cv-dots i:nth-child(6){animation-delay:-3.40s}
#conversationsWrap .cv-dots i:nth-child(7){animation-delay:-4.08s}
#conversationsWrap .cv-dots i:nth-child(8){animation-delay:-4.76s}
@supports not (offset-path: path("M 0 0 H 1")){
  #conversationsWrap .cv-dots{display:none}
}

/* ---- the orb, the live site's own four blobs --------------------------
   The demo section runs this orb on #232328, where a pale base gradient reads
   as a lit aurora. Here it stands on the light band, so it carries the live
   widget's SATURATED base (#7ED6A4 -> #9CD9FF, unlightened), full opacity, and
   an inset rim + floor so it reads as a sphere with volume and not as a flat
   pastel disc. That, plus a wider halo, is what the founder was missing. */
#conversationsWrap .cv-orbwrap{
  position:absolute;left:50%;top:50%;width:var(--orb);height:var(--orb);
  margin:calc(var(--orb) / -2) 0 0 calc(var(--orb) / -2);z-index:3;
}
#conversationsWrap .cv-halo{
  position:absolute;inset:-72%;border-radius:50%;pointer-events:none;
  background:radial-gradient(circle closest-side,
    rgba(0,210,106,.30) 0%,rgba(31,168,232,.20) 40%,rgba(124,107,242,.11) 64%,rgba(124,107,242,0) 100%);
}
#conversationsWrap .cv-orbit{
  position:absolute;inset:-15%;border-radius:50%;pointer-events:none;
  border:1px solid rgba(31,168,232,.20);
  border-top-color:rgba(0,210,106,.62);border-left-color:rgba(93,255,195,.48);
  animation:cv-spin 18s linear infinite;animation-play-state:paused;
}
@keyframes cv-spin{from{transform:rotate(0deg)}to{transform:rotate(360deg)}}
#conversationsWrap .cv-orb{
  position:absolute;inset:0;border-radius:999px;overflow:hidden;
  background:linear-gradient(125deg,#7ED6A4 8%,#9CD9FF 92%);
  box-shadow:
    inset 0 0 0 1px rgba(255,255,255,.55),
    inset 0 24px 50px -20px rgba(255,255,255,.85),
    inset 0 -34px 62px -26px rgba(0,86,60,.34),
    0 34px 74px -22px rgba(0,140,92,.36),
    0 2px 8px rgba(10,10,11,.06);
}
#conversationsWrap .cv-orb__b{position:absolute;inset:-28%;border-radius:999px;opacity:.66;will-change:transform}
#conversationsWrap .cv-orb__b2{opacity:.84}
#conversationsWrap .cv-orb__b3{opacity:.40}
#conversationsWrap .cv-orb__b4{opacity:.58}
#conversationsWrap .cv-orb__b1{background:radial-gradient(closest-side at 34% 58%,#2FBF6C 0%,#2FBF6C 10%,rgba(47,191,108,0) 72%);animation:cv-orbDrift1 13s cubic-bezier(.2,0,0,1) infinite alternate}
#conversationsWrap .cv-orb__b2{background:radial-gradient(closest-side at 74% 44%,#52C6FF 0%,rgba(82,198,255,0) 62%);animation:cv-orbDrift2 11s cubic-bezier(.2,0,0,1) infinite alternate;animation-delay:-3s}
#conversationsWrap .cv-orb__b3{background:radial-gradient(closest-side at 68% 86%,#2E6BE6 0%,rgba(46,107,230,0) 66%);animation:cv-orbDrift3 15s cubic-bezier(.2,0,0,1) infinite alternate;animation-delay:-7s}
#conversationsWrap .cv-orb__b4{background:radial-gradient(closest-side at 78% 28%,#EFFFF6 0%,rgba(239,255,246,0) 52%);animation:cv-orbDrift2 10s cubic-bezier(.2,0,0,1) infinite alternate;animation-delay:-5s}
/* the four shorthands above reset animation-play-state, so the pause the
   section runs off screen has to be written after them */
#conversationsWrap .cv-orb__b{animation-play-state:paused}
#conversationsWrap .cv-orb__grain{
  position:absolute;inset:0;pointer-events:none;mix-blend-mode:soft-light;opacity:.45;
  background-image:url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='.55'/%3E%3C/svg%3E");
  background-size:140px;
}
@keyframes cv-orbDrift1{from{transform:translate3d(-7%,4%,0)}to{transform:translate3d(9%,-6%,0)}}
@keyframes cv-orbDrift2{from{transform:translate3d(6%,-5%,0)}to{transform:translate3d(-8%,7%,0)}}
@keyframes cv-orbDrift3{from{transform:translate3d(4%,7%,0)}to{transform:translate3d(-6%,-8%,0)}}

/* ---- the cards, and there are no other nodes -------------------------- */
#conversationsWrap .cv-cards{position:absolute;inset:0;z-index:4;pointer-events:none}
#conversationsWrap .cv-card{
  position:absolute;left:0;top:0;width:var(--cw);height:var(--ch);
  margin:calc(var(--ch) / -2) 0 0 calc(var(--cw) / -2);
  display:flex;flex-direction:column;gap:3px;padding:5px;text-align:left;
  border-radius:var(--r-chrome);border:1px solid var(--line);
  background:linear-gradient(180deg,#FFFFFF 0%,#FAFCFE 100%);
  /* the lift carries a trace of the channel's own colour, which is what makes
     eight white boxes read as one coloured system instead of a spreadsheet */
  box-shadow:0 1px 2px rgba(10,10,11,.04),0 18px 38px -18px var(--cs,rgba(10,10,11,.3));
  opacity:0;will-change:transform,opacity;
}

/* the header container: brand glyph in a soft tint, name, truth tag */
#conversationsWrap .cv-top{display:flex;align-items:center;gap:8px;flex:none;height:var(--badge)}
#conversationsWrap .cv-badge{
  flex:none;width:var(--badge);height:var(--badge);border-radius:50%;
  display:flex;align-items:center;justify-content:center;
  background:var(--ct);color:var(--c);
}
#conversationsWrap .cv-badge svg{width:14px;height:14px}
#conversationsWrap .cv-name{
  font-size:13.5px;line-height:1.2;font-weight:800;color:var(--ink);letter-spacing:-.01em;white-space:nowrap;
}
/* LIVE (every channel, founder 2026-09-06) is the page's .tag--live, defined once in
   live-chrome.css. Nothing about the object is restated here; the only local
   thing is where it sits in the card's header row, and the fact that the live
   pill's 6px pip breathes while this section is on screen. */
#conversationsWrap .tag{margin-left:auto;flex:none}
#conversationsWrap:lang(ka) .tag{letter-spacing:0}
#conversationsWrap .tag--live::before{
  animation:cv-pulse 2.8s ease-in-out infinite;animation-play-state:paused;
}
@keyframes cv-pulse{0%,100%{transform:scale(1);opacity:1}50%{transform:scale(1.4);opacity:.55}}

/* the four cards that stand left of the orb wear their badge on the right, so
   every connector reaches its badge from the inside edge and never crosses a
   card on the way */
#conversationsWrap .cv-card--m .cv-top{flex-direction:row-reverse}
#conversationsWrap .cv-card--m .tag{margin-left:0;margin-right:auto}

/* ---- the live thread inside every card ------------------------------
   Founder (2026-09-05, with a screenshot): "can we have more dynamic
   illustrations, like new and new messages, comments etc. appearing; in the
   call card we show the conversation."

   So every card body is now a CONVERSATION IN PROGRESS, not a still. Each card
   runs one long loop, 13 to 18 s, every card on its own tempo and its own
   phase, so the eight of them never move in unison:

     question arrives      -> typing        -> answer arrives  -> long hold
     second question       -> typing        -> answer or outcome chip
     soft reset (a beat of empty thread, then it starts again)

   MECHANICS. Two fixed slots per thread: slot 1 hangs from the top and holds
   whatever the customer said, slot 2 stands on the floor and holds Suppo. Only
   one element ever occupies a slot, so nothing has to travel between them:
   each message is one element with exactly ONE keyframe animation, on opacity
   and transform. A reply that takes two lines grows UP into the gap rather than
   off the bottom edge, so the KA/EN swap can change every line length without
   clipping anything and no card needs a hand tuned slot pitch.

   COST. 4 messages + 1 typing bubble per card, 5 keyframe animations, no
   will-change, no shadow on a moving layer, no filter. All of it is gated on
   .cv-awake.cv-open (an IntersectionObserver writes .cv-awake, the scrub writes
   .cv-open), so a section off screen runs nothing, and prefers-reduced-motion
   freezes the first exchange instead of playing anything.

   HOLDS (fractions of each card's own cycle, so the rhythm is the same at 13 s
   and at 18 s): question in by 4 %, typing 13 to 20 %, answer in by 26 %, the
   pair holds together to 46 %; the second question takes the top slot at 50 to
   54 % and holds to 96 %, the first answer keeps the floor to 62 %, typing
   again 69 to 74 %, the closing answer in by 79 %.

   NO CARD IS EVER BLANK. The closing answer does not leave with its question:
   it holds the floor across the reset (to 5 % of the next cycle) and only
   clears once the next question has already landed above it. So one of the two
   slots is always occupied, in every frame of every cycle, on all eight cards.
   On the 16 s card a complete exchange stands still for 3.2 s and a customer
   line is readable for 6.7 s, which is what the founder means by legible.   */

#conversationsWrap .cv-body{
  flex:1 1 auto;min-height:0;border-radius:10px;padding:5px 7px;
  background:var(--tile);border:1px solid rgba(16,17,20,.05);
  display:flex;flex-direction:column;gap:4px;overflow:hidden;
}
#conversationsWrap .cv-thread{position:relative;flex:1 1 auto;min-height:0;width:100%}

/* every message: absolutely placed in its slot, one animation, nothing else */
#conversationsWrap .cv-msg{
  position:absolute;left:0;right:0;margin:0;opacity:0;
  font-size:12.5px;line-height:1.3;letter-spacing:-.002em;
  animation-duration:var(--cyc,15s);animation-delay:var(--ph,0s);
  animation-timing-function:cubic-bezier(.25,.8,.3,1);
  animation-iteration-count:infinite;animation-fill-mode:both;
}
/* slot 1 hangs from the top of the thread, slot 2 stands on its floor. Both
   ends of the window are therefore always occupied and a two line reply grows
   UP into the gap instead of off the bottom edge, whatever the language does
   to the line count. That is also why there is no per card slot pitch. */
#conversationsWrap .cv-s1{top:0}
#conversationsWrap .cv-s2{top:auto;bottom:0}
#conversationsWrap .cv-m1{animation-name:cv-q1}
#conversationsWrap .cv-m2{animation-name:cv-a1}
#conversationsWrap .cv-m3{animation-name:cv-q2}
#conversationsWrap .cv-m4{animation-name:cv-a2}
#conversationsWrap .cv-typ{animation-name:cv-typing}

@keyframes cv-q1{
  0%       {opacity:0;transform:translate3d(0,7px,0)}
  4%,46%   {opacity:1;transform:none}
  50%,100% {opacity:0;transform:translate3d(0,-7px,0)}
}
@keyframes cv-a1{
  0%,21%   {opacity:0;transform:translate3d(0,7px,0)}
  26%,62%  {opacity:1;transform:none}
  66%,100% {opacity:0;transform:translate3d(0,-7px,0)}
}
/* the second exchange takes the top slot at the exact frame the first leaves
   it, so the card never stands empty in the middle of its own cycle */
@keyframes cv-q2{
  0%,50%   {opacity:0;transform:translate3d(0,7px,0)}
  54%,96%  {opacity:1;transform:none}
  100%     {opacity:0;transform:translate3d(0,-7px,0)}
}
/* the answer that closes the exchange does not leave with its question: it
   stays on the floor of the card across the reset and only clears once the
   next question has already landed on top of it, so no card is ever blank */
@keyframes cv-a2{
  0%,5%    {opacity:1;transform:none}
  9%,74%   {opacity:0;transform:translate3d(0,7px,0)}
  79%,100% {opacity:1;transform:none}
}
/* one element, two pulses: the agent is composing before each of its answers */
@keyframes cv-typing{
  0%,9%    {opacity:0;transform:translate3d(0,5px,0)}
  13%,17%  {opacity:1;transform:none}
  20%,66%  {opacity:0;transform:translate3d(0,5px,0)}
  69%,71%  {opacity:1;transform:none}
  74%,100% {opacity:0;transform:translate3d(0,5px,0)}
}
/* the call answers on the spot, which is the whole claim of the phone card:
   its two replies arrive a beat after the question instead of after a pause */
@keyframes cv-a1f{
  0%,10%   {opacity:0;transform:translate3d(0,7px,0)}
  15%,60%  {opacity:1;transform:none}
  64%,100% {opacity:0;transform:translate3d(0,-7px,0)}
}
@keyframes cv-a2f{
  0%,5%    {opacity:1;transform:none}
  9%,65%   {opacity:0;transform:translate3d(0,7px,0)}
  70%,100% {opacity:1;transform:none}
}
#conversationsWrap .cv-body--call .cv-m2{animation-name:cv-a1f}
#conversationsWrap .cv-body--call .cv-m4{animation-name:cv-a2f}

/* ONE CLOCK, EIGHT PHASES (the way stats runs its counters). The eight threads
   used to run coprime cycles, 13 to 18 s, which drifts them apart for good but
   also lets four, five, six of them change inside the same half second: the eye
   then reads the wall as flicker instead of as eight conversations. On one 18 s
   cycle split into eight even phases exactly one card turns over every 2.25 s,
   and every card still stands open, which is the thing the founder asked for. */
#conversationsWrap .cv-card{--cyc:18s}
#conversationsWrap .cv-card[data-key="phone"]    {--ph:0s}
#conversationsWrap .cv-card[data-key="messenger"]{--ph:-2.25s}
#conversationsWrap .cv-card[data-key="instagram"]{--ph:-4.5s}
#conversationsWrap .cv-card[data-key="whatsapp"] {--ph:-6.75s}
#conversationsWrap .cv-card[data-key="telegram"] {--ph:-9s}
#conversationsWrap .cv-card[data-key="facebook"] {--ph:-11.25s}
#conversationsWrap .cv-card[data-key="viber"]    {--ph:-13.5s}
#conversationsWrap .cv-card[data-key="email"]    {--ph:-15.75s}

/* ---- chat cards: incoming white bubble left, Suppo green bubble right --- */
#conversationsWrap .cv-them{
  right:auto;width:max-content;max-width:100%;
  padding:4px 8px;border-radius:10px;border-top-left-radius:4px;
  background:#FFFFFF;border:1px solid rgba(16,17,20,.08);
  color:var(--muted);font-weight:500;
}
#conversationsWrap .cv-us{
  position:absolute;left:auto;right:0;width:max-content;max-width:100%;
  padding:4px 8px;border-radius:10px;border-bottom-right-radius:4px;
  background:linear-gradient(180deg,#EFFCF4 0%,#E7FAEE 100%);
  border:1px solid rgba(0,185,94,.18);color:#0A2E1C;font-weight:600;
}
#conversationsWrap .cv-typ{
  left:auto;right:0;width:36px;height:20px;
  border-radius:10px;border-bottom-right-radius:4px;
  background:linear-gradient(180deg,#EFFCF4 0%,#E7FAEE 100%);
  border:1px solid rgba(0,185,94,.18);
  display:flex;align-items:center;justify-content:center;gap:3px;
}
#conversationsWrap .cv-typ--rep{left:12px;right:auto}
#conversationsWrap .cv-typ i{
  display:block;width:4px;height:4px;border-radius:50%;background:rgba(10,46,28,.38);
}

/* two channel truths worth keeping as still detail, both free of animation:
   WhatsApp marks a message read with a blue double tick, and a Facebook page
   answering "where are you" answers with a place. */
#conversationsWrap .cv-us--tick{padding-right:24px}
#conversationsWrap .cv-ticks{position:absolute;right:7px;bottom:4px;width:15px;height:8px;color:#34B7F1}
#conversationsWrap .cv-ticks svg{width:15px;height:8px;display:block}
#conversationsWrap .cv-pinmark{
  display:inline-block;vertical-align:-2px;width:12px;height:12px;margin-right:3px;color:#0866FF;
}
#conversationsWrap .cv-pinmark svg{width:12px;height:12px;display:block}

/* the outcome chip: what the conversation actually produced */
#conversationsWrap .cv-chip{
  left:auto;right:0;width:max-content;max-width:100%;
  display:flex;align-items:center;gap:5px;padding:4px 10px 4px 6px;border-radius:100px;
  background:rgba(0,185,94,.11);color:var(--green-ink);font-weight:700;font-size:12px;line-height:1.25;
}
#conversationsWrap .cv-chip svg{width:14px;height:14px;flex:none}
#conversationsWrap .cv-chip--hand{background:rgba(115,96,242,.11);color:#4A38C4}

/* ---- comment cards (Instagram, Facebook): a public comment and the public
       reply threaded under it, indented the way a comment reply is --------- */
#conversationsWrap .cv-cmt{color:var(--muted);font-weight:500}
#conversationsWrap .cv-hand{
  display:block;font-size:12px;line-height:1.25;font-weight:800;
  color:var(--c);letter-spacing:-.01em;margin-bottom:1px;
}
#conversationsWrap .cv-rep{
  left:12px;right:auto;width:max-content;max-width:calc(100% - 12px);padding:4px 8px;border-left:2px solid #00B95E;border-radius:4px 10px 10px 4px;
  background:linear-gradient(180deg,#EFFCF4 0%,#E7FAEE 100%);
  color:#0A2E1C;font-weight:600;
}

/* ---- the call card: a live line, a running timer, captions --------------- */
#conversationsWrap .cv-callbar{display:flex;align-items:center;gap:8px;flex:none;height:15px}
#conversationsWrap .cv-wave{display:flex;align-items:flex-end;gap:3px;height:14px;flex:none}
#conversationsWrap .cv-wave i{
  display:block;width:3px;height:13px;border-radius:2px;background:rgba(0,185,94,.55);
  transform:scaleY(.28);transform-origin:50% 50%;
  animation:cv-bar 1.1s ease-in-out infinite alternate;
}
@keyframes cv-bar{from{transform:scaleY(.24)}to{transform:scaleY(1)}}
#conversationsWrap .cv-wave i:nth-child(1){animation-duration:.86s;animation-delay:-.30s}
#conversationsWrap .cv-wave i:nth-child(2){animation-duration:1.12s;animation-delay:-.72s}
#conversationsWrap .cv-wave i:nth-child(3){animation-duration:.94s;animation-delay:-.12s}
#conversationsWrap .cv-wave i:nth-child(4){animation-duration:1.26s;animation-delay:-.55s}
/* the timer is one strip of five stamps stepped by one keyframe track, so a
   running clock costs a single animation and never touches layout */
#conversationsWrap .cv-timer{margin-left:auto;flex:none;height:15px;overflow:hidden}
#conversationsWrap .cv-treel{
  display:block;animation:cv-treel var(--cyc,17s) linear var(--ph,0s) infinite both;
}
#conversationsWrap .cv-treel b{
  display:block;height:15px;font-size:12px;line-height:15px;font-weight:700;
  color:var(--green-ink);letter-spacing:.01em;font-variant-numeric:tabular-nums;
}
@keyframes cv-treel{
  0%,19.9%    {transform:translate3d(0,0,0)}
  20%,39.9%   {transform:translate3d(0,-15px,0)}
  40%,59.9%   {transform:translate3d(0,-30px,0)}
  60%,79.9%   {transform:translate3d(0,-45px,0)}
  80%,100%    {transform:translate3d(0,-60px,0)}
}
#conversationsWrap .cv-body--call .cv-s1{top:7px}
#conversationsWrap .cv-body--call .cv-s2{top:27px;bottom:auto}
#conversationsWrap .cv-cap{
  padding-left:9px;border-left:2px solid rgba(16,17,20,.16);
  color:var(--muted);font-weight:500;
}
#conversationsWrap .cv-cap--us{border-left-color:#00B95E;color:#0A2E1C;font-weight:600}

/* ---- the email card: a subject line in, a written price reply out -------- */
#conversationsWrap .cv-mail{color:var(--muted);font-weight:500}
/* a 12px label takes the page's label ink (--muted-2); --faint is non-text */
#conversationsWrap .cv-subj{
  display:block;font-size:12px;line-height:1.25;font-weight:700;
  color:var(--muted-2);letter-spacing:.005em;margin-bottom:2px;
}
#conversationsWrap .cv-rows,
#conversationsWrap .cv-rcpt{
  left:auto;right:0;width:max-content;max-width:100%;
  display:flex;flex-direction:column;gap:2px;padding:4px 9px;border-radius:8px;
  background:#FFFFFF;border:1px solid rgba(0,185,94,.20);
}
#conversationsWrap .cv-row{
  display:flex;align-items:baseline;justify-content:space-between;gap:14px;
  font-size:12.5px;line-height:1.3;font-weight:600;color:var(--muted);
}
#conversationsWrap .cv-num{font-weight:800;color:var(--ink);font-size:12.5px;white-space:nowrap}
#conversationsWrap .cv-rrow{
  display:flex;align-items:center;gap:6px;
  font-size:12.5px;line-height:1.3;font-weight:600;color:var(--muted);
}
#conversationsWrap .cv-rrow .cv-num{margin-left:auto}
#conversationsWrap .cv-ok{width:14px;height:14px;flex:none;display:block}
/* the booking tick is drawn by the card's own landing progress, not by a loop */
#conversationsWrap .cv-tickline{stroke-dasharray:14;stroke-dashoffset:14}
#conversationsWrap .cv-foot{font-size:12px;line-height:1.3;color:var(--green-ink);font-weight:700}

/* ---- the gate: nothing loops off screen, nothing loops before it lands --- */
#conversationsWrap .cv-msg,
#conversationsWrap .cv-loop,
#conversationsWrap .cv-wave i{animation-play-state:paused}
#conversationsWrap.cv-awake.cv-open .cv-msg,
#conversationsWrap.cv-awake.cv-open .cv-loop,
#conversationsWrap.cv-awake .cv-wave i{animation-play-state:running}

/* ---- a folded channel keeps its badge and nothing else ----------------
   measure() folds Facebook and Viber whenever it takes the two column
   profile, which a short frame can force at ANY width (the English sub wraps,
   the head grows, the four row wing no longer fits), so the rule cannot sit
   inside the tablet media query. */
#conversationsWrap .cv-card--fold{
  width:auto;height:auto;padding:6px;border-radius:100px;
  margin:-19px 0 0 -19px;
  box-shadow:0 1px 1px rgba(10,10,11,.03),0 10px 22px -10px var(--cs,rgba(10,10,11,.3));
}
#conversationsWrap .cv-card--fold .cv-body,
#conversationsWrap .cv-card--fold .cv-name,
#conversationsWrap .cv-card--fold .tag{display:none}
#conversationsWrap .cv-card--fold .cv-top{gap:0}

/* ---- the pill under the illustration ---------------------------------- */
/* no size override here: the pill is the page's .btn--live at its own default
   (15px / 700 / 14px 26px 11px), the same object as every other CTA on the
   page. Only the contact CTA is allowed to be the larger .btn--lg. */
#conversationsWrap .cv-cta{position:relative;z-index:2;flex:none;margin-top:8px;opacity:0}

/* ---- off screen costs nothing ----------------------------------------- */
#conversationsWrap.cv-awake .cv-orb__b,
#conversationsWrap.cv-awake .cv-orbit,
#conversationsWrap.cv-awake .cv-wave i,
#conversationsWrap.cv-awake .tag--live::before{animation-play-state:running}

/* ============================ tablet ==================================
   640 to 1059: the frame is too narrow for two columns of four, so it runs two
   columns of three cards flanking the orb; Facebook and Viber fold to
   badge-only nodes stacked with the orb, which keeps six conversations
   legible instead of eight being crushed. */
@media (max-width:1059px){
  #conversationsWrap{--orb:184px;--cw:222px;--ch:136px}
  #conversationsWrap .cv-frame{padding:82px 22px 20px}
  /* one size per breakpoint, both languages: the KA/EN split at every step was
     half of this section's share of the page's ten step H2 ladder */
  #conversationsWrap .cv-h2,
  #conversationsWrap:lang(ka) .cv-h2{font-size:clamp(28px,4.6vw,40px)}
  #conversationsWrap .cv-sub{font-size:15px;max-width:600px}
}

/* ============================ phone ===================================
   Founder (2026-09-06 10:27, with phone screenshots): "on mobile all of this
   layout is not optimized, [conversations] is not as sexy as on desktop".
   He was right, and the reason was structural: a PINNED 390x844 frame cannot
   give a two column grid the ~170px that eight two-slot threads need, so the
   phone build had frozen every card to its settled answer, shrunk the orb to
   88px and dropped the connectors and the light dots altogether.

   Under 640 the section therefore UNPINS. position:static, the wrapper takes
   its natural height, and the phone carries the desktop's whole life:

     head       88px clear of the nav island, 20px gutters, H2 28 KA / 30 EN,
                sub 15px, one column
     orb        148px with its halo, its orbit ring and TWO short connectors
                that run from the rim to the badges of the first row, one
                travelling light dot riding each of them, drawn once the orb
                is on screen (an IntersectionObserver, not the scrub)
     cards      eight, two columns, 16px apart, radius 16, 10px inner padding,
                thread window 112px = two real message slots, so every card
                runs its OWN cycle and phase exactly as it does on desktop:
                question, typing, reply, second exchange, outcome chip
     stagger    MOTION.reveal per card (left column, then right), the pill last

   Nothing here depends on a pin, so no beat can leave a blank screen and no
   card can be cut by a frame. Desktop (>= 1060) is untouched. */
@media (max-width:639px){
  #conversationsWrap{
    position:relative;height:auto;
    --orb:148px;--cw:100%;--ch:auto;--badge:26px;
  }
  /* UNPIN: the frame stops being a viewport and becomes a normal block */
  #conversationsWrap .pin{position:static;height:auto;display:block;overflow:visible}
  #conversationsWrap .cv-frame{
    height:auto;padding:88px 20px 72px;
    display:flex;flex-direction:column;align-items:stretch;justify-content:flex-start;
  }

  /* the aurora ground follows the taller flow box instead of one screen */
  #conversationsWrap .cv-mesh1{top:30%;width:84vw;height:520px}
  #conversationsWrap .cv-mesh2{top:58%;width:82vw;height:500px}
  #conversationsWrap .cv-mesh3{top:14%;width:76vw;height:380px}

  #conversationsWrap .cv-head{max-width:none;margin-bottom:0}
  #conversationsWrap .cv-h2{font-size:30px;line-height:1.08}
  #conversationsWrap:lang(ka) .cv-h2{font-size:30px;line-height:1.18}
  #conversationsWrap .cv-sub{margin-top:12px;max-width:none;font-size:15px;line-height:1.5}

  #conversationsWrap .cv-stage{
    display:flex;flex-direction:column;align-items:center;gap:22px;
    max-height:none;min-height:0;margin-top:30px;flex:none;
  }
  /* the connectors stay: they are short here, rim to first row, and they are
     the thing that says the eight channels hang off ONE brain */
  #conversationsWrap .cv-lines,
  #conversationsWrap .cv-dots{display:block}
  #conversationsWrap.cv-stack .cv-lines path{transition:stroke-dashoffset 1s var(--ease) .1s}
  #conversationsWrap.cv-stack.cv-open .cv-lines path{stroke-dashoffset:0}
  #conversationsWrap .cv-dots i{width:10px;height:10px}

  #conversationsWrap .cv-orbwrap{position:relative;left:auto;top:auto;margin:0;flex:none}
  #conversationsWrap .cv-halo{inset:-58%}
  #conversationsWrap .cv-orbit{inset:-12%}

  #conversationsWrap .cv-cards{
    position:static;inset:auto;width:100%;
    display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);
    gap:16px;align-content:start;min-height:0;
  }
  /* the scrub carried the landing on desktop; in flow MOTION.reveal does, one
     transition per card, the right column a beat behind the left */
  #conversationsWrap.cv-stack .cv-card{
    position:relative;width:auto;height:auto;min-width:0;margin:0;
    padding:10px;gap:6px;border-radius:var(--r-chrome);
    opacity:0;transform:translate3d(0,32px,0);
    transition:opacity 1s var(--ease) var(--d,0s),transform 1s var(--ease) var(--d,0s);
    box-shadow:0 1px 2px rgba(10,10,11,.04),0 14px 30px -16px var(--cs,rgba(10,10,11,.3));
  }
  #conversationsWrap.cv-stack .cv-card.in{opacity:1;transform:none}
  #conversationsWrap.cv-stack .cv-tickline{transition:stroke-dashoffset .7s var(--ease) .35s}
  #conversationsWrap.cv-stack .cv-card.in .cv-tickline{stroke-dashoffset:0}

  /* a max-content bubble sets the grid track's min width, which blows the two
     column grid off a 390px screen: on the phone every bubble is fluid */
  #conversationsWrap .cv-them,
  #conversationsWrap .cv-us,
  #conversationsWrap .cv-chip,
  #conversationsWrap .cv-rep,
  #conversationsWrap .cv-rows,
  #conversationsWrap .cv-rcpt{width:auto;max-width:100%}
  #conversationsWrap .cv-card--m .cv-top{flex-direction:row}
  #conversationsWrap .cv-card--m .tag{margin-left:auto;margin-right:0}
  /* "ტელეფონი" plus the live pill does not fit one 167px row: the row wraps
     instead of clipping the truth tag off the card. Georgian is the only
     language where it wraps, and a pill alone on a second line reads as a
     stray if it is still pushed to the far right, so in KA it hangs under the
     name instead; in EN "Phone LIVE" fits one row and keeps its right edge. */
  #conversationsWrap .cv-top{gap:7px;height:auto;flex-wrap:wrap;row-gap:5px}
  #conversationsWrap:lang(ka) .cv-card[data-key="phone"] .tag--live{
    margin-left:calc(var(--badge) + 7px);margin-right:auto;
  }
  #conversationsWrap .cv-name{min-width:0;font-size:12.5px}
  #conversationsWrap .cv-badge svg{width:14px;height:14px}
  #conversationsWrap .tag{font-size:12px}
  #conversationsWrap .tag--live{padding:3px 9px 3px 7px}

  /* THE THREAD WINDOW, and why the phone does not use the desktop's one.
     On desktop the two slots are absolutely placed, slot 1 hanging from the
     ceiling and slot 2 standing on the floor of a ~90px window, so the gap
     between them is never more than a line. Carried to a 167px phone card that
     window has to grow to ~130px to hold a three line reply, and the moment a
     card is stretched by a taller neighbour (the phone card's header wraps in
     Georgian and it also carries the call bar, so it is 47px taller than
     Messenger beside it) the two messages are flung to opposite ends of a 177px
     box with a hole between them. That is not a chat, that is an empty card.

     So on the phone the thread is a two row GRID and both rows hug the FLOOR:
     row 1 holds every slot 1 message stacked in one cell, row 2 holds slot 2,
     the rows are sized by their own tallest message in either language, and
     align-content plus align-items both end, so the pair sits on the floor and
     a bordered card (the booking receipt, the price rows) is not stretched to
     the height of the longest sentence that shares its slot. Nothing can ever clip
     (the row IS the tallest message) and any spare height falls above the
     conversation, which is exactly what an unfilled chat window looks like.
     The animations are untouched: they are opacity and transform only, and do
     not care whether the element is absolute or in flow. */
  /* the phone card is the tallest in its row (its Georgian header wraps and it
     also carries the call bar), and a stretched grid row would hand Messenger
     beside it 47px of EMPTY GREY PANEL. So on the phone the panel is sized by
     its own conversation and the spare height falls under it, inside the white
     card, where it reads as breathing room instead of an unfilled window. */
  #conversationsWrap .cv-body{padding:9px;border-radius:14px;gap:6px;flex:0 0 auto}
  #conversationsWrap .cv-thread{
    display:grid;grid-template-columns:100%;grid-auto-rows:min-content;
    row-gap:7px;align-content:end;align-items:end;min-height:104px;
  }
  #conversationsWrap .cv-msg{position:static;grid-column:1}
  #conversationsWrap .cv-s1{grid-row:1}
  #conversationsWrap .cv-s2{grid-row:2}
  /* a price row on a 147px card cannot afford a 14px column gap */
  #conversationsWrap .cv-row{gap:10px}
  #conversationsWrap .cv-callbar{height:16px}
  /* `left` is inert in flow: the public reply keeps its indent as a margin */
  #conversationsWrap .cv-rep{left:auto;margin-left:10px;max-width:calc(100% - 10px)}

  #conversationsWrap .cv-cta{margin-top:30px;text-align:center;transform:translate3d(0,32px,0)}
  #conversationsWrap.cv-stack .cv-cta{
    transition:opacity 1s var(--ease) .08s,transform 1s var(--ease) .08s;
  }
  #conversationsWrap.cv-stack .cv-cta.in{opacity:1;transform:none}
  /* the shared .btn--live is already 15px on a 44px pill; the phone only needs
     the extra horizontal room */
  #conversationsWrap .cv-cta .btn--live{padding-left:30px;padding-right:30px}
}

/* ---- reduced motion: the settled diagram, no loops -------------------- */
@media (prefers-reduced-motion: reduce){
  #conversationsWrap .cv-orb__b,
  #conversationsWrap .cv-orbit,
  #conversationsWrap .cv-dots i,
  #conversationsWrap .cv-wave i,
  #conversationsWrap .tag--live::before,
  #conversationsWrap .cv-loop,
  #conversationsWrap .cv-msg,
  #conversationsWrap .cv-treel{animation:none}
  #conversationsWrap .cv-m3,
  #conversationsWrap .cv-m4,
  #conversationsWrap .cv-typ{display:none}
  #conversationsWrap .cv-m1,
  #conversationsWrap .cv-m2{opacity:1;transform:none}
  #conversationsWrap .cv-orb__b,
  #conversationsWrap .cv-card{will-change:auto}
  #conversationsWrap .cv-wave i{transform:scaleY(.62)}
}

/* ===== bento ===== */
/* ============================================================
   BENTO (Suppo)  "პასუხობს. წერს. არ იგონებს."
   Non-pinned, normal flow, full-bleed band, stagger card reveal +
   view-mode parallax scrub. ONE content column: .col is exactly
   var(--maxw) wide, centred.

   ROUND 5, the founder's note on the screenshot: "here also we need more
   animation sequence, it is too small in chronometrage". The grid, the copy
   and the colour panels are unchanged; every vignette is now a LONG film with
   named steps and long holds instead of a short two-state blink:

     card 1  four waiting things arrive one at a time, each waits its own beat,
             each turns green; then the four answered chips are held.
     card 2  name, service, service written one row at a time, the tick draws
             itself, the SMS chip pulses and turns "Sent"; then held.
     card 3  the highlight walks the conversation list row by row, the channel
             glyph of the lit row pulses, then a new call slides in at the top
             and takes the highlight.
     card 4  three exchanges taking turns 0.7 s apart: caller line, the agent
             thinking, the refusal, the green outcome; then held.
     card 5  the button presses, 45 rolls up to 50, and the change ripples
             outward through the eight channels in pairs; then it rolls back.

   ROUND 6, ONE MASTER CLOCK. Five films of five different lengths meant two of
   them ran in exact phase and four of the five cards could be moving in the same
   half second, which is the wrong frame for the page's densest reading task.
   Every film is now 20 s, every film's motion is confined to 10 % - 45 % of it
   (2.0 s - 9.0 s, a 7 s window) and 0 % - 10 % is a static, finished pose. The
   five cards are phase-shifted 4 s apart (--o: 0 / -4 / -8 / -12 / -16 s), so a
   7 s window over points spaced 4 s apart can hold at most TWO of them: no more
   than 2 of the 5 cards are ever changing in the same half second, and 10 of
   every 20 seconds have at most one card moving at all.

   Rules held: transform / opacity ONLY, with the two documented exceptions the
   brief allows on sub-30px elements (the 11px tick's stroke-dashoffset). No
   filter anywhere. Every loop sits on an inner node so the scrubbed outer
   element keeps its parallax transform, and every loop is paused until its own
   card intersects (.card.live, set from JS). will-change is declared only on
   the nine elements the scrub writes every frame. Elements that move carry no
   box-shadow, or carry it on a static parent that does not move.
   ============================================================ */
/* the nav pill is fixed and ends at y=102; without this the #bentoWrap anchor
   drops the H2 straight behind the glass */
#bentoWrap{scroll-margin-top:118px;position:relative;background:var(--band);
  /* page spec, tokenised here so it cannot drift; the var() fallbacks are the
     spec values, so the section is correct with or without the shared hoist */
  --band-pt:96px;--band-pb:92px;
  --h2-ka:54px;--h2-en:56px;
  --sub-size:16px;--sub-lh:1.55;--sub-max:640px;
  --tile-grey:var(--tile,#F1F1F4);      /* ONE tile grey, never the page band  */
  --ink-green:var(--green-ink,#067A45); /* green that is legal as TEXT on white */
  --card-r:var(--r-card,32px);
  --rise:32px;--rise-dur:1s}
#bentoWrap .band{padding:var(--band-pt) 0 var(--band-pb)}
#bentoWrap .col{width:100%;max-width:var(--maxw);margin:0 auto;padding:0}

/* ---------- header ---------- */
#bentoWrap .head{text-align:center}
#bentoWrap .ttl{font-size:var(--h2-ka);line-height:1.06;letter-spacing:-.012em;color:var(--ink);font-weight:800}
#bentoWrap .ttl .w{display:inline-block}
/* Every one-shot reveal in this file is ONE animation, not a transition on two
   properties: same curves, same delays, half the compositor objects. */
#bentoWrap .ttl .w > span{display:inline-block;opacity:0;transform:translateY(20px)}
#bentoWrap .head.in .ttl .w > span{animation:bRise .95s var(--ease) var(--d) both}
@keyframes bRise{from{opacity:0;transform:translateY(20px)}
  60%{opacity:1} to{opacity:1;transform:none}}
/* Latin runs a touch larger and tighter than Georgian; Georgian is never text-transformed */
#bentoWrap .ttl:lang(en){font-size:var(--h2-en);letter-spacing:-.032em}
#bentoWrap .sub{font-size:var(--sub-size);line-height:var(--sub-lh);max-width:var(--sub-max);margin:16px auto 0;color:var(--muted);font-weight:500;
  opacity:0;transform:translateY(16px)}
#bentoWrap .head.in .sub{animation:bSubIn .9s var(--ease) .26s both}
@keyframes bSubIn{from{opacity:0;transform:translateY(16px)}
  62%{opacity:1} to{opacity:1;transform:none}}

/* ---------- grid ---------- */
#bentoWrap .grid{display:grid;grid-template-columns:repeat(3,1fr);gap:20px;margin-top:44px}
/* The card does not clip its own contents: every illustration lives inside .vig,
   which clips to its own 24px radius. One clip does the work. */
#bentoWrap .card{position:relative;background:var(--panel);border-radius:var(--card-r);
  box-shadow:var(--shadow-soft);
  opacity:0;transform:translateY(var(--rise))}
#bentoWrap .card.in{animation:bCardIn var(--rise-dur) var(--ease) var(--d) both}
@keyframes bCardIn{from{opacity:0;transform:translateY(32px)}
  60%{opacity:1} to{opacity:1;transform:none}}
#bentoWrap .card.wide{grid-column:span 2}
#bentoWrap .card h3{position:relative;z-index:1;margin:18px 26px 0;font-size:21px;line-height:1.28;
  letter-spacing:-.008em;font-weight:800;color:var(--ink)}
#bentoWrap .card h3 .num{font-variant-numeric:tabular-nums}
#bentoWrap .card h3 em.hl{font-style:normal}
#bentoWrap .card p{position:relative;z-index:1;margin:8px 26px 26px;font-size:14px;line-height:1.55;color:var(--muted);
  font-weight:500;letter-spacing:0}
#bentoWrap .card.wide p{max-width:430px}
/* ---------- the filled vignette panel ----------
   Every card is a white frame around a solid aurora panel: the panel sits inside the
   card's own 26px gutter, its top edge flush with that gutter, and the illustration
   lives inside it with its own padding. One tint per card, no two neighbours alike:
     1 sky  2 mint  3 lavender      (top row)
     4 pale green (wide)  5 teal    (bottom row) */
#bentoWrap .vig{position:relative;z-index:1;height:221px;overflow:hidden;
  margin:26px 26px 0;border-radius:24px;background:var(--tint)}
#bentoWrap .v1{--tint:#86D6F8}
#bentoWrap .v2{--tint:#9BE7C4}
#bentoWrap .v3{--tint:#C9C2FF}
#bentoWrap .v4{--tint:#C8F2D9}
#bentoWrap .v5{--tint:#8EE3E0}
/* --o is where each film starts on the one 20 s clock. Every loop in a vignette
   adds it to its own animation-delay. Four seconds apart, evenly, is what caps the
   page at two moving cards: each film moves for 7 s of its 20, and five points
   spaced 4 s apart can never put three of them inside one 7 s window. */
#bentoWrap .v1{--o:-0s}
#bentoWrap .v2{--o:-4s}
#bentoWrap .v3{--o:-8s}
#bentoWrap .v4{--o:-12s}
#bentoWrap .v5{--o:-16s}

/* ---------- shared vignette furniture ---------- */
#bentoWrap .panel{position:absolute;background:var(--panel);border-radius:14px;padding:12px 12px;overflow:hidden;
  box-shadow:0 1px 2px rgba(10,10,11,.05),0 12px 26px rgba(10,10,11,.09)}
#bentoWrap .phead{display:flex;align-items:center;justify-content:space-between;gap:8px;height:19px}
#bentoWrap .ptitle{display:flex;align-items:center;gap:6px;font-size:12.5px;font-weight:700;letter-spacing:0;white-space:nowrap}
#bentoWrap .grip{width:3px;height:11px;flex:none;
  background-image:radial-gradient(circle at 1.5px 1.5px,#D4D7DE 1.1px,transparent 1.3px);background-size:3px 4px}
/* the page's tag shape is a pill; this was the one tag on it that was not.
   #F3F3F5 was exactly --band, so the chip vanished into the ground showing
   through a white card: --tile is the one grey a tile takes. */
#bentoWrap .chip{display:inline-flex;align-items:center;gap:4px;font-size:12px;font-weight:600;color:var(--muted);
  background:var(--tile-grey);border-radius:999px;padding:3px 9px;white-space:nowrap}
#bentoWrap .chip.ok{background:#E9F7F0}
#bentoWrap .num{font-variant-numeric:tabular-nums;letter-spacing:0}

/* ============================================================
   CARD 1  "Answers 24/7, on every channel"   20 s, moving 2.0 - 9.0 s
   ------------------------------------------------------------
   0.0 - 2.0 s   four answered chips, held (the still design)
   2.0 - 2.3 s   the four clear together (the cut between takes)
   2.3 - 3.1 s   the missed call arrives          3.7 - 4.0 s  it turns green
   4.0 - 4.8 s   the unread message arrives       5.4 - 5.6 s  it turns green
   5.6 - 6.5 s   the Sunday silence arrives       7.0 - 7.3 s  it turns green
   7.3 - 8.2 s   the unread letter arrives        8.7 - 9.0 s  it turns green
   9.0 - 20.0 s  held, and straight on into the 2 s hold at the top: thirteen
                 seconds of stillness with all four answered, which is the
                 frame the reader is meant to be able to read.
   Each chip's badge is a 22px window over a two-state roll (waiting dots ->
   green ANSWERS), so the state change is ONE transform, not a cross-fade of two.
   0% of every timeline is the answered, complete state, so a paused card and a
   reduced-motion card both read exactly like the still design.
   ============================================================ */
/* one parallax wrapper for the three rings and the blob: they always took the exact
   same translateY, so they were four per-frame writes and four promoted layers for
   one movement. Now it is one write, one layer. */
#bentoWrap .ringsp{position:absolute;inset:0;will-change:transform}
#bentoWrap .v1 .ring{position:absolute;left:50%;top:106px;border:1px solid rgba(10,10,11,.07);border-radius:50%}
#bentoWrap .v1 .r1{width:258px;height:258px;margin:-129px 0 0 -129px}
#bentoWrap .v1 .r2{width:206px;height:206px;margin:-103px 0 0 -103px}
#bentoWrap .v1 .r3{width:154px;height:154px;margin:-77px 0 0 -77px}
#bentoWrap .v1 .blob{position:absolute;left:50%;top:116px;width:200px;height:200px;margin:-100px 0 0 -100px;border-radius:50%;
  background:radial-gradient(circle,rgba(10,10,11,.045),rgba(10,10,11,0) 70%)}
/* the stack is centred rather than pinned to a fixed inset: at the 380px design card
   that lands it where it was drawn, and on a narrower card it shrinks with the card
   instead of pushing the green badge past the overflow edge */
#bentoWrap .stack{position:absolute;left:12px;right:12px;top:22px;width:auto;max-width:302px;
  margin:0 auto;height:176px;
  opacity:0;transition:opacity .8s var(--ease) .18s}
#bentoWrap .card.in .stack{opacity:1}
/* .stackp carries the scrub parallax so the chips below are free to loop */
#bentoWrap .stackp{position:absolute;inset:0;will-change:transform}
/* the four slots are always drawn, so the panel keeps its shape while it fills:
   an empty slot reads as a thing still waiting rather than as a hole. They are
   static, so they neither animate nor promote a layer. */
/* Each slot carries a faint ghost of the row it is waiting for (glyph tile, one
   line, badge block), so a slot that has not been filled yet reads as a thing
   still queued rather than as a hole in the panel. All static: no animation, no
   promoted layer, and the arriving chip covers its slot exactly. */
#bentoWrap .slot{position:absolute;left:0;right:0;height:38px;border-radius:13px;background:rgba(255,255,255,.34);
  display:flex;align-items:center;gap:7px;padding:0 7px;box-sizing:border-box}
#bentoWrap .slot i{display:block;background:rgba(255,255,255,.62);border-radius:8px}
#bentoWrap .slot .sp{width:24px;height:24px;flex:none}
#bentoWrap .slot .sl{flex:1;max-width:104px;height:7px;border-radius:4px;margin-right:auto}
#bentoWrap .slot .sb{width:68px;height:22px;flex:none}
/* three different line lengths, so the waiting rows read as three different
   queued things rather than as one loading skeleton repeated */
#bentoWrap .s2 .sl{max-width:84px}
#bentoWrap .s4 .sl{max-width:72px}
#bentoWrap .s1{top:0}
#bentoWrap .s2{top:46px}
#bentoWrap .s3{top:92px}
#bentoWrap .s4{top:138px}
/* the chip moves by translate only and never scales, so its one soft shadow is
   rasterised once and composited, never re-rastered */
#bentoWrap .ch{position:absolute;left:0;right:0;height:38px;display:flex;align-items:center;gap:7px;
  padding:0 7px;background:var(--panel);border-radius:13px;
  box-shadow:0 8px 18px rgba(10,10,11,.10)}
#bentoWrap .k1{top:0}
#bentoWrap .k2{top:46px}
#bentoWrap .k3{top:92px}
#bentoWrap .k4{top:138px}
#bentoWrap .pic{width:24px;height:24px;border-radius:8px;flex:none;display:grid;place-items:center;background:var(--tile-grey)}
#bentoWrap .pt{display:flex;align-items:center;gap:6px;flex:1;min-width:0;overflow:hidden;white-space:nowrap}
#bentoWrap .ptl{min-width:0;overflow:hidden;text-overflow:ellipsis;font-size:12.5px;font-weight:600;color:var(--ink)}
#bentoWrap .pt .day{display:inline-block;margin-right:5px;background:var(--ink);color:#fff;border-radius:6px;
  padding:1px 5px;font-size:12px;font-weight:700}
#bentoWrap .tm{flex:none;font-size:12px;font-weight:700;color:var(--faint)}
/* 68px is the widest badge word (ANSWERS 56, პასუხობს 58) plus its padding: any
   wider and the longest EN chip label ("A call nobody picked up", 139px) truncates */
#bentoWrap .bwin{position:relative;flex:none;width:68px;height:22px;overflow:hidden;border-radius:8px}
#bentoWrap .broll{position:absolute;left:0;right:0;top:0;height:44px;transform:translateY(-22px)}
#bentoWrap .bst{position:absolute;left:0;right:0;height:22px;display:flex;align-items:center;justify-content:center;
  gap:3px;border-radius:8px;font-size:12px;font-weight:700}
#bentoWrap .pend{top:0;background:#EFEFF2}
#bentoWrap .pend i{width:3.5px;height:3.5px;border-radius:50%;background:#B4B7C0}
#bentoWrap .ans{top:22px;background:var(--live);color:var(--ink)}

#bentoWrap .k1{animation:bCh1 20s var(--ease) infinite both;animation-delay:var(--o)}
#bentoWrap .k2{animation:bCh2 20s var(--ease) infinite both;animation-delay:var(--o)}
#bentoWrap .k3{animation:bCh3 20s var(--ease) infinite both;animation-delay:var(--o)}
#bentoWrap .k4{animation:bCh4 20s var(--ease) infinite both;animation-delay:var(--o)}
/* the cut at 10..11.4% takes all four away together; each chip then walks back in
   on its own beat, and everything is finished by 45%. The 0.1% step is 20 ms, one
   frame at 60fps: the reset is never seen. */
@keyframes bCh1{
  0%{opacity:1;transform:none} 10%{opacity:1;transform:none}
  11.4%{opacity:0;transform:translateY(-9px)} 11.5%{opacity:0;transform:translateY(16px)}
  15.6%{opacity:1;transform:none} 100%{opacity:1;transform:none}}
@keyframes bCh2{
  0%{opacity:1;transform:none} 10%{opacity:1;transform:none}
  11.4%{opacity:0;transform:translateY(-9px)} 19.8%{opacity:0;transform:translateY(16px)}
  24%{opacity:1;transform:none} 100%{opacity:1;transform:none}}
@keyframes bCh3{
  0%{opacity:1;transform:none} 10%{opacity:1;transform:none}
  11.4%{opacity:0;transform:translateY(-9px)} 28.2%{opacity:0;transform:translateY(16px)}
  32.4%{opacity:1;transform:none} 100%{opacity:1;transform:none}}
@keyframes bCh4{
  0%{opacity:1;transform:none} 10%{opacity:1;transform:none}
  11.4%{opacity:0;transform:translateY(-9px)} 36.6%{opacity:0;transform:translateY(16px)}
  40.8%{opacity:1;transform:none} 100%{opacity:1;transform:none}}

#bentoWrap .b1{animation:bBd1 20s var(--ease) infinite both;animation-delay:var(--o)}
#bentoWrap .b2{animation:bBd2 20s var(--ease) infinite both;animation-delay:var(--o)}
#bentoWrap .b3{animation:bBd3 20s var(--ease) infinite both;animation-delay:var(--o)}
#bentoWrap .b4{animation:bBd4 20s var(--ease) infinite both;animation-delay:var(--o)}
/* the roll snaps back to the waiting dots inside the frame in which its chip is
   invisible (11.3 -> 11.4%), then rolls up to green a beat after the chip lands */
@keyframes bBd1{
  0%{transform:translateY(-22px)} 11.3%{transform:translateY(-22px)}
  11.4%{transform:translateY(0)} 18.4%{transform:translateY(0)}
  19.8%{transform:translateY(-22px)} 100%{transform:translateY(-22px)}}
@keyframes bBd2{
  0%{transform:translateY(-22px)} 11.3%{transform:translateY(-22px)}
  11.4%{transform:translateY(0)} 26.8%{transform:translateY(0)}
  28.2%{transform:translateY(-22px)} 100%{transform:translateY(-22px)}}
@keyframes bBd3{
  0%{transform:translateY(-22px)} 11.3%{transform:translateY(-22px)}
  11.4%{transform:translateY(0)} 35.2%{transform:translateY(0)}
  36.6%{transform:translateY(-22px)} 100%{transform:translateY(-22px)}}
@keyframes bBd4{
  0%{transform:translateY(-22px)} 11.3%{transform:translateY(-22px)}
  11.4%{transform:translateY(0)} 43.6%{transform:translateY(0)}
  45%{transform:translateY(-22px)} 100%{transform:translateY(-22px)}}

/* ============================================================
   CARD 2  "Writes the booking, not a note about it"   20 s, moving 2.0 - 8.8 s
   ------------------------------------------------------------
   0.0 - 2.0 s   the finished receipt, held (the still design)
   2.0 s         the panel empties
   2.0 - 3.5 s   the name is written, then the time beside it
   3.5 - 5.0 s   the service, then its price
   5.0 - 6.5 s   the second service, then its price
   6.9 - 7.9 s   the tick draws itself in the header chip
   8.0 - 8.8 s   the SMS chip pulses and turns "Sent"
   8.8 - 20.0 s  held (11.2 s), running into the 2 s hold at the top
   ============================================================ */
/* both ghost slabs take the identical parallax: one wrapper, one write, one layer */
#bentoWrap .ghostsp{position:absolute;inset:0;will-change:transform}
#bentoWrap .v2 .ghost{position:absolute;top:40px;width:64px;height:150px}
/* white, not grey: the slabs are the receipts stacked behind the front one, and on
   the mint panel a grey gradient reads as dirt rather than as paper */
#bentoWrap .v2 .ghost::before{content:"";position:absolute;inset:0;border-radius:17px;
  background:linear-gradient(180deg,rgba(255,255,255,.62),rgba(255,255,255,.86))}
/* the two ghost slabs sit a fixed distance either side of the receipt panel instead
   of on the card edges, so a wide card does not fling them into the corners; on a
   narrow card the max() clamps them back to the edge */
#bentoWrap .v2 .gl{left:max(0px,calc(50% - 194px))}
#bentoWrap .v2 .gr{right:max(0px,calc(50% - 194px))}
#bentoWrap .att{left:50%;top:19px;margin-left:-124px;width:248px;will-change:transform;
  opacity:0;transition:opacity .7s var(--ease) .16s}
#bentoWrap .card.in .att{opacity:1}
/* the tick pops and draws itself in ONE animation: the 11px path's stroke-dashoffset
   is the single non-composited property in this file, and the brief allows it on a
   sub-30px element. It is erased instantly at the cut, while the chip is at scale .5. */
#bentoWrap .tk{transform:scale(1);animation:bOk 20s var(--ease) infinite both;animation-delay:var(--o)}
@keyframes bOk{
  0%{transform:scale(1)} 10%{transform:scale(1)}
  10.1%{transform:scale(.5)} 34.75%{transform:scale(.5)}
  37.75%{transform:scale(1.14)} 39.25%{transform:scale(1)} 100%{transform:scale(1)}}
#bentoWrap .tkp{stroke-dasharray:12;stroke-dashoffset:0;animation:bTick 20s var(--ease) infinite both;animation-delay:var(--o)}
@keyframes bTick{
  0%{stroke-dashoffset:0} 10%{stroke-dashoffset:0}
  10.1%{stroke-dashoffset:12} 34.75%{stroke-dashoffset:12}
  39.25%{stroke-dashoffset:0} 100%{stroke-dashoffset:0}}
#bentoWrap .bk{list-style:none;margin-top:8px}
#bentoWrap .bk li{display:flex;align-items:center;justify-content:space-between;gap:10px;
  height:32px;box-sizing:border-box;border-bottom:1px solid #F1F1F3}
#bentoWrap .bk li:last-child{border-bottom:0}
#bentoWrap .bkn{font-size:13px;font-weight:600;color:var(--ink);white-space:nowrap}
#bentoWrap .bkv{font-size:13px;font-weight:800;color:var(--ink);white-space:nowrap}
#bentoWrap .r1 .bkn{animation:bW1 20s var(--ease) infinite both;animation-delay:var(--o)}
#bentoWrap .r1 .bkv{animation:bW2 20s var(--ease) infinite both;animation-delay:var(--o)}
#bentoWrap .r2 .bkn{animation:bW3 20s var(--ease) infinite both;animation-delay:var(--o)}
#bentoWrap .r2 .bkv{animation:bW4 20s var(--ease) infinite both;animation-delay:var(--o)}
#bentoWrap .r3 .bkn{animation:bW5 20s var(--ease) infinite both;animation-delay:var(--o)}
#bentoWrap .r3 .bkv{animation:bW6 20s var(--ease) infinite both;animation-delay:var(--o)}
/* six writes, 3.75% (0.75 s) apart, each sliding in from the left the way a line is
   written rather than pasted. Same six beats as before, on the 20 s clock. */
@keyframes bW1{0%{opacity:1;transform:none} 10%{opacity:1;transform:none}
  10.1%{opacity:0;transform:translateX(-9px)} 10.75%{opacity:0;transform:translateX(-9px)}
  13.75%{opacity:1;transform:none} 100%{opacity:1;transform:none}}
@keyframes bW2{0%{opacity:1;transform:none} 10%{opacity:1;transform:none}
  10.1%{opacity:0;transform:translateX(6px)} 14.5%{opacity:0;transform:translateX(6px)}
  17.5%{opacity:1;transform:none} 100%{opacity:1;transform:none}}
@keyframes bW3{0%{opacity:1;transform:none} 10%{opacity:1;transform:none}
  10.1%{opacity:0;transform:translateX(-9px)} 18.25%{opacity:0;transform:translateX(-9px)}
  21.25%{opacity:1;transform:none} 100%{opacity:1;transform:none}}
@keyframes bW4{0%{opacity:1;transform:none} 10%{opacity:1;transform:none}
  10.1%{opacity:0;transform:translateX(6px)} 22%{opacity:0;transform:translateX(6px)}
  25%{opacity:1;transform:none} 100%{opacity:1;transform:none}}
@keyframes bW5{0%{opacity:1;transform:none} 10%{opacity:1;transform:none}
  10.1%{opacity:0;transform:translateX(-9px)} 25.75%{opacity:0;transform:translateX(-9px)}
  28.75%{opacity:1;transform:none} 100%{opacity:1;transform:none}}
@keyframes bW6{0%{opacity:1;transform:none} 10%{opacity:1;transform:none}
  10.1%{opacity:0;transform:translateX(6px)} 29.5%{opacity:0;transform:translateX(6px)}
  32.5%{opacity:1;transform:none} 100%{opacity:1;transform:none}}
#bentoWrap .smsrow{display:flex;align-items:center;gap:8px;margin-top:10px}
#bentoWrap .sms{position:relative;display:inline-flex;align-items:center;gap:6px;background:#E9F7F0;
  border-radius:10px;padding:5px 9px;opacity:0;transform:translateY(8px)}
#bentoWrap .card.in .sms{animation:bPop .85s var(--ease-pop) .34s both}
@keyframes bPop{from{opacity:0;transform:translateY(8px)}
  55%{opacity:1} to{opacity:1;transform:none}}
/* the SMS pulse is a pre-rendered ring; only its opacity and scale move, and it
   fires once per cycle, right after the last row is written */
#bentoWrap .sms .pulse{position:absolute;inset:-3px;border-radius:13px;border:1.5px solid var(--live);
  opacity:0;animation:bPulse 20s var(--ease) infinite both;animation-delay:var(--o)}
/* the ring resets INSIDE the frame it finishes in, so it holds one static value
   for the other 11 seconds instead of creeping back down invisibly */
@keyframes bPulse{
  0%{transform:scale(.88);opacity:0} 37.75%{transform:scale(.88);opacity:0}
  40%{transform:scale(.92);opacity:.75} 43.75%{transform:scale(1.34);opacity:0}
  43.85%{transform:scale(.88);opacity:0} 100%{transform:scale(.88);opacity:0}}
/* --live and --live-press are FILL colours: as text they measure 2.4:1 on white.
   Anything green that has to be read uses --green-ink (5.42:1). */
#bentoWrap .smsl{font-size:12px;font-weight:700;color:var(--ink-green);letter-spacing:.02em}
/* the "Sent" stamp sits OUTSIDE the green chip, so the chip keeps its own width
   and the space the stamp reserves is invisible until the stamp lands */
#bentoWrap .sent{font-size:12px;font-weight:700;color:var(--ink-green);white-space:nowrap;
  animation:bSent 20s var(--ease) infinite both;animation-delay:var(--o)}
@keyframes bSent{
  0%{opacity:1;transform:none} 10%{opacity:1;transform:none}
  10.1%{opacity:0;transform:translateX(-6px)} 39.25%{opacity:0;transform:translateX(-6px)}
  43.75%{opacity:1;transform:none} 100%{opacity:1;transform:none}}

/* ============================================================
   CARD 3  "Every conversation, word for word"   20 s, moving 2.0 - 9.0 s
   ------------------------------------------------------------
   0.0 - 2.0 s   the newest call sits at the top of the list, lit (the still design)
   2.0 s         the list fades a frame and steps back to the older three
   2.6 - 4.0 s   the email row is lit, its envelope beats twice
   4.3 - 5.5 s   the site-chat row is lit, its bubble beats twice
   5.8 - 7.0 s   the older call is lit, its handset beats twice
   7.3 - 8.0 s   a new call slides in at the top and pushes the list down
   8.2 - 9.0 s   the new row lights and its handset gives one slower beat
   9.0 - 20.0 s  held, into the 2 s hold at the top
   ============================================================ */
#bentoWrap .c3 .dots{position:absolute;left:0;right:0;top:0;bottom:0;z-index:0;will-change:transform;
  background-image:radial-gradient(circle at 1px 1px,rgba(10,10,11,.11) .8px,transparent .95px);background-size:39px 4px;
  -webkit-mask-image:linear-gradient(180deg,transparent 0,#000 7%,#000 76%,transparent 95%);
  mask-image:linear-gradient(180deg,transparent 0,#000 7%,#000 76%,transparent 95%)}
#bentoWrap .doc{position:absolute;top:44px;width:80px;height:96px;padding:11px 10px 13px;background:var(--panel);border-radius:12px;
  display:flex;flex-direction:column;gap:9px;box-shadow:0 2px 6px rgba(10,10,11,.05),0 16px 30px rgba(10,10,11,.08);
  opacity:0}
#bentoWrap .doc .sq{display:block;width:32px;height:28px;border-radius:8px;background:#EFEFF2;margin-bottom:auto}
#bentoWrap .doc .ln{display:block;height:5px;border-radius:3px;background:#EDEDF0}
#bentoWrap .doc .ln:last-child{width:64%}
#bentoWrap .d2 .sq{margin-left:auto}
#bentoWrap .d1{left:calc(50% - 158px);--dd:.24s;
  --from:translate(22px,14px) scale(.94);--to:rotate(-8.5deg);transform:var(--from)}
#bentoWrap .d2{left:calc(50% + 78px);--dd:.3s;
  --from:translate(-22px,14px) scale(.94);--to:rotate(8.5deg);transform:var(--from)}
#bentoWrap .card.in .doc{animation:bDocIn .95s var(--ease-pop) var(--dd) both}
@keyframes bDocIn{from{opacity:0;transform:var(--from)}
  55%{opacity:1} to{opacity:1;transform:var(--to)}}
#bentoWrap .tile{position:absolute;left:50%;top:36px;margin-left:-118px;width:236px;border-radius:16px;
  background:var(--panel);padding:11px 11px 0;
  box-shadow:0 2px 6px rgba(10,10,11,.06),0 18px 34px rgba(10,10,11,.10);
  opacity:0;transform:scale(.55)}
#bentoWrap .card.in .tile{animation:bTileIn .8s var(--ease-pop) .38s both}
@keyframes bTileIn{from{opacity:0;transform:scale(.55)}
  50%{opacity:1} to{opacity:1;transform:none}}
/* a three-row window over four rows: the fourth is the call that has not landed yet */
#bentoWrap .cvwin{position:relative;height:105px;overflow:hidden;margin-top:6px}
#bentoWrap .cv{list-style:none;position:absolute;left:0;right:0;top:0}
#bentoWrap .cvroll{animation:bCvRoll 20s var(--ease) infinite both;animation-delay:var(--o)}
@keyframes bCvRoll{
  0%{transform:translateY(0);opacity:1} 10%{transform:translateY(0);opacity:1}
  11.3%{transform:translateY(0);opacity:0} 11.4%{transform:translateY(-35px);opacity:0}
  12.8%{transform:translateY(-35px);opacity:1} 36.5%{transform:translateY(-35px);opacity:1}
  40%{transform:translateY(0);opacity:1} 100%{transform:translateY(0);opacity:1}}
#bentoWrap .cv li{position:relative;display:flex;align-items:center;gap:7px;height:35px;box-sizing:border-box;
  border-bottom:1px solid #F1F1F3}
#bentoWrap .cv li:last-child{border-bottom:0}
#bentoWrap .cg{flex:none;width:18px;height:18px;display:grid;place-items:center}
#bentoWrap .cv .ln{position:relative;flex:1;min-width:14px;height:5px;border-radius:3px;background:#EDEDF0}
#bentoWrap .cv .tm{color:var(--faint)}
#bentoWrap .src{position:relative;display:inline-flex;align-items:center;align-self:center;background:var(--tile-grey);
  color:var(--ink);border-radius:7px;padding:2px 6px;font-size:12px;font-weight:700;white-space:nowrap}
#bentoWrap .src .st{position:relative}
/* the green "active source" pill is a pre-rendered layer; only its opacity moves */
#bentoWrap .src .sbg{position:absolute;inset:0;border-radius:7px;background:var(--live);opacity:0}
#bentoWrap .cv .a .sbg{opacity:1;animation:bSrcA 20s var(--ease) infinite both;animation-delay:var(--o)}
#bentoWrap .cv .b .sbg{animation:bSrcB 20s var(--ease) infinite both;animation-delay:var(--o)}
#bentoWrap .cv .c .sbg{animation:bSrcC 20s var(--ease) infinite both;animation-delay:var(--o)}
#bentoWrap .cv .d .sbg{animation:bSrcD 20s var(--ease) infinite both;animation-delay:var(--o)}
@keyframes bSrcA{0%{opacity:1} 10%{opacity:1} 11.3%{opacity:0} 39%{opacity:0} 41%{opacity:1} 100%{opacity:1}}
@keyframes bSrcB{0%{opacity:0} 12.8%{opacity:0} 14%{opacity:1} 18.8%{opacity:1} 20.2%{opacity:0} 100%{opacity:0}}
@keyframes bSrcC{0%{opacity:0} 20.2%{opacity:0} 21.5%{opacity:1} 26.3%{opacity:1} 27.7%{opacity:0} 100%{opacity:0}}
@keyframes bSrcD{0%{opacity:0} 27.7%{opacity:0} 29%{opacity:1} 33.8%{opacity:1} 35.2%{opacity:0} 100%{opacity:0}}
/* the lit row's channel glyph gives two soft beats while it holds the highlight.
   Row A is the exception: it lights as the new call lands, at the very end of the
   window, so it gets ONE slower beat (0.4 s up, 0.4 s down) rather than two rushed
   ones. Every glyph rests at scale(1), so 0 - 10% is a static pose for all four. */
#bentoWrap .cv .a .cg{animation:bCgA 20s var(--ease) infinite both;animation-delay:var(--o)}
#bentoWrap .cv .b .cg{animation:bCgB 20s var(--ease) infinite both;animation-delay:var(--o)}
#bentoWrap .cv .c .cg{animation:bCgC 20s var(--ease) infinite both;animation-delay:var(--o)}
#bentoWrap .cv .d .cg{animation:bCgD 20s var(--ease) infinite both;animation-delay:var(--o)}
@keyframes bCgA{0%{transform:scale(1)} 41%{transform:scale(1)} 43%{transform:scale(1.16)}
  45%{transform:scale(1)} 100%{transform:scale(1)}}
@keyframes bCgB{0%{transform:scale(1)} 14%{transform:scale(1)} 15.6%{transform:scale(1.16)}
  17%{transform:scale(1)} 18.4%{transform:scale(1.16)} 19.8%{transform:scale(1)} 100%{transform:scale(1)}}
@keyframes bCgC{0%{transform:scale(1)} 21.5%{transform:scale(1)} 23.1%{transform:scale(1.16)}
  24.5%{transform:scale(1)} 25.9%{transform:scale(1.16)} 27.3%{transform:scale(1)} 100%{transform:scale(1)}}
@keyframes bCgD{0%{transform:scale(1)} 29%{transform:scale(1)} 30.6%{transform:scale(1.16)}
  32%{transform:scale(1)} 33.4%{transform:scale(1.16)} 34.8%{transform:scale(1)} 100%{transform:scale(1)}}

/* ============================================================
   CARD 4  "The answer it refuses to give" (wide)   20 s, moving 2.0 - 8.8 s
   ------------------------------------------------------------
   Three exchanges on the same 20 s clock, started 0.7 s apart instead of 6 s.
   Six seconds apart meant this card was mid-sentence somewhere for fourteen of
   its eighteen seconds, which on its own broke the page's quiet frame. Now the
   three take their turns inside one 2.4 s cascade and the whole strip then holds
   for eleven seconds. Each exchange's own six beats, from its own start:
     0.00 - 0.18 s  the caller's line clears
     0.18 - 0.54 s  the caller's line lands
     0.64 - 0.90 s  the agent starts thinking (three dots over the answer's slot)
     2.70 - 3.24 s  the dots clear and the refusal is spoken
     3.96 - 4.68 s  the green outcome is stamped underneath
     4.68 - 18.0 s  held, then it clears and the take starts again
   The filled panel takes 52px of width off the wide card, so the wide vignette
   is a flex row at every width: glyph left, the three exchanges right, height
   following the copy. Nothing to clip.
   ============================================================ */
#bentoWrap .v4{height:auto;display:flex;align-items:flex-start;gap:17px;padding:27px 26px 24px}
#bentoWrap .appic{position:static;flex:none;margin:0;width:60px;height:60px;border-radius:17px;background:var(--panel);
  display:grid;place-items:center;will-change:transform;
  box-shadow:0 2px 6px rgba(10,10,11,.06),0 16px 30px rgba(10,10,11,.08)}
#bentoWrap .strip{position:static;flex:1;min-width:0;width:auto;margin:0;
  display:flex;gap:13px;align-items:stretch;
  will-change:transform;opacity:0;transition:opacity .8s var(--ease) .16s}
#bentoWrap .card.in .strip{opacity:1}
/* the lift shadow lives on .ex, which never moves after its reveal; .exi, which
   does move, carries no shadow at all */
#bentoWrap .ex{flex:1;min-width:0;display:flex;border-radius:14px;
  box-shadow:0 5px 15px rgba(10,10,11,.07);
  opacity:0;transform:translateY(12px)}
#bentoWrap .ex:nth-child(1){--i:0}
#bentoWrap .ex:nth-child(2){--i:1}
#bentoWrap .ex:nth-child(3){--i:2}
#bentoWrap .card.in .ex{animation:bExIn .9s var(--ease-pop) calc(.24s + var(--i) * .09s) both}
@keyframes bExIn{from{opacity:0;transform:translateY(12px)}
  55%{opacity:1} to{opacity:1;transform:none}}
#bentoWrap .exi{position:relative;flex:1;min-width:0;background:var(--card-2);border:1px solid var(--line);
  border-radius:14px;padding:12px 13px 11px;display:flex;flex-direction:column;transform:translateY(0)}
/* a POSITIVE i * .7s puts exchange 2 seven tenths of a second behind exchange 1
   and exchange 3 another seven tenths behind that, so the three still take their
   turns in reading order but the whole cascade fits inside the card's one window */
#bentoWrap .exi{animation:bExLift 20s var(--ease) infinite both;animation-delay:calc(var(--i) * .7s + var(--o))}
#bentoWrap .ask{animation:bAsk 20s var(--ease) infinite both;animation-delay:calc(var(--i) * .7s + var(--o))}
#bentoWrap .typ{animation:bTyp 20s var(--ease) infinite both;animation-delay:calc(var(--i) * .7s + var(--o))}
#bentoWrap .say{animation:bSay 20s var(--ease) infinite both;animation-delay:calc(var(--i) * .7s + var(--o))}
#bentoWrap .note{animation:bNote 20s var(--ease) infinite both;animation-delay:calc(var(--i) * .7s + var(--o))}
#bentoWrap .ex .ask{position:relative;margin:0;font-size:12px;line-height:1.4;font-weight:600;color:var(--faint);letter-spacing:0}
#bentoWrap .mid{position:relative;margin-top:7px}
/* the thinking dots sit over the answer's slot, so nothing reflows when they clear */
#bentoWrap .typ{position:absolute;left:0;top:0;display:flex;align-items:center;gap:4px;height:19px;
  padding:0 9px;border-radius:10px;background:#EDEDF1;opacity:0}
/* the thinking indicator actually thinks: three 4.5px dots on one short transform
   loop, staggered, so the beat where the agent is working is alive rather than a
   frozen glyph. They are inside .typ, which is at opacity 0 for the rest of the film. */
#bentoWrap .typ i{width:4.5px;height:4.5px;border-radius:50%;background:#9A9DA6;
  animation:bDot 1.3s var(--ease) infinite both}
#bentoWrap .typ i:nth-child(2){animation-delay:.17s}
#bentoWrap .typ i:nth-child(3){animation-delay:.34s}
@keyframes bDot{0%{transform:translateY(0)} 22%{transform:translateY(-3.5px)}
  46%{transform:translateY(0)} 100%{transform:translateY(0)}}
#bentoWrap .ex .say{position:relative;margin:0;font-size:12.5px;line-height:1.45;font-weight:600;color:var(--ink);letter-spacing:0}
#bentoWrap .ex .note{position:relative;display:block;margin-top:auto;padding-top:9px;font-size:12px;line-height:1.35;
  font-weight:700;color:var(--ink-green)}
/* the panel rides 3px up while its take is being played and settles once the
   outcome has landed; 0% is the settled pose, so a paused card is a settled card */
@keyframes bExLift{
  0%{transform:translateY(0)} 10%{transform:translateY(0)}
  11%{transform:translateY(-3px)} 33.4%{transform:translateY(-3px)}
  37%{transform:translateY(0)} 100%{transform:translateY(0)}}
/* 0% of each of these is the FINISHED exchange, held to 10%, and the take then
   restarts inside 20 ms. So the panel is never a hole in the grid: the caller's
   question is back within 0.6 s, the thinking dots hold the answer's slot while
   it is empty, and the green outcome is the last thing to land. */
@keyframes bAsk{
  0%{opacity:1;transform:none} 10%{opacity:1;transform:none} 10.9%{opacity:0;transform:none}
  11%{opacity:0;transform:translateY(-6px)} 12.7%{opacity:1;transform:none}
  100%{opacity:1;transform:none}}
@keyframes bTyp{
  0%{opacity:0} 13.2%{opacity:0} 14.5%{opacity:1} 23.5%{opacity:1} 26.2%{opacity:0} 100%{opacity:0}}
@keyframes bSay{
  0%{opacity:1;transform:none} 10%{opacity:1;transform:none} 10.9%{opacity:0;transform:none}
  11%{opacity:0;transform:translateY(6px)} 23.5%{opacity:0;transform:translateY(6px)}
  27.1%{opacity:1;transform:none} 100%{opacity:1;transform:none}}
@keyframes bNote{
  0%{opacity:1;transform:none} 10%{opacity:1;transform:none} 10.9%{opacity:0;transform:none}
  11%{opacity:0;transform:translateY(5px)} 29.8%{opacity:0;transform:translateY(5px)}
  33.4%{opacity:1;transform:none} 100%{opacity:1;transform:none}}

/* ============================================================
   CARD 5  "Change the price once"   20 s, moving 2.0 - 7.9 s
   ------------------------------------------------------------
   0.00 - 2.00 s  held at 45 (the still design)
   2.00 - 2.70 s  the button presses itself
   2.00 - 2.60 s  45 rolls up out of the window and 50 rolls in under it
   2.80 - 5.92 s  the change ripples outward through the eight channels, the
                  pair on each side of the hub lighting together, five steps
                  0.5 s apart
   5.92 - 7.00 s  held at the new price
   6.80 - 7.90 s  the button presses again, 50 rolls back to 45
   7.90 - 20.0 s  held at 45, into the 2 s hold at the top
   ============================================================ */
#bentoWrap .orbit{position:absolute;left:50%;top:113px;width:0;height:0;will-change:transform}
#bentoWrap .gv{position:absolute;left:-16px;top:-16px;width:32px;height:32px;opacity:0;
  transform:rotate(var(--a)) translateY(-88px) scale(.45)}
#bentoWrap .card.in .gv{animation:bGvIn .85s var(--ease-pop) var(--dd) both}
@keyframes bGvIn{
  from{opacity:0;transform:rotate(var(--a)) translateY(-88px) scale(.45)}
  55% {opacity:1}
  to  {opacity:1;transform:rotate(var(--a)) translateY(-88px)}}
/* a hairline reads the same at 32px on white as a blurred shadow would, and costs
   nothing when the ring under it counter-rotates every frame */
#bentoWrap .gv > i{position:relative;display:grid;place-items:center;width:100%;height:100%;border-radius:10px;
  background:var(--panel);border:1px solid rgba(10,10,11,.09);box-sizing:border-box;
  transform:rotate(calc(-1 * var(--a)))}
/* the "it knows" ring: one keyframe set, phase-shifted per channel by a positive
   delay, so the ripple leaves the hub and reaches the far side 2.2 s later */
#bentoWrap .lit{position:absolute;inset:-4px;border-radius:13px;border:2px solid var(--live);
  opacity:0;transform:scale(.68);
  animation:bLit 20s var(--ease) infinite both;animation-delay:calc(2.8s + var(--k) * .5s + var(--o))}
/* the ring resets inside the frame it finishes in, so it is a static value for the
   other 18.9 s instead of scaling back down for free under opacity 0 */
@keyframes bLit{
  0%{opacity:0;transform:scale(.68)} 1.4%{opacity:.92;transform:scale(1)}
  5.6%{opacity:0;transform:scale(1.44)} 5.7%{opacity:0;transform:scale(.68)}
  100%{opacity:0;transform:scale(.68)}}
/* the hub rides the ring's parallax through .hubw, so .hub keeps its own pop transform */
#bentoWrap .hubw{position:absolute;left:50%;top:62px;margin-left:-73px;width:146px;height:100px;will-change:transform}
#bentoWrap .hub{position:absolute;inset:0;border-radius:18px;
  background:var(--panel);padding:11px 11px 10px;display:flex;flex-direction:column;align-items:center;
  box-shadow:0 4px 14px rgba(10,10,11,.08),0 18px 36px rgba(10,10,11,.10);
  opacity:0;transform:scale(.7)}
#bentoWrap .card.in .hub{animation:bTileIn .8s var(--ease-pop) .1s both}
#bentoWrap .hlab{font-size:12px;font-weight:600;color:var(--faint);white-space:nowrap}
/* the roll clips at the price window, so 45 and 50 read as one rolling numeral */
#bentoWrap .prices{position:relative;display:block;width:100%;height:34px;margin-top:1px;overflow:hidden}
#bentoWrap .prices b{position:absolute;left:0;right:0;top:0;line-height:34px;text-align:center;font-size:26px;
  font-weight:800;letter-spacing:-.01em}
#bentoWrap .pOld{color:var(--ink);animation:bPOld 20s var(--ease) infinite both;animation-delay:var(--o)}
#bentoWrap .pNew{color:var(--ink-green);opacity:0;animation:bPNew 20s var(--ease) infinite both;animation-delay:var(--o)}
@keyframes bPOld{
  0%{opacity:1;transform:translateY(0)} 10%{opacity:1;transform:translateY(0)}
  13%{opacity:0;transform:translateY(-13px)} 35%{opacity:0;transform:translateY(-13px)}
  35.1%{opacity:0;transform:translateY(13px)} 39.5%{opacity:1;transform:translateY(0)}
  100%{opacity:1;transform:translateY(0)}}
@keyframes bPNew{
  0%{opacity:0;transform:translateY(13px)} 10%{opacity:0;transform:translateY(13px)}
  13%{opacity:1;transform:translateY(0)} 35%{opacity:1;transform:translateY(0)}
  39.5%{opacity:0;transform:translateY(-13px)} 99.9%{opacity:0;transform:translateY(-13px)}
  100%{opacity:0;transform:translateY(13px)}}
/* the button presses itself before each flip: one scale, nothing else */
#bentoWrap .hbtn{position:relative;display:block;width:100%;text-align:center;background:var(--live);color:var(--ink);
  border-radius:100px;padding:6px 6px;font-size:12px;font-weight:700;white-space:nowrap;overflow:hidden;
  animation:bPress 20s var(--ease) infinite both;animation-delay:var(--o)}
#bentoWrap .hbl{position:relative;display:block;font-style:normal;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
@keyframes bPress{
  0%{transform:scale(1)} 10%{transform:scale(1)} 11%{transform:scale(.955)} 13.5%{transform:scale(1)}
  33%{transform:scale(1)} 34%{transform:scale(.955)} 36.5%{transform:scale(1)}
  100%{transform:scale(1)}}

/* ---------- loop gate ----------
   every looping node carries .lp. Loops idle until the BAND is intersecting (JS
   adds .live to all five cards at once), so nothing off-screen burns a frame and
   the five films always resume in the 4 s phase relationship they were cut in.
   These two rules must sit AFTER every `animation:` shorthand above (the
   shorthand resets animation-play-state to running) and must out-specify the
   deepest of them, hence the doubled .lp rather than an importance flag. */
#bentoWrap .card .lp.lp{animation-play-state:paused}
#bentoWrap .card.live .lp.lp{animation-play-state:running}

/* readers who ask for less motion get the still design: every loop's base CSS
   state is the finished frame of its film, so dropping the animation leaves the
   four answered chips, the written receipt, the lit newest row, the three
   complete exchanges and the old price exactly as drawn */
@media (prefers-reduced-motion:reduce){
  #bentoWrap .card .lp.lp{animation:none;will-change:auto}
  #bentoWrap .typ{opacity:0}
}

/* ---------- narrower viewports ----------
   The card, not the viewport, is what the five vignettes are drawn for: every one
   of them is composed for the 380px card the 1180 column gives at three up. So the
   grid drops a column before the card can get much under that, and the vignettes
   stay at their design size inside it rather than being redrawn per breakpoint.
     > 1120   three up, card 340..380
     721-1120 two up,   card 318..540  (the wide card spans both, keeping its layout)
     <= 720   one up,   card 262..656
*/
@media (max-width:1244px){
  #bentoWrap .col{padding:0 32px}
}
@media (max-width:1180px){
  #bentoWrap .ttl{font-size:4.58vw}
  /* `.ttl:lang(en)` out-specifies a bare `.ttl`, so every step down the ladder
     has to restate it or the EN headline stays frozen at its 56px design size
     (which is what it did on a 390px phone: three words at 56px, 4px off the
     gutters). Same rule at 900 and at the phone breakpoint below. */
  #bentoWrap .ttl:lang(en){font-size:4.75vw}
}
@media (max-width:1120px){
  /* dense packing backfills the hole the two-column wide card would otherwise leave:
     visual order becomes 1,2 / 3,5 / wide, DOM order (and so reading order) is untouched */
  #bentoWrap .grid{grid-template-columns:repeat(2,1fr);grid-auto-flow:row dense}
}
@media (max-width:900px){
  #bentoWrap .band{padding:72px 0 68px}
  #bentoWrap .ttl{font-size:38px}
  #bentoWrap .ttl:lang(en){font-size:40px}
}
/* under 800 the three exchanges can no longer hold three lines side by side, so the
   strip stacks under the glyph and each exchange gets the full card width */
@media (max-width:800px){
  #bentoWrap .v4{flex-direction:column;gap:14px;padding:24px 26px 22px}
  #bentoWrap .strip{flex:none;width:100%;flex-direction:column}
  /* once the strip is stacked the glyph is no longer beside anything, so the 60px
     badge sat alone with the whole panel width empty next to it. At 52px, 14px
     above the stack, it reads as the icon over the conversation stack. */
  #bentoWrap .appic{width:52px;height:52px;border-radius:15px}
}
@media (max-width:720px){
  #bentoWrap .grid{grid-template-columns:1fr}
  #bentoWrap .card.wide{grid-column:span 1}
  #bentoWrap .card.wide p{max-width:none}
}
/* ---------- the phone system (<= 600) ----------
   ONE layout system for the whole page on a phone: 20px side gutters, one
   column, one head scale, one card rhythm, one inner padding.

   What does NOT change: the five vignettes. Each keeps its full film (16 / 15 /
   14 / 18 / 14 s), its 221px colour panel and its illustration at the size it
   was composed at. Nothing is restacked into a poorer mobile drawing; the card
   simply becomes the width of the screen and the type steps up to phone reading
   sizes, because the founder's note on the screenshots was that the panels read
   "super duper tight".
*/
@media (max-width:600px){
  #bentoWrap .band{padding:80px 0 76px}
  #bentoWrap .col{padding:0 20px}

  /* head: one scale, 30px KA / 32px EN, sub 15px */
  #bentoWrap .ttl{font-size:30px;line-height:1.1;letter-spacing:-.008em}
  #bentoWrap .ttl:lang(en){font-size:32px;letter-spacing:-.026em}
  #bentoWrap .sub{font-size:15px;line-height:1.55;margin-top:14px;max-width:none}

  /* rhythm: 18px between cards, 32px from the head to the first card */
  #bentoWrap .grid{gap:18px;margin-top:32px}

  /* card: full width, the SAME card radius token as desktop, phone type, room
     around it. 20px gutters and 24px under the copy, so no line sits on an edge.
     The radius is restated rather than inherited: bento is the one card on the
     page that already reads right on a phone, so it is the source of the token. */
  #bentoWrap .card{border-radius:var(--card-r)}
  #bentoWrap .card h3{margin:20px 20px 0;font-size:22px;line-height:1.3}
  #bentoWrap .card p{margin:9px 20px 24px;font-size:15px;line-height:1.6}
  /* the colour panel keeps the DESKTOP 24px radius (not a smaller mobile one)
     and the same 20px gutter as the copy under it */
  #bentoWrap .vig{margin:20px 20px 0;border-radius:24px}

  /* card 1: the chip stack takes the full width of the panel it sits in. At the
     old 12px inset the longest EN label ("A call nobody picked up") ellipsed on
     a 390 phone; 8px of inset plus a 64px badge window (the widest badge word is
     58px) gives it back the ~18px it was short. The 318px cap is the same stack
     the 380px desktop card draws, so at 430 the panel keeps 16px of colour on
     each side of the chips instead of 8, exactly as on desktop. */
  #bentoWrap .stack{left:8px;right:8px;max-width:318px}
  #bentoWrap .bwin{width:64px}
  /* the ghost slot's badge block must be the same window as the chip's, or the
     arriving chip lands 4px short of the shape it was supposed to cover */
  #bentoWrap .slot .sb{width:64px}

  /* card 4: the app glyph was a 60px badge alone at the top-left of a 306px row
     with 240px of dead panel beside it. At 52px, 14px above the stack, it reads
     as the icon over the conversation stack instead of an orphan. The three
     exchanges get phone type (13 / 14 / 13) and 15px of inner padding. */
  #bentoWrap .v4{padding:22px 20px 20px}
  #bentoWrap .strip{gap:14px}
  #bentoWrap .exi{padding:15px 16px 14px}
  #bentoWrap .ex .ask{font-size:13px;line-height:1.42}
  #bentoWrap .ex .say{font-size:14px;line-height:1.5}
  #bentoWrap .ex .note{font-size:13px;line-height:1.38;padding-top:11px}
}

/* ===== audience ===== */
/* ============================================================
   AUDIENCE (Suppo)  "ვისთვის არის Suppo"
   Non-pinned, normal flow, full-bleed band, one-shot stagger reveal
   (header, then ten cards). No loops, no scrub, no pinning.

   Ten category cards, two a row, white on the band. Each card is a
   44px glyph tile beside a name, one problem line and a wrapped row
   of business-type chips (93 in total). Transform / opacity only in
   the reveal; nothing is promoted (the one-shot animation is the only
   motion in the section, so will-change would only cost memory).
   ============================================================ */
#audienceWrap{scroll-margin-top:118px;position:relative;background:var(--band);
  --band-pt:96px;--band-pb:92px;
  --h2-ka:54px;--h2-en:56px;
  --sub-size:16px;--sub-lh:1.55;--sub-max:640px;
  --tile-grey:var(--tile,#F1F1F4);
  --card-r:var(--r-card,32px);
  --chip-r:var(--r-pill,999px);
  --ico-r:var(--r-chrome,16px)}
#audienceWrap .band{padding:var(--band-pt) 0 var(--band-pb)}
#audienceWrap .col{width:100%;max-width:var(--maxw);margin:0 auto;padding:0}

/* ---------- header ---------- */
#audienceWrap .head{text-align:center}
#audienceWrap .auKicker{opacity:0;transform:translateY(12px)}
#audienceWrap .head.in .auKicker{animation:auRise .8s var(--ease) 0s both}
#audienceWrap .ttl{margin-top:16px;font-size:var(--h2-ka);line-height:1.06;letter-spacing:-.012em;color:var(--ink);font-weight:800}
#audienceWrap .ttl:lang(en){font-size:var(--h2-en);letter-spacing:-.032em}
#audienceWrap .ttl .w{display:inline-block}
#audienceWrap .ttl .w > span,
#audienceWrap .ttl .w > em{display:inline-block;opacity:0;transform:translateY(20px)}
#audienceWrap .ttl .w > em.hl{font-style:normal}
#audienceWrap .head.in .ttl .w > span,
#audienceWrap .head.in .ttl .w > em{animation:auRise .95s var(--ease) var(--d) both}
/* the third word is empty in Georgian: no phantom gap before it */
#audienceWrap .ttl .w > span:empty{display:none}
#audienceWrap .sub{font-size:var(--sub-size);line-height:var(--sub-lh);max-width:var(--sub-max);margin:16px auto 0;
  color:var(--muted);font-weight:500;opacity:0;transform:translateY(16px)}
#audienceWrap .head.in .sub{animation:auRise .9s var(--ease) .26s both}
@keyframes auRise{from{opacity:0;transform:translateY(20px)}
  60%{opacity:1} to{opacity:1;transform:none}}

/* ---------- grid ---------- */
#audienceWrap .grid{display:grid;grid-template-columns:repeat(2,1fr);gap:16px;margin-top:44px}
#audienceWrap .card{display:grid;grid-template-columns:44px 1fr;column-gap:18px;align-items:start;
  background:var(--panel);border-radius:var(--card-r);padding:24px 26px 24px 24px;
  box-shadow:var(--shadow-soft);
  opacity:0;transform:translateY(28px)}
#audienceWrap .card.in{animation:auCardIn 1s var(--ease) var(--d) both}
@keyframes auCardIn{from{opacity:0;transform:translateY(28px)}
  60%{opacity:1} to{opacity:1;transform:none}}

#audienceWrap .ico{display:flex;align-items:center;justify-content:center;width:44px;height:44px;
  border-radius:var(--ico-r);background:var(--tile-grey);color:var(--ink)}
#audienceWrap .ico svg{width:22px;height:22px;display:block}

#audienceWrap .body{min-width:0}
#audienceWrap .card h3{margin:0;font-size:20px;line-height:1.2;letter-spacing:-.008em;font-weight:800;color:var(--ink)}
#audienceWrap .card p{margin:6px 0 0;font-size:14px;line-height:1.5;color:var(--muted);font-weight:500;letter-spacing:0;max-width:52ch}

#audienceWrap .chips{list-style:none;margin:14px 0 0;padding:0;display:flex;flex-wrap:wrap;gap:6px}
#audienceWrap .chips li{display:inline-flex;align-items:center;min-height:26px;padding:5px 11px 4px;
  border-radius:var(--chip-r);background:var(--tile-grey);color:var(--ink);
  font-size:12.5px;font-weight:600;line-height:1.25;letter-spacing:0;white-space:nowrap}

@media (prefers-reduced-motion:reduce){
  #audienceWrap .auKicker,
  #audienceWrap .ttl .w > span,
  #audienceWrap .ttl .w > em,
  #audienceWrap .sub,
  #audienceWrap .card,
  #audienceWrap .head.in .auKicker,
  #audienceWrap .head.in .ttl .w > span,
  #audienceWrap .head.in .ttl .w > em,
  #audienceWrap .head.in .sub,
  #audienceWrap .card.in{animation:none;opacity:1;transform:none}
}

/* ---------- narrower viewports ---------- */
@media (max-width:1244px){
  #audienceWrap .col{padding:0 32px}
}
@media (max-width:1180px){
  #audienceWrap .ttl{font-size:4.58vw}
  #audienceWrap .ttl:lang(en){font-size:4.75vw}
}
@media (max-width:900px){
  #audienceWrap .band{padding:72px 0 68px}
  #audienceWrap .ttl{font-size:38px}
  #audienceWrap .ttl:lang(en){font-size:40px}
}
@media (max-width:720px){
  #audienceWrap .grid{grid-template-columns:1fr;gap:14px;margin-top:36px}
}
/* ---------- the phone system (<= 600): 20px gutters, 30/32 H2, sub 15 ---------- */
@media (max-width:600px){
  #audienceWrap .band{padding:80px 0 76px}
  #audienceWrap .col{padding:0 20px}
  #audienceWrap .ttl{font-size:30px;line-height:1.1;letter-spacing:-.008em}
  #audienceWrap .ttl:lang(en){font-size:32px;letter-spacing:-.026em}
  #audienceWrap .sub{font-size:15px;margin-top:14px}
  #audienceWrap .card{grid-template-columns:40px 1fr;column-gap:14px;padding:20px 20px 20px 18px;border-radius:24px}
  #audienceWrap .ico{width:40px;height:40px;border-radius:14px}
  #audienceWrap .ico svg{width:20px;height:20px}
  #audienceWrap .card h3{font-size:18px}
  #audienceWrap .card p{font-size:13.5px}
  /* on a phone the chips take the full card width under the glyph row:
     .body becomes display:contents so its three children are grid items */
  #audienceWrap .card{grid-template-areas:"ico name" "ico prob" "chips chips";grid-template-rows:auto auto auto}
  #audienceWrap .ico{grid-area:ico;align-self:start}
  #audienceWrap .body{display:contents}
  #audienceWrap .card h3{grid-area:name}
  #audienceWrap .card p{grid-area:prob}
  #audienceWrap .chips{grid-area:chips;margin-top:14px}
}

/* ===== integrations ===== */
/* SUPPO / INTEGRATIONS: the wall
   Round 3 (founder, 2026-09-06): "the fan carousel is too weird, I prefer to
   show many options". The pinned arc deck is gone. What stays is the panel's
   white card on the aurora band, the caps headline and the design system; what
   replaces the deck is a category filter row and a responsive grid of logo
   tiles, one tile per system Suppo can plug into, plus one closing card for
   "any system with an API".

   FLOW section: no pin, no scrub. One-shot reveals (MOTION.reveal) on the head,
   the chips and the tiles, transform + opacity only. The aurora mesh behind the
   panel is the round 2 build untouched (three transform-only layers, paused off
   screen from section.js).

   Grid: 12 tiles a row at 1440 (panel 1180, 40px inner gutter, 10px gap, so a
   tile is 82.5px), 8 at tablet, 3 on a phone. The closing card spans five
   columns at desktop and a full row on a phone. With "all" selected the section
   is ~1010px tall at 1440 (43 tiles + card = 48 cells = 4 rows). On a phone the
   wall opens collapsed to three rows and a "show all" expander, so the beat does
   not become 1700px of scrolling before the demo. */

#integrationsWrap{
  position:relative;
  background:var(--band);
  padding:96px 0 92px;                 /* the page band rhythm */
  isolation:isolate;
  /* the static saturation at the walls (the two blobs the mesh no longer
     carries), the three drifting layers ride on top of it */
  background-image:
    radial-gradient(46% 66% at -6% 30%,rgba(93,255,195,.26) 0%,rgba(93,255,195,.13) 40%,rgba(93,255,195,.04) 68%,rgba(93,255,195,0) 90%),
    radial-gradient(46% 64% at 106% 26%,rgba(62,197,255,.26) 0%,rgba(62,197,255,.13) 40%,rgba(62,197,255,.04) 68%,rgba(62,197,255,0) 90%),
    radial-gradient(54% 58% at 46% 118%,rgba(138,124,255,.22) 0%,rgba(138,124,255,.11) 40%,rgba(138,124,255,.04) 68%,rgba(138,124,255,0) 90%);
}

/* ---- aurora mesh ground (round 2, unchanged) ---------------------------- */
#integrationsWrap .ig-mesh{
  position:absolute;inset:0;
  overflow:hidden;pointer-events:none;contain:strict;
  z-index:0;
}
#integrationsWrap .ig-mesh i{
  position:absolute;display:block;
  background:radial-gradient(closest-side ellipse at 50% 50%,
    rgba(var(--c),.92) 0%,rgba(var(--c),.80) 16%,rgba(var(--c),.60) 33%,
    rgba(var(--c),.38) 50%,rgba(var(--c),.20) 66%,rgba(var(--c),.08) 82%,
    rgba(var(--c),0) 100%);
  opacity:.34;
  transform:translateZ(0);backface-visibility:hidden;will-change:transform;
  animation:igMeshA var(--dur,11s) ease-in-out var(--del,0s) infinite alternate;
  animation-play-state:paused;
}
#integrationsWrap.ig-awake .ig-mesh i{animation-play-state:running}
#integrationsWrap .ig-mesh i:nth-child(1){--c:93,255,195;left:-14vw;top:-8vh;width:88vw;height:104vh;--dur:12s;--del:-3s;animation-name:igMeshC}
#integrationsWrap .ig-mesh i:nth-child(2){--c:62,197,255;left:22vw;top:-6vh;width:77vw;height:100vh;--dur:15s;--del:-9s;animation-name:igMeshB}
#integrationsWrap .ig-mesh i:nth-child(3){--c:138,124,255;left:8vw;bottom:-10vh;width:82vw;height:100vh;--dur:13s;--del:-5s}
@keyframes igMeshA{
  0%  {transform:translate3d(0,0,0)}
  30% {transform:translate3d(8vw,6vh,0)}
  62% {transform:translate3d(-5vw,12vh,0)}
  100%{transform:translate3d(4vw,-6vh,0)}
}
@keyframes igMeshC{
  0%  {transform:translate3d(0,0,0)}
  30% {transform:translate3d(8vw,6vh,0)}
  62% {transform:translate3d(3vw,12vh,0)}
  100%{transform:translate3d(6vw,-6vh,0)}
}
@keyframes igMeshB{
  0%  {transform:translate3d(0,0,0)}
  30% {transform:translate3d(-8vw,7vh,0)}
  62% {transform:translate3d(-2vw,-6vh,0)}
  100%{transform:translate3d(-10vw,10vh,0)}
}
#integrationsWrap .ig-mesh-clear{
  position:absolute;inset:0;z-index:1;pointer-events:none;
  background:
    linear-gradient(var(--band) 0%,rgba(243,243,245,.62) 6%,rgba(243,243,245,0) 17%,
                    rgba(243,243,245,0) 83%,rgba(243,243,245,.62) 94%,var(--band) 100%);
}
@media (min-width:761px) and (max-width:1100px){
  #integrationsWrap .ig-mesh i{opacity:.5}
}

/* ---- the panel ---------------------------------------------------------- */
#integrationsWrap .ig-stage{
  position:relative;z-index:1;
  width:100%;
  padding:0 20px;
  display:flex;justify-content:center;
}
#integrationsWrap .ig-panel{
  position:relative;
  width:100%;max-width:var(--maxw);   /* 1180px = one content column */
  padding:48px 40px 40px;
  background:var(--panel);
  border-radius:var(--r-card);
  box-shadow:var(--shadow-soft);
}

/* ---- head --------------------------------------------------------------- */
#integrationsWrap .ig-head{
  text-align:center;
  display:flex;flex-direction:column;align-items:center;gap:18px;
}
#integrationsWrap .ig-h2{
  font-size:56px;                     /* the shared H2 scale, EN */
  font-weight:800;
  letter-spacing:-.03em;
  line-height:1.08;
  color:var(--ink);
}
#integrationsWrap .ig-ln{display:block}
/* Georgian sets one step smaller and looser; Mtavruli caps come from the
   OpenType `case` feature, never text-transform */
#integrationsWrap .ig-h2:lang(ka){font-size:54px;letter-spacing:-.012em}
#integrationsWrap .ig-h2:lang(ka) .ig-w{font-feature-settings:"case" 1}
#integrationsWrap .ig-w{display:inline-block;white-space:nowrap}
/* the aurora accent on the second sentence, as the approved copy marks it: the
   shared em.hl paints the gradient, the words clip it */
#integrationsWrap .ig-h2 em.hl{font-style:normal;background-image:none;background-color:transparent;color:inherit}
#integrationsWrap .ig-h2 em.hl .ig-w{
  background-image:var(--grad);
  background-size:520px 100%;
  background-repeat:no-repeat;
  background-color:#1177A8;
  -webkit-background-clip:text;
  background-clip:text;
  color:transparent;
}

/* ---- filter row --------------------------------------------------------- */
#integrationsWrap .ig-filters{
  display:flex;flex-wrap:wrap;justify-content:center;gap:8px;
  margin:34px auto 28px;
  max-width:980px;
}
#integrationsWrap .ig-chip{
  display:inline-flex;align-items:center;gap:8px;
  min-height:38px;padding:9px 14px 8px;
  border:0;border-radius:var(--r-pill);
  background:var(--tile);
  color:var(--ink);
  font-family:inherit;font-size:13.5px;font-weight:700;line-height:1.1;
  letter-spacing:-.005em;white-space:nowrap;cursor:pointer;
  transition:background var(--t-fast) ease,color var(--t-fast) ease;
}
#integrationsWrap .ig-chip:hover{background:var(--tile-deep)}
#integrationsWrap .ig-chip[aria-selected="true"]{background:var(--ink);color:#fff}
#integrationsWrap .ig-chip:focus-visible{outline:2px solid var(--ink);outline-offset:3px}
#integrationsWrap .ig-chip-n{
  font-size:12px;font-weight:700;line-height:1;
  color:var(--muted-2);
  min-width:22px;padding:5px 6px 4px;border-radius:var(--r-pill);
  background:rgba(10,10,11,.06);
  text-align:center;
  font-variant-numeric:tabular-nums;
}
#integrationsWrap .ig-chip[aria-selected="true"] .ig-chip-n{color:#fff;background:rgba(255,255,255,.16)}

/* ---- the wall ----------------------------------------------------------- */
#integrationsWrap .ig-wall{
  display:grid;
  grid-template-columns:repeat(12,minmax(0,1fr));
  gap:10px;
}
#integrationsWrap .ig-cell[hidden]{display:none}
#integrationsWrap .ig-cell--api{grid-column:span 5}
#integrationsWrap .ig-tile{
  position:relative;
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;
  height:104px;padding:12px 6px 10px;
  border-radius:var(--r-chrome);
  background:var(--tile);
  color:var(--ink);                    /* the mono marks draw in currentColor */
  cursor:default;
  transition:background var(--t-fast) ease,color var(--t-fast) ease;
}
#integrationsWrap .ig-markbox{
  display:grid;place-items:center;
  width:54px;height:32px;flex:none;
}
#integrationsWrap .ig-mark{width:30px;height:30px}
#integrationsWrap .ig-mark--wide{width:54px;height:24px}
#integrationsWrap .ig-name{
  font-size:12px;font-weight:700;line-height:1.15;
  letter-spacing:-.01em;
  text-align:center;
  color:var(--ink);
  max-width:100%;
}
/* the green state, as the centre tile of the deck had it: flat brand green,
   white mark, ink-on-green name (white 12px text on the green fails contrast) */
#integrationsWrap .ig-tile:hover,
#integrationsWrap .ig-tile.is-on{
  background:var(--live);
  color:#fff;
  box-shadow:0 1px 2px rgba(10,10,11,.06),0 12px 26px -10px rgba(0,194,103,.5);
}
#integrationsWrap .ig-tile:hover .ig-mark path,
#integrationsWrap .ig-tile.is-on .ig-mark path{fill:#fff}
#integrationsWrap .ig-tile:hover .ig-name,
#integrationsWrap .ig-tile.is-on .ig-name{color:var(--accent-ink)}

/* ---- closing card: any system with an API -------------------------------- */
#integrationsWrap .ig-api{
  display:flex;flex-direction:column;justify-content:center;gap:6px;
  height:104px;padding:14px 20px 12px;
  border-radius:var(--r-chrome);
  background:var(--ink);
  color:#fff;
  text-decoration:none;
  position:relative;overflow:hidden;
  transition:background var(--t-fast) ease;
}
#integrationsWrap .ig-api:hover{background:var(--ink-hover,#1C1C1F)}
#integrationsWrap .ig-api:focus-visible{outline:2px solid var(--ink);outline-offset:3px}
#integrationsWrap .ig-api-glyph{
  position:absolute;right:16px;top:14px;
  width:34px;height:34px;display:grid;place-items:center;
  border-radius:var(--r-pill);
  background:var(--live);color:var(--accent-ink);
}
#integrationsWrap .ig-api-glyph svg{width:18px;height:18px}
#integrationsWrap .ig-api-t{
  font-size:15px;font-weight:700;line-height:1.2;letter-spacing:-.01em;
  padding-right:48px;
}
#integrationsWrap .ig-api-x{
  font-size:12.5px;font-weight:500;line-height:1.35;
  color:rgba(255,255,255,.72);
  padding-right:48px;
}
#integrationsWrap .ig-api-cta{
  display:inline-flex;align-items:center;gap:6px;
  margin-top:2px;
  font-size:12.5px;font-weight:700;line-height:1;
  color:var(--mint,#7CF5B6);
}
#integrationsWrap .ig-api-cta svg{width:14px;height:14px;transition:transform var(--t-fast) ease}
#integrationsWrap .ig-api:hover .ig-api-cta svg{transform:translateX(3px)}

/* ---- "show all" expander (phone only) ---------------------------------- */
#integrationsWrap .ig-more{display:none}

/* ---- one-shot reveals (transform + opacity only) ------------------------- */
#integrationsWrap .ig-eyebrow,
#integrationsWrap .ig-ln,
#integrationsWrap .ig-chip,
#integrationsWrap .ig-cell{opacity:0}
#integrationsWrap .ig-panel.in .ig-eyebrow{animation:igRise .8s var(--ease) 0s both}
#integrationsWrap .ig-panel.in .ig-ln{animation:igRise .9s var(--ease) .06s both}
#integrationsWrap .ig-panel.in .ig-ln + .ig-ln{animation-delay:.14s}
#integrationsWrap .ig-panel.in .ig-chip{animation:igRise .7s var(--ease) calc(.22s + var(--d,0s)) both}
#integrationsWrap .ig-panel.in .ig-cell{animation:igRise .7s var(--ease) calc(.3s + var(--d,0s)) both}
/* a filter change replays a shorter rise on the cells left standing */
#integrationsWrap .ig-panel.in .ig-wall.is-swap .ig-cell{animation:igPop .45s var(--ease) var(--d,0s) both}
@keyframes igRise{
  from{opacity:0;transform:translate3d(0,16px,0)}
  to  {opacity:1;transform:translate3d(0,0,0)}
}
@keyframes igPop{
  from{opacity:0;transform:translate3d(0,8px,0) scale(.97)}
  to  {opacity:1;transform:translate3d(0,0,0) scale(1)}
}
@media (prefers-reduced-motion:reduce){
  #integrationsWrap .ig-eyebrow,
  #integrationsWrap .ig-ln,
  #integrationsWrap .ig-chip,
  #integrationsWrap .ig-cell{opacity:1;animation:none}
  #integrationsWrap .ig-panel.in .ig-eyebrow,
  #integrationsWrap .ig-panel.in .ig-ln,
  #integrationsWrap .ig-panel.in .ig-chip,
  #integrationsWrap .ig-panel.in .ig-cell,
  #integrationsWrap .ig-panel.in .ig-wall.is-swap .ig-cell{animation:none}
  #integrationsWrap .ig-mesh i{animation:none}
}

/* ---- tablet --------------------------------------------------------------- */
@media (max-width:1100px){
  #integrationsWrap .ig-panel{padding:40px 28px 28px}
  #integrationsWrap .ig-h2{font-size:44px}
  #integrationsWrap .ig-h2:lang(ka){font-size:42px}
  #integrationsWrap .ig-wall{grid-template-columns:repeat(8,minmax(0,1fr))}
  #integrationsWrap .ig-cell--api{grid-column:span 4}
}

/* ---- phone ---------------------------------------------------------------- */
@media (max-width:760px){
  #integrationsWrap{padding:72px 0 64px}
  #integrationsWrap .ig-panel{padding:32px 20px 20px;border-radius:var(--r-inner)}
  #integrationsWrap .ig-head{gap:14px}
  #integrationsWrap .ig-h2{font-size:30px;line-height:1.15}
  #integrationsWrap .ig-h2:lang(ka){font-size:28px}
  /* the chips wrap to centred rows (a scroll strip would hide half the
     categories on a phone, and the wall is the thing to scroll) */
  #integrationsWrap .ig-filters{margin:24px 0 20px;gap:6px}
  #integrationsWrap .ig-chip{min-height:36px;padding:8px 12px 7px;font-size:13px}
  #integrationsWrap .ig-wall{grid-template-columns:repeat(3,minmax(0,1fr));gap:8px}
  #integrationsWrap .ig-cell--api{grid-column:1 / -1}
  #integrationsWrap .ig-tile{height:100px}
  #integrationsWrap .ig-name{font-size:12px}
  #integrationsWrap .ig-api{height:auto;min-height:104px}
  /* collapsed: three rows of tiles, the API card stays; everything else waits
     behind the expander */
  #integrationsWrap .ig-wall.is-collapsed .ig-cell:not(.ig-cell--api):nth-child(n+10){display:none}
  #integrationsWrap .ig-more{
    display:inline-flex;align-items:center;justify-content:center;gap:8px;
    width:100%;margin-top:12px;min-height:44px;padding:13px 18px 11px;
    border:1px solid var(--line-strong);border-radius:var(--r-pill);
    background:var(--paper);color:var(--ink);
    font-family:inherit;font-size:14px;font-weight:700;line-height:1.1;cursor:pointer;
  }
  #integrationsWrap .ig-more svg{width:16px;height:16px}
  #integrationsWrap .ig-more-n{color:var(--muted-2);font-variant-numeric:tabular-nums}
  #integrationsWrap .ig-more[aria-expanded="true"],
  #integrationsWrap .ig-more.is-hidden{display:none}
  #integrationsWrap .ig-mesh i{opacity:.45}
}

#integrationsWrap .ig-tag{position:absolute;top:8px;right:8px;font-size:10px;line-height:1;letter-spacing:.04em;text-transform:uppercase;padding:4px 6px;border-radius:4px;color:var(--ink-2,#666);background:rgba(0,0,0,.06)}
#integrationsWrap .ig-tag--live{color:var(--accent-ink,#062);background:var(--live,#5DFFC3)}

/* ===== demo ===== */
/* ============================================================================
   SUPPO / DEMO   "მოისმინეთ თქვენი მომავალი თანამშრომელი"
   Pinned section. The live call widget of suppo.ge, opened out of its floating
   panel and given the centre of a screen.

   ROUND 5 VISUAL PASS (2026-09-05). The founder's note was "this section is not
   sexy at all, but we need it for sure". Nothing about the call behaviour moved;
   every id, hook and handler in section.js is untouched. What changed is the
   composition:

     the panel   flat #1C1C1F -> a graded #232328 to #1B1B1F with a radial light
                 sitting exactly where the orb sits, a 1px rgba(255,255,255,.07)
                 line and radius 32. Softness is baked into gradient STOPS: there
                 is not one filter or backdrop-filter in this file.
     the orb     the conversations .cv-orb recipe (four radial blobs + a grain
                 tile) grown to the size of a face, given a rim/specular/floor
                 built out of three radial gradients instead of inset shadows
                 (the orb is transform-scaled by the live voice, and a shadow on
                 a per-frame transformed layer is the one thing that costs), a
                 soft halo, and two thin orbit rings each carrying one small
                 travelling light.
     the pane    three grey placeholder bars -> a real conversation: four turns
                 as bubbles (customer left, Suppo right, time stamps) and the
                 handover chip, arriving on a 17s loop while the line is idle and
                 replaced wholesale by the live transcript the moment a real call
                 writes its first row.
     the input   a proper pill: one rounded well holding a transparent field and
                 the green send button.
     the numbers one strip along the foot of the panel, the eyebrow at its head,
                 aurora numerals, hairline dividers.

   Three nested boxes still carry the three transforms that would otherwise fight:
     .dmOrbBox     scroll-scrubbed entrance (written inline by section.js)
     .dmOrbBreath  the idle breath keyframe, paused off screen and while speaking
     .dmOrb        the --amp voice swell, exactly as the live widget does it

   Every loop in this file is a transform/opacity keyframe animation and every
   one of them is paused by `#demoWrap:not(.is-vis)`, the class an
   IntersectionObserver in section.js writes, and again under
   prefers-reduced-motion.
   ========================================================================= */

#demoWrap{
  position:relative;
  /* 0.7 pinned screens of travel. PACING PASS 2026-09-05: this was 200vh, and
     the choreography spent only its first third, so 500px of the pin was a frame
     that did not move at all (tools/audit.py called it a dead zone in demoWrap).
     A button screen still needs a hold, but a hold is 150px of stillness, not
     500: the enter now starts before the pin (negative progress, so the card is
     already composed when it arrives), the hold is about 160px, and the last
     40% is a continuous lift out. */
  height:170vh;
  background:var(--band);
  /* live-chrome.css gives every section[id] a 96px scroll-margin, which for a
     PINNED section lands the anchor 96px BEFORE the pin engages: the visitor
     arrives on the tail of the previous band and has to scroll again to reach
     p=0. The band's 96px is not a scroll offset, it is padding, so it moves
     into the pin below and the anchor lands exactly on the composed pose. */
  scroll-margin-top:0;
}
/* The band's own rhythm, 96 over / 92 under, carried by the pinned frame. It is
   a clamp and not a flat pair because this band is 100vh tall by construction:
   on a 813px laptop frame a flat 96 pushes the numbers strip off the bottom of
   the pin, which is the one thing the strip cannot survive. */
#demoWrap .pin{overflow:hidden;align-items:start;padding:clamp(70px,9.2vh,96px) 0 clamp(66px,8.8vh,92px)}

#demoWrap .dmStage{
  width:min(var(--maxw),calc(100% - 64px));
  margin:0 auto;
  display:flex;flex-direction:column;align-items:center;
}

/* ---------- the two page primitives this section consumes -------------------
   The section used to carry four private copies of the outlined pill (four
   paddings, four trackings, three fill alphas) and two of the label eyebrow,
   500px apart in the same panel. Both are shared components in live-chrome.css
   now: .eyebrow (12/700/.14em, --muted-2, a 6px --live dot as its ::before) and
   .tag / .tag--onDark (12/600, pill radius, 3px 9px, rgba fill and hairline).
   The markup wears the classes; the only thing left here is the one value the
   component cannot know, which is that ONE of the two eyebrows stands on the
   ink panel, where the component's paper-grey ink would measure 3.0:1. */
#demoWrap .dmCard .eyebrow{color:#9A9AA4}

/* ---------- head ---------- */
#demoWrap .dmHead{text-align:center;will-change:transform,opacity}
#demoWrap .dmHead h2{
  margin-top:clamp(5px,.9vh,10px);font-size:clamp(32px,3.7vw,56px);line-height:1.07;letter-spacing:-.03em;color:var(--ink);
}
#demoWrap .dmHead h2:lang(ka){font-size:clamp(30px,3.6vw,54px);letter-spacing:-.012em}
/* one keyframe rather than an opacity transition plus a transform transition:
   same slide-up, one animation object per word instead of two */
@keyframes dmRise{from{opacity:0;transform:translateY(var(--rise,20px))}to{opacity:1;transform:none}}
#demoWrap .dmWord{
  display:inline-block;opacity:0;transform:translateY(20px);
}
#demoWrap .dmHead.in .dmWord{animation:dmRise .82s var(--ease) var(--d) both}
#demoWrap .dmSub{
  --rise:14px;
  margin:clamp(5px,.9vh,10px) auto 0;max-width:640px;font-size:16px;line-height:1.55;font-weight:500;color:var(--muted);
  opacity:0;transform:translateY(14px);text-wrap:balance;
}
#demoWrap .dmHead.in .dmSub{animation:dmRise .8s var(--ease) .3s both}

/* ---------- the dark console card ------------------------------------------
   Three layers, all gradients, no filter: the green light that the orb throws
   onto the panel, a cooler counter-light in the far corner, and the graded ink
   body the brief asks for (#232328 down to #1B1B1F). */
#demoWrap .dmCard{
  width:100%;margin-top:clamp(10px,1.6vh,20px);
  color:#fff;
  background:
    radial-gradient(62% 108% at 16% 104%,rgba(0,210,106,.20) 0%,rgba(0,194,103,.07) 38%,rgba(0,194,103,0) 72%),
    radial-gradient(54% 92% at 92% 104%,rgba(31,168,232,.14) 0%,rgba(31,168,232,.04) 40%,rgba(31,168,232,0) 70%),
    linear-gradient(158deg,#232328 0%,#202025 46%,#1B1B1F 100%);
  border:1px solid rgba(255,255,255,.07);
  border-radius:var(--r-card,32px);padding:clamp(12px,1.7vh,18px) clamp(15px,1.5vw,21px) clamp(11px,1.5vh,15px);
  /* was the page's one hand-written shadow, a third stronger than --shadow-lift
     because a dark card on a light band needs more separation than a white one.
     That is a token, not a local decision, so it is consumed as one. */
  box-shadow:var(--shadow-dark,0 40px 80px rgba(10,10,11,.16),0 8px 20px rgba(10,10,11,.08));
  will-change:transform;
}
/* The orb column carries the section: it is the face of the line and the
   thing the brief puts centre stage, so it takes a full third rather than a
   sidebar's width, and the transcript stops being a wide empty plain. */
#demoWrap .dmCols{display:grid;grid-template-columns:minmax(0,clamp(286px,26vw,376px)) minmax(0,1fr);gap:clamp(16px,1.6vw,24px);align-items:stretch}

/* ---------- console column ---------- */
#demoWrap .dmConsole{
  position:relative;
  display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;
  background:
    radial-gradient(78% 50% at 50% 40%,rgba(0,210,106,.10) 0%,rgba(31,168,232,.04) 46%,rgba(31,168,232,0) 78%),
    linear-gradient(180deg,rgba(255,255,255,.06) 0%,rgba(255,255,255,.014) 58%,rgba(255,255,255,0) 100%),
    linear-gradient(180deg,#26262D 0%,#1E1E24 100%);
  border:1px solid rgba(255,255,255,.07);
  border-radius:var(--r-inner,24px);padding:clamp(11px,1.5vh,15px) 16px clamp(12px,1.7vh,16px);
}
/* the pill itself is .tag .tag--onDark; only the stacking is the badge's own */
#demoWrap .dmBadge{position:relative;z-index:2}

/* ---------- the orb, its halo and its two orbit rings ---------------------- */
#demoWrap .dmOrbBox{
  --ob:clamp(126px,19vh,184px);
  position:relative;width:var(--ob);height:var(--ob);flex:none;
  margin:clamp(18px,2.7vh,28px) 0 clamp(14px,2.1vh,22px);
  will-change:transform;
}
/* the light the orb throws: five stops, so the falloff is smooth without a blur */
#demoWrap .dmHalo{
  position:absolute;inset:-64%;border-radius:50%;pointer-events:none;display:block;
  background:radial-gradient(circle closest-side,
    rgba(0,210,106,.52) 0%,rgba(0,210,106,.33) 30%,rgba(31,168,232,.20) 52%,
    rgba(31,168,232,.08) 74%,rgba(31,168,232,0) 100%);
  animation:dmHalo 9.5s var(--ease) infinite alternate;
  /* the halo is the largest painted box in the section and it scales, so it gets
     its own layer rather than a re-raster of a 350px gradient every frame */
  will-change:transform;
}
@keyframes dmHalo{from{opacity:.72;transform:scale(.94)}to{opacity:1;transform:scale(1.06)}}

/* Two hairline orbits. The ring itself is a uniform 1px circle, so the thing
   the eye follows is the small light riding it: one long slow pass each way. */
#demoWrap .dmRing{
  position:absolute;border-radius:50%;pointer-events:none;display:block;
  will-change:transform;
}
#demoWrap .dmRing::after{
  content:"";position:absolute;top:-3.5px;left:50%;width:7px;height:7px;margin-left:-3.5px;
  border-radius:50%;
}
#demoWrap .dmRing1{
  inset:-12%;border:1px solid rgba(255,255,255,.15);
  animation:dmSpin 26s linear infinite;
}
#demoWrap .dmRing1::after{background:radial-gradient(circle,#EFFFF6 0%,#00D26A 55%,rgba(0,210,106,0) 100%)}
#demoWrap .dmRing2{
  inset:-26%;border:1px solid rgba(255,255,255,.085);
  animation:dmSpin 42s linear infinite reverse;
}
#demoWrap .dmRing2::after{
  width:6px;height:6px;margin-left:-3px;top:-3px;
  background:radial-gradient(circle,#DFF3FF 0%,#1FA8E8 55%,rgba(31,168,232,0) 100%);
}
@keyframes dmSpin{from{transform:rotate(0deg)}to{transform:rotate(360deg)}}

#demoWrap .dmOrbBreath{position:absolute;inset:0;animation:dmBreathe 5.6s var(--ease) infinite alternate;will-change:transform}

#demoWrap .dmOrb{
  --amp:0;--gain:.1;
  position:absolute;inset:0;border-radius:999px;overflow:hidden;
  background:linear-gradient(125deg,#7ED6A4 8%,#9CD9FF 92%);
  transform:scale(calc(1 + var(--amp) * var(--gain))) translateZ(0);
  transition:transform 110ms linear,opacity .14s var(--ease);
}
#demoWrap .dmB{position:absolute;inset:-28%;border-radius:999px;display:block;will-change:transform}
#demoWrap .dmB1{background:radial-gradient(closest-side at 36% 56%,#2FBF6C 0%,#2FBF6C 26%,rgba(47,191,108,0) 68%);
  animation:dmDrift1 11s var(--ease) infinite alternate}
#demoWrap .dmB2{background:radial-gradient(closest-side at 74% 44%,#52C6FF 0%,rgba(82,198,255,0) 62%);
  animation:dmDrift2 9s var(--ease) infinite alternate;animation-delay:-3s}
#demoWrap .dmB3{background:radial-gradient(closest-side at 70% 84%,#2E6BE6 0%,rgba(46,107,230,0) 58%);
  animation:dmDrift3 13s var(--ease) infinite alternate;animation-delay:-7s}
#demoWrap .dmB4{background:radial-gradient(closest-side at 78% 28%,#EFFFF6 0%,rgba(239,255,246,0) 52%);
  animation:dmDrift2 8s var(--ease) infinite alternate;animation-delay:-5s}
#demoWrap .dmGrain{
  position:absolute;inset:0;pointer-events:none;mix-blend-mode:soft-light;opacity:.6;display:block;
  background-image:url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='.55'/%3E%3C/svg%3E");
  background-size:140px;
}
/* Volume. The conversations orb buys this with four inset box-shadows; this one
   is scaled every frame by the live speaker level, so the same specular, floor
   and rim are three radial gradients instead: same read, nothing to repaint. */
#demoWrap .dmRim{
  position:absolute;inset:0;border-radius:999px;pointer-events:none;display:block;
  background:
    radial-gradient(circle closest-side,rgba(255,255,255,0) 74%,rgba(255,255,255,.08) 88%,rgba(255,255,255,.42) 98%,rgba(255,255,255,.60) 100%),
    radial-gradient(66% 52% at 26% 12%,rgba(255,255,255,.40) 0%,rgba(255,255,255,.10) 28%,rgba(255,255,255,0) 56%),
    radial-gradient(116% 88% at 66% 112%,rgba(0,66,46,.46) 0%,rgba(0,66,46,.16) 36%,rgba(0,66,46,0) 64%);
}
@keyframes dmDrift1{from{transform:translate3d(-7%,4%,0)}to{transform:translate3d(9%,-6%,0)}}
@keyframes dmDrift2{from{transform:translate3d(6%,-5%,0)}to{transform:translate3d(-8%,7%,0)}}
@keyframes dmDrift3{from{transform:translate3d(4%,7%,0)}to{transform:translate3d(-6%,-8%,0)}}
@keyframes dmBreathe{from{transform:scale(.985)}to{transform:scale(1.015)}}
@keyframes dmRing{0%{opacity:.8;transform:scale(.82)}75%,100%{opacity:0;transform:scale(1.04)}}

/* Idle: the line is not open yet, so the weather is quiet, desaturated and slow.
   The live widget sits on white and can afford opacity .68; here the card is
   #232328, where the same value reads as switched off rather than resting, so
   the alpha is lifted and the desaturation does the quieting. */
/* PERF 2026-09-05: the quieting used to be filter:saturate(). The orb is
   transformed every frame (--amp, and the inline blob matrix while speaking),
   and a filter on a transformed layer is re-run on every one of those frames,
   so the state colour is carried by blob opacity instead: the pastel base
   gradient shows through and reads the same, at zero filter cost. */
#demoWrap .dmOrb.is-idle{opacity:1}
#demoWrap .dmOrb.is-idle .dmB{animation-duration:18s;opacity:.88}
/* Ended: the line closed. Held for a beat, dimmer than idle, then it settles
   back to idle on its own so the section never looks switched off. */
#demoWrap .dmOrb.is-ended{opacity:.68}
#demoWrap .dmOrb.is-ended .dmB{animation-duration:22s;opacity:.36}
/* Connecting: a soft ring reaches out while the handshake runs. */
#demoWrap .dmOrb.is-connecting::after{
  content:"";position:absolute;inset:0;border-radius:999px;
  border:2px solid rgba(255,255,255,.75);animation:dmRing 1.5s var(--ease) infinite;
}
/* Thinking: the weather speeds up while it decides what to say. */
#demoWrap .dmOrb.is-thinking .dmB1{animation-duration:3.2s}
#demoWrap .dmOrb.is-thinking .dmB2{animation-duration:2.6s}
#demoWrap .dmOrb.is-thinking .dmB3{animation-duration:3.8s}
#demoWrap .dmOrb.is-thinking .dmB4{animation-duration:2.9s}
/* Speaking: --amp is the real speaker level and section.js moves the blobs inline
   every frame, so the keyframes must be off here or they win over the inline
   transforms. The idle breath stops too: the voice is the only motion left. */
/* the voice used to lift saturate()+brightness() every frame; the same lift is
   now the white blob coming up on opacity, which the compositor does for free */
#demoWrap .dmOrb.is-speaking{--gain:.14}
#demoWrap .dmOrb.is-speaking .dmB4{opacity:calc(.55 + var(--amp) * .45)}
#demoWrap .dmOrb.is-speaking .dmB{animation:none;transition:none}
#demoWrap.is-voiced .dmOrbBreath{animation-play-state:paused}
/* loops never run off screen */
#demoWrap:not(.is-vis) .dmB,
#demoWrap:not(.is-vis) .dmOrbBreath,
#demoWrap:not(.is-vis) .dmHalo,
#demoWrap:not(.is-vis) .dmRing,
#demoWrap:not(.is-vis) .dmOrb.is-connecting::after,
#demoWrap:not(.is-vis) .dmTurn,
#demoWrap:not(.is-vis) .dmEmpty{animation-play-state:paused}

/* the call's own state dot, at the page's one dot size */
#demoWrap .dmState::before{
  content:"";width:6px;height:6px;border-radius:var(--r-pill);background:var(--live);flex:none;display:block;
}
/* one slot, one control: the pill while the line is closed and the way out in
   its exact place while it is open, so nothing under it moves on a state change */
#demoWrap .dmAct{
  display:flex;align-items:center;justify-content:center;
  min-height:50px;margin-top:clamp(8px,1.1vh,13px);
}
#demoWrap .dmCall{
  font-size:15.5px;padding:15px 32px 12px;
  box-shadow:0 12px 28px rgba(0,210,106,.26),0 0 0 6px rgba(0,210,106,.09);
}
#demoWrap .dmCall[hidden]{display:none}
#demoWrap .dmCall[disabled]{opacity:.55;cursor:default;box-shadow:none}
#demoWrap .dmEnd{
  display:inline-flex;align-items:center;gap:8px;
  font-family:inherit;font-size:14px;font-weight:700;line-height:1;cursor:pointer;
  color:#FF6B6B;background:transparent;border:1px solid rgba(255,107,107,.42);
  border-radius:999px;padding:11px 18px;
  transition:background .14s ease,border-color .14s ease,color .14s ease;
}
#demoWrap .dmEnd:hover{background:rgba(255,107,107,.12);border-color:rgba(255,107,107,.7);color:#FF8585}
#demoWrap .dmEnd:focus-visible{outline:2px solid #FF8585;outline-offset:2px}
#demoWrap .dmEnd[hidden]{display:none}
#demoWrap .dmEnd svg{flex:none;display:block}
#demoWrap .dmHint{
  margin-top:clamp(7px,1vh,11px);font-size:13px;line-height:1.45;color:#8E8E97;max-width:252px;min-height:36px;
}
#demoWrap .dmHint[hidden]{display:none}
/* the price of the click, stated before the click */
#demoWrap .dmCost{
  margin-top:clamp(5px,.8vh,9px);font-size:12.5px;line-height:1.42;color:#8E8E97;max-width:252px;
  text-wrap:balance;transition:opacity .2s ease;
}
/* once the line is open the microphone has already been asked for: the sentence
   goes, its slot stays, so nothing under the button moves on a state change */
#demoWrap.is-voiced .dmCost{opacity:0}
#demoWrap .dmTurnstile{display:flex;justify-content:center;margin-top:8px}
#demoWrap .dmTurnstile:empty{display:none}

/* ---------- transcript column ---------------------------------------------
   Opaque on purpose: the two fades at the ends of the log have to be able to
   name the exact colour they fade into, and a translucent panel over a graded
   card has no single such colour. */
#demoWrap .dmTalk{
  display:flex;flex-direction:column;min-width:0;
  background:linear-gradient(180deg,#26262D 0%,#1F1F25 100%);
  border:1px solid rgba(255,255,255,.07);
  border-radius:var(--r-inner,24px);padding:clamp(11px,1.5vh,15px) 16px clamp(11px,1.5vh,15px);
  will-change:transform;
}
#demoWrap .dmTalkHead{display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding-bottom:11px;border-bottom:1px solid rgba(255,255,255,.07)}
#demoWrap .dmTalkTitle{font-size:12px;font-weight:700;letter-spacing:.12em;color:#B7B7C0}
#demoWrap .dmTalkTags{display:inline-flex;align-items:center;gap:8px}
/* the idle thread is written copy, not a recording; the tag goes the moment a
   real row lands (section.js writes .is-real) and the live dot takes over */
#demoWrap.is-real .dmSample{display:none}
#demoWrap .dmTalkLive{display:inline-flex;align-items:center;gap:7px;font-size:12px;font-weight:600;
  color:#6E6E77;transition:color .3s ease}
#demoWrap .dmTalkLive i{width:7px;height:7px;border-radius:999px;background:#45454E;display:block;
  transition:background .3s ease}
#demoWrap.is-live .dmTalkLive{color:var(--live)}
#demoWrap.is-live .dmTalkLive i{background:var(--live)}

/* The sample thread is IN FLOW, so it is what gives the column its height and
   the console stretches to match it. The live log is the absolute layer over
   it, which is why the wrapper still keeps a min-height for the state where the
   thread is gone and only real rows remain. */
/* The pane is a ROW (the live log is an absolute layer over the sample thread),
   so the axis that bottom-anchors the thread is the cross axis: align-items,
   not justify-content. Anchored rather than stretched, .dmEmpty is exactly as
   tall as its own five turns, which is also what makes the dmThread stops below
   exact percentages of the thread instead of of a stretched box.
   The floor is the height the SETTLED five-turn thread needs (measured 318px at
   1000, 1280, 1440 and 2000, in both languages, since every turn keeps its line
   count). It used to be a clamp topping out at 240, so the moment a real call
   cleared the sample the pane collapsed by 78px and the whole card jumped. */
#demoWrap .dmLogWrap{position:relative;flex:1 1 auto;min-height:320px;display:flex;align-items:flex-end;overflow:hidden}
/* The log scrolls itself to the newest line, so the row at the bottom edge is
   normally cut in half. The fade says "there is more below" instead of letting
   a sentence look broken against the typing field. */
#demoWrap .dmLogWrap::after{
  content:"";position:absolute;left:0;right:0;bottom:0;height:20px;display:block;pointer-events:none;z-index:2;
  background:linear-gradient(to top,#202026,rgba(32,32,38,0));
}
/* and the same at the top, where a scrolled log cuts its oldest line against
   the header rule and a half sentence under a border reads as a broken layout
   rather than as a conversation that started before this screenful */
#demoWrap .dmLogWrap::before{
  content:"";position:absolute;left:0;right:0;top:0;height:16px;display:block;pointer-events:none;z-index:2;
  background:linear-gradient(to bottom,#25252C,rgba(37,37,44,0));
}
#demoWrap .dmLog{
  position:absolute;inset:0;overflow-y:auto;padding:8px 2px 6px;
  display:flex;flex-direction:column;justify-content:flex-end;gap:8px;
}
/* the sample thread, in flow, anchored to the bottom the way a chat is */
#demoWrap .dmEmpty{
  position:relative;flex:1 1 auto;min-width:0;overflow:hidden;
  display:flex;flex-direction:column;justify-content:flex-end;gap:8px;
  padding:8px 2px 6px;pointer-events:none;
}
#demoWrap .dmEmpty[hidden]{display:none}

/* ---------- the bubbles ----------------------------------------------------
   One rule set serves both threads. The sample turns in the markup and the rows
   section.js builds during a real call are the same element: .dmMsg is Suppo on
   the right, .dmMsg--caller is the customer on the left. */
#demoWrap .dmMsg{
  align-self:flex-end;max-width:88%;
  padding:8px 13px 9px;border-radius:16px 16px 5px 16px;
  background:linear-gradient(180deg,rgba(0,210,106,.17) 0%,rgba(0,194,103,.08) 100%);
  border:1px solid rgba(0,210,106,.22);
  font-size:13px;line-height:1.46;color:#EAFBF2;
}
#demoWrap .dmMsg b{display:block;font-size:12px;line-height:1.25;letter-spacing:.06em;font-weight:700;color:#3BE08F;margin:0}
#demoWrap .dmMsg--caller{
  align-self:flex-start;border-radius:16px 16px 16px 5px;
  background:rgba(255,255,255,.055);border-color:rgba(255,255,255,.09);color:#D8D8E0;
}
#demoWrap .dmMsg--caller b{color:#9A9AA4}
#demoWrap .dmMeta{display:flex;align-items:baseline;gap:8px;margin-bottom:2px}
#demoWrap .dmMeta b{margin:0}
#demoWrap .dmMeta i{font-style:normal;font-size:12px;font-weight:600;color:#77777F;font-variant-numeric:tabular-nums}
#demoWrap .dmSay{display:block}
/* live rows carry the speaker name alone, so the name needs the gap the meta
   row would otherwise have given it */
#demoWrap .dmMsg > b{margin-bottom:2px}
#demoWrap .dmSys{align-self:center}
#demoWrap .dmSys svg{color:var(--live);flex:none;display:block}

/* ---------- the idle arrival loop ------------------------------------------
   11 s, and the proof is on screen when the reader arrives.

   The old cut spent 8.5 s of a 17 s cycle writing the thread and 2.5 s with the
   pane empty, so a visitor who reached this section at a random moment had
   better than even odds of meeting a half written conversation or a blank dark
   card. The section's whole argument is the four turns and the handover, so the
   build is compressed into the first 3.5 s (0 to 32%) and the finished thread
   then stands for the remaining 7.5 s.

   The reset is no longer an all-clear. The turns roll off newest first over the
   last 8% and dmTurn1, the opening question, is the last one out: it is the only
   turn still on screen when the thread snaps back to its start position, so the
   only thing that fades at the seam is the line the next cycle is about to ask
   again. Five keyframe blocks rather than one with staggered delays: a delay
   would slide each turn's whole cycle, so the thread would also clear itself in
   the same staggered order, which reads as a glitch rather than as an ending. */
#demoWrap .dmTurn{opacity:0;animation-duration:11s;animation-timing-function:var(--ease);
  animation-iteration-count:infinite;animation-fill-mode:both}
/* The pane is exactly as tall as the finished thread, so an un-arrived turn
   would otherwise hold an empty band at the FOOT of the chat, which is the one
   place a real chat is never empty. The thread therefore starts pushed down by
   the height of everything that has not arrived yet and climbs one turn at a
   time, so the newest bubble always sits on the typing field the way a thread
   scrolls itself. The stops are measured off the built page (turn bottoms at
   65/131/206/291/325 inside a 323px column) and they hold identically at 1280,
   1440 and 2000 and in both languages, because every turn keeps its line count.
   One transform on one box: the bubbles ride it, none of them is re-laid out. */
#demoWrap .dmEmpty{animation:dmThread 11s var(--ease) infinite both}
@keyframes dmThread{
  0%,6%{transform:translate3d(0,78%,0)}
  8%,12%{transform:translate3d(0,57.6%,0)}
  16%,20%{transform:translate3d(0,34.4%,0)}
  24%,28%{transform:translate3d(0,8%,0)}
  32%,100%{transform:none}
}
#demoWrap .dmTurn1{animation-name:dmTurnA}
#demoWrap .dmTurn2{animation-name:dmTurnB}
#demoWrap .dmTurn3{animation-name:dmTurnC}
#demoWrap .dmTurn4{animation-name:dmTurnD}
#demoWrap .dmTurn5{animation-name:dmTurnE}
/* Entries at 0 / 8 / 16 / 24 / 32%, exits rolling NEWEST FIRST at 92 / 93.5 /
   95 / 96.5 / 98.5%, so the opening question is the last turn on screen and the
   only one that fades at the restart. The thread's start pose is 252px below its
   settled one, so the seam is the one instant in the cycle where the pane cannot
   hold anything: turn 1 is given the shortest possible fade either side of it and
   the pane is empty for 1.5% of the cycle (0.17s), against 15% (2.5s) before. */
@keyframes dmTurnA{0%{opacity:0;transform:translate3d(0,10px,0)}1.5%,98.5%{opacity:1;transform:none}100%{opacity:0;transform:translate3d(0,-6px,0)}}
@keyframes dmTurnB{0%,4.5%{opacity:0;transform:translate3d(0,10px,0)}8%,96.5%{opacity:1;transform:none}99%,100%{opacity:0;transform:translate3d(0,-6px,0)}}
@keyframes dmTurnC{0%,12.5%{opacity:0;transform:translate3d(0,10px,0)}16%,95%{opacity:1;transform:none}98%,100%{opacity:0;transform:translate3d(0,-6px,0)}}
@keyframes dmTurnD{0%,20.5%{opacity:0;transform:translate3d(0,10px,0)}24%,93.5%{opacity:1;transform:none}96.5%,100%{opacity:0;transform:translate3d(0,-6px,0)}}
@keyframes dmTurnE{0%,28.5%{opacity:0;transform:translate3d(0,8px,0)}32%,92%{opacity:1;transform:none}95%,100%{opacity:0;transform:translate3d(0,-6px,0)}}

/* ---------- the typed lane, as one pill ---------- */
#demoWrap .dmForm{
  display:flex;align-items:center;gap:6px;margin-top:clamp(9px,1.3vh,13px);
  background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.09);
  border-radius:999px;padding:5px 5px 5px 8px;
  transition:border-color .16s ease,background .16s ease;
}
#demoWrap .dmForm.is-off{opacity:.45;pointer-events:none}
#demoWrap .dmForm:focus-within{border-color:rgba(0,210,106,.45);background:rgba(255,255,255,.06)}
#demoWrap .dmInput{
  flex:1 1 auto;min-width:0;font-family:inherit;font-size:13.5px;color:#fff;
  background:transparent;border:0;padding:8px 10px;
}
/* 2.83:1 at #6E6E77; 4.66:1 here, the value .dmHint already uses two rules away */
#demoWrap .dmInput::placeholder{color:#8E8E97}
#demoWrap .dmInput:focus{outline:none}
#demoWrap .dmSend{
  border:0;cursor:pointer;font-family:inherit;font-size:13px;font-weight:700;
  background:rgba(255,255,255,.09);color:#B7B7C0;border-radius:999px;padding:8px 16px;white-space:nowrap;
  transition:background .14s ease,color .14s ease;
}
#demoWrap .dmSend.is-ready{background:var(--live);color:var(--accent-ink)}

/* ---------- the foot strip: eyebrow, then the three measured numbers ---------
   One strip along the bottom of the panel. The row rises once, in the first 16%
   of the pin, and is then constant for the rest of the section: nothing writes
   it per frame after that, so it holds no layer. */
#demoWrap .dmFoot{
  display:flex;align-items:flex-start;gap:clamp(16px,2vw,30px);
  margin-top:clamp(10px,1.5vh,17px);padding-top:clamp(10px,1.5vh,17px);
  border-top:1px solid rgba(255,255,255,.08);
}
#demoWrap .dmEye{flex:none;width:clamp(96px,8.6vw,124px);padding-top:4px;align-items:flex-start;line-height:1.45}
#demoWrap .dmStats{flex:1 1 auto;display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(16px,1.8vw,28px)}
#demoWrap .dmStat{
  min-width:0;padding-left:clamp(16px,1.8vw,28px);
  border-left:1px solid rgba(255,255,255,.09);
  opacity:0;transform:translateY(22px);
}
#demoWrap .dmVal{font-size:clamp(24px,1.95vw,32px);font-weight:800;letter-spacing:-.035em;line-height:1;
  font-variant-numeric:tabular-nums}
/* page rule: the aurora belongs to em.hl and to stat numerals, nothing else */
#demoWrap .dmNum{
  background-image:var(--grad);-webkit-background-clip:text;background-clip:text;color:transparent;
}
#demoWrap .dmLab{margin-top:6px;font-size:12.5px;line-height:1.4;color:#9A9AA4;font-weight:500}

/* ---------- tablet ---------- */
@media (max-width:1000px){
  #demoWrap{height:190vh}
  #demoWrap .pin{padding-top:clamp(80px,10vh,104px)}
  #demoWrap .dmStage{width:calc(100% - 44px)}
  /* the radius family does not shrink with the viewport: 32 is 32 */
  #demoWrap .dmCard{padding:clamp(13px,1.8vh,18px) 16px clamp(12px,1.7vh,16px)}
  #demoWrap .dmCols{grid-template-columns:minmax(0,268px) minmax(0,1fr);gap:16px}
  #demoWrap .dmOrbBox{--ob:clamp(106px,14.4vh,132px);margin:clamp(16px,2.4vh,24px) 0 clamp(13px,2vh,20px)}
  #demoWrap .dmEye{width:88px}
  #demoWrap .dmLab{font-size:12px}
  #demoWrap .dmHint{max-width:230px}
  #demoWrap .dmCost{max-width:230px}
  #demoWrap .dmMsg{max-width:92%}
}

/* ---------- phone -----------------------------------------------------------
   MOBILE PASS 2026-09-06. The founder's note was that the phone carries a
   poorer page than the desktop. The old phone rule here was a HEIGHT BUDGET: it
   kept the section pinned inside one 844px screen and paid for it by deleting
   the badge, the sub, the eyebrow, the typed lane and three of the five turns
   of the thread. That is a different, smaller product, not the same one.

   So the phone UNPINS. `#demoWrap` goes to auto height, `.pin` goes static, and
   the same composition simply stacks: head, then the dark panel with the orb
   console above the transcript, then the numbers. Nothing is hidden, nothing is
   scaled down to fit, and the scrubbed choreography is replaced by one reveal
   per block (section.js branches on the same 720px query).

   The system for the page: 20px gutters, one column, H2 28 to 32, sub 15,
   radius 26/20, 20px of panel padding, 16px between the stacked blocks.
   -------------------------------------------------------------------------- */
@media (max-width:720px){
  #demoWrap{height:auto}
  /* static, not sticky: the frame is now as tall as its content, so no beat can
     be cut off the bottom of a pinned screen */
  #demoWrap .pin{position:static;height:auto;display:block;overflow:visible;
    padding:96px 0 92px}
  #demoWrap .dmStage{width:calc(100% - 40px)}

  #demoWrap .dmHead h2,#demoWrap .dmHead h2:lang(ka){font-size:clamp(28px,8.2vw,32px);line-height:1.1}
  /* 360 is the measure, not the column: at 390 the gutters already hold the sub
     to 350 and the cap does nothing, and at 430 it stops a 15px sentence from
     running the full 390 of the frame, which reads as a paragraph pushed against
     both walls rather than as a centred lead line. */
  #demoWrap .dmSub{margin-top:12px;font-size:16px;line-height:1.5;max-width:360px}

  /* the panel: full width inside the 20px gutters, 20px of inner air on every
     side, and the desktop radius family kept (26 on a 350px card reads as the
     same object as 32 on a 1180px one).

     The card's light is REDRAWN, not inherited. On the desktop the green sits
     at 16% 104% because that is where the orb sits, in the bottom left of a
     two column card. Stacked, the orb is at the top centre (about 160px down
     from the card's top edge) and the desktop light would be a green glow in
     an empty corner with the orb lit by nothing. So the green moves to the orb
     and is sized in PIXELS rather than percentages, because this card is 1290px
     tall on a phone and a percentage radius would smear one glow over the whole
     panel. The cool counter light stays at the foot, under the numbers. */
  #demoWrap .dmCard{
    margin-top:24px;padding:20px;
    background:
      radial-gradient(300px 270px at 50% 158px,rgba(0,210,106,.22) 0%,rgba(0,194,103,.08) 44%,rgba(0,194,103,0) 76%),
      radial-gradient(340px 300px at 50% 100%,rgba(31,168,232,.14) 0%,rgba(31,168,232,.04) 42%,rgba(31,168,232,0) 72%),
      linear-gradient(176deg,#232328 0%,#202025 46%,#1B1B1F 100%);
  }
  #demoWrap .dmCols{grid-template-columns:1fr;gap:16px}

  /* ---- the orb console, stacked above the transcript ---- */
  #demoWrap .dmConsole{padding:20px 18px 22px}
  #demoWrap .dmOrbBox{--ob:clamp(132px,36vw,150px);margin:22px 0 18px}
  /* Touch. Both controls are 46 and 49px tall, and both are given the same
     190px floor: the pill is the one thing on this screen a thumb is meant to
     hit, and at its intrinsic 130px it read as a chip on a 308px column. The
     floor is shared so the slot does not resize when the call opens. */
  #demoWrap .dmAct{min-height:52px;margin-top:14px}
  #demoWrap .dmCall{font-size:15.5px;padding:16px 32px 13px;min-width:190px;
    box-shadow:0 10px 24px rgba(0,210,106,.24),0 0 0 5px rgba(0,210,106,.09)}
  #demoWrap .dmEnd{font-size:14px;padding:14px 20px;min-width:190px;justify-content:center}
  /* section.js rewrites this line for every call state, and the strings run from
     four words to fourteen, so the width is a cap and `balance` does the rest:
     at 260 the English idle line dropped "Georgian." onto a line of its own. */
  #demoWrap .dmHint{margin-top:12px;font-size:13px;line-height:1.45;min-height:0;max-width:280px;
    text-wrap:balance}
  #demoWrap .dmCost{margin-top:8px;font-size:12.5px;max-width:280px}

  /* ---- the transcript ---- */
  #demoWrap .dmTalk{padding:16px 16px 16px}
  /* The head is one row, always. At 390 the pane is 274px wide and the two
     status chips take 148 of it, which leaves 114 for the title; the Georgian
     title at the desktop's .12em tracking measures 118 and wrapped onto a
     second line, so a 12px label sat two lines tall next to a 26px pill and
     the row read as broken. The tracking comes down to .06em (108px) and the
     title is pinned to one line. The English title is 84px and never came
     close to the limit either way. */
  #demoWrap .dmTalkHead{padding-bottom:12px;gap:10px}
  #demoWrap .dmTalkTitle{letter-spacing:.06em;white-space:nowrap}
  #demoWrap .dmTalkTags{gap:7px;flex:none}
  /* The pane holds the WHOLE thread here, not a clipped window over two of its
     five turns: at 390 the four bubbles and the handover chip measure 413px and
     the pane simply grows to them (the 300 is the floor for the state where a
     real call has cleared the sample and only one row is left). */
  /* the floor is the settled thread's own height at 390 (measured 354px), so a
     live call that clears the sample does not collapse the pane under itself */
  #demoWrap .dmLogWrap{min-height:356px}
  #demoWrap .dmLog,#demoWrap .dmEmpty{padding:10px 2px 8px;gap:9px}
  #demoWrap .dmMsg{max-width:92%;font-size:13.5px;padding:8px 13px 9px}
  #demoWrap .dmEmpty{animation-name:dmThreadM}

  /* ---- the typed lane: shown, thumb sized, and legible ----------------------
     Both controls clear 44px (13px of padding on a 19.5px line box = 45.5).
     The field is sized off its own placeholder rather than off a guess: the
     Georgian string measures 149px at 13px, and the widths below leave it 152,
     so the phone shows the whole sentence instead of cutting it against the
     send button the way it did at 14px in a 136px box. */
  #demoWrap .dmForm{margin-top:16px;padding:6px 6px 6px 12px}
  #demoWrap .dmInput{font-size:13px;padding:13px 6px}
  #demoWrap .dmSend{font-size:13px;padding:13px 13px}

  /* ---- the numbers ---- */
  #demoWrap .dmFoot{flex-direction:column;gap:16px;margin-top:20px;padding-top:20px}
  #demoWrap .dmEye{width:auto;padding-top:0;line-height:1.4;font-size:12px}
  #demoWrap .dmStats{grid-template-columns:1fr;gap:16px}
  #demoWrap .dmStat{display:flex;align-items:baseline;gap:14px;padding-left:0;border-left:0}
  #demoWrap .dmVal{font-size:24px;flex:none;min-width:58px}
  #demoWrap .dmLab{margin-top:0;font-size:13px;line-height:1.4}

  /* Unpinned means there is no scrubbed timeline to ride in on, so each block
     arrives once on its own, the way every other flow section on the page does.
     section.js clears the desktop inline transforms and calls MOTION.reveal. */
  #demoWrap .dmCard{opacity:0;transform:translateY(26px);
    transition:opacity .9s var(--ease),transform .9s var(--ease)}
  #demoWrap .dmCard.in{opacity:1;transform:none}
  #demoWrap .dmStat{opacity:0;transform:translateY(18px);
    transition:opacity .7s var(--ease) var(--d),transform .7s var(--ease) var(--d)}
  #demoWrap .dmFoot.in .dmStat{opacity:1;transform:none}
}

/* The phone thread rides exactly the way the desktop one does, so the newest
   bubble always sits on the typing field, but the phone column wraps its turns
   differently, so the stops are its own. Measured off the built page: turn
   bottoms 68/155/222/368 inside a 413px column at 390, and 68/135/203/329
   inside 374 at 430, which agree to within one percent. */
@keyframes dmThreadM{
  0%,6%{transform:translate3d(0,83%,0)}
  8%,12%{transform:translate3d(0,63%,0)}
  16%,20%{transform:translate3d(0,46%,0)}
  24%,28%{transform:translate3d(0,11.5%,0)}
  32%,100%{transform:none}
}

/* Short viewports: a laptop at 700 keeps the card whole, so the least
   load-bearing lines go first. (The phone no longer needs a height budget: it
   is not pinned, so there is no frame for its last beats to fall out of.) */
/* Short viewports. A 1440x900 window is 813px of frame, and this pass added
   the cost line, a 54px headline and a 16px lead line to a card that already
   filled 787 of it, so the compact card has to start at the laptop, not below
   it: at 800 the full-size card overflowed the pin and the numbers strip was
   clipped off the bottom of the screen. */
@media (min-width:1001px) and (max-height:900px){
  #demoWrap .dmHead h2,#demoWrap .dmHead h2:lang(ka){font-size:38px}
  #demoWrap .dmOrbBox{--ob:clamp(104px,15vh,132px);margin:16px 0 13px}
}

/* A tall frame (an iPad in portrait, a big desktop) is far taller than this
   card, and top-aligning it leaves a third of the pinned screen empty under
   the numbers. Above 1000px of viewport there is room for the nav island over
   a centred card, so the card takes the middle of the frame instead. */
@media (min-height:1000px){
  #demoWrap .pin{align-items:center;padding:clamp(0px,2.2vh,26px) 0}
}

@media (prefers-reduced-motion:reduce){
  #demoWrap .dmB,#demoWrap .dmOrbBreath,#demoWrap .dmHalo,#demoWrap .dmRing,
  #demoWrap .dmOrb.is-connecting::after{animation:none}
  #demoWrap .dmTurn{animation:none;opacity:1;transform:none}
  #demoWrap .dmEmpty{animation:none;transform:none}
  #demoWrap .dmOrb{transition:none}
}

/* ===== stats ===== */
/* ============================================================
   SUPPO / STATS   "ზარი და არა ლოდინი" / "A call, not a wait"

   ROUND 6 (2026-09-05). Founder note on the screenshot: "this section is also
   inconsistent". It was: tile 2 carried a 58px aurora numeral, the other three
   carried 30px ink phrases; the 2px rule was scrubbed from 14% to 100% width so
   no two rules were the same length or, once the values wrapped differently, the
   same height; the icon chip of whichever tile held the beat turned green while
   its three neighbours stayed grey; the footnote floated on its own centred
   780px measure that matched nothing in the grid above it.

   The four tiles are now one component drawn four times:
     - one chip: 38px, radius 16 (the small step of the page's 32/24/16 family), var(--tile), one glyph weight (24-box outline,
       stroke 1.6, round caps, optical height ~16px), brand green glyph, never
       tinted per tile;
     - one headline: 29px / 1.26 for all four, ink, bottom aligned in a shared
       subgrid row, so 24/7 is a headline that happens to be a numeral rather
       than a different typographic object. Only the numeral itself keeps the
       aurora, exactly the way em.hl carries it in the h2 above;
     - one rule: 56px wide, 3px, same y in every tile (the subgrid row), never
       scrubbed;
     - one label grid: 14px / 1.5, same top, same baselines;
     - one column padding: 18px each side of every tile, and the footnote sits
       on the same 18px text edge with its rule spanning the whole grid.
   Choreography is unchanged in kind (bento's rise + .09s stagger, then a
   scrubbed parallax), but every scrubbed write is now a transform: no colour,
   no background-position, nothing that repaints.

   ROUND 7 (2026-09-05), the art direction pass over that pass. Three things were
   still wrong on screen and are fixed below, each at its own block:
     1. the four chips rendered as empty grey squares for over a second after
        their tiles had finished fading in, because the glyph pop was armed by a
        setTimeout at rise + stagger. It now rides the tile's own rise in CSS.
     2. the "/7" was held back during the count with opacity:0, which does not
        hide a child of a background-clip:text box: "18/7" was on screen for the
        whole count. It is held with visibility instead.
     3. the divider was a border-left, so column 1 measured 242px and the other
        three 241px and their text edges sat 1px off the column-1 rhythm. It is a
        pseudo element on the boundary now, and every column is exactly 1fr.
   Plus: panel padding balanced top to bottom (41 / 28 was top heavy), and the
   scrubbed parallax moved from four .stin boxes onto the grid itself.
   ============================================================ */
#statsWrap{position:relative;background:var(--band)}
#statsWrap .band{padding:92px 0 88px}

/* ---------- head (one column, same width as the panel) ---------- */
#statsWrap .head{width:min(var(--maxw),calc(100% - 64px));margin:0 auto;text-align:center}
#statsWrap .ttl{font-size:54px;line-height:1.08;letter-spacing:-.012em;font-weight:800;color:var(--ink)}
#statsWrap .ttl:lang(en){font-size:56px;letter-spacing:-.03em}
#statsWrap .ttl .w{display:inline-block}
/* PERF PASS 2026-09-05. Every reveal in this section used to be a PAIR of
   transitions (opacity + transform) on five elements per tile, which is 34
   animations running at once the moment the band enters the viewport
   (tools/audit.py counted exactly that). One keyframe does both properties in
   one animation object, and the value, rule and label now ride their tile's
   own fade instead of each carrying a transition of their own. Same look, same
   durations, same .09s stagger; seven animations instead of thirty-four. */
@keyframes statsRise{from{opacity:0;transform:translateY(var(--rise,20px))}to{opacity:1;transform:none}}
#statsWrap .ttl .w > span,
#statsWrap .ttl .w > em{display:inline-block;opacity:0;transform:translateY(20px)}
#statsWrap .head.in .ttl .w > span,
#statsWrap .head.in .ttl .w > em{animation:statsRise .95s var(--ease) var(--d) both}
#statsWrap .sub{--rise:16px;max-width:640px;margin:16px auto 0;font-size:17px;line-height:1.6;color:var(--muted);font-weight:500;
  opacity:0;transform:translateY(16px)}
#statsWrap .head.in .sub{animation:statsRise .9s var(--ease) .26s both}

/* ---------- white panel on the band ---------- */
/* ROUND 7: the first chip sat 41px under the panel edge and the footnote finished
   28px above it, so the plate read top heavy. Padding bottom 38 puts the two optical
   margins within 3px of each other. */
#statsWrap .panel{width:min(var(--maxw),calc(100% - 64px));margin:44px auto 0;background:var(--panel);
  border-radius:var(--r-card);box-shadow:var(--shadow-soft);padding:38px 34px 38px}

/* ROUND 7: the parallax is written to the grid, not to four .stin boxes. One
   transform instead of four means one will-change instead of four and one
   composited layer for the whole row, and it makes it structurally impossible
   for the four columns to drift out of line while the section scrubs. */
#statsWrap .grid{display:grid;grid-template-columns:repeat(4,1fr);will-change:transform}
#statsWrap .st{--rise:36px;position:relative;padding:0 18px;
  opacity:0;transform:translateY(36px)}
#statsWrap .st.in{animation:statsRise 1.05s var(--ease) var(--d) both}
/* ROUND 7: the divider is a pseudo element on the column boundary, not a
   border-left. A border ate 1px of the tile's own content box, so column 1 was
   242px wide and columns 2 to 4 were 241px and their text edge sat 1px to the
   right of the rhythm column 1 set. Every column is now exactly 1fr with the
   same 18px text inset, and the hairline sits on the gutter centre. */
#statsWrap .st + .st::before{content:"";position:absolute;left:0;top:0;bottom:0;width:1px;
  background:var(--line)}

/* ---------- the chip: identical in all four tiles, at rest and in motion ----------
   The hand-off used to repaint one chip green while the other three stayed grey,
   which is what makes a still of this row look like four unrelated components.
   The beat now lives entirely in the 7px lift of the tile (transform, section.js);
   the chip keeps one tint for the life of the page. */
#statsWrap .ico{width:38px;height:38px;border-radius:16px;display:grid;place-items:center;
  background:var(--tile);color:#00B95E}
/* ROUND 7: the glyph pop rides the tile's own rise instead of a setTimeout.
   It used to be armed from JS at rise duration + stagger, which is 1.09s to 1.36s
   after the observer fired, and until then the chip was a bare grey square on a
   tile that had already finished fading in: every screenshot taken in that window
   showed four empty chips, and so did a real reader on a slow first paint. The pop
   now starts .3s into the tile's own rise and lands .13s before it, so the glyph
   is never visible as a hole and never arrives after the tile has settled. The
   `from` state only exists while .in is on the tile, so a page whose JS never runs
   shows the glyph rather than hiding it. */
@keyframes statsPop{from{opacity:0;transform:scale(.62)}to{opacity:1;transform:none}}
#statsWrap .ico svg{display:block;will-change:transform}
#statsWrap .st.in .ico{animation:statsPop .62s var(--ease-pop) calc(var(--d) + .3s) both}

/* ---------- idle loop: one chip at a time, 16s cycle ----------
   Transform only, gated by .st-awake (IntersectionObserver in section.js) so it
   costs nothing off screen, and phase shifted by a NEGATIVE delay per tile
   (--ad) so the row is already spread across the cycle on the first frame
   instead of starting four chips together. 16s with a 4s step means one chip is
   moving at a time and each move takes about five seconds: slow enough to read,
   never a flicker. It breathes rather than lifts: a 4px rise would have put one
   chip off the shared chip row in every still of the section, which is the exact
   thing this pass is fixing. A 5% scale about the chip's own centre leaves the
   row dead level. */
@keyframes statsIdle{
  0%,64%,100%{transform:scale(1)}
  32%{transform:scale(1.18)}
}
/* ROUND 7: the loop moved off the CHIP and onto the GLYPH, and the arrival moved
   the other way. Two reasons. The chip is the alignment element of the row, so
   nothing should ever scale it: a 5% pulse on a 38px box lifted its top edge 1px
   off the shared chip line, which is the one thing this section is not allowed to
   do. And 5% of 38px is 1.9px of travel, which at reading distance is not a beat
   at all: 18% of a 20px glyph is 3.6px on a smaller object, which reads clearly
   without the row moving by a hair. */
#statsWrap.st-awake .ico svg{animation:statsIdle 16s ease-in-out var(--ad,0s) infinite}


/* ---------- the headline: one size, one line height, four tiles ---------- */
/* ROUND 7: top aligned, not bottom aligned. The rules sit on a shared subgrid row
   either way, so this only decides WHERE the slack goes when one headline in a row
   wraps and its neighbours do not. Bottom aligning put the slack between the chip
   and the headline, which detached three chips from their own headlines and read as
   a bug; top aligning puts it between the headline and the rule, where it reads as
   air. Visible two up and on phones, where the headlines do wrap. */
#statsWrap .val{margin-top:22px;display:flex;align-items:flex-start}
/* 29px is the largest size at which the longest Georgian headline
   ("ამოიცნობს ენას", 231px) still fits one line in the 242px column, so in the
   default language all four headlines are single line and the chip to headline
   gap is identical across the row. English wraps that one headline to two lines,
   which the subgrid absorbs: the rules and labels stay on their shared row. */
#statsWrap .num{display:block;font-size:29px;font-weight:800;letter-spacing:-.014em;line-height:1.26;
  color:var(--ink)}
#statsWrap .num:lang(en){letter-spacing:-.026em}
/* the only numeral in the section keeps the aurora, the same recipe em.hl uses
   in the h2 above. Same size, same weight, same line as its three neighbours. */
/* ROUND 8 (review pass): tracking was -.03em against the row's -.014em. On a four
   glyph numeral that extra tightening is the whole word, so "24/7" set denser and
   read smaller than the three phrases beside it at the identical font size. It now
   tracks with the row it belongs to. */
#statsWrap .num-fig{background-image:var(--grad);-webkit-background-clip:text;background-clip:text;
  color:transparent;font-feature-settings:"tnum" 1;letter-spacing:-.014em}
#statsWrap .n{color:inherit}
/* REVIEW PASS 2026-09-06: the count-up is gone, and with it the .counting
   machinery that hid the separator while it ran. 24/7 is a fact from the
   approved copy, not a measurement, and a counter walking 12, 18, 19 up to it
   is a number the page does not have, inside the one section whose whole
   argument is that nothing here is invented. The numeral now arrives with its
   own tile, on the same 1050ms statsRise as the other three, and reads 24/7 on
   every frame including the first. */

/* one rule: same width, same height, same y (the subgrid row), never scrubbed */
#statsWrap .ul{display:block;width:56px;height:3px;margin-top:18px;border-radius:2px;
  background-image:var(--grad);background-size:56px 100%}

/* --muted, not --faint: at 14px on white the faint grey drops to about 4.7:1 and
   reads as disabled text next to an ink headline. --muted is the secondary colour
   the integrations panel uses and holds the same weight in all four columns. */
#statsWrap .lab{margin-top:15px;font-size:14px;line-height:1.5;font-weight:500;color:var(--muted);
  letter-spacing:-.004em}

/* the footnote sits on the grid: the rule spans the whole row (the p), the sentence
   starts on the same 22px text edge as tile 1 and holds three of the four columns */
#statsWrap .foot{margin:30px 0 0;padding:24px 18px 0;border-top:1px solid var(--line);
  will-change:transform}
/* 816px is exactly three of the four columns less the 18px text inset, so the
   sentence ends on the column 3 / column 4 boundary above it */
/* ROUND 8 (review pass): the footnote used to be the one thing in the panel that was
   simply there. Head, then four tiles at a .09s stagger, then a sentence already
   sitting at the bottom of the plate: the sequence ended on nothing. The sentence now
   closes it at .42s, which is just after the fourth tile lands, so the eye has one
   more thing to follow and the panel finishes rather than stopping. The rise is on the
   SPAN, never on .foot, because .foot carries the scrubbed parallax and a filled
   animation on it would pin that transform to none for the life of the page. */
#statsWrap .footin{display:block;max-width:816px;font-size:15px;line-height:1.55;font-weight:500;
  color:var(--muted);--rise:14px;opacity:0;transform:translateY(14px)}
#statsWrap .foot.in .footin{animation:statsRise .95s var(--ease) .42s both}

/* ---------- narrower viewports: still one column ---------- */
/* The 4-up row only holds at the full 1180 column. Narrower than that an English
   headline wraps to a third line and the labels start colliding with the dividers,
   so the row goes 2-up, where every headline fits in two lines. */
@media (max-width:1243px){
  #statsWrap .ttl{font-size:45px}
  #statsWrap .ttl:lang(en){font-size:47px}
  #statsWrap .grid{grid-template-columns:repeat(2,1fr);row-gap:34px}
  /* two up: the hairline belongs to the right hand tile of each band only */
  #statsWrap .st:nth-child(3)::before{content:none}
  /* Fallback slots for browsers without subgrid: the value sits in a fixed,
     bottom aligned box so the rule under it lands at one height across a row
     whatever the headline wraps to. 82px clears the worst case in either
     language two up, which is a two-line 33px headline. */
  #statsWrap .val{min-height:80px;margin-top:18px}
}
@media (max-width:900px){
  #statsWrap .band{padding:78px 0 74px}
  #statsWrap .ttl{font-size:42px}
  #statsWrap .ttl:lang(en){font-size:44px}
  #statsWrap .panel{padding:30px 26px 32px}
}
/* Phones keep the 2x2. A four-tile column put a whole empty headline slot above
   every value and pushed the footnote three screens down; the grid holds at 390
   once the headline steps down a size and the tiles trade their 26px side padding
   for 12px. Nothing here goes under 12px: the label bottoms out at 12.5px. */
@media (max-width:660px){
  #statsWrap .band{padding:72px 0 68px}
  #statsWrap .head{width:min(var(--maxw),calc(100% - 40px))}
  #statsWrap .ttl,#statsWrap .ttl:lang(en){font-size:32px;letter-spacing:-.014em}
  #statsWrap .ttl:lang(en){letter-spacing:-.03em}
  #statsWrap .sub{font-size:15px;margin-top:14px}
  /* REVIEW PASS 2026-09-06: no phone-only radius. The page ships 32 / 24 / 16
     at every width, so the plate keeps the desktop 32 here too. */
  #statsWrap .panel{width:min(var(--maxw),calc(100% - 40px));margin-top:32px;padding:26px 18px 28px}
  #statsWrap .grid{grid-template-columns:repeat(2,1fr);row-gap:26px}
  #statsWrap .st{padding:0 12px}
  #statsWrap .ico{width:34px;height:34px}
  #statsWrap .ico svg{width:18px;height:18px}
  #statsWrap .val{min-height:72px;margin-top:14px}
  #statsWrap .num{font-size:21px;line-height:1.26}
  #statsWrap .ul{margin-top:13px;width:44px;background-size:44px 100%}
  #statsWrap .lab{margin-top:11px;font-size:12.5px;line-height:1.45}
  #statsWrap .foot{margin-top:24px;padding:20px 12px 0}
  #statsWrap .footin{font-size:13.5px;max-width:none}
}

/* ---------- the value slot, sized by the row instead of by a constant ----------
   The four headlines are phrases of unequal length, so the 3px rule can only sit
   at one height across a row if every headline box is the same height. The
   min-height slots above do that, but a constant has to clear the tallest
   headline in EITHER language, which leaves the short ones floating on a hole.
   Subgrid buys the same alignment for nothing: chip, headline, rule and label
   each take a row of the parent grid, so the headline row is exactly as tall as
   the tallest headline IN THAT ROW and the rules still land on one line.
   Browsers without subgrid fall back to the fixed slots above. */
@supports (grid-template-rows:subgrid){
  #statsWrap .grid{grid-template-rows:repeat(4,auto);row-gap:0}
  #statsWrap .st{display:grid;grid-template-rows:subgrid;grid-row:span 4}
  #statsWrap .stin{display:grid;grid-template-rows:subgrid;grid-row:span 4}
  #statsWrap .val{min-height:0}
  /* two bands of tiles: the band gap is a margin on the second band, because a
     row-gap would open between every one of the eight subgrid rows */
  @media (max-width:1243px){
    #statsWrap .grid{grid-template-rows:repeat(8,auto)}
    #statsWrap .st:nth-child(n+3){margin-top:34px}
  }
  @media (max-width:660px){
    #statsWrap .st:nth-child(n+3){margin-top:26px}
  }
}

/* ============================================================
   THE PHONE (<=560): one tile per row, the desktop component intact
   ------------------------------------------------------------
   MOBILE ROUND 2026-09-06. Two-up survived down to 390 but only by paying
   for it twice: the headline had to drop from 29px to 21px, which is a
   different typographic object from the 29px it is on the desktop, and the
   label had to drop to 12.5px, half a pixel off the floor. And because the
   four headlines are phrases of unequal length, one of them ("ამოიცნობს ენას"
   in KA, "Average time..." in EN) wrapped to two lines in a 157px column
   while its neighbour set one, so the subgrid opened a visible hole under
   the short one. That is the slack the review called out.

   One tile per row removes the cause rather than the symptom: the column is
   310px instead of 157px, so every headline sets one line in both languages
   at 26px and every label sets at most two at 14px. The tile keeps all four
   of its desktop parts (chip, headline, gradient rule, label) and keeps
   their order; only the chip moves from above the headline to beside it,
   which is what buys the width back. The rules land on one x by
   construction, so the two-up subgrid machinery is switched off here.
   ============================================================ */
@media (max-width:560px){
  /* the page-wide phone system: 20px side gutters, section padding 80/76,
     H2 30px, sub 15px, card radius from the same family as the desktop panel. */
  #statsWrap .band{padding:80px 0 76px}
  #statsWrap .head{width:calc(100% - 40px)}
  #statsWrap .ttl,#statsWrap .ttl:lang(en){font-size:30px}
  #statsWrap .sub{font-size:15px;line-height:1.55;margin-top:14px;max-width:none}
  /* 22px of inner padding on all four sides of the plate: at 20px the longest
     English label ("Average time to first word of the answer") ended exactly on
     the padding edge, which is the "nothing may touch" the founder called out on
     the desktop panel. At 22 it wraps to a second line and the plate breathes;
     one label wrapping costs nothing now that the tiles are stacked rows rather
     than columns that had to share a baseline. */
  #statsWrap .panel{width:calc(100% - 40px);margin-top:30px;padding:22px 22px 26px}

  #statsWrap .grid{display:block;grid-template-rows:none;grid-template-columns:none;row-gap:0}
  #statsWrap .st{display:block;grid-row:auto;grid-template-rows:none;padding:22px 0;margin-top:0}
  #statsWrap .st:first-child{padding-top:4px}
  /* the divider turns with the layout: a hairline between rows, full bleed
     across the panel's text column, never a column rule. Tile 3 gets its rule
     BACK: two up it opens the second band, so the 1243 block cancels it, and
     that cancel was still in force at 390, where it left the stack with a
     hairline after tiles 1 and 3 and nothing between 2 and 3. */
  #statsWrap .st + .st::before{content:"";left:0;right:0;top:0;bottom:auto;width:auto;height:1px}

  #statsWrap .stin{display:grid;grid-row:auto;grid-template-rows:auto auto auto;
    grid-template-columns:40px minmax(0,1fr);column-gap:16px;align-items:start}
  #statsWrap .ico{grid-column:1;grid-row:1;width:40px;height:40px;margin-top:-3px}
  #statsWrap .ico svg{width:20px;height:20px}
  #statsWrap .val{grid-column:2;grid-row:1;margin-top:0;min-height:0}
  #statsWrap .num{font-size:26px;line-height:1.24}
  #statsWrap .ul{grid-column:2;grid-row:2;margin-top:14px;width:52px;background-size:52px 100%}
  #statsWrap .lab{grid-column:2;grid-row:3;margin-top:12px;font-size:14px;line-height:1.5}

  #statsWrap .foot{margin-top:0;padding:24px 0 0}
  #statsWrap .footin{font-size:14px;line-height:1.55;max-width:none}
}
@supports (grid-template-rows:subgrid){
  @media (max-width:560px){
    /* the two-up subgrid is what keeps four rules on one line in a 2x2; in a
       single column they are on one line anyway, and leaving the subgrid on
       would make each tile span four rows of a grid that no longer exists. */
    #statsWrap .grid{grid-template-rows:none}
    #statsWrap .st{display:block;grid-row:auto}
    #statsWrap .st:nth-child(n+3){margin-top:0}
    #statsWrap .stin{display:grid;grid-row:auto;grid-template-rows:auto auto auto}
  }
}

/* ---------- reduced motion, LAST in the file on purpose ----------
   Every override below matches a rule of exactly the same specificity somewhere
   above it (#statsWrap .foot.in .footin, #statsWrap .st.in and so on), so the
   block only wins by coming last. Moving it up the file silently re-enables
   whichever arrival is declared after it. */
/* ROUND 8 (review pass): the reduce block only stopped the loop and the chip pop.
   The 36px tile rise, the two head words and the sub still animated, which is the
   travel a reader who asked for less motion is asking not to see, and it also left
   .st at opacity 0 for a second on that setting. Every arrival now resolves on the
   first frame; the section is complete and still, and the scrubbed parallax stays
   because it is scroll position, not motion of its own. */
@media (prefers-reduced-motion:reduce){
  #statsWrap.st-awake .ico svg{animation:none}
  #statsWrap .st.in .ico{animation:none;opacity:1;transform:none}
  #statsWrap .st,
  #statsWrap .st.in,
  #statsWrap .ttl .w > span,
  #statsWrap .ttl .w > em,
  #statsWrap .head.in .ttl .w > span,
  #statsWrap .head.in .ttl .w > em,
  #statsWrap .sub,
  #statsWrap .head.in .sub,
  #statsWrap .footin,
  #statsWrap .foot.in .footin{animation:none;opacity:1;transform:none}
}

/* ---------- the 97-language wall (founder 2026-09-06) ----------
   One block, one arrival (the same statsRise the footnote rides, .5s after it),
   no per-chip animation. Chips are the page's small step: 12px text on a
   var(--tile) pill, the same tint as the four icon chips above. The twelve
   native-name chips carry the name in bold and the Georgian name beside it. */
#statsWrap .langs{margin-top:28px;padding:26px 18px 0;border-top:1px solid var(--line)}
#statsWrap .langsHead{display:flex;flex-wrap:wrap;align-items:baseline;gap:8px 22px}
#statsWrap .langsSub{margin:0;max-width:640px;font-size:15px;line-height:1.55;font-weight:500;color:var(--muted)}
#statsWrap .langsList{list-style:none;margin:18px 0 0;padding:0;display:flex;flex-wrap:wrap;gap:8px}
#statsWrap .lc{display:inline-flex;align-items:center;gap:5px;padding:6px 11px;border-radius:var(--r-pill);
  background:var(--tile);color:var(--ink);font-size:13px;line-height:1.2;font-weight:600;letter-spacing:-.004em;white-space:nowrap}
#statsWrap .lc-top{background:rgba(0,185,94,.11);color:var(--green-ink)}
#statsWrap .lc-top b{font-weight:800}
#statsWrap .lc-top span{font-weight:600;opacity:.8}
#statsWrap .langsMore{display:none}
#statsWrap .langsIn{display:block;opacity:0;transform:translateY(14px);--rise:14px}
#statsWrap .langs.in .langsIn{animation:statsRise .95s var(--ease) .1s both}
/* headline 3 is a numeral plus a word: the numeral keeps the aurora like 24/7,
   the word beside it is ink like the other headlines */
#statsWrap .num-lang .nw{background:none;-webkit-text-fill-color:var(--ink);color:var(--ink);font-feature-settings:normal}
@media (max-width:660px){
  #statsWrap .langs{padding:22px 0 0;margin-top:22px}
  #statsWrap .langsSub{font-size:14px}
  #statsWrap .lc{font-size:12.5px;padding:6px 10px}
}
@media (max-width:560px){
  /* twelve chips and a button; the rest opens on tap */
  #statsWrap .langsList:not(.is-open) .lc:nth-child(n+13){display:none}
  #statsWrap .langsMore{display:inline-flex;align-items:center;justify-content:center;margin-top:16px;
    min-height:44px;padding:0 20px;border-radius:var(--r-pill);border:1px solid var(--line-solid);background:var(--paper);
    color:var(--ink);font:inherit;font-size:14px;font-weight:700;cursor:pointer}
  #statsWrap .langsList.is-open + .langsMore{display:none}
}
@media (prefers-reduced-motion:reduce){
  #statsWrap .langsIn,#statsWrap .langs.in .langsIn{animation:none;opacity:1;transform:none}
}

/* ===== steps ===== */
/* STEPS: pinned deck of three onboarding steps. Same beat as the round-1 quotes
   section (fan opens, hold, cycle, hold), extended by one more cycle for the third
   card. Geometry keeps the round-1 rhythm expressed in viewport-height fractions,
   re-proportioned for a step card (wider than tall). The two teaser answers that
   used to sit under the deck moved into the full faq section that follows it. */
#stepsWrap{
  position:relative;
  /* PACING 2026-09-05: 3.4 pinned screens spent 1100px of it on three holds the
     audit read as dead scroll (600 + 300 + 200). Cut to 2.6 screens (1.6 of real
     travel) and re-timed in section.js so no hold is longer than a fifth of the
     timeline, with a real exit beat where the last hold used to sit. */
  height:260vh;
  background:var(--band);
  --ch:clamp(308px,39.4vh,344px);            /* front card height */
  --cw:min(calc(var(--ch) * 1.19),396px);    /* step card is landscape, unlike the round-1 portrait card */
  --fanrise:1;                               /* how far the open fan lifts; section.js reads it (see the tablet block) */
  /* ONE vertical anchor for the whole composition: the deck's centre. The card,
     the fan and the prev / next row are all measured off it, so the gap under the
     card is 26px at every viewport height instead of drifting with a second vh
     term of its own (at 1080 the two independent clamps left 81px there and a
     280px void under the row). The ceiling is high enough that the vh term still
     governs on any real display; it only stops the deck running away on a wall. */
  --deckY:clamp(366px,54vh,760px);
}
#stepsWrap .pin{overflow:hidden}
#stepsWrap .stStage{position:relative;width:100%;height:100%}

/* ---- heading ---- */
#stepsWrap .stHead{
  position:absolute;top:clamp(88px,13.8vh,140px);left:50%;transform:translateX(-50%);
  width:min(var(--maxw),calc(100% - 64px));text-align:center;z-index:6;pointer-events:none;
}
#stepsWrap .stHead h2{font-size:clamp(36px,3.889vw,56px);letter-spacing:-.03em;color:var(--ink);line-height:1.06}
/* Georgian has no case and needs looser tracking than the Latin headline, and the
   page-wide H2 scale is 54px KA / 56px EN (see the other sections-suppo sections) */
#stepsWrap .stHead h2:lang(ka){font-size:clamp(35px,3.75vw,54px);letter-spacing:-.012em}
/* PERF: one keyframe animation per revealed element instead of a pair of property
   transitions. Same pose, same easing, same duration; half as many animation
   objects for the engine to tick on the frame the section comes into view. */
@keyframes stRise{from{opacity:0;transform:translateY(var(--dy,20px))}to{opacity:1;transform:none}}
#stepsWrap .stWord{display:inline-block;opacity:0;--dy:20px}
#stepsWrap .stHead.in .stWord{animation:stRise .76s var(--ease) var(--d) both}
#stepsWrap .stHead .sub{
  font-size:16px;line-height:1.4;max-width:680px;margin:10px auto 0;color:var(--muted);font-weight:500;
  opacity:0;--dy:14px;
}
#stepsWrap .stHead.in .sub{animation:stRise .8s var(--ease) .30s both}

/* ---- deck ---- */
#stepsWrap .stDeck{position:absolute;left:50%;top:var(--deckY);width:0;height:0;z-index:2}

#stepsWrap .stCard{
  position:absolute;
  left:calc(var(--cw) / -2);
  top:calc(var(--ch) / -2);
  width:var(--cw);height:var(--ch);
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  padding:28px 26px 26px;text-align:center;overflow:hidden;
  background:var(--panel);border:1px solid var(--line);border-radius:var(--r-card);
  /* TOKENS 2026-09-06: the page had seven card radii and this was one of the two
     odd ones out; the literal shadow was the last hand-rolled copy of the shared
     soft shadow. Both are the token now, so a step card is the same object as a
     pricing card or a bento tile. */
  box-shadow:var(--shadow-soft);
  transform-origin:50% 55%;backface-visibility:hidden;
}
/* PERF: seven card layers plus the arrow row are promoted ONLY while the deck is
   the thing on screen. Held for the whole document they were seven rasterised
   surfaces carried across twenty-one screens of scrolling for nothing; section.js
   adds .st-live from an IntersectionObserver, which is exactly the window in which
   the scrub writes them every frame. */
#stepsWrap.st-live .stCard,
#stepsWrap.st-live .stArrows,
#stepsWrap.st-live .stArrow{will-change:transform,opacity}
/* the deck anchor is promoted only for the exit beat: an always-on
   will-change:opacity here would wrap all seven cards in one render surface for
   the 88% of the timeline in which the deck as a whole never moves.
   VERIFY 2026-09-05: .st-live is required as well. The exit class is set from the
   scrub and pin progress rests at 1 once the section has been scrolled past, so
   .st-exit alone stayed on for the whole rest of the page: measured at the footer,
   the deck was still one promoted surface wrapping all seven cards two screens
   after it had left. Chaining the two means the promotion dies with the section. */
#stepsWrap.st-live.st-exit .stDeck{will-change:transform,opacity}
#stepsWrap .stBack{
  background:linear-gradient(178deg,#FFFFFF 0%,var(--card-2) 46%,#F6F6F8 100%);
  border-color:rgba(10,10,11,.04);
  box-shadow:0 14px 28px rgba(10,10,11,.035),0 3px 10px rgba(10,10,11,.03);
  z-index:1;
}
/* the back sheets carry the real steps, dimmed to a whisper so the fan is never
   blank filler but never competes with the card at the centre */
/* PERF: no blur on the ghost content, it is at .07 opacity anyway; the blur cost a 250ms raster hitch on section entry */
#stepsWrap .stBack > *{opacity:.06}
#stepsWrap .stBack .stChip{box-shadow:none}
/* the swap fades the CONTENT, not the card surface, so the two slabs stay solid
   white through the turn instead of washing out over the band */
#stepsWrap .stFront{z-index:4}
#stepsWrap .stFront > *{opacity:var(--co,1)}
#stepsWrap .stFront[data-front="1"]{z-index:5}
#stepsWrap .stFront[data-front="2"]{z-index:6}

/* ---- card contents ---- */
#stepsWrap .stChip{
  flex:none;width:58px;height:58px;border-radius:18px;background:var(--live);
  display:grid;place-items:center;
  box-shadow:0 8px 18px rgba(0,210,106,.28);
}
#stepsWrap .stNum{font-size:21px;font-weight:800;letter-spacing:-.02em;color:var(--ink);line-height:1}
#stepsWrap .stTitle{
  font-size:20px;font-weight:800;letter-spacing:-.012em;line-height:1.22;
  margin-top:16px;color:var(--ink);max-width:22ch;
}
/* the glyph sits on a hairline rule, so a short step and a long one keep the same
   horizontal anchor where the round-1 card carried its star row */
#stepsWrap .stGlyph{display:flex;align-items:center;justify-content:center;gap:14px;margin-top:14px;color:var(--live);line-height:0}
#stepsWrap .stGlyph::before,#stepsWrap .stGlyph::after{content:"";width:46px;height:1px;background:var(--line);flex:none}
#stepsWrap .stBody{
  font-size:13.5px;font-weight:500;line-height:1.5;color:var(--muted);
  margin-top:12px;
}

/* ---- prev / next ---- */
#stepsWrap .stArrows{
  position:absolute;left:50%;top:calc(var(--deckY) + var(--ch) / 2 + 26px);transform:translateX(-50%);
  display:flex;align-items:center;gap:12px;z-index:6;
}
#stepsWrap .stArrow{
  width:50px;height:50px;border-radius:50%;
  background:var(--panel);border:1px solid var(--line);color:var(--ink);
  display:grid;place-items:center;cursor:pointer;
  box-shadow:0 2px 6px rgba(10,10,11,.04);
  transition:border-color .2s ease,background .2s ease;
}
#stepsWrap .stArrow:hover{border-color:rgba(10,10,11,.2)}
/* the deck is operable by keyboard: both buttons are in the tab order and drive
   the same scroll the thumb does, so they need a ring of their own (the same one
   the faq rows carry) rather than the UA default over a white pill */
#stepsWrap .stArrow:focus-visible{outline:2px solid var(--live);outline-offset:3px}
/* the button name lives in the markup rather than in an aria-label, so the KA/EN
   toggle translates it the way it translates everything else on the page */
#stepsWrap .stSr{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;font-size:14px}
#stepsWrap .stArrow[aria-disabled="true"]{opacity:.4;cursor:default}
#stepsWrap .stCount{
  display:inline-flex;align-items:baseline;gap:3px;min-width:34px;justify-content:center;
  font-size:13px;font-weight:700;letter-spacing:.01em;color:var(--faint);
}
#stepsWrap .stCountNow{color:var(--ink)}


/* Short viewports: the head, the deck and the buttons all have to stack inside
   one screen, under a nav whose bottom edge sits at a fixed 102px no matter how
   short the window is. Two things follow. The head is anchored in
   PIXELS, not vh, or it slides under that nav. And the buttons are anchored off
   the deck plus --ch, not off vh of their own, so the gap under the card stays
   26px instead of collapsing before the one above it does.
   Shrinking --ch alone would not be enough either, because --cw is derived from
   it: a shorter card is also a narrower card, the body rewraps onto an extra
   line and the content outgrows the box it was meant to fit. So the card keeps
   its full width here and gives up internal spacing and a little type size,
   which is the only trade that actually buys height. */
@media (max-height:800px){
  /* With the fan gone the card and the two buttons are the whole composition, so
     they are centred in what is left under the head rather than pinned high with
     200px of dead band beneath them. The head ends at about 190 at every size in
     this range, and the block under it is the card plus a 26px gap plus the 50px
     buttons, so centring it resolves to 50vh + 57 for the card's own centre. */
  #stepsWrap{--ch:clamp(288px,40vh,312px);--cw:min(396px,calc(100vw - 120px));--deckY:calc(50vh + 57px)}
  /* The fan is dropped rather than shrunk. Measured at 1440x780: the head ends
     at 185, and a sheet opened at even a third of its normal lift has its top
     corner at 165. Every way of keeping it (less lift, a lower deck, a smaller
     spread) either crosses the headline or pushes the arrows off the screen, so
     under 800px of height the deck reads as the single card the phone shows. */
  #stepsWrap .stBack{display:none}
  #stepsWrap .stHead{top:112px}                            /* the nav ends at 102: never tuck under it */
  #stepsWrap .stHead h2,#stepsWrap .stHead h2:lang(ka){font-size:clamp(30px,3.1vw,42px)}
  #stepsWrap .stHead .sub{margin-top:6px}
  #stepsWrap .stCard{padding:18px 24px}
  #stepsWrap .stChip{width:50px;height:50px;border-radius:16px}
  #stepsWrap .stNum{font-size:19px}
  #stepsWrap .stTitle{font-size:19px;margin-top:11px}
  #stepsWrap .stGlyph{margin-top:10px}
  #stepsWrap .stBody{font-size:13px;line-height:1.46;margin-top:9px}
  #stepsWrap .stArrow{width:44px;height:44px}
}


/* ============================================================
   TABLET (<=1000px). The fan sheets still open, but the deck is
   narrowed so the outer sheets stay inside the frame instead of
   running off both edges of a 820px pin.
   ============================================================ */
@media (max-width:1000px){
  #stepsWrap{
    --ch:clamp(300px,38vh,336px);--cw:min(calc(var(--ch) * 1.19),368px);
    /* At full lift the open sheets put their top corners at 150 on an 820x844
       tablet, which is 58px INSIDE the sub line. The head cannot move up (the
       island nav ends at 102) so the deck moves down and the lift is cut to a
       third: measured, that puts the highest sheet corner at 240 against a head
       that ends at 208, and still leaves 126px under the arrows. */
    --fanrise:.3;
    --deckY:clamp(400px,57vh,620px);
  }
  #stepsWrap .stHead h2{font-size:clamp(34px,4.6vw,44px)}
  #stepsWrap .stHead h2:lang(ka){font-size:clamp(32px,4.4vw,42px)}
  #stepsWrap .stHead .sub{max-width:420px;font-size:15px}
}
/* ...except on a short tablet, where the centred stack of the max-height block
   above is the one that fits: the tablet --deckY assumes a fan that is already
   gone below 800px of height, and its 400px floor would push the card too low. */
@media (max-width:1000px) and (max-height:800px){
  #stepsWrap{--deckY:calc(50vh + 57px)}
}

/* ============================================================
   PHONE (<=760px). MOBILE ROUND 2026-09-06. The phone used to get a
   single card with the fan deleted, which is the "poorer mobile
   version" the founder objected to: on the desktop this section is a
   DECK, and a deck with one card in it is a card. So the fan comes
   back, posed exactly the way the desktop poses it (same STACK and
   FAN arrays, same rotations, same lift curve) and simply cropped by
   the pin, which is what the desktop already does with its outer
   sheets against the 1180 column. What changes for the phone is only
   the two numbers the stylesheet owns: how far the fan lifts
   (--fanrise) and how far it spreads (--fanspread, read by
   section.js, which then skips the desktop spread formula).
   The INNER pair is dropped: at 344px its offset lands within a few
   pixels of the outer pair's and the two print as one thick edge.
   Everything else follows the page-wide phone system: 20px gutters,
   a 28..32 head, 15px sub, a 22px radius and 26px of inner padding,
   so nothing in the card touches its own edge.
   ============================================================ */
@media (max-width:760px){
  #stepsWrap{
    height:230vh;
    /* the card is sized to its CONTENT, not to the screen: measured at 390 the
       tallest of the six card texts runs 258px from the chip to the last line,
       so 52px of padding plus air resolves to ~320. The old 42vh made the card
       354 tall and every step floated in 100px of empty white. */
    --ch:clamp(316px,38vh,352px);
    --cw:min(calc(100vw - 40px),390px);   /* INTEGRATION 09-06: the page gutter is 20px in every other section (hero, bento, integrations, stats, pricing, faq, contact, footer all draw their cards 20..370 at 390). This card was 28px in at 390 and 62px in at 430, the only card on the page that floated narrow. Now 350 at 390 and 390 at 430, edge to edge with the rest. */
    /* REVIEW 2026-09-06: .55 threw the sheets 244px off centre, which at a 390
       frame put every visible part of them outside the pin: the screenshots came
       back with no deck at all, which is the same result as deleting them. The
       phone deck is a STACK that peeks, not a fan that opens: the sheets sit
       just outside the front card and lean, and the rise carries their top
       corners into the band between the sub line and the card. */
    --fanrise:.52;
    --fanspread:.055;                           /* section.js reads this instead of its own formula */
    /* VERIFIED 2026-09-06: this number is inert on the phone and is kept only as
       the documented spread. section.js poses the two surviving sheets from
       PH_FAN with kk = 1, so the desktop spread formula (and therefore this
       override of it) is never consulted below 760. Measured: the right-hand
       sheet's bounding box ends at 408.7 at --fanspread .050 and at .300 alike.
       The bounding box is also not a document overflow: the pin clips it and
       documentElement.scrollWidth stays 390 at every scrub point. */
    /* the deck sits low enough that the risen sheet corners clear the sub line
       (measured at 390x844: highest corner 314, the head ends at 230) */
    --deckY:calc(276px + 12vh + var(--ch) / 2);
  }
  /* the outer pair is re-enabled here (the short-viewport block above drops every
     sheet, and on a 390x780 phone that block is also live) */
  #stepsWrap .stCard:nth-of-type(1),
  #stepsWrap .stCard:nth-of-type(2){display:flex}
  #stepsWrap .stCard:nth-of-type(3),
  #stepsWrap .stCard:nth-of-type(4){display:none}
  /* the sheets carry no ghost text at this width: on the desktop the whisper of
     a step behind the card reads as another card, but at 390 the only part of a
     sheet that clears the front card is its outer third, so all the eye gets is
     half-words bleeding off both edges. Clean paper instead. */
  #stepsWrap .stBack > *{opacity:0}
  #stepsWrap .stBack{border-color:rgba(10,10,11,.07)}
  #stepsWrap .stHead{top:112px;width:calc(100% - 40px)}
  #stepsWrap .stHead h2,#stepsWrap .stHead h2:lang(ka){font-size:30px;line-height:1.1}
  #stepsWrap .stHead .sub{font-size:15px;line-height:1.45;max-width:330px;margin-top:8px}
  #stepsWrap .stCard{padding:26px 22px}
  #stepsWrap .stChip{width:46px;height:46px;border-radius:15px}
  #stepsWrap .stNum{font-size:18px}
  #stepsWrap .stTitle{font-size:18px;line-height:1.24;margin-top:12px;max-width:20ch}
  #stepsWrap .stGlyph{margin-top:11px;gap:12px}
  #stepsWrap .stGlyph::before,#stepsWrap .stGlyph::after{width:34px}
  #stepsWrap .stBody{font-size:13.5px;line-height:1.5;margin-top:10px}
  #stepsWrap .stArrows{top:calc(var(--deckY) + var(--ch) / 2 + 22px);gap:14px}
  #stepsWrap .stArrow{width:48px;height:48px}
}

/* Short phones (an iPhone SE at 667, or any phone in landscape-ish chrome):
   the head loses its sub line rather than letting the card lose its last
   sentence, because the sub repeats what the three cards already say, and the
   fan goes with it: under 700px of height there is no band above the card for
   the sheets to rise into without crossing the headline. */
@media (max-width:760px) and (max-height:700px){
  #stepsWrap{--ch:clamp(296px,50vh,340px);--deckY:calc(214px + var(--ch) / 2);--fanspread:0}
  #stepsWrap .stCard:nth-of-type(1),
  #stepsWrap .stCard:nth-of-type(2){display:none}
  #stepsWrap .stHead h2,#stepsWrap .stHead h2:lang(ka){font-size:27px}
  #stepsWrap .stHead .sub{display:none}
}

/* ===== pricing ===== */
/* ============================================================
   PRICING as a SUBSCRIPTION BUILDER (2026-09-06, the founder's brief:
   "bundle it up: ask people what you want to buy: messages, social media
   posts, advertising, calls, like 4 options with their benefits").

   One head (eyebrow, H2, lead, the monthly/yearly toggle), FOUR option
   cards in one row, each a selectable card, then ONE sticky summary bar
   that builds the bundle as the visitor picks, and one line of fine print.

   Motion: flow section (no pinning). One-shot rise+fade stagger
   (MOTION.reveal, --d delays) on the head, the four cards and the bar.
   A view-mode scrub parallaxes the card bodies and drifts the dot field.
   One idle loop: a 13 s light sweep across the summary CTA while something
   is selected. Transform/opacity only, paused off screen by .px-awake
   (IntersectionObserver, section.js), off under prefers-reduced-motion.
   will-change: 4 card bodies + the dot field = 5.
   ============================================================ */

/* overflow:clip, not hidden: clip does NOT create a scroll container, so the
   sticky summary bar keeps sticking to the viewport and the dot field, which
   hangs 40px past both edges, is still clipped away. */
#pricingWrap{scroll-margin-top:118px;position:relative;background:var(--band);overflow:clip;
  --stroke:rgba(10,10,11,.09);--sel:rgba(0,210,106,.10)}
#pricingWrap .band{position:relative;padding:96px 0 92px}
/* base.css gives .wrap 32px of inner padding, so the max-width grows by exactly
   that to land the row on a true 1180 like every other section. */
#pricingWrap .wrap{position:relative;z-index:1;max-width:calc(var(--maxw) + 64px)}

/* faint dot texture behind the cards, parallaxed by the scrub */
#pricingWrap .dots{position:absolute;left:40px;right:40px;top:150px;bottom:26px;z-index:0;will-change:transform;
  background-image:radial-gradient(circle at 1px 1px,rgba(10,10,11,.085) .9px,transparent 1.05px);background-size:39px 32px;
  -webkit-mask-image:linear-gradient(180deg,transparent 0,#000 8%,#000 80%,transparent 98%),
    linear-gradient(90deg,transparent 0,#000 6%,#000 94%,transparent 100%);
  mask-image:linear-gradient(180deg,transparent 0,#000 8%,#000 80%,transparent 98%),
    linear-gradient(90deg,transparent 0,#000 6%,#000 94%,transparent 100%);
  -webkit-mask-composite:source-in;mask-composite:intersect}

@keyframes priceRise{from{opacity:0;transform:translateY(var(--rise,18px))}to{opacity:1;transform:none}}

/* ---------- header ---------- */
#pricingWrap .head{text-align:center}
#pricingWrap .kick{--rise:10px;display:flex;justify-content:center;opacity:0;transform:translateY(10px)}
#pricingWrap .head.in .kick{animation:priceRise .8s var(--ease) both}
#pricingWrap .ttl{font-size:54px;font-weight:800;line-height:1.1;letter-spacing:-.012em;color:var(--ink);margin-top:10px}
#pricingWrap .ttl:lang(en){font-size:56px;letter-spacing:-.032em}
#pricingWrap .ttl .w{display:block}
#pricingWrap .ttl .w > *{display:inline-block;font-style:normal;opacity:0;transform:translateY(18px)}
#pricingWrap .head.in .ttl .w > *{animation:priceRise .9s var(--ease) var(--d) both}
#pricingWrap .lead{--rise:14px;font-size:16px;line-height:1.55;max-width:640px;margin:16px auto 0;color:var(--muted);
  font-weight:500;opacity:0;transform:translateY(14px)}
#pricingWrap .head.in .lead{animation:priceRise .9s var(--ease) .22s both}

/* ---------- the segmented control, once ----------
   track var(--tile), pill radius, 3px padding and gap; selected #fff on a
   1px shadow in --ink; the rest --muted-2. Billing (.bb) and volume (.sg)
   are the same object at two sizes. */
#pricingWrap .bill{--rise:12px;display:inline-flex;align-items:center;gap:3px;margin-top:20px;padding:3px;
  background:var(--tile);border:0;border-radius:var(--r-pill);opacity:0;transform:translateY(12px)}
#pricingWrap .head.in .bill{animation:priceRise .9s var(--ease) .3s both}
#pricingWrap .bb{display:inline-flex;align-items:center;gap:8px;border:0;background:transparent;cursor:pointer;
  font-size:14px;font-weight:700;letter-spacing:-.01em;color:var(--muted-2);padding:9px 18px;border-radius:var(--r-pill);
  transition:background .25s var(--ease),color .25s var(--ease)}
#pricingWrap .bb.on{background:#fff;color:var(--ink);box-shadow:0 1px 2px rgba(10,10,11,.10)}
#pricingWrap .bb:focus-visible{outline:2px solid var(--ink);outline-offset:2px}

/* ---------- the four options ---------- */
#pricingWrap .cfg{margin-top:28px}
#pricingWrap .row{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:16px;align-items:stretch}
#pricingWrap .card{--rise:28px;position:relative;background:var(--panel);border-radius:var(--r-card);overflow:hidden;
  box-shadow:var(--shadow-soft);opacity:0;transform:translateY(28px);cursor:pointer;
  transition:box-shadow .35s var(--ease),background .35s var(--ease)}
#pricingWrap .card.in{animation:priceRise 1s var(--ease) var(--d,0s) both}
#pricingWrap .card:hover{box-shadow:0 0 0 1.6px var(--line-strong),var(--shadow-soft)}
/* selected: the brand-green ring, a faint green wash, the check chip, the foot
   button flipped to its "added" state. One colour means one thing here. */
#pricingWrap .card.on{box-shadow:0 0 0 2px var(--live),var(--shadow-soft)}
#pricingWrap .card.on:hover{box-shadow:0 0 0 2px var(--live),var(--shadow-soft)}
#pricingWrap .cbody{position:relative;z-index:1;display:flex;flex-direction:column;height:100%;padding:22px 22px 20px;
  will-change:transform}

/* card head: the icon tile left, the check chip right */
#pricingWrap .ch{display:flex;align-items:center;justify-content:space-between;gap:10px}
#pricingWrap .ico{display:grid;place-items:center;width:40px;height:40px;border-radius:var(--r-chrome);
  background:var(--tile);color:var(--ink);transition:background .3s var(--ease),color .3s var(--ease)}
#pricingWrap .card.on .ico{background:var(--sel);color:var(--green-ink)}
#pricingWrap .onmark{display:grid;place-items:center;width:24px;height:24px;border-radius:50%;
  background:var(--live);color:var(--accent-ink);opacity:0;transform:scale(.55);
  transition:opacity .3s var(--ease),transform .4s var(--ease-pop)}
#pricingWrap .card.on .onmark{opacity:1;transform:none}
#pricingWrap .cname{margin-top:14px;font-size:22px;font-weight:800;letter-spacing:-.02em;line-height:1.15;color:var(--ink)}
#pricingWrap .cdesc{margin-top:5px;font-size:13px;line-height:1.4;font-weight:500;color:var(--muted);min-height:54px}

/* price */
#pricingWrap .price{display:flex;align-items:baseline;flex-wrap:wrap;gap:6px 8px;margin-top:12px;
  font-feature-settings:"tnum" 1;font-variant-numeric:tabular-nums}
#pricingWrap .was{display:none;font-size:15px;font-weight:600;color:var(--faint)}
#pricingWrap .cfg[data-bill="year"] .was{display:inline}
#pricingWrap .amt{display:inline-flex;align-items:baseline;color:var(--ink)}
#pricingWrap .amt .n{font-size:36px;font-weight:800;letter-spacing:-.035em;line-height:1.05}
/* the lari mark comes from the Georgian face, not Gilroy: its sidebearings are
   tight next to an 800-weight numeral, so it gets its own air. */
#pricingWrap .amt .cur{font-size:23px;font-weight:700;letter-spacing:-.02em;margin-left:.09em}
#pricingWrap .per{font-size:13px;font-weight:600;color:var(--muted-2)}
#pricingWrap .card.nflip .price .n,
#pricingWrap .card.nflip .price .was{animation:pxFlip .42s var(--ease)}
@keyframes pxFlip{
  0%{opacity:1;transform:translateY(0)}
  38%{opacity:0;transform:translateY(-.32em)}
  39%{opacity:0;transform:translateY(.32em)}
  100%{opacity:1;transform:translateY(0)}
}

/* volume segments: the whole track spans the card so the three call sizes
   share one width with the two message sizes */
#pricingWrap .segs{display:flex;gap:3px;padding:3px;margin-top:12px;background:var(--tile);border-radius:var(--r-pill)}
#pricingWrap .sg{flex:1 1 0;min-width:0;border:0;background:transparent;cursor:pointer;border-radius:var(--r-pill);padding:7px 6px;
  font-family:inherit;font-size:12.5px;font-weight:700;letter-spacing:-.005em;color:var(--muted-2);white-space:nowrap;
  text-align:center;transition:background .25s var(--ease),color .25s var(--ease)}
#pricingWrap .sg.on{background:#fff;color:var(--ink);box-shadow:0 1px 2px rgba(10,10,11,.10)}
#pricingWrap .sg:focus-visible{outline:2px solid var(--ink);outline-offset:2px}
/* the ads card has no volume: the slot holds one static fact in the same
   geometry, so the four price blocks stay on one line across the row */
#pricingWrap .segs--one .sg{cursor:default;color:var(--muted);font-weight:600;white-space:normal;line-height:1.2}

/* benefits */
#pricingWrap .feats{list-style:none;display:grid;gap:7px;align-content:start;flex:1;
  margin-top:14px;padding-top:14px;border-top:1px solid var(--line)}
#pricingWrap .feats li{display:flex;align-items:flex-start;gap:8px;font-size:13px;line-height:1.35;font-weight:500;color:#3A3A42}
#pricingWrap .feats svg{flex:none;margin-top:2px;color:var(--green-ink);opacity:.85}
#pricingWrap .vline > span{display:none}
#pricingWrap .card[data-v="0"] .vline .v0,
#pricingWrap .card[data-v="1"] .vline .v1,
#pricingWrap .card[data-v="2"] .vline .v2{display:inline}

/* the one fact under the list (quota, requirement) */
#pricingWrap .req{margin-top:12px;font-size:12px;line-height:1.4;font-weight:500;color:var(--muted-2)}

/* ---------- the select button: the card's foot, the real control ----------
   The whole card is a click target for the pointer; this button is the one
   the keyboard and the screen reader get (aria-pressed says the state).
   Off: ghost. On: the brand green, with the label flipped to "added". */
#pricingWrap .pick{display:flex;align-items:center;justify-content:center;width:100%;min-height:44px;margin-top:14px;flex:none;
  cursor:pointer;border-radius:var(--r-pill);background:var(--paper);border:1px solid var(--line-strong);color:var(--ink);
  font-family:inherit;font-size:14px;font-weight:700;letter-spacing:-.01em;padding:0 12px;
  transition:background .25s var(--ease),border-color .25s var(--ease),color .25s var(--ease),transform .25s var(--ease)}
#pricingWrap .pick:hover{border-color:var(--ink);background:var(--paper-3)}
#pricingWrap .pick[aria-pressed="true"]{background:var(--live);border-color:var(--live);color:var(--accent-ink)}
#pricingWrap .pick[aria-pressed="true"]:hover{background:var(--live-hover);border-color:var(--live-hover)}
#pricingWrap .pick .t-on{display:none}
#pricingWrap .pick[aria-pressed="true"] .t-off{display:none}
#pricingWrap .pick[aria-pressed="true"] .t-on{display:inline}
#pricingWrap .pick:focus-visible{outline:2px solid var(--ink);outline-offset:3px}

/* ---------- the bundle: a sticky summary ----------
   sticky to the viewport's bottom edge while the row is in view, so the total
   is never off screen while the visitor is still picking; it settles into its
   own place under the row once the row scrolls past. */
#pricingWrap .sumbar{--rise:18px;position:sticky;bottom:14px;z-index:4;margin-top:16px;
  opacity:0;transform:translateY(18px)}
#pricingWrap .sumbar.in{animation:priceRise .95s var(--ease) var(--d,0s) both}
#pricingWrap .sumbar__in{display:flex;align-items:center;gap:22px;padding:12px 12px 12px 22px;
  background:#fff;
  border:1px solid var(--stroke);border-radius:var(--r-inner);box-shadow:var(--shadow-lift)}
#pricingWrap .sumbar .col{flex:1;min-width:0}
#pricingWrap .items{display:flex;align-items:center;flex-wrap:wrap;gap:7px;min-height:30px}
#pricingWrap .items .empty{font-size:14px;font-weight:700;color:var(--ink)}
#pricingWrap .items.has .empty{display:none}
#pricingWrap .chips{display:flex;align-items:center;flex-wrap:wrap;gap:7px}
#pricingWrap .chip{display:inline-flex;align-items:baseline;gap:6px;padding:6px 11px;border-radius:var(--r-pill);
  background:var(--tile);font-size:12.5px;font-weight:600;color:var(--muted);
  font-feature-settings:"tnum" 1;font-variant-numeric:tabular-nums}
#pricingWrap .chip b{font-weight:700;color:var(--ink)}
#pricingWrap .chip i{font-style:normal}
#pricingWrap .chip.cut{background:var(--sel);color:var(--green-ink)}
#pricingWrap .chip.cut b{color:var(--green-ink)}
/* the two rules under the chips: the 15% line (hint until both are on, then
   the applied state) and the first-week note */
#pricingWrap .rule{display:flex;align-items:center;flex-wrap:wrap;gap:4px 8px;margin-top:7px;
  font-size:12px;line-height:1.35;font-weight:500;color:var(--muted-2)}
#pricingWrap .rule__hint,#pricingWrap .rule__on{display:inline-flex;align-items:center;gap:6px}
#pricingWrap .rule__on{display:none;color:var(--green-ink);font-weight:600}
#pricingWrap .sumbar.both .rule__hint{display:none}
#pricingWrap .sumbar.both .rule__on{display:inline-flex}
#pricingWrap .rdot{flex:none;width:5px;height:5px;border-radius:50%;background:var(--live)}
#pricingWrap .sep{color:var(--faint)}

#pricingWrap .tot{flex:none;display:flex;flex-direction:column;align-items:flex-end;line-height:1.15;
  font-feature-settings:"tnum" 1;font-variant-numeric:tabular-nums}
#pricingWrap .tot__row{display:inline-flex;align-items:baseline;gap:7px}
#pricingWrap .tot__was{display:none;font-size:15px;font-weight:600;color:var(--faint)}
#pricingWrap .cfg[data-bill="year"] .sumbar.has .tot__was{display:inline}
#pricingWrap .tot__n{font-size:28px;font-weight:800;letter-spacing:-.03em;color:var(--ink)}
#pricingWrap .tot__n .cur{letter-spacing:normal;margin-left:.06em}
#pricingWrap .tot__per{font-size:13px;font-weight:600;color:var(--muted-2)}
#pricingWrap .tot__s{margin-top:3px;font-size:12px;font-weight:600;color:var(--muted-2);white-space:nowrap}
#pricingWrap .ysuf{display:none}
#pricingWrap .cfg[data-bill="year"] .ysuf{display:inline}
#pricingWrap .cfg[data-bill="year"] .msuf{display:none}
#pricingWrap .ysuf .n{color:var(--ink);font-weight:700}
#pricingWrap .sumbar.flip .tot__n{animation:pxFlip .42s var(--ease)}

/* the section's ONE call to action, the shared .btn--live (44px) */
#pricingWrap .go{position:relative;overflow:hidden;flex:none;min-height:44px;padding-left:30px;padding-right:30px;
  transition:background var(--t-fast) ease,transform .25s var(--ease),box-shadow .25s var(--ease)}
#pricingWrap .go:hover{transform:translateY(-1px);box-shadow:0 10px 26px rgba(0,210,106,.32)}
#pricingWrap .go:focus-visible{outline:2px solid var(--ink);outline-offset:3px}
#pricingWrap .go__t{position:relative;z-index:1}
#pricingWrap .go::after{content:"";position:absolute;top:0;bottom:0;left:0;width:60%;z-index:0;transform:translateX(-180%);
  background:linear-gradient(100deg,rgba(255,255,255,0) 0%,rgba(255,255,255,.6) 50%,rgba(255,255,255,0) 100%)}
#pricingWrap.px-awake .sumbar.has .go::after{animation:pxSweep 13s linear infinite}
@keyframes pxSweep{0%{transform:translateX(-180%)}13%{transform:translateX(320%)}100%{transform:translateX(320%)}}

/* ---------- fine print: one line under the bar ---------- */
#pricingWrap .note{--rise:12px;margin:14px auto 0;text-align:center;font-size:12px;line-height:1.5;
  font-weight:500;color:var(--muted-2);opacity:0;transform:translateY(12px)}
#pricingWrap .note.in{animation:priceRise .9s var(--ease) .1s both}

/* ============================================================
   RESPONSIVE
   ============================================================ */
@media (max-width:1180px){
  #pricingWrap .row{gap:12px}
  #pricingWrap .cbody{padding:20px 18px 18px}
  #pricingWrap .amt .n{font-size:32px}
  #pricingWrap .amt .cur{font-size:21px}
}
/* tablet: two by two */
@media (max-width:1000px){
  #pricingWrap .ttl{font-size:5.2vw}
  #pricingWrap .ttl:lang(en){font-size:5.4vw}
  #pricingWrap .row{grid-template-columns:repeat(2,minmax(0,1fr));gap:16px}
  #pricingWrap .cbody{padding:22px 22px 20px}
  #pricingWrap .cdesc{min-height:0}
  #pricingWrap .amt .n{font-size:36px}
  #pricingWrap .amt .cur{font-size:23px}
}
/* the thumb floor holds across the whole touch range: every control 44px */
@media (max-width:860px){
  #pricingWrap .band{padding:88px 0 84px}
  #pricingWrap .ttl{font-size:44px}
  #pricingWrap .ttl:lang(en){font-size:46px}
  #pricingWrap .bb{min-height:46px}
  #pricingWrap .sg{display:inline-flex;align-items:center;justify-content:center;min-height:44px;padding:0 10px}
  #pricingWrap .segs--one .sg{min-height:44px}
  #pricingWrap .pick{min-height:48px}
}
@media (max-width:720px){
  #pricingWrap .sumbar__in{flex-wrap:wrap;gap:12px;padding:14px}
  #pricingWrap .sumbar .col{order:1;width:100%;flex:none}
  #pricingWrap .tot{order:2;flex:1;align-items:flex-start}
  #pricingWrap .go{order:3;flex:none}
}
/* ============================================================
   THE PHONE (<=560): 20px gutters, one column, H2 30/32, every control at
   least 44px tall, nothing under 12.5px, the summary stacked with a full
   width CTA and still sticky to the bottom of the screen.
   ============================================================ */
@media (max-width:560px){
  #pricingWrap .wrap{padding:0 20px}
  #pricingWrap .band{padding:80px 0 76px}
  #pricingWrap .dots{left:16px;right:26px;top:120px;bottom:20px}

  #pricingWrap .ttl{font-size:30px}
  #pricingWrap .ttl:lang(en){font-size:32px}
  #pricingWrap .lead{font-size:15px;line-height:1.5;margin-top:14px;max-width:none}

  #pricingWrap .bill{display:inline-flex;flex-wrap:nowrap;width:auto;max-width:100%;gap:3px;padding:3px;margin-top:20px}
  #pricingWrap .bb{flex-direction:row;justify-content:center;min-height:48px;padding:0 15px;gap:7px;font-size:14.5px;white-space:nowrap}

  #pricingWrap .cfg{margin-top:28px}
  #pricingWrap .row{grid-template-columns:1fr;gap:16px}
  #pricingWrap .cbody{padding:24px 22px 22px}
  #pricingWrap .cname{font-size:22px;margin-top:14px}
  #pricingWrap .cdesc{margin-top:6px;font-size:14px;line-height:1.45}
  #pricingWrap .price{margin-top:14px}
  #pricingWrap .amt .n{font-size:38px}
  #pricingWrap .amt .cur{font-size:24px}
  #pricingWrap .per{font-size:13.5px}
  #pricingWrap .was{font-size:15.5px}

  /* the track scrolls sideways under the thumb if a label set ever stops
     fitting, instead of squeezing the labels or breaking the page */
  #pricingWrap .segs{margin-top:14px;overflow-x:auto;scrollbar-width:none;-webkit-overflow-scrolling:touch}
  #pricingWrap .segs::-webkit-scrollbar{display:none}
  #pricingWrap .sg{flex:1 0 auto;min-height:44px;padding:0 12px;font-size:13px}
  #pricingWrap .segs--one .sg{flex:1 1 auto}

  #pricingWrap .feats{gap:10px;margin-top:16px;padding-top:16px}
  #pricingWrap .feats li{font-size:13.5px;line-height:1.4;gap:9px}
  #pricingWrap .feats svg{margin-top:3px}
  #pricingWrap .req{margin-top:14px;font-size:12.5px;line-height:1.4}
  #pricingWrap .pick{min-height:48px;margin-top:18px;font-size:15px}

  /* the summary, COMPACT: it is sticky over a screen a fifth as wide as the
     desktop, so it must not eat the screen. Chips on top (the discount chip is
     the visible 15% line here), the first-week note, then ONE row: the total
     left, the CTA right. The two 15% sentences are the desktop's; on the phone
     the discount chip says it. */
  #pricingWrap .sumbar{bottom:10px;margin-top:16px}
  #pricingWrap .sumbar__in{flex-direction:row;flex-wrap:wrap;align-items:center;gap:10px;padding:14px 14px 14px 16px}
  #pricingWrap .sumbar .col{order:1;width:100%;flex:none}
  #pricingWrap .items{gap:6px;min-height:0}
  #pricingWrap .items .empty{font-size:14px}
  #pricingWrap .chip{font-size:12px;padding:4px 9px;gap:5px}
  #pricingWrap .rule{margin-top:6px;font-size:12px;line-height:1.35}
  #pricingWrap .rule__hint,#pricingWrap .sumbar.both .rule__on,#pricingWrap .sep{display:none}
  #pricingWrap .tot{order:2;flex:1;min-width:0;align-items:flex-start}
  #pricingWrap .tot__n{font-size:26px}
  #pricingWrap .tot__was{font-size:13px}
  #pricingWrap .tot__per{font-size:12.5px}
  #pricingWrap .tot__s{margin-top:1px;font-size:12px;white-space:normal}
  #pricingWrap .msuf{display:none}
  #pricingWrap .go{order:3;flex:none;width:auto;min-height:48px;padding-left:26px;padding-right:26px}

  #pricingWrap .note{margin-top:16px;font-size:12.5px;line-height:1.55}
}

/* ---------- reduced motion: every idle loop stops, nothing is left mid state ---------- */
@media (prefers-reduced-motion:reduce){
  #pricingWrap .go::after{animation:none;transform:translateX(-180%)}
  #pricingWrap.px-awake .sumbar.has .go::after{animation:none}
}

/* ===== faq ===== */
/* ============================================================
   SUPPO / FAQ   "ის, რის კითხვასაც აპირებდით" / "The things you were about to ask"
   New flow section, the full list the live site carries (8 approved
   pairs, verbatim). Composition is the live site's: a sticky title
   column on the left, the accordion on the right, one hairline per
   row and a counter in the gutter. Choreography is this page's: the
   headline slides up per phrase like stats and steps, the rows rise
   one by one as they arrive, and one scrubbed
   beat (the rail under the title) tracks progress through the list.
   The answers open on measured height, driven from section.js.
   ============================================================ */
/* PACING 2026-09-05: 104 + 100 of padding on this section met the closing
   section's own 132 top, which put 232px of empty white between the last answer
   and the next headline. Trimmed to the 92 the other flow sections use, and the
   foot cut to 72 because the band below carries the air. */
/* RHYTHM 2026-09-06: 96 / 92, the tail's band rhythm. The 72 foot was cut when
   the closing band still carried 132 of its own top padding; that band is 96 / 92
   now too, so a 72 here left the list sitting closer to the section below it than
   to its own heading. */
#faqWrap{position:relative;background:var(--panel);padding:96px 0 92px}

#faqWrap .fqIn{
  width:min(var(--maxw),calc(100% - 64px));margin:0 auto;
  /* AUDIT 2026-09-06: at 5fr / 7fr the sticky column held a kicker, a two-line
     headline and a 260px rail against 2,100px of accordion, and the 601px of white
     under it was the largest single void on the page. The column is narrower now
     and it carries a line that earns the height it does keep. */
  display:grid;grid-template-columns:minmax(0,4fr) minmax(0,8fr);gap:40px 72px;align-items:start;
}

/* ---------- left: sticky title column ---------- */
/* 112px clears the island nav (its bottom edge sits at 102) */
#faqWrap .fqHead{position:sticky;top:112px}
/* PERF 2026-09-05: every reveal in this section is ONE keyframe animation rather
   than a pair of property transitions. Identical to the eye (same offsets, same
   easing, same durations) but the animation engine holds half as many objects:
   the audit counted 22 running inside this section on entry and now counts 11. */
@keyframes fqRise{from{opacity:0;transform:translateY(var(--dy,20px))}to{opacity:1;transform:none}}
/* TOKENS 2026-09-06: the label itself is the shared .eyebrow (12/700, .14em,
   --muted-2, the 6px live dot, Mtavruli by font-feature rather than by
   text-transform). All this section still owns is the state the reveal animates
   from, which is why the class pair is kept rather than the rule. */
#faqWrap .fqKicker{opacity:0;--dy:12px}
#faqWrap .fqHead.in .fqKicker{animation:fqRise .7s var(--ease) both}

#faqWrap .fqTtl{
/* 46 not the page-wide 54: this headline lives in a narrow column and at 54 the
   Georgian outgrows it. At 4fr it sets as a three-line staircase in both
   languages, which is the shape this column is now built around. */
  margin-top:18px;font-size:46px;line-height:1.1;letter-spacing:-.012em;font-weight:800;color:var(--ink);
}
#faqWrap .fqTtl:lang(en){font-size:48px;letter-spacing:-.03em}
#faqWrap .fqTtl .w{display:inline-block}
#faqWrap .fqTtl .w > span,
#faqWrap .fqTtl .w > em{display:inline-block;opacity:0;--dy:20px}
#faqWrap .fqHead.in .fqTtl .w > span,
#faqWrap .fqHead.in .fqTtl .w > em{animation:fqRise .88s var(--ease) var(--d) both}

/* the one scrubbed beat: a rail that fills in the aurora as the list
   travels through the viewport, so the sticky column is not inert */
#faqWrap .fqRail{display:block;margin-top:34px;height:2px;width:100%;max-width:260px;background:var(--line);border-radius:2px;overflow:hidden}
#faqWrap .fqRail i{display:block;height:100%;width:100%;background:var(--grad);border-radius:2px;
  transform:scaleX(0);transform-origin:0 50%}
/* PERF VERIFY 2026-09-05: the rail was the one element in this section holding a
   will-change for the whole document. The scrub only writes it while the section
   is travelling the viewport, so the promotion is gated on the same window: the
   observer in section.js adds .fq-live. Off screen the aurora gradient is no
   longer a rasterised surface the compositor has to keep. */
#faqWrap.fq-live .fqRail i{will-change:transform}

/* ---------- the ask line ----------
   The last thing the sticky column says, and the reason it is allowed to be
   sticky: a reader who has run out of questions can see where to send the one
   the list did not answer, from anywhere in the list. It rides the same rise as
   the rail above it, one beat later. */
#faqWrap .fqAsk{
  margin-top:30px;max-width:26ch;
  font-size:14.5px;line-height:1.6;font-weight:500;color:var(--muted);
  opacity:0;--dy:16px;
}
#faqWrap .fqHead.in .fqAsk{animation:fqRise .8s var(--ease) .34s both}
#faqWrap .fqAskLink{
  display:inline-block;margin-top:4px;
  color:var(--ink);font-weight:600;text-decoration:none;
  border-bottom:1px solid var(--line-solid);
  transition:border-color .2s ease;
}
#faqWrap .fqAskLink:hover{border-color:var(--ink)}
#faqWrap .fqAskLink:focus-visible{outline:2px solid var(--live);outline-offset:3px;border-radius:4px}

/* ---------- right: the accordion ---------- */
#faqWrap .fqList{border-top:1px solid var(--line);counter-reset:fq}
/* PERF 2026-09-05: the reveal used to fire from the LIST, so all eight rows
   transitioned at once and the audit caught 22 animations running inside this
   section. Each row is now revealed on its own as it arrives, the residual
   stagger is cut from .42s to .12s and the durations from .8/.9s to .6/.68s, so
   the compositor is asked for two or three rows at a time instead of eight, and
   the reveal is over before the next scroll burst lands. The beat is the same:
   the rows still rise in order, driven by the scroll rather than by a timer. */
#faqWrap .fqItem{
  border-bottom:1px solid var(--line);counter-increment:fq;
  opacity:0;--dy:22px;
}
#faqWrap .fqItem.in{animation:fqRise .64s var(--ease) var(--d) both}

#faqWrap .fqQ{
  list-style:none;cursor:pointer;display:grid;grid-template-columns:44px minmax(0,1fr) 34px;
  align-items:center;gap:14px;padding:22px 0;
}
#faqWrap .fqQ::-webkit-details-marker{display:none}
#faqWrap .fqQ::before{
  content:counter(fq,decimal-leading-zero);
  font-size:12px;letter-spacing:.14em;font-weight:700;color:var(--faint);
  font-variant-numeric:tabular-nums;transition:color .2s ease;
}
#faqWrap .fqQ::after{
  content:"";width:34px;height:34px;border-radius:50%;
  border:1px solid var(--line);background:#fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2 4.2l4 4 4-4' fill='none' stroke='%230A0A0B' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center/12px no-repeat;
  transition:transform .5s var(--ease),background-color .25s ease,border-color .25s ease;
}
#faqWrap .fqQt{
  font-size:17.5px;font-weight:600;line-height:1.45;color:var(--ink);letter-spacing:-.008em;
  transition:color .2s ease;
}
#faqWrap .fqQ:hover::after{border-color:rgba(10,10,11,.28)}
#faqWrap .fqQ:hover::before{color:var(--ink)}
/* the summary is the tab stop, so it must show a ring of its own */
#faqWrap .fqQ:focus-visible{outline:2px solid var(--live);outline-offset:4px;border-radius:12px}
#faqWrap .fqItem.is-open .fqQ::before{color:var(--ink)}
#faqWrap .fqItem.is-open .fqQ::after{
  transform:rotate(180deg);border-color:var(--ink);
  background:var(--ink) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2 4.2l4 4 4-4' fill='none' stroke='%23fff' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center/12px no-repeat;
}

/* the height animation runs on the BOX and the padding lives on the
   paragraph inside it, so a collapsed row is 0 tall and not 26 */
/* the open/close slide is the one height animation on the page; containment keeps
   the relayout it forces inside the row instead of walking the whole list */
#faqWrap .fqA{overflow:hidden;contain:layout paint}
#faqWrap .fqA.is-anim{transition:height .5s var(--ease),opacity .5s var(--ease)}
#faqWrap .fqAt{
  padding:0 48px 26px 58px;color:var(--muted);font-size:15.5px;line-height:1.7;font-weight:500;
}

/* ---------- tablet ---------- */
@media (max-width:1000px){
  #faqWrap{padding:84px 0 64px}
  #faqWrap .fqIn{grid-template-columns:1fr;gap:34px}
  #faqWrap .fqHead{position:static}
  #faqWrap .fqTtl{font-size:42px}
  #faqWrap .fqTtl:lang(en){font-size:44px}
  #faqWrap .fqRail{margin-top:26px;max-width:200px}
  #faqWrap .fqAsk{margin-top:22px;max-width:none}
  #faqWrap .fqAt{padding:0 24px 24px 58px}
}

/* ---------- phone ---------- */
/* MOBILE ROUND 2026-09-06. The page-wide phone system: 20px gutters, a 72px
   section rhythm, a 28..32 head, rows that are at least 56px tall so a thumb
   can hit one without aiming, and an answer that starts under its own question
   rather than under a 58px hanging indent (at 390 that indent left the answer
   sixteen characters wide). The numeral gutter narrows with it, and the toggle
   grows back to 32px so the glyph sits on the same optical centre as the first
   line of the question instead of drifting toward the middle of a two-line row. */
@media (max-width:760px){
  #faqWrap{padding:72px 0 60px}
  #faqWrap .fqIn{width:calc(100% - 40px);gap:26px}
  #faqWrap .fqTtl{margin-top:14px;font-size:32px;line-height:1.12}
  #faqWrap .fqTtl:lang(en){font-size:33px}
  #faqWrap .fqRail{margin-top:20px;max-width:160px}
  #faqWrap .fqAsk{margin-top:18px;font-size:14px}
  /* the row: 30px numeral, the question, a 32px toggle. 19px of padding puts a
     one-line question at 60px and a two-line one at 82, both comfortably over
     the 44px a thumb needs and over the 56 the phone system asks for. */
  #faqWrap .fqQ{grid-template-columns:30px minmax(0,1fr) 32px;gap:10px;padding:19px 0}
  #faqWrap .fqQ::before{align-self:start;padding-top:2px}
  #faqWrap .fqQ::after{width:32px;height:32px;background-size:12px;align-self:start}
  #faqWrap .fqItem.is-open .fqQ::after{background-size:12px}
  #faqWrap .fqQt{font-size:16px;line-height:1.4}
  #faqWrap .fqAt{padding:0 0 22px 40px;font-size:15px;line-height:1.62}
}

/* ===== contact ===== */
/* ============================================================
   SUPPO / CONTACT   "უპასუხო მიმართვა დაკარგული მომხმარებელია"
                     "A message left unanswered is a lost customer"
   The closing beat, on the live site's aurora mesh band. The mesh
   itself (.band--mesh, .mesh, .mesh--close) is the shared layer in
   shared/live-chrome.css; what this file adds is the DRIFT the live
   stylesheet gives those blobs, scoped to this section so no other
   section inherits a loop it did not ask for.

   Colour is atmosphere here and never a reading surface: the blobs
   sit behind the type at z-index -1 and .mesh__clear paints a static
   radial clearing over them, so the headline reads on paper, not on
   a flat white scrim.

   PERF ROUND: there is now NO filter in this section at all. The shared
   .mesh i carries blur(56px), and five of those under a section that is
   also running a scrubbed transform meant five blurred render surfaces
   the compositor re-resolved whenever anything above them moved. The
   field is three layers now (green, blue, violet: the aurora), each one
   a plain gradient box whose softness lives in a long alpha ramp instead
   of a filter, and only translate3d moves. Same look, one paint.
   ============================================================ */
/* The field was five blobs; it is three now. What the missing two carried was
   not motion, it was the SATURATION at the walls, so that comes back as a static
   background paint on the section itself: three gradients whose centres sit past
   the edges (a background can do that, an element box cannot without overflowing)
   under the three that drift. Static paint, no layer, no per-frame cost, and the
   band reads at the same strength as the five-blob version. */
#contactWrap{
  /* RHYTHM 2026-09-06: 96 / 92, the tail's band rhythm, shared with the questions
     above. 112 / 116 was set when the faq below it stopped on a 72 foot. */
  position:relative;padding:96px 0 92px;overflow:hidden;
  background:
    radial-gradient(58% 88% at -6% 44%,rgba(93,255,195,.62) 0%,rgba(93,255,195,.34) 38%,rgba(93,255,195,.12) 66%,rgba(93,255,195,0) 88%),
    radial-gradient(56% 86% at 106% 38%,rgba(62,197,255,.62) 0%,rgba(62,197,255,.34) 38%,rgba(62,197,255,.12) 66%,rgba(62,197,255,0) 88%),
    radial-gradient(50% 66% at 46% 122%,rgba(138,124,255,.55) 0%,rgba(138,124,255,.30) 38%,rgba(138,124,255,.10) 66%,rgba(138,124,255,0) 88%),
    var(--panel);
}

/* the blur override, plus the pre-softened stops that replace it. rgb triplets
   rather than the shared --m* hexes, because the alpha ramp needs the channels. */
#contactWrap .mesh i{
  filter:none;
  background:radial-gradient(closest-side circle at 50% 50%,
    rgba(var(--cc),.92) 0%,rgba(var(--cc),.80) 15%,rgba(var(--cc),.60) 32%,
    rgba(var(--cc),.38) 50%,rgba(var(--cc),.20) 67%,rgba(var(--cc),.08) 82%,
    rgba(var(--cc),0) 100%);
}
#contactWrap .mesh i:nth-child(1){--cc:93,255,195}    /* --m1 #5DFFC3 */
#contactWrap .mesh i:nth-child(2){--cc:62,197,255}    /* --m2 #3EC5FF */
#contactWrap .mesh i:nth-child(3){--cc:138,124,255}   /* --m3 #8A7CFF */
/* The shared rule parks the blue blob past the RIGHT wall (right:-14%) and the
   drift carries it 9vw further, which is the one thing the overflow probe
   flags on this section. Overhang to the left is free, so the blob is pulled
   back to a left offset whose right edge lands on the wall at its furthest
   drift. The ellipse fades to zero at its own edge now, so nothing is cut. */
#contactWrap .mesh i:nth-child(2){right:auto;left:49%}
/* the drifting layers sit on the static ground, so they carry the movement
   rather than all of the colour */
#contactWrap .mesh i{opacity:.62}

/* the drift: transform only, long and out of phase so the field never
   reads as a loop. Parked until the section is on screen (section.js
   flips .ct-awake from an IntersectionObserver). */
#contactWrap .mesh i{
  animation:ctDrift var(--dur,22s) ease-in-out var(--del,0s) infinite alternate;
  animation-play-state:paused;
}
#contactWrap.ct-awake .mesh i{animation-play-state:running}
#contactWrap .mesh i:nth-child(1){--dur:21s;--del:-3s}
#contactWrap .mesh i:nth-child(2){--dur:26s;--del:-9s}
#contactWrap .mesh i:nth-child(3){--dur:23s;--del:-5s}
@keyframes ctDrift{
  0%  {transform:translate3d(0,0,0)}
  34% {transform:translate3d(9vw,5vh,0)}
  67% {transform:translate3d(-7vw,9vh,0)}
  100%{transform:translate3d(5vw,-5vh,0)}
}

/* ---------- the column ---------- */
#contactWrap .ctIn{
  position:relative;width:min(var(--maxw),calc(100% - 64px));margin:0 auto;
  display:flex;flex-direction:column;align-items:center;text-align:center;
  /* the only element in this section the scrub writes every frame */
  will-change:transform;
}

/* TOKENS 2026-09-06: the label is the shared .eyebrow, exactly as the questions
   section's is. Nothing but the reveal state is local to this section now. */
#contactWrap .ctKicker{opacity:0;--rise:20px}

/* the clearing that comes with .mesh--close is a radial only, so the band
   would butt hard against the white section above and the footer below.
   These two linear stops melt both edges into paper. Static layer, no cost. */
#contactWrap .mesh--close .mesh__clear{
  background:
    radial-gradient(56% 56% at 50% 42%,rgba(255,255,255,.60) 0%,rgba(255,255,255,0) 72%),
    /* SEAM 2026-09-06: percentages of a band whose height changes with the copy
       and the viewport gave a melt that was 34px deep at 390 and 170 at 2000, so
       on a phone the band met the white above it as a hard step. Fixed pixels
       instead, and the bottom stop lands on --paper-2, which is the ground the
       closing block below actually paints, rather than on white. */
    linear-gradient(var(--panel) 0,rgba(255,255,255,0) 140px),
    linear-gradient(rgba(255,255,255,0) calc(100% - 160px),var(--paper-2) 100%);
}

/* 760px, not the live site's 18ch: ch is measured off the Latin zero and the
   Georgian is wider per glyph, so at 18ch the second phrase snaps in half and
   the closing line lands on three ragged rows instead of two. 860 is the
   measured width of the longest phrase in either language plus a little air. */
#contactWrap .ctTtl{
  margin-top:20px;max-width:860px;
  font-size:54px;line-height:1.08;letter-spacing:-.012em;font-weight:800;color:var(--ink);
}
#contactWrap .ctTtl:lang(en){font-size:56px;letter-spacing:-.03em}
#contactWrap .ctTtl .w{display:inline-block}
#contactWrap .ctTtl .w > span{display:inline-block;opacity:0;--rise:32px}

/* 16 / 1.55, the page's body scale. 17 / 1.62 was the one lede on the page set
   larger than the rest, and next to the 54px headline above it the extra point
   read as a second heading rather than as a line of prose. */
#contactWrap .ctLede{
  margin-top:20px;max-width:56ch;font-size:16px;line-height:1.55;font-weight:500;color:var(--muted);
  opacity:0;--rise:20px;
}

#contactWrap .ctCtas{
  margin-top:34px;display:flex;flex-wrap:wrap;gap:12px;justify-content:center;
  opacity:0;--rise:20px;
}

/* ---------- the reveal ----------
   PERF 2026-09-06: this was the last section on the page built out of property
   transitions. Eight of them (four elements, opacity and transform each) were
   held by the animation engine for the whole document, because a transition's
   "from" state is a live declaration and not a keyframe that ends. One keyframe
   per element now, the same shape pricing uses, on a 0 / .08s / .16s ladder:
   the two headline phrases are the card tier (32px over 1s), the label, the lede
   and the button row are the item tier (20px over .7s). Same arrival to the eye,
   half the objects, and every one of them finishes and is dropped. */
@keyframes ctRise{from{opacity:0;transform:translateY(var(--rise,20px))}to{opacity:1;transform:none}}
#contactWrap .ctIn.in .ctKicker{animation:ctRise .7s var(--ease) both}
#contactWrap .ctIn.in .ctTtl .w > span{animation:ctRise 1s var(--ease) var(--d,0s) both}
#contactWrap .ctIn.in .ctLede{animation:ctRise .7s var(--ease) .08s both}
#contactWrap .ctIn.in .ctCtas{animation:ctRise .7s var(--ease) .16s both}
#contactWrap .ctCtas .btn:hover{transform:translateY(-1px)}
#contactWrap .ctCtas .btn:focus-visible{outline:2px solid var(--ink);outline-offset:3px}

/* Phones take the shared 92vw blob, which cannot fit next to a 9vw drift: the
   blob is trimmed and the drift halved. Half the travel on a box that wide is
   also the cheaper loop, and at this size the field reads the same. */
@media (max-width:900px){
  #contactWrap .mesh i{width:88vw;height:88vw;animation-name:ctDriftNarrow}
  #contactWrap .mesh i:nth-child(1){left:-24%;top:-18%}
  #contactWrap .mesh i:nth-child(2){left:6%;top:-22%}
  #contactWrap .mesh i:nth-child(3){left:0;bottom:-30%}
}
@keyframes ctDriftNarrow{
  0%  {transform:translate3d(0,0,0)}
  34% {transform:translate3d(5vw,4vh,0)}
  67% {transform:translate3d(-4vw,7vh,0)}
  100%{transform:translate3d(3vw,-4vh,0)}
}

/* ---------- tablet ---------- */
@media (max-width:1000px){
  #contactWrap{padding:92px 0 96px}
  #contactWrap .ctTtl{font-size:42px}
  #contactWrap .ctTtl:lang(en){font-size:44px}
  #contactWrap .ctLede{max-width:46ch}
}

/* ---------- phone ---------- */
/* MOBILE ROUND 2026-09-06. The page-wide phone system: 20px gutters, a 28..32
   head, a 15px lede, and the two pills stacked full width with a 16px gap.
   Side by side at 390 they would each be about 165px and the Georgian CTA does
   not fit on one line in that box; stacked, both are 52px tall, which is over
   the 44px a thumb needs. The lede is given the full column rather than a 38ch
   measure: at this width 38ch was breaking the last sentence onto a two-word
   line under a paragraph that had room for it. */
@media (max-width:760px){
  #contactWrap{padding:76px 0 80px}
  #contactWrap .ctIn{width:calc(100% - 40px)}
  #contactWrap .ctTtl{margin-top:16px;font-size:31px;line-height:1.14;max-width:none}
  #contactWrap .ctTtl:lang(en){font-size:32px}
  #contactWrap .ctLede{margin-top:18px;font-size:15px;line-height:1.6;max-width:42ch}
  #contactWrap .ctCtas{margin-top:28px;flex-direction:column;align-self:stretch;gap:16px}
  #contactWrap .ctCtas .btn{width:100%;min-height:52px}
}

#contactWrap .ctLine{margin-top:20px;font-size:15px;color:var(--ink-2,#666)}
#contactWrap .ctLine a{color:inherit;text-decoration:none;border-bottom:1px solid currentColor}

/* ===== footer ===== */
/* ---------- FOOTER (Suppo) : the live site's footer, in flow ----------
   Founder decision 2026-09-04: the chrome is the live site's, so this section is not a
   floating white panel. It is the live footer element exactly as suppo.ge builds it
   (paper-2 band under one hairline, 1.6fr + 3 column grid, bottom rule).

   FOUNDER 2026-09-06: the giant ghost wordmark is gone. It was a pinned closing screen
   whose whole reason to exist was one beat, the sharp edge of a static mask sweeping a
   hairline-coloured "Suppo." in from the left. He asked for it removed fully, so the
   markup, the mask, the sliding stage, the phone veil, the will-change on the three
   type layers, the 150vh wrapper and the scrub that drove it all left with it. What is
   left is the footer as a footer: it sits on the page ground at its natural height and
   the rows arrive once on a soft MOTION.reveal.

   The wrapper markup is byte-compatible with the lift build-legal.py performs on the
   footer element, so the legal pages keep following it. That lift is a regex on the
   opening tag, so this comment must never spell that tag out. */
#footerWrap{
  position:relative;
  background:var(--paper-2);
}
/* INTEGRATOR 2026-09-05: same one-column fix as pricing. The lifted footer rules give
   the footer's own wrap a 24px inner padding (right for the live site, where every band
   shares it), which left this grid on a 1132px column under sections that sit on 1180.
   Scoped to this section so the legal pages, whose reading column IS 1132, keep theirs. */
#footerWrap .footer > .wrap{max-width:calc(var(--maxw) + 48px)}

/* the shared band is 64/40; the closing block wants a little more air above it now that
   nothing hangs below the columns, and a little more under the rule so the page does not
   stop on the copyright line */
#footerWrap .footer{padding:88px 0 56px}

/* ---------- rows ----------
   PERF 2026-09-05 / 2026-09-06: nothing here is scrubbed and nothing is promoted. The
   settled state IS the CSS, so a page whose JS never runs shows a finished footer; the
   entry below only exists while .in is on the footer, and it is transform + opacity. */
#footerWrap .fRow{opacity:1}
#footerWrap .fBlurb{margin-top:18px;max-width:30ch}
#footerWrap .fSocial{
  display:flex;
  gap:8px;
  margin-top:22px;
}
#footerWrap .fBtn{
  width:38px;height:38px;
  border-radius:100px;
  border:1px solid var(--line-solid);
  background:var(--paper);
  color:var(--ink);
  display:grid;place-items:center;
  transition:border-color .2s ease,background .2s ease;
}
#footerWrap .fBtn[hidden]{display:none}
#footerWrap .fBtn:hover{border-color:var(--ink);background:var(--paper-3)}

/* ---------- the registered entity ----------
   REVIEW 2026-09-06: the page carried no trust signal of any kind and the one it
   is entitled to show was one click away on contact.html. A registered Georgian
   company with a public identification number is a fact, not a claim, so it sits
   in the closing block where a visitor looks for it. <address> because that is
   what the element is for; the italic every UA gives it is turned off. Set at the
   .meta size the column already uses, one notch quieter than the blurb above it,
   so it reads as a colophon rather than as a second paragraph. */
/* Scoped to .footer and NOT to #footerWrap, unlike everything else in this file.
   build-legal.py lifts the footer ELEMENT onto the seven legal pages and onto
   contact and 404, and the section wrapper does not travel with it; a rule under
   #footerWrap would leave the entity block unstyled (and italic, since it is an
   <address>) on nine of the ten built pages. .footer is the element that does
   travel, so the block is the same object everywhere it appears. */
.footer .fCompany{
  margin-top:22px;font-style:normal;
  display:flex;flex-direction:column;gap:3px;
  font-size:13px;line-height:1.55;
  color:var(--muted-2);
}
.footer .fCoName{color:var(--muted);font-weight:600}
.footer .fCoNum{font-variant-numeric:tabular-nums;letter-spacing:.01em}

/* ---------- the brand lockup ----------
   FOUNDER 2026-09-06: "use the proper logo here". The column used to carry a bare tracked
   word. It now carries the NAV's lockup: the founder's headset vector inline (the real
   file, favicon.svg, never redrawn) beside the wordmark, at the nav's own
   proportions scaled to 32px tall, which is 32/35 of the island's mark. Gap and type
   scale with it (12 -> 11, 17 -> 16) so the two read as the same object.

   Ink, not white: the island paints .brand__mark #fff because it sits on the dark pill;
   here the ground is paper, so the mark takes the shared default (--ink for the shell and
   the two outer bars, --live for the middle bar and the mic dot) and the wordmark takes
   the shared .footer .brand__name ink.

   The three bars breathe in the island because the island is always on screen and that
   loop is the page's one always-on animation. A second copy of it down here would be a
   second perpetual loop under the live dot's ring, and the closing block is where the
   page settles, so the footer mark is still. */
#footerWrap .fIntro .brand{
  display:inline-flex;
  align-items:center;
  gap:11px;
  text-decoration:none;
}
#footerWrap .fIntro .brand__mark{width:35px;height:32px;color:var(--ink)}
#footerWrap .fIntro .brand__mark .m-bar{animation:none}
#footerWrap .fIntro .brand__name{font-size:16px;letter-spacing:.15em;color:var(--ink)}

/* the live dot's ring ships paused in the shared chrome; the closing block is the only
   place it appears, so this section is what wakes it, and only while it is on screen */
#footerWrap.f-awake .dot-live::after{animation-play-state:running}

/* ---------- entry ----------
   One soft arrival, fired once by MOTION.reveal on the footer element, staggered down the
   four columns and then the bottom rule. transform + opacity only, no promotion: five
   short animations that run once and are never asked for again. */
#footerWrap .footer.in .fRow{animation:fRowRise .8s var(--ease) var(--d,0s) both}
#footerWrap .footer.in .fIntro{--d:0s}
#footerWrap .footer.in .fCol:nth-of-type(2){--d:.06s}
#footerWrap .footer.in .fCol:nth-of-type(3){--d:.12s}
#footerWrap .footer.in .fCol:nth-of-type(4){--d:.18s}
#footerWrap .footer.in .footer__bottom{--d:.26s}
@keyframes fRowRise{from{opacity:0;transform:translate3d(0,18px,0)}to{opacity:1;transform:none}}

/* ---------- narrower viewports ----------
   Two columns at tablet come from the shared chrome; on phones a full-width intro and one
   column of links. Nothing drops below 13px. */
@media (max-width:900px){
  #footerWrap .footer{padding:72px 0 48px}
  #footerWrap .fBlurb{max-width:34ch}
}

/* ---------- PHONE (<=640px) ----------
   MOBILE ROUND 2026-09-06: the columns stack one per row with 24px between and every link
   is given a 44px tap target, so the spacing IS the tap area. */
@media (max-width:640px){
  #footerWrap .footer{padding:64px 0 40px}
  #footerWrap .footer > .wrap{padding-left:20px;padding-right:20px}

  #footerWrap .footer__grid{grid-template-columns:1fr;gap:24px}
  #footerWrap .fIntro{grid-column:auto}
  #footerWrap .fBlurb{margin-top:12px;max-width:38ch}
  #footerWrap .fSocial{margin-top:18px;gap:10px}
  .footer .fCompany{margin-top:20px}
  #footerWrap .fBtn{width:44px;height:44px}
  /* every link is a 44px target: the list gives up its own gap and each row carries the
     height instead */
  #footerWrap .footer ul{margin-top:6px;gap:0}
  #footerWrap .footer li a{display:flex;align-items:center;min-height:44px;font-size:15px}
  #footerWrap .fCol:last-child{grid-column:auto}
  #footerWrap .fCol:last-child ul{display:flex;grid-template-columns:none;gap:0}

  #footerWrap .footer__bottom{margin-top:32px;padding-top:20px;gap:10px}
  /* the entity line and the live signature are two separate statements. In KA the entity
     line already fills the row and the signature wraps on its own; in EN it does not, and
     "Tech Nation Global LLC" ran straight into the green dot as if it were one sentence.
     Give the signature the whole next row in both languages. */
  #footerWrap .footer__sig{flex:0 0 100%;margin-left:0}
}