/* Figtree, self-hosted. SIL Open Font License 1.1, which permits redistribution.
   Serving it ourselves removes the last third-party origin from the page, which
   is what allows the Content-Security-Policy to name no external hosts at all,
   and it stops Google receiving a visitor's IP on every page view. */
@font-face{font-family:'Figtree';font-style:normal;font-weight:400 800;font-display:swap;
  src:url('/assets/figtree-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:'Figtree';font-style:normal;font-weight:400 800;font-display:swap;
  src:url('/assets/figtree-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}

/* ═══════════════════════════════════════════════════════════════════════════
   PALETTE
   The previous version leaned on one teal-to-coral gradient for headings,
   eyebrows, buttons, the logo and two big blurred radial blobs. That specific
   combination (soft mesh gradient + gradient-filled text) is the visual signature
   of a generated page, which is a bad look for a product whose whole claim is
   that it does not sound generated.
   So: no gradient text anywhere, no decorative radial glows, one accent used
   decisively, and hierarchy carried by weight, scale and rules instead of colour
   washes. Gradients survive in exactly one place, simulating brushed metal on the
   phone, where they are describing a material rather than decorating a heading.
   ═══════════════════════════════════════════════════════════════════════════ */
:root{
  --ink:#12201E;           /* near-black, faint green cast */
  --muted:#5A6B67;
  --line:#E4DFD5;
  --bg:#FBF9F5;            /* warm paper, never #FFF: pure white reads clinical */
  --panel:#F3EFE7;
  --teal:#0E6E63;          /* the one accent, always flat */
  --teal-deep:#0A544B;
  --navy:#0C1A18;          /* dark sections */
  --ember:#C4602F;         /* used ONLY for loss/urgency, never decoration */
  --ff:"Figtree",sans-serif;

  /* WhatsApp dark mode, matched to the real client */
  --wa-bg:#0B141A;--wa-head:#1F2C34;--wa-in:#1F2C34;--wa-out:#005C4B;
  --wa-ink:#E9EDEF;--wa-dim:#8696A0;--wa-tick:#53BDEB;
}
*{margin:0;padding:0;box-sizing:border-box}
html{scroll-behavior:smooth}
body{font-family:var(--ff);background:var(--bg);color:var(--ink);font-size:17px;line-height:1.6;-webkit-font-smoothing:antialiased;overflow-x:hidden}
::selection{background:var(--teal);color:#fff}
a{color:inherit}
:focus-visible{outline:2px solid var(--teal);outline-offset:3px;border-radius:4px}
.wrap{max-width:1180px;margin:0 auto;padding:0 28px}
h1,h2,h3{font-weight:800;letter-spacing:-.025em;line-height:1.05}
h2{font-size:clamp(32px,4.4vw,50px)}

/* Eyebrow: a flat rule plus small caps. Was gradient-filled text. */
.eyebrow{font-size:12.5px;letter-spacing:.16em;text-transform:uppercase;font-weight:700;color:var(--teal);display:inline-flex;align-items:center;gap:10px}
.eyebrow::before{content:"";width:26px;height:2px;background:var(--teal);flex:none}
.dark .eyebrow{color:#6FD3C4}.dark .eyebrow::before{background:#6FD3C4}

/* Emphasis is a colour swap, not a gradient fill. */
.gtext{color:var(--teal)}
.dark .gtext{color:#6FD3C4}
.etext{color:var(--ember)}

.btn{display:inline-flex;align-items:center;gap:10px;padding:15px 28px;border-radius:999px;font-weight:700;font-size:15.5px;text-decoration:none;transition:transform .3s cubic-bezier(.2,.8,.2,1),box-shadow .3s,background .3s,border-color .3s;position:relative}
.btn:hover{transform:translateY(-2px)}
.btn-primary{background:var(--teal);color:#fff;box-shadow:0 10px 28px -12px rgba(14,110,99,.55)}
.btn-primary:hover{background:var(--teal-deep);box-shadow:0 16px 34px -12px rgba(14,110,99,.6)}
.btn-ghost{border:1.5px solid var(--line);color:var(--ink);background:transparent}
.btn-ghost:hover{border-color:var(--teal);color:var(--teal)}
.dark .btn-ghost{border-color:rgba(255,255,255,.24);color:#fff}
.dark .btn-ghost:hover{border-color:#fff}
.wa-glyph{width:19px;height:19px;flex:none}
.flag{font-size:1.05em;line-height:1}

.rv{opacity:0;transform:translateY(24px);transition:opacity .8s cubic-bezier(.2,.7,.2,1),transform .8s cubic-bezier(.2,.7,.2,1)}
.rv.on{opacity:1;transform:none}
.rv-d1{transition-delay:.08s}.rv-d2{transition-delay:.16s}.rv-d3{transition-delay:.24s}

/* nav */
nav{position:fixed;inset:0 0 auto;z-index:60;transition:.35s}
nav.scrolled{background:rgba(251,249,245,.88);backdrop-filter:blur(14px);box-shadow:0 1px 0 var(--line)}
.nav-in{display:flex;align-items:center;justify-content:space-between;height:70px}
.logo{font-weight:800;font-size:20px;text-decoration:none;letter-spacing:-.02em;display:flex;align-items:center;gap:9px}
.logo .mark{width:13px;height:13px;border-radius:50% 50% 50% 2px;background:var(--teal);transform:rotate(-8deg)}
.nav-links{display:flex;gap:32px;align-items:center;list-style:none}
.nav-links a{text-decoration:none;font-size:15px;font-weight:600;color:var(--ink)}
.nav-links a:not(.btn):hover{color:var(--teal)}
.nav-links a.nav-cta:hover{color:#fff}
.nav-links .btn{padding:10px 20px;font-size:14px}

/* ── The persistent CTA ───────────────────────────────────────────────────────
   A dark pill that blooms into colour on hover. Twelve blurred circles sit below
   the surface at scale 0; on hover they inflate on staggered delays so the fill
   arrives as a wave rather than a single wipe, and because they are blurred and
   overlapping the result reads as liquid light instead of twelve dots.

   Colours are the cool half of the phone-field spectrum (teal, aqua, blue,
   violet) so the button belongs to the same world as the animation, and the warm
   end is deliberately left out because warm is reserved for the loss timeline.

   Written from scratch. The structure follows a common pattern; the styling,
   easing, stagger and palette are ours.

   Still restrained where it matters: a button on screen for the entire visit is
   ignored if it never stops moving, so the sheen fires on a long interval and
   never while hovered. */
.nav-cta,.nav-links a.nav-cta{color:#fff}
.nav-cta{position:relative;overflow:hidden;isolation:isolate;
  background:#0B1917;border:1px solid rgba(111,211,196,.34);
  will-change:transform;
  transition:transform .34s cubic-bezier(.2,.8,.2,1),box-shadow .34s ease,border-color .34s ease}
.nav-cta{animation:ctaHalo 6.5s ease-in-out infinite alternate}
/* A slow halo so the button reads as lit even at rest. Kept low: this sits in a
   fixed header for the entire visit and a strong pulse there is exhausting. */
@keyframes ctaHalo{
  0%  {box-shadow:0 4px 18px -8px rgba(47,179,160,.55), 0 0 22px -4px rgba(47,179,160,.34)}
  100%{box-shadow:0 8px 26px -8px rgba(126,155,216,.62), 0 0 30px -4px rgba(142,143,212,.42)}
}
/* Hover lifts it, it does not switch it on. Roughly a third brighter, which
   registers as a response without becoming a light show. */
.nav-cta:hover{border-color:rgba(111,211,196,.7);
  box-shadow:0 10px 34px -8px rgba(47,179,160,.72), 0 0 44px -4px rgba(142,143,212,.55)}

.nav-cta__in{display:inline-flex;align-items:center;gap:8px;position:relative;z-index:3}
.nav-cta__dot{width:6px;height:6px;border-radius:50%;background:#6FD3C4;flex:none;position:relative}
.nav-cta__dot::after{content:"";position:absolute;inset:-3px;border-radius:50%;
  border:1px solid #6FD3C4;animation:ctaPing 2.6s cubic-bezier(.16,1,.3,1) infinite}
@keyframes ctaPing{0%{transform:scale(.5);opacity:.9}70%,100%{transform:scale(2.4);opacity:0}}
.nav-cta__arw{width:14px;height:14px;flex:none;margin-left:-2px;opacity:.75;
  transition:transform .34s cubic-bezier(.2,.8,.2,1),opacity .3s ease}
.nav-cta:hover .nav-cta__arw{transform:translateX(4px);opacity:1}

/* the bloom */
.nav-cta__fx{position:absolute;inset:0;z-index:1;pointer-events:none;
  opacity:.7;transition:opacity .5s ease;
  border-radius:inherit;overflow:hidden;
  clip-path:inset(0 round 999px);                        /* clip to the pill, not its bounding box */
  -webkit-mask-image:-webkit-radial-gradient(#fff,#000)} /* forces the rounded clip in Safari */
.nav-cta:hover .nav-cta__fx{opacity:1}
.nav-cta__fx .c{position:absolute;bottom:0;border-radius:50%;
  filter:blur(11px);opacity:0;
  animation:ctaRise var(--dur,9s) linear infinite;
  animation-delay:var(--dly,0s)}
/* A full pass: in from below, through the dark crown, out of the top. */
@keyframes ctaRise{
  0%  {transform:translate3d(0,150%,0) scale(.45);opacity:0}
  16% {opacity:.42}
  46% {transform:translate3d(var(--dx,5px),25%,0) scale(1);opacity:.50}
  74% {opacity:.34}
  100%{transform:translate3d(calc(var(--dx,5px) * -1),-110%,0) scale(.55);opacity:0}
}
/* Durations are mutually irrational-ish and delays negative, so the twelve
   never sync up and the pill never has a "moment" where it looks arranged. */
.nav-cta__fx .c1 {left:-6%; width:38px;height:38px;background:#0E6E63;--dur:9.4s; --dly:-0.0s;--dx:6px}
.nav-cta__fx .c2 {left:4%;  width:30px;height:30px;background:#12897C;--dur:7.3s; --dly:-2.7s;--dx:-5px}
.nav-cta__fx .c3 {left:13%; width:34px;height:34px;background:#2FB3A0;--dur:11.1s;--dly:-5.2s;--dx:7px}
.nav-cta__fx .c4 {left:23%; width:26px;height:26px;background:#6FD3C4;--dur:8.6s; --dly:-1.4s;--dx:-6px}
.nav-cta__fx .c5 {left:32%; width:36px;height:36px;background:#3FBFD6;--dur:10.3s;--dly:-7.1s;--dx:5px}
.nav-cta__fx .c6 {left:42%; width:28px;height:28px;background:#8CC7E8;--dur:7.9s; --dly:-3.6s;--dx:-7px}
.nav-cta__fx .c7 {left:51%; width:34px;height:34px;background:#6FA8DC;--dur:12.2s;--dly:-8.4s;--dx:6px}
.nav-cta__fx .c8 {left:61%; width:26px;height:26px;background:#7E9BD8;--dur:8.1s; --dly:-4.9s;--dx:-5px}
.nav-cta__fx .c9 {left:70%; width:36px;height:36px;background:#8E8FD4;--dur:10.8s;--dly:-2.1s;--dx:7px}
.nav-cta__fx .c10{left:80%; width:30px;height:30px;background:#A98BD0;--dur:7.6s; --dly:-6.3s;--dx:-6px}
.nav-cta__fx .c11{left:89%; width:34px;height:34px;background:#B98BCE;--dur:11.7s;--dly:-3.1s;--dx:5px}
.nav-cta__fx .c12{left:97%; width:28px;height:28px;background:#D68FC0;--dur:9.0s; --dly:-9.6s;--dx:-7px}

/* the sheen sits above the bloom but below the label */
.nav-cta::after{content:"";position:absolute;inset:0;z-index:2;pointer-events:none;
  border-radius:inherit;clip-path:inset(0 round 999px);
  background:linear-gradient(104deg,transparent 34%,rgba(255,255,255,.26) 47%,rgba(255,255,255,.04) 55%,transparent 66%);
  transform:translateX(-135%)}
.nav-cta.is-sheen::after{animation:ctaSheen 1.1s cubic-bezier(.35,.7,.3,1)}
@keyframes ctaSheen{from{transform:translateX(-135%)}to{transform:translateX(135%)}}

@media (prefers-reduced-motion: reduce){
  .nav-cta__dot::after,.nav-cta.is-sheen::after,.nav-cta__fx .c,.nav-cta{animation:none}
  .nav-cta{transition:none}
  .nav-cta__fx .c{transform:translate3d(0,25%,0) scale(.8);opacity:.4}
}
@media(max-width:860px){.nav-links li:not(:last-child){display:none}}

/* ── hero: no phone now, so it is a single centred column ─────────────────── */
.hero{position:relative;padding:170px 0 90px}
.hero-in{max-width:840px}
.hero h1{font-size:clamp(42px,5.6vw,72px)}
.hero h1 .line{display:block;overflow:hidden}
.hero h1 .line>span{display:inline-block;transform:translateY(112%);animation:rise .95s cubic-bezier(.2,.7,.15,1) forwards}
.hero h1 .line:nth-child(2)>span{animation-delay:.1s}
.hero h1 .line:nth-child(3)>span{animation-delay:.2s}
@keyframes rise{to{transform:none}}
.hero-sub{margin:26px 0 34px;font-size:19px;color:var(--muted);max-width:620px;opacity:0;animation:fadeUp .9s .45s cubic-bezier(.2,.7,.2,1) forwards}
.hero-sub b{color:var(--ink)}
.hero-cta{display:flex;gap:14px;flex-wrap:wrap;opacity:0;animation:fadeUp .9s .6s cubic-bezier(.2,.7,.2,1) forwards}
.hero-note{margin-top:22px;font-size:13.5px;color:var(--muted);opacity:0;animation:fadeUp .9s .75s cubic-bezier(.2,.7,.2,1) forwards}
.hero-note b{color:var(--ink)}
@keyframes fadeUp{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:none}}
.hero-scroll{margin-top:64px;display:flex;align-items:center;gap:12px;font-size:13px;color:var(--muted);opacity:0;animation:fadeUp .9s .9s cubic-bezier(.2,.7,.2,1) forwards}
.hero-scroll i{display:block;width:1px;height:34px;background:linear-gradient(var(--line),transparent);animation:drop 2.2s ease-in-out infinite}
@keyframes drop{0%,100%{transform:scaleY(.4);transform-origin:top}50%{transform:scaleY(1);transform-origin:top}}

/* ═══ SCROLL-LOCKED SCENES ═══
   Two of them only: the phone and the calculator. The pattern is a tall outer
   section with a sticky full-height inner, so the viewport "holds" while the
   page scrolls behind it. Scroll position inside the section becomes a 0..1
   progress value that drives the animation. No library needed. */
.pin{position:relative}
.pin__inner{position:sticky;top:0;height:100svh;display:grid;align-content:center;overflow:hidden;isolation:isolate}
/* The particle field fills the whole locked viewport rather than sitting behind
   the device, so the scene reads as one environment the phone lives inside. */
.fx{position:absolute;inset:0;width:100%;height:100%;pointer-events:none;z-index:0;display:block;
  opacity:.2;
  /* Promote to its own layer so repainting it never dirties the sticky ancestor,
     which is what made scrolling stutter around this section on iOS. */
  transform:translateZ(0);backface-visibility:hidden;will-change:opacity}   /* scrubbed up to 1 as the phone flies in; see paintPhone */
.stage{position:relative;z-index:1}

/* ── "there is more below" ────────────────────────────────────────────────────
   A pinned section hides the two things a reader needs: how far through it they
   are, and whether anything follows. Without them the page feels stuck and
   people leave. This gives both: a rail that drains as the pin is scrolled, and
   the name of the next section, which fades up as the end approaches so the
   reveal happens BEFORE the release rather than after it. */
.scene-cue{position:absolute;left:50%;bottom:20px;transform:translateX(-50%);
  z-index:3;display:flex;flex-direction:column;align-items:center;gap:9px;
  pointer-events:none;text-align:center}
.scene-cue__rail{width:1px;height:46px;background:rgba(255,255,255,.14);
  position:relative;overflow:hidden;border-radius:99px}
.scene-cue__rail i{position:absolute;inset:0 0 auto 0;height:0%;
  background:linear-gradient(#6FD3C4,rgba(111,211,196,.25));border-radius:99px}
.scene-cue__next{display:flex;flex-direction:column;gap:2px;
  opacity:0;transform:translateY(7px);
  transition:opacity .5s var(--ease,cubic-bezier(.2,.8,.2,1)),transform .5s cubic-bezier(.2,.8,.2,1)}
.scene-cue.near .scene-cue__next{opacity:1;transform:none}
.scene-cue__eyebrow{font-size:10px;letter-spacing:.18em;text-transform:uppercase;
  font-weight:700;color:#6FD3C4}
.scene-cue__title{font-size:13.5px;font-weight:600;color:rgba(255,255,255,.82)}
.scene-cue__chev{width:15px;height:15px;color:rgba(255,255,255,.42);
  opacity:0;transition:opacity .5s ease;animation:cueNudge 2.1s ease-in-out infinite}
.scene-cue.near .scene-cue__chev{opacity:1}
@keyframes cueNudge{0%,100%{transform:translateY(0)}50%{transform:translateY(4px)}}
@media(max-width:620px){.scene-cue{bottom:12px}.scene-cue__rail{height:34px}}
@media (prefers-reduced-motion: reduce){
  .scene-cue__chev{animation:none}
  .scene-cue__next{opacity:1;transform:none}
}
#scene-phone{height:225svh;background:var(--navy);color:#fff}
.calc-sec{padding:110px 0}

/* ── the device ───────────────────────────────────────────────────────────── */
.stage{display:grid;grid-template-columns:1fr auto;gap:60px;align-items:center;max-width:1180px;margin:0 auto;padding:0 28px;width:100%}
.stage-copy{max-width:440px}
.stage-copy h2{font-size:clamp(30px,3.6vw,46px)}
.stage-copy p{color:rgba(255,255,255,.62);margin-top:18px;font-size:17px}
.stage-steps{margin-top:30px;display:flex;flex-direction:column;gap:2px;list-style:none}
.stage-steps li{display:flex;gap:14px;align-items:flex-start;padding:13px 0;border-top:1px solid rgba(255,255,255,.1);font-size:15px;color:rgba(255,255,255,.55);transition:color .45s ease}
.stage-steps li:last-child{border-bottom:1px solid rgba(255,255,255,.1)}
.stage-steps li b{color:#fff;font-weight:700;display:block;margin-bottom:2px}
.stage-steps li .dot{width:7px;height:7px;border-radius:50%;background:rgba(255,255,255,.22);margin-top:8px;flex:none;transition:background .45s ease,box-shadow .45s ease}
.stage-steps li.on{color:rgba(255,255,255,.86)}
.stage-steps li.on .dot{background:#6FD3C4;box-shadow:0 0 0 4px rgba(111,211,196,.16)}

/* Perspective lives on the wrapper so the phone's own transform stays readable. */
/* A slow wash behind the device. It is deliberately low-contrast and very slow:
   the brief was subtle, and a fast or saturated version of this is exactly the
   decorative-blob look we stripped out of the rest of the page. The two colour
   stops are custom properties so selecting a business can transition them. */
.dev-wrap{perspective:1500px;perspective-origin:50% 42%;flex:none;position:relative}
.dev-wrap::before{
  content:"";position:absolute;left:50%;top:50%;width:150%;aspect-ratio:1;
  transform:translate(-50%,-50%);border-radius:50%;pointer-events:none;z-index:0;
  background:
    radial-gradient(circle at var(--gx1,38%) var(--gy1,34%),var(--scene-a,rgba(14,110,99,.34)),transparent 58%),
    radial-gradient(circle at var(--gx2,66%) var(--gy2,68%),var(--scene-b,rgba(111,211,196,.20)),transparent 60%);
  filter:blur(46px);
  opacity:calc(.82 + var(--bloom,0) * .5);
  transition:background 1.1s cubic-bezier(.4,0,.2,1),opacity .5s ease;
  animation:breathe 19s ease-in-out infinite alternate;
}
/* Pointer-tracked highlight. Separate layer so the breathing keyframes above
   keep ownership of `transform` and the two never overwrite each other. */
.dev-wrap::after{
  content:"";position:absolute;left:50%;top:50%;width:150%;aspect-ratio:1;
  transform:translate(-50%,-50%);border-radius:50%;pointer-events:none;z-index:0;
  background:radial-gradient(circle at var(--mx,50%) var(--my,50%),
    var(--scene-glow,rgba(160,235,220,.26)),transparent 42%);
  filter:blur(58px);
  opacity:calc(.28 + var(--bloom,0) * .85);
  transition:opacity .45s ease,background 1.1s cubic-bezier(.4,0,.2,1);
}
@keyframes breathe{
  0%{transform:translate(-50%,-50%) scale(1) rotate(0deg)}
  100%{transform:translate(-52%,-48%) scale(1.14) rotate(8deg)}
}
.dev{position:relative;z-index:1;text-align:start}
.wa-top,.chat,.wa-foot,.statusbar{text-align:start}
.dev{
  width:358px;height:754px;   /* 77.6 x 163.4 mm, to scale */
  position:relative;transform-style:preserve-3d;
  will-change:transform;
}
/* Chassis. The border-radius is the real 55mm-scaled corner, and the layered
   gradients are doing the job of anodised aluminium catching light: a bright
   chamfer at the very edge, a darker body, a rim highlight down each side. */
.dev__body{
  position:absolute;inset:0;border-radius:62px;
  background:
    linear-gradient(150deg,#8d8f92 0%,#3f4245 18%,#6e7175 34%,#2c2f32 55%,#5f6367 76%,#33363a 100%);
  box-shadow:
    0 60px 120px -40px rgba(0,0,0,.85),
    0 0 0 1px rgba(255,255,255,.09),
    inset 0 0 0 1px rgba(255,255,255,.16);
  padding:5px;
}
/* The black glass sits inside the metal, which is what gives the frame its
   visible thickness rather than a painted-on border. */
.dev__glass{position:absolute;inset:5px;border-radius:58px;background:#05070a;padding:4px;box-shadow:inset 0 0 22px rgba(0,0,0,.9)}
.dev__screen{position:absolute;inset:9px;border-radius:53px;overflow:hidden;background:var(--wa-bg);display:flex;flex-direction:column}
/* A single specular streak. Kept low-opacity: this is the one effect that tips
   from "glass" into "cheap CGI" if it is too strong. */
.dev__gloss{position:absolute;inset:0;border-radius:62px;pointer-events:none;
  background:linear-gradient(112deg,transparent 34%,rgba(255,255,255,.11) 45%,rgba(255,255,255,.03) 51%,transparent 62%)}
.dev__island{position:absolute;top:21px;left:50%;transform:translateX(-50%);width:116px;height:34px;border-radius:99px;background:#000;z-index:5}
.dev__btn{position:absolute;background:linear-gradient(180deg,#6a6d71,#3a3d40);border-radius:2px}
.dev__btn.vu{left:-2px;top:150px;width:3px;height:56px}
.dev__btn.vd{left:-2px;top:220px;width:3px;height:56px}
.dev__btn.act{left:-2px;top:104px;width:3px;height:32px}
.dev__btn.side{right:-2px;top:170px;width:3px;height:78px}
.dev__btn.cam{right:-2px;top:270px;width:3px;height:38px}

/* ── WhatsApp UI, matched to the real dark-mode client ────────────────────── */
.wa-top{background:var(--wa-head);padding:44px 11px 11px;display:flex;align-items:center;gap:9px;flex:none}
/* The name block takes the remaining width and anchors LEFT, a fixed gap from
   the avatar. Left as an auto-width flex child it drifted toward the middle of
   the header, which is not where the real client puts it. */
.wa-meta{flex:1;min-width:0;text-align:left}
.wa-name,.wa-status{text-align:left;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.wa-back{color:var(--wa-dim);font-size:20px;line-height:1;margin-right:-3px}
.wa-ava{width:38px;height:38px;border-radius:50%;background:var(--ava-bg,#0E6E63);display:flex;align-items:center;justify-content:center;flex:none;transition:background .5s ease}
.wa-ava svg{width:21px;height:21px;fill:#fff;opacity:.94}
.wa-name{font-weight:600;font-size:14.5px;line-height:1.2;color:var(--wa-ink)}
.wa-status{font-size:11.5px;color:var(--wa-dim)}
/* WhatsApp's wallpaper is a faint doodle field; at this size a low-contrast
   speckle reads the same and costs nothing. */
.wa-body{flex:1;position:relative;overflow:hidden;background:
  radial-gradient(circle at 20% 30%,rgba(255,255,255,.014) 0 2px,transparent 2px),
  radial-gradient(circle at 70% 60%,rgba(255,255,255,.014) 0 2px,transparent 2px),
  var(--wa-bg);background-size:70px 70px,90px 90px}
.chat{position:absolute;inset:0;padding:12px 9px;display:flex;flex-direction:column;gap:3px;justify-content:flex-end}
.msg{max-width:82%;padding:6px 9px 5px;border-radius:8px;font-size:13.4px;line-height:1.4;color:var(--wa-ink);text-align:start;
  opacity:0;transform:translateY(9px) scale(.985);
  transition:opacity .32s cubic-bezier(.2,.7,.2,1),transform .32s cubic-bezier(.2,.7,.2,1);
  box-shadow:0 1px 1px rgba(0,0,0,.22);position:relative;word-wrap:break-word}
.msg.show{opacity:1;transform:none}
.msg.in{background:var(--wa-in);align-self:flex-start}
.msg.out{background:var(--wa-out);align-self:flex-end}
/* Only the first bubble of a run gets the tail, exactly like the real client. */
.msg.in.first{border-top-left-radius:0}
.msg.out.first{border-top-right-radius:0}
.msg .meta{float:right;font-size:10px;color:rgba(233,237,239,.5);margin:6px 0 0 8px;display:inline-flex;align-items:center;gap:3px}
.msg .tick{color:var(--wa-tick);font-size:11px;letter-spacing:-3px}
.tag{display:inline-block;font-size:9px;font-weight:800;letter-spacing:.07em;text-transform:uppercase;padding:2px 6px;border-radius:99px;margin-bottom:4px}
.tag-staff{background:rgba(111,211,196,.16);color:#6FD3C4}
.typing{display:inline-flex;gap:4px;padding:11px 13px;background:var(--wa-out);border-radius:8px;border-top-right-radius:0;align-self:flex-end;opacity:0;transition:opacity .25s}
.typing.show{opacity:1}
.typing i{width:6.5px;height:6.5px;border-radius:50%;background:rgba(233,237,239,.55);animation:blink 1.2s infinite}
.typing i:nth-child(2){animation-delay:.2s}.typing i:nth-child(3){animation-delay:.4s}
@keyframes blink{0%,60%,100%{opacity:.35;transform:translateY(0)}30%{opacity:1;transform:translateY(-3px)}}
.leadcard{align-self:stretch;text-align:start;background:rgba(111,211,196,.09);border:1px solid rgba(111,211,196,.28);border-radius:9px;padding:9px 11px;font-size:11.5px;color:var(--wa-ink);
  opacity:0;transform:translateY(9px);transition:opacity .34s,transform .34s}
.leadcard.show{opacity:1;transform:none}
.lc-head{font-weight:800;font-size:9.5px;letter-spacing:.07em;text-transform:uppercase;color:#6FD3C4;display:flex;align-items:center;gap:6px;margin-bottom:6px}
.lc-dot{width:5px;height:5px;border-radius:50%;background:#6FD3C4}
.lc-row{display:flex;justify-content:space-between;gap:12px;padding:2px 0;color:rgba(233,237,239,.62)}
.lc-row b{color:var(--wa-ink);font-weight:600}
.wa-foot{flex:none;background:var(--wa-bg);padding:7px 9px 13px;display:flex;align-items:center;gap:7px}
.wa-input{flex:1;background:var(--wa-head);border-radius:99px;padding:8px 12px;font-size:12.5px;color:var(--wa-dim);display:flex;align-items:center;gap:8px;min-width:0}
.wa-input .ph{flex:1;min-width:0}
.wa-input svg{width:15px;height:15px;fill:var(--wa-dim);flex:none}
.wa-mic{width:34px;height:34px;border-radius:50%;background:var(--wa-out);flex:none;display:flex;align-items:center;justify-content:center}
.wa-mic svg{width:16px;height:16px;fill:#fff}
.statusbar{flex:none;font-size:10.5px;font-weight:600;padding:6px 12px;display:flex;align-items:center;gap:7px;background:rgba(14,110,99,.18);color:#6FD3C4;transition:.4s}
.statusbar .sd{width:6px;height:6px;border-radius:50%;background:currentColor}
.statusbar.human{background:rgba(196,96,47,.2);color:#F0A46F}

/* The chips sit on high-contrast line work, so they need their own ground.
   A single blurred panel behind the row keeps the field at full strength and
   fixes only the thing that was actually broken: legibility. */
.stage-chips{display:flex;gap:7px;flex-wrap:wrap;margin-top:26px;position:relative;isolation:isolate}
/* No backdrop-filter here. A blurred backdrop over a STATIC background is cheap;
   over a continuously animating one the browser must re-blur it every single
   frame, which is expensive on iOS. A solid translucent panel reads the same and
   costs nothing. */
.stage-chips::before{content:"";position:absolute;inset:-11px -15px;border-radius:26px;
  background:rgba(6,16,15,.78);
  border:1px solid rgba(255,255,255,.08);z-index:-1}
.chip{border:1.5px solid rgba(255,255,255,.20);background:rgba(10,22,20,.42);border-radius:999px;padding:7px 14px;font-size:12.5px;font-weight:600;color:rgba(255,255,255,.55);cursor:pointer;font-family:var(--ff);transition:.25s;white-space:nowrap}
.chip:hover{border-color:rgba(255,255,255,.45);color:#fff;background:rgba(14,30,27,.6)}
.chip.on{color:var(--navy);background:#6FD3C4;border-color:#6FD3C4}

/* ── sections ─────────────────────────────────────────────────────────────── */
.gap{padding:110px 0}
.dark{background:var(--navy);color:#fff}
.dark h2,.dark h3{color:#fff}
.gap-sub{color:rgba(255,255,255,.62);max-width:660px;margin-top:18px;font-size:18px}
.cooler{margin:52px 0 0;background:rgba(255,255,255,.045);border:1px solid rgba(255,255,255,.1);border-radius:20px;padding:26px}
.cooler-top{display:flex;align-items:center;gap:16px;flex-wrap:wrap;font-size:14px}
.cooler-left{display:flex;align-items:center;gap:8px;font-weight:600}
.live{width:8px;height:8px;border-radius:50%;background:#6FD3C4;
  animation:pulse var(--beat,1.8s) infinite;transition:background .5s linear}
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.35}}
/* Flatline: the pulse stops rather than speeding up. A dead lead is not urgent,
   it is over, and that lands harder than a shake. */
.cooler.gone .live{animation:none;opacity:.32}
.cooler.gone .cooler-clock{opacity:.82}
.cooler{transition:filter .9s ease}
.cooler.gone{filter:saturate(.55)}
.cooler-clock,.cooler-state{transition:color .5s linear}
.cooler-clock{font-variant-numeric:tabular-nums;font-weight:800;font-size:22px;margin-left:auto}
/* Centred over the bar. Pushed to the middle it stops competing with the header
   row and points the eye straight down at the track, which is the thing that is
   actually saying something. */
.cooler-state{font-size:13.5px;color:rgba(255,255,255,.6);text-align:center;margin:22px 0 0;
  min-height:1.4em;transition:color .5s linear,opacity .26s ease,transform .26s ease}
.cooler-state.swap{opacity:0;transform:translateY(-4px)}
.track{height:8px;border-radius:99px;background:rgba(255,255,255,.09);margin:12px 0 30px;position:relative;
  overflow:visible}   /* the fill clips itself, so the track must NOT clip the marker */
.fill{position:absolute;inset:0;width:100%;border-radius:99px;
  background:linear-gradient(90deg,
    #6FD3C4 0%,      /* CueCove has already replied */
    #8FD9A8 12%,
    #E8C15C 32%,     /* golden window closing */
    #E0603A 56%,     /* odds halving */
    #C4142F 78%,     /* critical */
    #5E1030 100%);   /* past red: the heat is gone */
  clip-path:inset(0 100% 0 0)}
/* The range CueCove actually replies in, not a single point. The band maps the
   5s to 45s window onto the same non-linear scale the clock uses. */
/* The range CueCove answers in: a bracket under the bar with its own label, so
   it reads as a claim rather than as a smudge on the track. */
.you{position:absolute;left:.6%;top:-5px;width:8.2%;height:18px;
  border:2px solid #6FD3C4;border-radius:3px;background:rgba(111,211,196,.16);
  box-shadow:0 0 14px rgba(111,211,196,.35)}
.you span{position:absolute;top:22px;left:0;white-space:nowrap;font-size:11px;font-weight:700;
  letter-spacing:.04em;color:#6FD3C4}
.you::after{content:"";position:absolute;left:50%;top:18px;width:1px;height:5px;background:rgba(111,211,196,.6)}
@media(max-width:620px){.you span{font-size:10px}}
.mstones{display:grid;grid-template-columns:repeat(4,1fr);gap:14px;font-size:12.5px;color:rgba(255,255,255,.42)}
.mstones>div{transition:color .4s}
.mstones b{display:block;color:rgba(255,255,255,.6);font-size:13px;margin-bottom:2px;transition:color .4s}
.mstones>div.hit{color:rgba(255,255,255,.62)}
.mstones>div.hit b{color:#fff}
/* Once passed, each milestone tints toward the bar colour at its position, well
   desaturated: the label carries the mood, it does not compete with the bar. */
#m0.hit b{color:#8FE3D3}
#m1.hit b{color:#EBCB86}
#m2.hit b{color:#E8927C}
#m3.hit b{color:#C4788C}
#m3.hit{color:rgba(196,120,140,.55)}
.cooler-foot{margin-top:20px;font-size:13px;color:rgba(255,255,255,.5)}
.cooler-foot b{color:#6FD3C4}
.gap-stats{display:grid;grid-template-columns:repeat(3,1fr);gap:26px;margin-top:56px}
.gs .n{font-size:52px;font-weight:800;letter-spacing:-.03em;color:#fff;line-height:1}
.gs p{margin-top:10px;font-size:15px;color:rgba(255,255,255,.6)}
.gs p b{color:#fff}
.gap-src{margin-top:34px;font-size:12px;color:rgba(255,255,255,.32)}

.how{padding:110px 0}
.how-head{max-width:720px;margin-bottom:52px}
.how-head p{color:var(--muted);margin-top:18px;font-size:18px}
.rule{display:grid;grid-template-columns:130px 1fr;gap:28px;padding:34px 0;border-top:1px solid var(--line)}
.rule:last-child{border-bottom:1px solid var(--line)}
.rn{font-size:12px;font-weight:800;letter-spacing:.14em;color:var(--teal)}
.rule h3{font-size:24px}
.rule p{margin-top:12px;color:var(--muted);max-width:680px}

/* ── Industries ──────────────────────────────────────────────────────────────
   A scrolling ribbon of nouns says "we serve lots of people" and nothing else,
   and every third site has one. This instead shows the ACTUAL first message each
   industry receives, in the language it arrives in, so the same floor space
   proves breadth AND the multilingual claim at once.

   A soft focus travels the grid on its own, like a switchboard routing calls, so
   it works without a pointer. Hovering or tapping takes control. */
.inds{padding:104px 0;background:var(--panel);border-block:1px solid var(--line)}
.inds-lead{margin-top:16px;color:var(--muted);max-width:56ch}
.ind-grid{margin-top:44px;display:grid;gap:1px;background:var(--line);
  border:1px solid var(--line);border-radius:18px;overflow:hidden;
  grid-template-columns:repeat(auto-fit,minmax(230px,1fr))}
.ind{appearance:none;border:0;text-align:left;font:inherit;cursor:pointer;
  background:var(--bg);padding:20px 20px 18px;display:block;position:relative;
  transition:background .4s ease;contain:layout paint}
.ind::before{content:"";position:absolute;left:0;top:0;bottom:0;width:2px;
  background:var(--teal);transform:scaleY(0);transform-origin:top;
  transition:transform .45s cubic-bezier(.2,.8,.2,1)}
.ind.on{background:#EEF6F3}
.ind.on::before{transform:scaleY(1)}
.ind-top{display:flex;align-items:center;gap:9px}
.ind-dot{width:7px;height:7px;border-radius:50%;background:var(--line);flex:none;
  transition:background .4s ease,box-shadow .4s ease}
.ind.on .ind-dot{background:var(--teal);box-shadow:0 0 0 4px rgba(14,110,99,.14)}
.ind-name{font-weight:700;font-size:15.5px;letter-spacing:-.01em}
/* The message space is RESERVED, not animated open. Transitioning
   grid-template-rows animates layout: every frame reflows the tile, the grid and
   everything below it, ten tiles at a time. That was the choppiness in this
   section, and it had nothing to do with the canvas. Now only opacity and
   transform change, which the compositor handles without touching layout. */
.ind-wrap{display:block}
.ind-inner{overflow:hidden}
.ind{min-height:128px}
.ind-msg{margin-top:10px;font-size:14px;color:var(--muted);line-height:1.5;
  opacity:0;transform:translateY(-4px);transition:opacity .35s ease .06s,transform .35s ease .06s}
.ind.on .ind-msg{opacity:1;transform:none}
.ind-msg b{color:var(--teal);font-weight:600;font-size:11px;letter-spacing:.1em;
  text-transform:uppercase;display:block;margin-bottom:5px}
.ind:hover .ind-name{color:var(--teal)}
@media (prefers-reduced-motion: reduce){
  .ind-wrap{grid-template-rows:1fr}.ind-msg{opacity:1;transform:none}
}

.feats{padding:110px 0}
.feats-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:1px;margin-top:52px;background:var(--line);border:1px solid var(--line);border-radius:18px;overflow:hidden}
.feat{background:var(--bg);padding:32px 26px}
.feat h3{font-size:18px;display:flex;align-items:center;gap:9px}
.fdot{width:7px;height:7px;border-radius:50%;background:var(--teal);flex:none}
.feat p{margin-top:12px;font-size:15px;color:var(--muted)}
.ex{display:block;margin-top:16px;font-size:13px;color:var(--teal);font-weight:600}

/* calculator */
.calc-grid{display:grid;grid-template-columns:1fr 1fr;gap:56px;align-items:center;width:100%}
.calc-lead{margin-top:18px;color:var(--muted)}
.calc-card{background:var(--panel);border:1px solid var(--line);border-radius:22px;padding:32px}
.slider-row{margin-bottom:26px}
.slider-row label{display:flex;justify-content:space-between;align-items:baseline;font-size:14px;font-weight:600;margin-bottom:12px}
.slider-row output{font-variant-numeric:tabular-nums;font-weight:800;font-size:18px;color:var(--teal)}
input[type=range]{width:100%;height:4px;border-radius:99px;background:var(--line);appearance:none;outline:none}
input[type=range]::-webkit-slider-thumb{appearance:none;width:22px;height:22px;border-radius:50%;background:var(--teal);cursor:pointer;border:3px solid var(--bg);box-shadow:0 2px 8px rgba(14,110,99,.4)}
input[type=range]::-moz-range-thumb{width:22px;height:22px;border-radius:50%;background:var(--teal);cursor:pointer;border:3px solid var(--bg)}
.cur-toggle{display:inline-flex;gap:2px;padding:3px;background:var(--bg);border:1px solid var(--line);border-radius:99px;margin-bottom:24px}
.cur-toggle button{border:0;background:transparent;font:inherit;font-size:13px;font-weight:700;padding:6px 15px;border-radius:99px;cursor:pointer;color:var(--muted);transition:.22s}
.cur-toggle button.on{background:var(--teal);color:#fff}
.calc-out{border-top:1px solid var(--line);padding-top:24px}
.co-label{font-size:12.5px;letter-spacing:.12em;text-transform:uppercase;font-weight:700;color:var(--muted)}
.co-num{font-size:clamp(38px,5vw,56px);font-weight:800;letter-spacing:-.03em;color:var(--ink);line-height:1.05;margin:8px 0;
  font-variant-numeric:tabular-nums;
  transition:color .45s ease,text-shadow .45s ease,letter-spacing .45s ease}
.co-sub{font-size:14.5px;color:var(--muted)}
.calc-note{margin-top:20px;font-size:12.5px;color:var(--muted);opacity:.8}
.calc-cta{margin-top:24px}

.demo{padding:110px 0}
.demo-card{background:var(--navy);color:#fff;border-radius:26px;padding:52px;display:grid;grid-template-columns:1fr 1fr;gap:52px}
.demo-card h2{font-size:clamp(28px,3.2vw,40px)}
.dl{margin-top:18px;color:rgba(255,255,255,.62)}
.demo-meta{margin-top:28px;display:flex;flex-direction:column;gap:12px;font-size:14px;color:rgba(255,255,255,.66)}
.tick{color:#6FD3C4;font-weight:800;margin-right:7px}
.demo-steps{list-style:none;display:flex;flex-direction:column;gap:20px}
.demo-steps li{padding-left:20px;border-left:2px solid rgba(111,211,196,.35);font-size:14.5px;color:rgba(255,255,255,.62)}
.demo-steps b{display:block;color:#fff;margin-bottom:5px;font-size:15.5px}

.faq{padding:110px 0;background:var(--panel)}
.faq-in{max-width:820px}
/* <details> has no transitionable height, so the answer is wrapped in a grid
   row that animates from 0fr to 1fr. That is the one technique that eases open
   without hard-coding a height the copy might outgrow. */
details{border-bottom:1px solid var(--line)}
/* The height is animated from JS. A CSS-only <details> animates open but snaps
   shut, because the browser removes the content the moment `open` is unset, so
   there is nothing left on screen to transition. */
details .a-wrap{overflow:hidden;height:0}
details .a{opacity:0;transform:translateY(-6px);transition:opacity .3s ease,transform .3s ease}
details.is-open .a{opacity:1;transform:none}
summary{transition:color .2s ease}
details.is-open>summary{color:var(--teal)}
summary{cursor:pointer;list-style:none;padding:24px 0;font-weight:700;font-size:18px;display:flex;justify-content:space-between;gap:20px;align-items:center}
summary::-webkit-details-marker{display:none}
.pl{color:var(--teal);font-weight:400;font-size:26px;transition:transform .3s;flex:none}
details[open] .pl{transform:rotate(45deg)}
.a{padding:0 0 24px;color:var(--muted);max-width:700px}

.final{padding:120px 0;text-align:center}
.final h2{font-size:clamp(30px,4vw,48px)}
.final p{margin:20px auto 34px;color:rgba(255,255,255,.62);max-width:560px}
.final .hero-cta{justify-content:center;opacity:1;animation:none}

footer{padding:52px 0;font-size:14.5px;color:var(--muted);background:var(--bg);border-top:1px solid var(--line)}
.foot-in{display:flex;flex-direction:column;gap:11px;align-items:flex-start}
.foot-row{display:flex;gap:26px;flex-wrap:wrap;align-items:center}
.foot-in a{text-decoration:none}
.foot-in a:hover{color:var(--teal)}
.foot-sep{color:var(--line)}
.foot-legal{margin-top:9px;font-size:13.5px;opacity:.8}

@media(max-width:980px){
  .stage{grid-template-columns:1fr;justify-items:center;text-align:center;gap:34px}
  .stage-copy{max-width:560px}
  .stage-copy p{display:none}
  .stage-steps{display:none}
  .stage-chips{justify-content:center}
  .dev{width:270px;height:568px}
  .dev__body{border-radius:47px}.dev__glass{border-radius:44px}.dev__screen{border-radius:39px}
  .calc-grid,.demo-card,.feats-grid,.gap-stats{grid-template-columns:1fr}
  .mstones{grid-template-columns:repeat(2,1fr)}
  .rule{grid-template-columns:1fr;gap:8px}
  .demo-card{padding:34px}
  #scene-phone{height:200svh}
}
@media(max-width:620px){
  .hero{padding:130px 0 70px}
  .dev{width:236px;height:497px}
  .dev__body{border-radius:41px}.dev__glass{border-radius:38px}.dev__screen{border-radius:34px}
  .dev__island{width:86px;height:26px;top:15px}
  .msg{font-size:12.6px}
}

/* Motion is the centrepiece, so a reduced-motion request collapses the scenes
   to static rather than merely speeding them up: the pins are released and the
   phone sits front-on with the conversation already complete. */
@media (prefers-reduced-motion: reduce){
  *,*::before,*::after{animation-duration:.01ms !important;animation-iteration-count:1 !important;transition-duration:.01ms !important}
  #scene-phone{height:auto}
  .pin__inner{position:static;height:auto;padding:90px 0}
  .dev{transform:none !important}
  .hero h1 .line>span,.hero-sub,.hero-cta,.hero-note,.hero-scroll{opacity:1;transform:none;animation:none}
  .rv{opacity:1;transform:none}
}
