    *,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
    :root{
      --bg:#000;--text:#fff;--muted:rgba(255,255,255,0.5);--dim:rgba(255,255,255,0.28);
      --border:rgba(255,255,255,0.09);--card:rgba(255,255,255,0.04);
      --blue:#5088FD;--green:#48CA7C;--dark-blue:#184383;--red:#FF6B6B;
      --grad:linear-gradient(90deg,#5088FD 0%,#48CA7C 55%,#8ef5c4 100%);
      --grad-diag:linear-gradient(135deg,#5088FD 0%,#48CA7C 100%);
      --font:'Inter',-apple-system,BlinkMacSystemFont,sans-serif;
      --max:1170px;--ease:cubic-bezier(0.22,1,0.36,1);
    }
    html{scroll-behavior:smooth}
    body{background:var(--bg);color:var(--text);font-family:var(--font);-webkit-font-smoothing:antialiased;overflow-x:hidden}
    a{color:inherit;text-decoration:none}
    ::-webkit-scrollbar{width:5px}
    ::-webkit-scrollbar-track{background:#0a0a0a}
    ::-webkit-scrollbar-thumb{background:rgba(255,255,255,.15);border-radius:3px}
    .wrap{max-width:var(--max);margin:0 auto;padding:0 28px;position:relative}
    /* The gradient pans left to right, forever, without a seam.

       Two things make the loop invisible. The gradient is a palindrome that
       ENDS on the colour it starts with, and the pan is exactly one full image
       width (background-size:200% travelled to background-position:200%). Since
       the background repeats, that lands on a pixel-identical state, so there is
       no jump at the wrap. Change one of those numbers and the seam appears. */
    .grad-text{
      background:linear-gradient(90deg,#5088FD 0%,#48CA7C 27%,#8ef5c4 50%,#48CA7C 73%,#5088FD 100%);
      background-size:200% auto;
      -webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;
      animation:gradShift 9s linear infinite;
    }
    @keyframes gradShift{to{background-position:200% center}}
    @media(prefers-reduced-motion:reduce){.grad-text{animation:none;background:var(--grad);background-size:auto}}
    .r{opacity:0;transform:translateY(28px);transition:opacity .7s var(--ease),transform .7s var(--ease)}
    .r.in{opacity:1;transform:none}
    .r.d1{transition-delay:.08s}.r.d2{transition-delay:.16s}.r.d3{transition-delay:.24s}
    .r.d4{transition-delay:.32s}.r.d5{transition-delay:.40s}.r.d6{transition-delay:.48s}

    /* Progress */
    #prog{position:fixed;top:0;left:0;height:2px;background:var(--grad);z-index:300;width:0;transition:width .08s linear;pointer-events:none}

    /* NAV */
    nav{position:fixed;top:0;left:0;right:0;z-index:200;padding:18px 0;transition:background .35s,border-color .35s,backdrop-filter .35s}
    nav.scrolled{background:rgba(0,0,0,0.75);backdrop-filter:blur(24px);-webkit-backdrop-filter:blur(24px);border-bottom:1px solid var(--border)}
    .nav-inner{display:flex;align-items:center;justify-content:space-between;max-width:var(--max);margin:0 auto;padding:0 28px}
    .nav-logo svg{height:28px;width:auto}
    .nav-links{display:flex;align-items:center;gap:28px;list-style:none}
    .nav-links a{font-size:16px;color:#fff;transition:opacity .2s}
    .nav-links a:hover{opacity:.72}
    .nav-cta{display:inline-flex;align-items:center;gap:8px;background:white;color:#000;padding:9px 18px;border-radius:999px;font-size:16px;font-weight:600;transition:opacity .2s,transform .2s;white-space:nowrap}
    .nav-cta:hover{opacity:.88;transform:scale(.97)}
    .nav-cta svg{width:16px;height:16px}

    /* HERO */
    .hero{min-height:100vh;display:flex;flex-direction:column;align-items:center;justify-content:center;padding:116px 28px 64px;text-align:center;position:relative;overflow:hidden}
    .hero-badge,.hero h1,.hero-sub,.hero-actions,.hero-rating{position:relative;z-index:1}
    /* Structure without lighting: a dot grid, masked to an ellipse so it never
       ends on a hard edge. Texture rather than glow — the blobs read as a light
       source, this reads as ground. */
    /* Dot field, fixed in place. ::before is the static grid; ::after is a
       vignette painted over it and over the sparks, so everything fades out at
       the edges without needing a mask that would have to move with them. */
    .hero::before{
      content:'';position:absolute;inset:0;pointer-events:none;z-index:0;
      background-image:radial-gradient(rgba(255,255,255,.17) 1.3px,transparent 1.3px);
      background-size:28px 28px;
      /* Anchored to the centre, not the top-left. A dot therefore always
         sits exactly at 50%/50%, so the sparks below can land on real grid
         positions with calc(50% + 28n) at ANY viewport width. */
      background-position:50% 50%;
    }
    .hero::after{
      content:'';position:absolute;inset:0;pointer-events:none;z-index:0;
      background:radial-gradient(ellipse 68% 60% at 50% 46%,transparent 18%,#000 82%);
    }

    /* Existing grid dots catching colour. These are NOT extra dots: each is
       positioned at calc(50% + 28n), which is exactly where a grid dot already
       sits, and is sized to sit on top of it. Nothing new appears between the
       grid — the grid itself lights up.

       Durations are all coprime-ish so the set never re-synchronises into a
       visible loop, and short enough that several are always lit at once. */
    /* preserveAspectRatio="none" on the svg is load-bearing: the artwork keeps
       height="690", so with the default "meet" it scaled to fit the HEIGHT and
       sat letterboxed in a wider box — widening the element changed nothing at
       all. "none" lets it stretch horizontally, which is invisible on a shape
       this blurred and is what actually widens the wash. */
    .hero-glow{
      /* Pulled up so the bright core of the wash sits behind the nav rather
         than through the headline. In px, not %, because a percentage resolves
         against the HERO's height and would drift whenever the hero resizes. */
      position:absolute;top:-330px;left:50%;
      transform:translateX(-50%) scaleY(-1);
      width:200%;max-width:2600px;pointer-events:none;opacity:1;z-index:1;
    }
    .hero-spark{
      position:absolute;width:3px;height:3px;border-radius:50%;
      transform:translate(-50%,-50%) scale(.4);
      pointer-events:none;z-index:0;opacity:0;
      animation:spark var(--t) ease-in-out infinite;animation-delay:var(--d);
      will-change:opacity,transform;
    }
    @keyframes spark{
      0%,100%{opacity:0;transform:translate(-50%,-50%) scale(.6)}
      25%    {opacity:.7;transform:translate(-50%,-50%) scale(1)}
      55%    {opacity:.7;transform:translate(-50%,-50%) scale(1)}
      80%    {opacity:0;transform:translate(-50%,-50%) scale(.6)}
    }
    @media(prefers-reduced-motion:reduce){.hero-spark{animation:none;opacity:.6;transform:translate(-50%,-50%)}}
    .hero-rating{
      display:inline-flex;align-items:center;gap:9px;margin-top:26px;
      font-size:13.5px;color:var(--muted);transition:color .2s;
    }
    .hero-rating:hover{color:rgba(255,255,255,.8)}
    .hero-rating strong{color:#f1f5f9;font-weight:600}
    .hero-stars{color:#FBBC04;font-size:14px;letter-spacing:1px}
    @keyframes rayPulse{0%,100%{opacity:.45}50%{opacity:.75}}
    @keyframes rayShift{0%{transform:translateX(-50%) scaleX(1)}50%{transform:translateX(-50%) scaleX(1.04)}100%{transform:translateX(-50%) scaleX(1)}}
    .hero-badge{display:inline-flex;align-items:center;gap:8px;background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.12);border-radius:999px;padding:6px 14px;font-size:16px;color:var(--muted);margin-bottom:28px;animation:fadeDown .8s var(--ease) both}
    .badge-dot{width:6px;height:6px;border-radius:50%;background:var(--grad-diag);flex-shrink:0}
    @keyframes fadeDown{from{opacity:0;transform:translateY(-14px)}to{opacity:1;transform:translateY(0)}}
    .hero h1{font-size:clamp(55px,8.75vw,105px);font-weight:300;line-height:1.0;letter-spacing:-0.035em;max-width:940px;animation:fadeUp .9s var(--ease) .08s both}
    .hero h1 strong{font-weight:600}
    .hero-sub{font-size:18px;color:var(--muted);max-width:660px;line-height:1.6;margin-top:22px;animation:fadeUp .9s var(--ease) .18s both}
    @keyframes fadeUp{from{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}
    .hero-actions{margin-top:36px;animation:fadeUp .9s var(--ease) .28s both;display:flex;gap:12px;flex-wrap:wrap;justify-content:center}
    .btn-chrome{display:inline-flex;align-items:center;gap:10px;padding:14px 26px;border-radius:999px;font-size:16px;font-weight:600;background:white;color:#000;position:relative;transition:transform .2s,opacity .2s;cursor:pointer;border:none;z-index:0}
    .btn-chrome::before{content:'';position:absolute;inset:-2px;border-radius:999px;background:var(--grad);z-index:-1;padding:2px}
    .btn-chrome::after{content:'';position:absolute;inset:0;border-radius:999px;background:white;z-index:-1}
    .btn-chrome:hover{transform:scale(.97)}
    .btn-chrome{background:white;color:#000}
    .btn-chrome svg{width:18px;height:18px;flex-shrink:0}
    .btn-ghost{display:inline-flex;align-items:center;gap:8px;padding:14px 22px;border-radius:999px;font-size:16px;color:var(--muted);border:1px solid var(--border);transition:color .2s,border-color .2s,transform .2s}
    .btn-ghost:hover{color:var(--text);border-color:rgba(255,255,255,.22);transform:scale(.98)}

    /* Hero plugin image */

    /* Tool tabs on hero */

    /* ── Hero story diagram ───────────────────────────────────────────────
       Wires draw themselves, then each box fades in as its wire arrives.
       pathLength="1" lets one dash rule cover paths of very different real
       lengths. Timing is one calc() driven by --i on each element. */
    .fx{position:relative;width:100%;max-width:1120px;margin:44px auto 0;z-index:1}
    .fx-svg{display:block;width:100%;height:auto;overflow:visible}
    .fx-stack{display:none}

    .fx-label{fill:rgba(255,255,255,.62);font-size:11.5px;font-weight:500}
    .fx-hub{fill:#f1f5f9;font-size:19px;font-weight:600;letter-spacing:-.01em}
    .fx-chip{fill:rgba(255,255,255,.06);stroke:rgba(255,255,255,.10)}
    .fx-chiptext{fill:rgba(255,255,255,.6);font-size:9.5px;font-weight:700;letter-spacing:.09em}

    .fx-wire{stroke-dasharray:1;stroke-dashoffset:1}
    .fx.is-live .fx-wire{animation:fxDraw .5s ease-out forwards;animation-delay:calc(var(--i) * .16s + .12s)}
    @keyframes fxDraw{to{stroke-dashoffset:0}}
    /* Arrowheads belong to the wire, so they must not appear before it lands. */
    .fx-wire[marker-end]{opacity:0}
    .fx.is-live .fx-wire[marker-end]{animation:fxDraw .5s ease-out forwards,fxShow .01s linear forwards;animation-delay:calc(var(--i) * .16s + .12s)}
    @keyframes fxShow{to{opacity:1}}

    /* ── The loop ─────────────────────────────────────────────────────────
       One short dash per wire, running the whole length on repeat. The delay
       is derived from --i so the pulse arrives at each segment roughly when
       the previous one finishes, reading as a single wave crossing the
       diagram rather than six unrelated blips.

       The 1.5s head start lets the entrance draw finish first, so the loop
       begins on a diagram that is already fully assembled. */
    .fx-pulse{stroke-dasharray:.1 .9;stroke-dashoffset:1;opacity:0;filter:drop-shadow(0 0 5px rgba(142,245,196,.55))}
    .fx.is-live .fx-pulse{animation:fxPulse 3.4s linear infinite;animation-delay:calc(1.5s + var(--i) * .13s)}
    @keyframes fxPulse{
      0%{stroke-dashoffset:1;opacity:0}
      6%{opacity:.95}
      55%{opacity:.95}
      70%{stroke-dashoffset:0;opacity:0}
      100%{stroke-dashoffset:0;opacity:0}
    }

    .fx-tile{opacity:0;transform:translateY(6px)}
    .fx.is-live .fx-tile{animation:fxIn .45s var(--ease) forwards;animation-delay:calc(var(--i) * .16s)}
    @keyframes fxIn{to{opacity:1;transform:none}}

    /* A 760-unit-wide diagram is illegible on a phone: swap it for the list. */
    @media(max-width:760px){
      .fx{margin-top:42px;max-width:420px}
      .fx-svg{display:none}
      .fx-stack{display:flex;flex-direction:column;gap:14px;list-style:none;margin:0;padding:0}
      .fx-stack li{
        position:relative;padding:13px 16px 13px 44px;border-radius:13px;
        background:#0d1117;border:1px solid rgba(255,255,255,.09);
        font-size:13.5px;line-height:1.5;color:var(--muted);
      }
      .fx-stack li b{color:#f1f5f9;font-weight:600}
      .fx-stack li::before{
        content:'';position:absolute;left:18px;top:19px;
        width:9px;height:9px;border-radius:50%;background:var(--grad-diag);
      }
    }

    @media(prefers-reduced-motion:reduce){
      .fx-wire,.fx-wire[marker-end]{stroke-dashoffset:0;opacity:1}
      .fx-pulse,.fx.is-live .fx-pulse{animation:none;opacity:0}
      .fx-tile{opacity:1;transform:none}
      .fx.is-live .fx-wire,.fx.is-live .fx-wire[marker-end],.fx.is-live .fx-tile{animation:none}
    }

    /* BROWSER MARKS IN THE HERO
       One line under the note: icons then sentence, so it reads as a caption
       rather than as a second logo strip competing with the customer row below
       it. Full colour and full opacity on purpose — these are trademarks, and
       most vendors' brand guidelines forbid recolouring or fading them, which
       is exactly what the customer logos above DO get. */
    /* A pill, in the same language as the hero badge above it (same translucent
       white, same hairline border, same 999px radius), so the hero opens and
       closes on matching chips instead of ending on loose text. Centred by the
       hero's own text-align, which is why it is inline-flex. */
    .hero-browsers{
      display:inline-flex;align-items:center;gap:13px;margin-top:26px;
      padding:7px 15px 7px 18px;
      background:rgba(255,255,255,.05);border:1px solid rgba(255,255,255,.11);
      border-radius:999px;
    }
    .hb-text{font-size:13.5px;color:var(--muted);line-height:1.4;white-space:nowrap}

    /* Still a stack, but a gentler one. At -8px on 36px icons the logos ran
       into each other and read as one blob; -5px on 28px keeps the stacked
       look while leaving every mark recognisable, which is the whole point of
       showing them. The z-index that puts the first on top is set per item by
       the renderer, hence position:relative. */
    .hb-stack{display:inline-flex;align-items:center}
    .hb-stack img{
      width:28px;height:28px;display:block;flex:none;position:relative;
      /* Traces each logo's own silhouette, so it separates a circle (Chrome)
         and a squircle (Safari) equally well. A box-shadow could not: these
         are transparent PNG-shaped SVGs, so it would draw a square. */
      filter:drop-shadow(0 1px 2px rgba(0,0,0,.55));
      transition:transform .18s var(--ease);
    }
    .hb-stack img + img{margin-left:-5px}
    /* The hovered logo lifts and comes to the front, so the stack can be read
       one browser at a time rather than only as a group. */
    .hb-stack img:hover{transform:translateY(-3px) scale(1.06);z-index:10}
    @media (max-width:560px){
      .hero-browsers{gap:10px;margin-top:18px;padding:7px 13px 7px 15px}
      .hb-text{font-size:12.5px}
      .hb-stack img{width:25px;height:25px}
      .hb-stack img + img{margin-left:-4px}
    }
    @media (max-width:400px){
      .hero-browsers{flex-direction:column;gap:9px;border-radius:18px;padding:10px 16px}
      .hb-text{white-space:normal;text-align:center}
    }
    @media (prefers-reduced-motion:reduce){.hb-stack img{transition:none}}

    /* TRUSTED-BY LOGOS
       A right-to-left marquee rather than a fixed row: six names sitting still
       read as "these six", the same six drifting past read as a roster that
       keeps going. Same loop mechanism as the feature marquee below — the list
       is rendered twice and the track travels exactly -50%, which lands on a
       pixel-identical state, so there is no seam to see.

       The artwork is white-on-transparent and needs no filter on this dark
       page; opacity alone keeps six logos from out-shouting the headline. */
    .logos{padding:46px 0 10px;--logo-h:26px}
    /* The bottom padding is the ONLY thing separating this strip from the hero
       video: site.css sets .hero-media{margin-top:0} because the media's position
       is driven by .hero-copy's min-height instead. So spacing below the logos
       has to be set here, and a change to it moves the video. */
    .logos-hero{padding:34px 0 104px;position:relative;z-index:1;--logo-h:24px}
    .logos-head{font-size:13px;letter-spacing:.08em;text-transform:uppercase;color:rgba(255,255,255,.62);font-weight:500;text-align:center;margin-bottom:24px}

    .logos-marquee{position:relative;overflow:hidden}
    /* Fades at both edges so logos arrive and leave instead of being chopped
       off at a hard border. Sized in vw so they stay proportional on a phone,
       where a fixed 160px would swallow most of the strip. */
    .logos-marquee::before,.logos-marquee::after{content:'';position:absolute;top:0;bottom:0;width:12vw;max-width:180px;z-index:2;pointer-events:none}
    .logos-marquee::before{left:0;background:linear-gradient(90deg,var(--bg) 0%,transparent 100%)}
    .logos-marquee::after{right:0;background:linear-gradient(-90deg,var(--bg) 0%,transparent 100%)}

    .logos-track{display:flex;width:max-content;animation:logosScroll var(--logos-dur,60s) linear infinite}
    .logos-track:hover{animation-play-state:paused}
    @keyframes logosScroll{from{transform:translateX(0)}to{transform:translateX(-50%)}}

    /* The trailing padding has to match the gap exactly, or the join between
       the two copies is a gap of the wrong width once per loop. */
    .logos-row{display:flex;align-items:center;gap:84px;padding-right:84px;list-style:none;margin:0}
    .logos-row li{display:flex;align-items:center;flex:none}
    /* Height only. These are all exported on a uniform 32px artboard, so their
       natural widths are already matched; capping width would shrink the widest
       wordmark against marks it was drawn to sit beside. Per-logo `scale` in
       content.mjs does the optical balancing instead. */
    .logos-row img{height:var(--logo-h);width:auto;display:block;opacity:.55;transition:opacity .2s var(--ease)}
    .logos-row img:hover{opacity:.95}

    @media (max-width:760px){
      .logos{padding:34px 0 6px}
      .logos-hero{padding:26px 0 68px;--logo-h:20px}
      .logos-row{gap:54px;padding-right:54px}
      .logos-head{margin-bottom:18px}
    }
    /* Someone who asked for less motion gets a still row, not a frozen frame
       mid-scroll: the track resets to the start so the first copy is the one
       on screen, and the duplicate simply sits off to the right unseen. */
    @media (prefers-reduced-motion:reduce){
      .logos-track{animation:none;transform:none}
      .logos-row img{transition:none}
    }

    /* MARQUEE */
    .marquee-wrap{overflow:hidden;padding:22px 0;border-top:1px solid var(--border);border-bottom:1px solid var(--border);position:relative;background:rgba(255,255,255,.015)}
    .marquee-wrap::before,.marquee-wrap::after{content:'';position:absolute;top:0;bottom:0;width:160px;z-index:2;pointer-events:none}
    .marquee-wrap::before{left:0;background:linear-gradient(90deg,var(--bg) 0%,transparent 100%)}
    .marquee-wrap::after{right:0;background:linear-gradient(-90deg,var(--bg) 0%,transparent 100%)}
    .marquee-track{display:flex;gap:0;width:max-content;animation:marquee 54s linear infinite}
    .marquee-track:hover{animation-play-state:paused}
    @keyframes marquee{from{transform:translateX(0)}to{transform:translateX(-50%)}}
    .mi{display:inline-flex;align-items:center;gap:0;font-size:15px;font-weight:400;color:rgba(255,255,255,.72);white-space:nowrap;flex-shrink:0;letter-spacing:.01em;padding:0 36px;}
    .mi-sep{width:1px;height:14px;background:rgba(255,255,255,.15);flex-shrink:0;margin:0;}
    .mi-dot{display:none;}

    /* SECTIONS */
    section{padding:96px 0;position:relative}
    /* Every section label is plain green text, no pill, and the Features
       label (.ex-pill in site.css) matches it. Change the two together. */
    .sec-eyebrow{display:inline-flex;align-items:center;gap:8px;font-size:13px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--green);margin-bottom:20px}
    .sec-eyebrow::before{display:none}
    /* Green is the resolve colour everywhere else on the page, so it reads as
       the wrong signal above "The problem". Red is the same #FF6B6B already
       used for high-severity visuals — a modifier, never the base rule, since
       every other eyebrow on the page stays green. */
    .sec-eyebrow.neg{color:var(--red)}
    h2.sec-title{font-size:clamp(30px,4vw,50px);font-weight:600;letter-spacing:-0.03em;line-height:1.1;margin-bottom:14px;text-align:center}
    h2.sec-title strong{font-weight:600}
    .sec-sub{font-size:16px;color:var(--muted);max-width:500px;line-height:1.65;text-align:center;margin:0 auto}

    /* FEATURES */
    .features-intro{margin-bottom:52px;text-align:center}
    .features-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:14px;}
    /* Icon beside the text, not stacked above it. Each card is one line now,
       and the stacked layout left most of the card empty. A 2-row grid with the
       icon spanning both keeps the icon optically aligned to the heading while
       the text sets its own rhythm — no wrapper element needed in the markup. */
    .feat-card{
      background:#0d1117;border:1px solid var(--border);border-radius:16px;
      padding:22px 24px;
      display:grid;grid-template-columns:44px 1fr;column-gap:16px;row-gap:5px;
      align-content:start;
      transition:border-color .25s,transform .25s;
    }
    .feat-card-icon{grid-column:1;grid-row:1 / span 2;align-self:start;}
    .feat-card h3{grid-column:2;grid-row:1;align-self:center;}
    .feat-card p{grid-column:2;grid-row:2;}
    .feat-card:hover{border-color:rgba(80,136,253,.4);transform:translateY(-2px);}
    .feat-card-icon{width:44px;height:44px;border-radius:12px;display:flex;align-items:center;justify-content:center;flex-shrink:0;}
    .feat-card h3{font-size:16px;font-weight:600;color:#f1f5f9;margin:0;}
    .feat-card p{font-size:14px;color:var(--muted);line-height:1.6;margin:0;}
    .feat-card .feat-tag{font-size:11px;padding:2px 8px;border-radius:20px;font-weight:600;vertical-align:middle;margin-left:8px;}
    .feat-card ul{margin:0;padding:0;list-style:none;display:flex;flex-direction:column;gap:7px;}
    .feat-card ul li{font-size:13px;color:var(--muted);line-height:1.5;padding-left:14px;position:relative;}
    .feat-card ul li::before{content:'–';position:absolute;left:0;color:var(--muted);}
    @media(max-width:640px){.features-grid{grid-template-columns:1fr;}}
    .feat:hover{background:rgba(255,255,255,.03)}
    .feat-icon{width:40px;height:40px;border-radius:10px;display:flex;align-items:center;justify-content:center;flex-shrink:0}
    .feat-icon svg{width:22px;height:22px}
    .feat-icon.blue{background:rgba(80,136,253,.14)}
    .feat-icon.green{background:rgba(72,202,124,.14)}
    .feat-icon.cyan{background:rgba(173,239,253,.12)}
    .feat-icon.yellow{background:rgba(254,188,46,.12)}
    .feat-icon.purple{background:rgba(180,100,255,.12)}
    .feat-icon.red{background:rgba(255,107,107,.12)}
    .feat h3{font-size:16px;font-weight:600;letter-spacing:-.01em}
    .feat-tag{display:inline-flex;align-items:center;gap:5px;font-size:16px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:var(--blue);background:rgba(80,136,253,.12);border-radius:4px;padding:2px 7px;width:fit-content}
    .feat ul{list-style:none;display:flex;flex-direction:column;gap:7px}
    .feat li{font-size:16px;color:var(--muted);line-height:1.55;padding-left:14px;position:relative}
    .feat li::before{content:'–';position:absolute;left:0;color:var(--dim)}
    .feat-sub{font-size:16px;color:var(--dim);font-weight:600;text-transform:uppercase;letter-spacing:.05em}

    /* ── Who it's for ──────────────────────────────────────────────────────
       Four columns, each led by its accent. The accent does three jobs rather
       than one: a thick glowing bar on top, a wash fading down behind the
       column, and the hover lift — so the block reads as lit from its own
       colour instead of being a caption under a hairline. --acc is set per
       item in the markup and every rule below derives from it. */
    #segments{background:rgba(255,255,255,.012)}
    .seg-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:20px;margin-top:52px}
    .seg{
      position:relative;padding:24px 18px 22px;border-radius:0 0 14px 14px;
      transition:transform .25s var(--ease);
    }
    /* the wash, fading out before it reaches the copy */
    .seg::before{
      content:'';position:absolute;inset:0;border-radius:inherit;pointer-events:none;
      background:linear-gradient(180deg,var(--acc) 0%,transparent 58%);
      opacity:.13;
    }
    /* the bar, with its own glow */
    .seg::after{
      content:'';position:absolute;left:0;right:0;top:0;height:3px;border-radius:3px;
      background:var(--acc);box-shadow:0 0 16px var(--acc),0 0 3px var(--acc);
    }
    .seg:hover{transform:translateY(-3px)}
    .seg-role{position:relative;font-size:17px;font-weight:600;color:#fff;letter-spacing:-.015em;margin-bottom:9px}
    .seg p{position:relative;font-size:13.5px;color:rgba(255,255,255,.62);line-height:1.6}

    @media(max-width:860px){.seg-grid{grid-template-columns:repeat(2,1fr);gap:18px}}
    @media(max-width:520px){.seg-grid{grid-template-columns:1fr;gap:14px}}

    /* HOW IT WORKS */
    #how{background:rgba(255,255,255,.012)}
    .how-grid{margin-top:60px;display:grid;grid-template-columns:repeat(3,1fr);gap:24px;}
    .how-card{background:#0d1117;border:1px solid var(--border);border-radius:16px;overflow:hidden;display:flex;flex-direction:column;}
    .how-card-img{width:100%;display:block;border-bottom:1px solid var(--border);}
    .how-card-body{padding:24px;display:flex;flex-direction:column;gap:10px;}
    .how-card-num{font-size:13px;font-weight:700;color:transparent;background:var(--grad);-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;letter-spacing:.06em;}
    .how-card-body h3{font-size:17px;font-weight:600;letter-spacing:-.02em;color:#f1f5f9;margin:0;}
    .how-card-body p{font-size:14px;color:var(--muted);line-height:1.65;margin:0;}
    @media(max-width:820px){.how-grid{grid-template-columns:1fr;}}

    /* Step visuals */
    .sv-install{width:100%;display:flex;flex-direction:column;gap:10px}
    .sv-install-bar{display:flex;align-items:center;gap:10px;background:rgba(255,255,255,.05);border:1px solid rgba(255,255,255,.08);border-radius:10px;padding:10px 14px}
    .sv-install-bar svg{width:22px;height:22px}
    .sv-install-text{flex:1}
    .sv-install-name{font-size:16px;font-weight:600}
    .sv-install-sub{font-size:16px;color:var(--dim)}
    .sv-install-btn{background:var(--blue);color:#fff;font-size:16px;font-weight:600;padding:5px 12px;border-radius:6px;white-space:nowrap}
    .sv-install-ok{font-size:16px;color:var(--green);text-align:center}

    .sv-report{width:100%}
    .sv-field{display:flex;align-items:center;gap:8px;padding:5px 0;border-bottom:1px solid rgba(255,255,255,.04);font-size:16px}
    .sv-field:last-child{border-bottom:none}
    .sv-label{color:var(--dim);width:64px;flex-shrink:0}
    .sv-val{color:var(--muted)}
    .sv-badge{padding:2px 7px;border-radius:4px;font-size:16px;font-weight:600}
    .sv-badge.crit{background:rgba(255,107,107,.15);color:#FF6B6B}

    .sv-notifs{width:100%;display:flex;flex-direction:column;gap:7px}
    .sv-notif{display:flex;align-items:center;gap:10px;background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.07);border-radius:8px;padding:9px 12px;font-size:16px}
    .sv-notif-icon{width:26px;height:26px;border-radius:7px;display:flex;align-items:center;justify-content:center;flex-shrink:0;font-size:16px}
    .sv-notif-body{flex:1}
    .sv-notif-title{font-weight:600;font-size:16px;margin-bottom:1px}
    .sv-notif-sub{color:var(--dim);font-size:16px}
    .sv-notif-time{color:var(--dim);font-size:16px}

    /* STATS */

    /* TESTIMONIALS */
    #testimonials{background:rgba(255,255,255,.012)}
    /* Edge fades, same treatment as the feature ticker, so cards dissolve rather
       than being cut off at the container edge. */
    .test-scroller{position:relative;margin-top:52px;overflow:hidden}
    .test-scroller::before,.test-scroller::after{content:'';position:absolute;top:0;bottom:0;width:120px;z-index:2;pointer-events:none}
    .test-scroller::before{left:0;background:linear-gradient(90deg,var(--bg) 0%,transparent 100%)}
    .test-scroller::after{right:0;background:linear-gradient(-90deg,var(--bg) 0%,transparent 100%)}
    .test-track{display:flex;width:max-content;animation:testScroll 46s linear infinite}
    .test-track:hover{animation-play-state:paused}
    @keyframes testScroll{to{transform:translateX(-50%)}}
    /* Spacing as margin-right on every card, NOT flex gap. With gap there is no
       gap after the last card, so half the track width lands 8px short of where
       the fifth card starts and the wrap visibly jumps. */
    .test-track .test-card{flex:0 0 400px;width:400px;margin-right:16px}
    @media(prefers-reduced-motion:reduce){.test-track{animation:none}}
    @media(max-width:640px){.test-track .test-card{flex-basis:300px;width:300px}}
    .test-card{background:var(--card);border:1px solid var(--border);border-radius:16px;padding:24px;display:flex;flex-direction:column;gap:14px;transition:border-color .2s}
    .test-card:hover{border-color:rgba(255,255,255,.18)}
    .test-stars{display:flex;gap:3px}
    .test-star{color:#FBBC04;font-size:16px}
    .test-star.empty{color:var(--dim)}
    .test-text{font-size:16px;color:var(--muted);line-height:1.7;flex:1}
    .test-author{display:flex;align-items:center;gap:10px;margin-top:4px}
    .test-avatar{width:36px;height:36px;border-radius:50%;background:var(--grad-diag);display:flex;align-items:center;justify-content:center;font-size:16px;font-weight:600;color:#fff;flex-shrink:0;overflow:hidden}.test-avatar img{width:100%;height:100%;object-fit:cover;border-radius:50%}
    .test-name{font-size:16px;font-weight:600}
    .test-date{font-size:16px;color:var(--dim)}
    .test-role{font-size:16px;color:var(--dim)}

    /* PRICING */
    #pricing{background:rgba(255,255,255,.012)}
    .pricing-grid{display:grid;grid-template-columns:1fr 1.6fr;gap:16px;margin-top:56px;max-width:780px;margin-left:auto;margin-right:auto;align-items:stretch}
    .plan{background:var(--card);border:1px solid var(--border);border-radius:18px;padding:28px;display:flex;flex-direction:column;gap:20px;transition:transform .3s,border-color .3s}
    .plan:hover{transform:translateY(-5px)}
    .plan.pro{background:linear-gradient(145deg,rgba(80,136,253,.12) 0%,rgba(10,10,18,.95) 50%,rgba(72,202,124,.08) 100%);border-color:transparent;position:relative;}
    .plan.pro::before{content:'';position:absolute;inset:0;border-radius:18px;padding:1px;background:linear-gradient(145deg,rgba(80,136,253,.6),rgba(72,202,124,.4));-webkit-mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);-webkit-mask-composite:xor;mask-composite:exclude;pointer-events:none}
    .plan.pro::after{content:'';position:absolute;inset:0;border-radius:18px;background:radial-gradient(ellipse at 30% 0%,rgba(80,136,253,.15) 0%,transparent 60%),radial-gradient(ellipse at 80% 100%,rgba(72,202,124,.1) 0%,transparent 55%);pointer-events:none}
    .plan.pro *{color:#fff!important}
    .plan.pro .plan-feat{border-color:rgba(255,255,255,.07)!important}
    .plan.pro .plan-check{color:var(--green)!important}
    .plan.pro .plan-btn{background:linear-gradient(90deg,var(--blue),var(--green));color:#fff!important;border-color:transparent}
    .plan.pro .plan-btn:hover{opacity:.88}
    .plan.pro .plan-tag{background:rgba(80,136,253,.15);color:var(--blue)!important}
    .plan.pro .plan-name{background:var(--grad);-webkit-background-clip:text;background-clip:text;color:transparent!important;-webkit-text-fill-color:transparent!important;font-weight:700;letter-spacing:.1em}
    .plan-name{font-size:16px;font-weight:600;text-transform:uppercase;letter-spacing:.07em;color:var(--dim);margin-bottom:8px}
    /* Billing period switch. A segmented pill rather than a checkbox toggle so
       both prices are legible at once — the yearly saving is the argument, and
       a switch that hides one number hides half of it. */
    .plan-billing{display:inline-flex;gap:2px;padding:3px;margin-bottom:14px;background:rgba(255,255,255,.06);border:1px solid var(--border);border-radius:999px}
    .pb-opt{background:none;border:none;cursor:pointer;font-family:var(--font);font-size:12.5px;font-weight:600;color:rgba(255,255,255,.55)!important;padding:6px 14px;border-radius:999px;transition:background .2s,color .2s;white-space:nowrap}
    .pb-opt:hover{color:#fff!important}
    .pb-opt.active{background:rgba(255,255,255,.14);color:#fff!important}
    .plan-price{display:flex;align-items:flex-end;gap:4px}
    .plan-curr{font-size:20px;font-weight:400;padding-bottom:5px}
    .plan-amt{font-size:48px;font-weight:300;letter-spacing:-0.04em;line-height:1}
    .plan-per{font-size:16px;color:var(--muted);padding-bottom:6px}
    .plan-tag{display:inline-flex;align-items:center;gap:5px;margin-top:10px;font-size:16px;font-weight:600;background:rgba(80,136,253,.12);color:var(--blue);border-radius:5px;padding:3px 9px;width:fit-content}
    .plan-desc{font-size:16px;color:var(--muted);line-height:1.6}
    .plan-feats{display:flex;flex-direction:column;gap:0;flex:1}
    .plan-feat{padding:8px 0;border-bottom:1px solid var(--border);font-size:16px;color:var(--muted);display:flex;align-items:flex-start;gap:8px}
    .plan-feat:last-child{border-bottom:none}
    .plan-check{color:var(--green);font-size:16px;flex-shrink:0;margin-top:1px}
    .plan-btn{display:block;text-align:center;padding:12px;border-radius:10px;font-size:16px;font-weight:600;border:1px solid var(--border);color:var(--text);transition:background .2s,transform .2s;cursor:pointer;background:none;width:100%;font-family:var(--font)}
    .plan-btn:hover{background:rgba(255,255,255,.08);transform:scale(.98)}

    /* ── Pricing cards ─────────────────────────────────────────────────────
       Price is the hero; the CTA is pinned to the bottom of the card with
       margin-top:auto so both buttons align on the same line however the two
       feature lists differ in length.

       Pro's accent is GOLD, not the brand blue/green: it is the same signal the
       app puts on a paid profile, so the badge someone sees after buying is the
       colour they were sold on. */
    .pr-cards{display:grid;grid-template-columns:1fr 1fr;gap:18px;max-width:860px;margin:56px auto 0;align-items:stretch}
    .pr-card{position:relative;display:flex;flex-direction:column;padding:30px 28px 30px;border-radius:20px;background:#0b0d13;border:1px solid var(--border);transition:transform .3s var(--ease),border-color .3s}
    .pr-card:hover{transform:translateY(-4px)}
    .pr-card--pro{background:radial-gradient(ellipse at 25% -10%,rgba(245,196,81,.13) 0%,transparent 62%),radial-gradient(ellipse at 90% 112%,rgba(224,164,25,.09) 0%,transparent 55%),#0f0d09;border-color:transparent}
    /* Gradient ring drawn with a mask so the card keeps its dark fill. */
    .pr-card--pro::before{content:'';position:absolute;inset:0;border-radius:20px;padding:1px;background:linear-gradient(150deg,rgba(245,196,81,.9),rgba(224,164,25,.55) 55%,rgba(245,196,81,.22));-webkit-mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);-webkit-mask-composite:xor;mask-composite:exclude;pointer-events:none}

    .pr-top{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:18px}
    .pr-name{font-size:12px;font-weight:700;text-transform:uppercase;letter-spacing:.12em;color:var(--dim)}
    .pr-name--pro{background:linear-gradient(135deg,#f5c451,#e0a419);-webkit-background-clip:text;background-clip:text;color:transparent;-webkit-text-fill-color:transparent}
    /* Green, not gold: the saving is a separate message from the plan itself,
       and in gold it read as more Pro branding rather than a discount. */
    .pr-badge{font-size:10.5px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:#48CA7C;background:rgba(72,202,124,.12);border:1px solid rgba(72,202,124,.32);border-radius:999px;padding:3px 10px;white-space:nowrap}

    /* The hero. */
    .pr-price{display:flex;align-items:baseline;gap:2px;font-size:54px;font-weight:300;letter-spacing:-.045em;line-height:1;color:var(--text)}
    .pr-cur{font-size:24px;font-weight:400;align-self:flex-start;margin-top:6px;color:var(--muted);letter-spacing:normal}
    /* letter-spacing:normal — the price's tight -.045em is inherited by these
       small spans and crushes them into 'peryear'. */
    .pr-per{font-size:14px;color:var(--muted);font-weight:400;margin-left:9px;align-self:flex-end;padding-bottom:5px;letter-spacing:normal}
    .pr-sub{font-size:13.5px;color:var(--muted);margin-top:12px;line-height:1.5}

    .pr-rule{height:1px;background:var(--border);margin:22px 0 20px}
    .pr-list{list-style:none;display:flex;flex-direction:column;gap:11px;margin:0 0 26px;padding:0}
    .pr-list li{position:relative;padding-left:24px;font-size:13.5px;line-height:1.5;color:var(--muted)}
    .pr-list li strong{color:var(--text);font-weight:600}
    .pr-list li::before{content:'✓';position:absolute;left:0;top:-1px;color:var(--green);font-size:13px}
    .pr-card--pro .pr-list li::before{color:#f5c451}

    /* margin-top:auto is what pins this to the bottom of the card. */
    .pr-cta{display:block;margin-top:auto;text-align:center;padding:13px 16px;border-radius:11px;font-size:14px;font-weight:600;border:1px solid var(--border);color:var(--text);transition:background .2s,opacity .2s,transform .2s}
    .pr-cta:hover{background:rgba(255,255,255,.08);transform:scale(.98)}
    .pr-cta--pro{background:linear-gradient(135deg,#f5c451,#e0a419);border-color:transparent;color:#2a1e00;font-weight:800}
    .pr-cta--pro:hover{opacity:.9;background:linear-gradient(135deg,#f5c451,#e0a419)}

    /* align-self, because a flex column stretches its children by default —
       the toggle would otherwise span the whole card instead of hugging it. */
    .pr-cards .plan-billing{align-self:flex-start;margin-bottom:16px}

    @media(max-width:760px){
      .pr-cards{grid-template-columns:1fr;max-width:440px;gap:16px}
      .pr-card{padding:26px 22px}
      .pr-price{font-size:44px}
    }

    /* FAQ */
    #faq{background:rgba(255,255,255,.012)}
    .faq-list{margin-top:52px;display:flex;flex-direction:column;gap:0;max-width:700px;margin-left:auto;margin-right:auto}
    .faq-item{border-bottom:1px solid var(--border)}
    .faq-q{width:100%;text-align:left;background:none;border:none;color:var(--text);font-family:var(--font);font-size:16px;font-weight:500;padding:22px 0;cursor:pointer;display:flex;align-items:center;justify-content:space-between;gap:16px;transition:color .2s}
    .faq-q:hover{color:rgba(255,255,255,.85)}
    .faq-arrow{flex-shrink:0;width:20px;height:20px;border-radius:50%;background:var(--card);border:1px solid var(--border);display:flex;align-items:center;justify-content:center;font-size:16px;transition:transform .3s var(--ease),background .2s}
    .faq-item.open .faq-arrow{transform:rotate(45deg);background:rgba(80,136,253,.15);border-color:rgba(80,136,253,.3)}
    .faq-a{font-size:16px;color:var(--muted);line-height:1.7;max-height:0;overflow:hidden;transition:max-height .4s var(--ease),padding .3s}
    /* Headroom for the longest answer at mobile width, where a ~250-character
       reply wraps to about 7 lines and clipped against the old 200px ceiling. */
    .faq-item.open .faq-a{max-height:400px;padding-bottom:20px}

    /* CTA */
    .cta-section{padding:120px 28px;text-align:center;position:relative;overflow:hidden}
    .cta-blob{display:none}
    .cta-inner{position:relative;z-index:1;max-width:720px;margin:0 auto}
    .cta-inner h2{font-size:clamp(43px,6.25vw,73px);font-weight:300;letter-spacing:-0.03em;margin-bottom:12px}
    .cta-inner h2 strong{font-weight:600}
    .cta-tagline{font-size:16px;color:rgba(255,255,255,.8);margin-bottom:36px;line-height:1.65;max-width:440px;margin-left:auto;margin-right:auto}
    .cta-checks{display:flex;align-items:center;justify-content:center;gap:24px;margin-top:24px;flex-wrap:wrap}
    .cta-check{font-size:16px;color:rgba(255,255,255,.85);display:flex;align-items:center;gap:6px}
    .cta-check-icon{color:#fff}

    /* FOOTER */
    .footer-wrap{position:relative;overflow:hidden}
    .footer-glow-img{position:absolute;bottom:0;left:50%;transform:translateX(-50%);width:130%;max-width:1600px;pointer-events:none;opacity:.85;z-index:0}
    footer{border-top:1px solid var(--border);padding:44px 0 32px;position:relative;z-index:1}
    .footer-inner{display:flex;align-items:flex-start;justify-content:space-between;gap:40px;flex-wrap:wrap;max-width:var(--max);margin:0 auto;padding:0 28px}
    .footer-brand{display:flex;flex-direction:column;gap:10px;max-width:220px}
    .footer-logo svg{height:26px;width:auto}
    .footer-brand p{font-size:16px;color:rgba(255,255,255,.75);line-height:1.6}
    .footer-links{display:flex;gap:36px;flex-wrap:wrap}
    .footer-link{font-size:16px;color:rgba(255,255,255,.85);transition:color .2s}
    .footer-link:hover{color:#fff}
    .footer-bottom{max-width:var(--max);margin:28px auto 0;padding:20px 28px 0;border-top:1px solid rgba(255,255,255,.2);display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:8px}
    .footer-bottom p{font-size:16px;color:rgba(255,255,255,.7)}
    .footer-bottom a{color:rgba(255,255,255,.8);transition:color .2s}
    .footer-bottom a:hover{color:#fff}

    /* NOTIFY MODAL */
    .modal-overlay{position:fixed;inset:0;background:rgba(0,0,0,.75);backdrop-filter:blur(12px);z-index:500;display:flex;align-items:center;justify-content:center;padding:20px;opacity:0;pointer-events:none;transition:opacity .3s}
    .modal-overlay.open{opacity:1;pointer-events:all}
    .modal{background:#111;border:1px solid rgba(255,255,255,.12);border-radius:20px;padding:36px;max-width:440px;width:100%;position:relative;transform:translateY(20px);transition:transform .3s var(--ease)}
    .modal-overlay.open .modal{transform:translateY(0)}
    .modal-close{position:absolute;top:16px;right:16px;background:rgba(255,255,255,.06);border:none;color:var(--muted);width:32px;height:32px;border-radius:50%;cursor:pointer;font-size:16px;display:flex;align-items:center;justify-content:center;transition:background .2s}
    .modal-close:hover{background:rgba(255,255,255,.12)}
    .modal h3{font-size:22px;font-weight:600;margin-bottom:8px}
    .modal p{font-size:16px;color:var(--muted);line-height:1.6;margin-bottom:24px}
    .modal-form{display:flex;flex-direction:column;gap:12px}
    .modal-input{background:rgba(255,255,255,.06);border:1px solid var(--border);border-radius:10px;padding:12px 16px;font-size:16px;color:var(--text);font-family:var(--font);width:100%;outline:none;transition:border-color .2s}
    .modal-input:focus{border-color:rgba(80,136,253,.5)}
    .modal-input::placeholder{color:var(--dim)}
    .modal-submit{background:var(--blue);color:#fff;border:none;border-radius:10px;padding:13px;font-size:16px;font-weight:600;cursor:pointer;font-family:var(--font);transition:opacity .2s,transform .2s}
    .modal-submit:hover{opacity:.88;transform:scale(.98)}
    .modal-submit:disabled{opacity:.5;cursor:not-allowed;transform:none}
    .modal-success{display:none;text-align:center;padding:20px 0}
    .modal-success .check{font-size:48px;margin-bottom:12px}
    .modal-success h4{font-size:18px;font-weight:600;margin-bottom:8px}
    .modal-success p{font-size:16px;color:var(--muted)}
    .modal.success-state .modal-form{display:none}
    .modal.success-state .modal-success{display:block}

    /* RESPONSIVE */
    @media(max-width:820px){
      .features-grid{grid-template-columns:1fr}
      .feat:last-child{grid-column:auto!important}
      .step{grid-template-columns:48px 1fr}
      .step-vis{display:none}
      .pricing-grid{grid-template-columns:1fr;max-width:420px}
      .nav-links{display:none}
      .footer-inner{flex-direction:column;gap:28px}
    }
    @media(max-width:600px){
      .hero h1{font-size:47px}
      .cta-inner h2{font-size:40px}
      .step-num{font-size:28px}
        }

/* ══ Typeface ══════════════════════════════════════════════════════════════
   BDO Grotesk, self-hosted. One variable file covers 300-900, which is the
   whole range the site uses, so it replaces what were five separate Inter
   weights fetched from Google — fewer bytes and no third-party request on
   first paint.

   Subset to Latin plus the punctuation actually rendered here; 260KB of TTF
   becomes 58KB of WOFF2. Licensed under the SIL OFL, which permits embedding
   provided the notice ships alongside: see assets/fonts/OFL.txt.

   font-display:swap deliberately. The face is preloaded, so the swap window
   is short, and text that is readable immediately beats text that is absent. */
@font-face{
  font-family:"BDO Grotesk";
  src:url("fonts/bdo-grotesk-var.woff2") format("woff2-variations"),
      url("fonts/bdo-grotesk-var.woff2") format("woff2");
  font-weight:300 900;
  font-style:normal;
  font-display:swap}

:root{--font:"BDO Grotesk",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif}
body{font-family:var(--font)}

/* BDO Grotesk has no star glyph, so the rating stars are given an explicit
   stack rather than left to whatever the browser reaches for next. */
.test-star,.hero-stars{font-family:-apple-system,"Segoe UI Symbol","Apple Color Emoji",sans-serif}

/* ══ Multi-page additions ═══════════════════════════════════════════════════
   base.css is the homepage's original stylesheet, kept intact so the hero,
   marquee, testimonials and pricing keep the treatment already signed off.
   Everything below is new: the navigation that now has to reach fourteen
   pages, the section components those pages are built from, and the hero
   story sequence. New class names are deliberately unprefixed (.card, .chk,
   .stp) because base.css namespaces all of its own (.feat-card, .pr-card),
   so the two sets cannot collide. */

/* ── Navigation ───────────────────────────────────────────────────────────
   Two dropdown groups, a text log-in and one primary action. The menus open
   on hover for pointers and on click for keyboards and touch, which is why
   the open state is driven by a class rather than :hover alone. */
.nav-inner{display:flex;align-items:center;gap:22px;position:relative}
.nav-links{display:flex;align-items:center;gap:4px;list-style:none;margin:0 auto 0 14px}
.nav-links > li > a,.nav-grp-btn{
  display:inline-flex;align-items:center;gap:5px;padding:8px 12px;border-radius:9px;
  font-size:14px;font-weight:500;color:rgba(255,255,255,.72);background:none;border:0;
  font-family:inherit;cursor:pointer;transition:color .18s,background .18s}
.nav-links > li > a:hover,.nav-grp-btn:hover,.nav-group.open .nav-grp-btn{color:#fff;background:rgba(255,255,255,.06)}
.nav-grp-btn svg{transition:transform .22s var(--ease);opacity:.6}
.nav-group.open .nav-grp-btn svg{transform:rotate(180deg)}
.nav-group{position:static}
/* ── Mega menu ─────────────────────────────────────────────────────────────
   A wide panel anchored to the header rather than to the button that opened
   it, so both menus share one edge and the eye does not have to re-find the
   panel when switching between them. Width follows the column count, so the
   four-item Solutions menu does not sit in a half-empty product-sized box. */
.nav-menu{
  position:absolute;top:calc(100% - 8px);left:50%;transform:translateX(-50%) translateY(-6px);
  padding:12px;border-radius:12px;
  /* Frosted glass: a translucent fill plus a blur of whatever is behind it.
     The fill has to stay semi-transparent — at full opacity the backdrop
     filter has nothing to show and it reads as a flat panel again. saturate
     keeps colour passing through from tipping grey. */
  /* Opaque enough to read against on its own. backdrop-filter is a
     progressive enhancement — Firefox users with it disabled, and any browser
     without GPU compositing, get no blur at all, and at .72 the hero headline
     was legible straight through the panel. */
  background:rgba(12,12,17,.985);
  -webkit-backdrop-filter:blur(48px) saturate(185%);
  backdrop-filter:blur(48px) saturate(185%);
  border:1px solid rgba(255,255,255,.12);
  box-shadow:
    0 30px 80px rgba(0,0,0,.6),
    inset 0 1px 0 rgba(255,255,255,.07);
  opacity:0;visibility:hidden;z-index:60;
  /* visibility is stepped, not eased: delayed by the fade so the panel stays
     present while it fades out, and appears instantly on the way in. */
  transition:opacity .18s,transform .18s,visibility 0s linear .18s}
/* Keyed on the panel, not on .nav-group: site.js re-parents the panel onto
   <nav>, so it is no longer a descendant of the group. The group selector is
   kept as well so the menu still opens if JS has not run yet. */
.nav-menu.open,
.nav-group.open .nav-menu{opacity:1;visibility:visible;transform:translateX(-50%);transition-delay:0s}
/* Where the blur genuinely renders, the fill can drop back and let it show. */
@supports ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  /* Still high, deliberately. A browser can report support for backdrop-filter
     and then not composite it (headless, GPU blocklists, low-power modes), so
     the fill has to carry legibility on its own; the blur is what makes it
     look like glass, not what makes it readable. */
  /* The blur reaches the page now that the panel is not inside a backdrop
     root, so the fill can come back down and let it show. */
  .nav-drawer{background:rgba(12,12,17,.94)}
}
.nav-menu-grid{
  display:grid;grid-template-columns:repeat(var(--cols,3),minmax(268px,1fr));
  gap:4px 10px}
/* Hairline rules between columns, drawn with a gradient so they fade at the
   ends instead of butting into the panel padding. */
.nav-menu-grid > .nav-item:not(:nth-child(var(--cols,3)n+1))::before{
  content:"";position:absolute;left:-5px;top:8px;bottom:8px;width:1px;
  background:linear-gradient(transparent,rgba(255,255,255,.09) 22%,rgba(255,255,255,.09) 78%,transparent)}
.nav-item{
  position:relative;display:flex;align-items:flex-start;gap:12px;
  padding:12px 13px;border-radius:8px;transition:background .16s}
.nav-item:hover{background:rgba(255,255,255,.055)}
.nav-item[aria-current="page"]{background:rgba(80,136,253,.14)}
.nav-item-ic{
  flex:none;display:grid;place-items:center;width:30px;height:30px;margin-top:1px;
  border-radius:8px;color:#8fb4ff;background:rgba(80,136,253,.12);
  border:1px solid rgba(255,255,255,.07);transition:color .18s}
.nav-item:hover .nav-item-ic{color:#cfe0ff}
.nav-item-ic .ic{width:17px;height:17px}
.nav-item-tx{display:block;min-width:0}
.nav-menu-t{display:block;font-size:13.5px;font-weight:600;color:#fff;letter-spacing:-.005em}
.nav-menu-d{display:block;font-size:12px;color:var(--muted);margin-top:3px;line-height:1.45}
.nav-right{display:flex;align-items:center;gap:8px;margin-left:auto}
.nav-login{padding:8px 12px;border-radius:9px;font-size:14px;font-weight:500;color:rgba(255,255,255,.72);transition:color .18s,background .18s}
.nav-login:hover{color:#fff;background:rgba(255,255,255,.06)}
.nav-burger{display:none;flex-direction:column;gap:4px;padding:9px;background:none;border:0;cursor:pointer}
.nav-burger span{display:block;width:18px;height:2px;border-radius:2px;background:#fff;transition:transform .22s,opacity .18s}
.nav-burger[aria-expanded="true"] span:nth-child(1){transform:translateY(6px) rotate(45deg)}
.nav-burger[aria-expanded="true"] span:nth-child(2){opacity:0}
.nav-burger[aria-expanded="true"] span:nth-child(3){transform:translateY(-6px) rotate(-45deg)}
/* Built by site.js and appended to <nav> on every page, so it must be hidden
   by default at every width — not only inside the mobile media query, where a
   missing rule left it painting as raw links over the hero. */
.nav-drawer{display:none}

/* ── Hero additions ───────────────────────────────────────────────────── */
.hero-eyebrow{
  position:relative;z-index:1;display:inline-block;margin-bottom:20px;padding:6px 13px;
  border:1px solid var(--border);border-radius:999px;background:rgba(255,255,255,.03);
  font-size:11.5px;font-weight:600;letter-spacing:.13em;text-transform:uppercase;color:rgba(255,255,255,.66);
  animation:fadeUp .9s var(--ease) .05s both}
.hero-note{position:relative;z-index:1;margin-top:20px;font-size:13.5px;color:rgba(255,255,255,.45);animation:fadeUp .9s var(--ease) .3s both}
/* Landing and persona pages open on a headline, not on a full-screen stage.
   base.css pins .hero to min-height:100vh, which is right for the homepage
   where the story sequence needs the room and wrong everywhere else — an
   inner page that costs a full viewport before its first section is a page
   people bounce off. */
.hero-compact{min-height:0;padding:150px 28px 72px}
/* 40% up from 58px. max-width is lifted with it: base.css caps .hero h1 at
   940px, which at this size would wrap the longer inner headlines into a
   third line and undo the effect. */
.hero-compact h1{font-size:81px;max-width:1120px;line-height:1.05}
.hero-compact .hero-sub{font-size:17.5px;max-width:620px}

/* ── Section furniture ────────────────────────────────────────────────── */
.sec-head{max-width:720px;margin:0 auto 54px;text-align:center}
.sec-head h2{font-size:40px;font-weight:600;letter-spacing:-.03em;line-height:1.14;text-wrap:balance}
.sec-head p{margin-top:14px;font-size:17px;line-height:1.6;color:var(--muted)}
.sec-cta{margin-top:44px;text-align:center}

/* ── Problem ──────────────────────────────────────────────────────────── */
.prob{padding:110px 0;border-top:1px solid var(--border)}
.prob-inner{max-width:760px;text-align:center}
.prob-inner h2{font-size:42px;font-weight:600;letter-spacing:-.03em;line-height:1.12;text-wrap:balance}
.prob-body{margin-top:26px;display:grid;gap:16px}
.prob-body p{font-size:17.5px;line-height:1.68;color:var(--muted)}
.prob-close{
  margin-top:34px;padding-top:30px;border-top:1px solid var(--border);
  font-size:19px;line-height:1.55;font-weight:500;color:#fff;text-wrap:balance}

/* ── Steps ────────────────────────────────────────────────────────────── */
/* flex, not grid: an item count that doesn't divide evenly by the column
   count (3, or 5, or any count not divisible by 3 or by 2 at the tablet
   breakpoint) leaves a partial last row. flex + justify-content:center lets
   that row centre itself instead of hugging the left edge; flex-basis
   reproduces the same per-breakpoint widths a grid would give a full row. */
.steps{list-style:none;display:flex;flex-wrap:wrap;justify-content:center;gap:22px;counter-reset:s}
.stp{
  flex:0 0 calc((100% - 44px) / 3);
  position:relative;padding:32px 28px 30px;border:1px solid var(--border);border-radius:16px;
  background:var(--card);overflow:hidden}
.stp::before{
  content:"";position:absolute;inset:0 0 auto 0;height:1px;
  background:var(--grad);opacity:0;transition:opacity .3s}
.stp:hover::before{opacity:.7}
.stp h3{font-size:19px;font-weight:600;letter-spacing:-.01em;margin-bottom:10px}
.stp p{font-size:14.5px;line-height:1.66;color:var(--muted)}

/* ── Card grid ────────────────────────────────────────────────────────── */
.cards{display:flex;flex-wrap:wrap;justify-content:center;gap:20px}
.card{
  flex:0 0 calc((100% - 40px) / 3);
  padding:28px 26px;border:1px solid var(--border);border-radius:16px;background:var(--card);
  transition:border-color .25s,transform .25s var(--ease)}
.card:hover{border-color:rgba(255,255,255,.2);transform:translateY(-3px)}
.card h3{font-size:17.5px;font-weight:600;letter-spacing:-.01em;margin-bottom:9px}
.card p{font-size:14.5px;line-height:1.66;color:var(--muted)}

/* ── Checklist split ──────────────────────────────────────────────────── */
.chk-inner{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:64px;align-items:start}
.chk-copy h2{font-size:40px;font-weight:600;letter-spacing:-.03em;line-height:1.14;text-wrap:balance}
.chk-copy p{margin-top:18px;font-size:17px;line-height:1.66;color:var(--muted)}
.chk{list-style:none;display:grid;gap:2px;align-self:center}
.chk li{
  display:flex;align-items:flex-start;gap:13px;padding:15px 4px;
  border-bottom:1px solid var(--border);font-size:15.5px;line-height:1.5;color:rgba(255,255,255,.86)}
.chk li:last-child{border-bottom:0}
.chk svg{flex:none;margin-top:3px;color:var(--green)}

/* ── Service showcase (Figma 734:8577) ────────────────────────────────── */
/* Two equal columns, 40px apart, rows alternating sides. The design's light
   panels are dark here, #0a0a0a, the colour every capture is drawn on. The
   704/682 panel ratio is the design's own. */
.sc-wrap{display:grid;gap:140px}
.sc-row{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:40px;align-items:center}
.sc-row.flip .sc-copy{order:2}
.sc-copy{display:flex;flex-direction:column;gap:72px;justify-content:center}
.sc-head{display:flex;flex-direction:column;align-items:flex-start;gap:16px}
/* The brand's section label (.sec-eyebrow: green, uppercase, wide
   tracking) inside the design's pill, tinted green to match. */
.sc-tag{
  display:inline-flex;align-items:center;padding:7px 14px;border-radius:999px;
  border:1px solid rgba(72,202,124,.28);background:rgba(72,202,124,.08);
  font-size:13px;font-weight:600;line-height:18px;letter-spacing:.09em;text-transform:uppercase;color:var(--green)}
.sc-head h2,.sc-head h3{font-size:40px;font-weight:600;letter-spacing:-.03em;line-height:1.1;text-wrap:balance}
.sc-list{display:flex;flex-direction:column}
.sc-item{padding-bottom:24px}
.sc-item:last-child{padding-bottom:0}
.sc-line{position:relative;height:1px;background:var(--border);overflow:hidden}
.sc-line span{position:absolute;inset:0 auto 0 0;width:0;background:var(--grad)}
.sc-item.on .sc-line span{width:100%}
.sc-row.auto .sc-item.on .sc-line span{width:0;animation:scFill var(--sc-dur,6s) linear forwards}
.sc-row.paused .sc-item.on .sc-line span{animation-play-state:paused}
@keyframes scFill{to{width:100%}}
.sc-btn{
  display:block;width:100%;padding:24px 0 0;border:0;background:none;text-align:left;cursor:pointer;
  font:inherit;font-size:15.5px;line-height:22px;color:rgba(255,255,255,.55);transition:color .2s}
.sc-btn:hover,.sc-item.on .sc-btn{color:#fff}
.sc-btn:focus-visible{outline:2px solid var(--blue);outline-offset:4px;border-radius:4px}
.sc-body{display:grid;grid-template-rows:0fr;transition:grid-template-rows .45s var(--ease)}
.sc-item.on .sc-body{grid-template-rows:1fr}
.sc-body p{
  overflow:hidden;max-width:420px;padding-top:0;font-size:14.5px;line-height:1.6;color:var(--muted);
  transition:padding-top .45s var(--ease)}
.sc-item.on .sc-body p{padding-top:10px}
.sc-more{
  display:inline-flex;align-items:center;gap:8px;align-self:flex-start;margin-top:-40px;
  font-size:15px;font-weight:500;color:var(--green)}
.sc-more svg{transition:transform .2s var(--ease)}
.sc-more:hover svg{transform:translateX(3px)}
.sc-panel{
  position:relative;aspect-ratio:704/682;border-radius:32px;overflow:hidden;
  background:#0a0a0a;border:1px solid var(--border)}
/* The colour behind the capture. site.js draws it live on a canvas
   (.sc-gl, see "Showcase mesh" there) and marks the panel .gl; everything
   below for .sc-mesh is only the fallback for browsers without WebGL.
   Fallback: each row shows one frame of the Figma mesh (209:1718), so each
   card keeps one colour set. Two copies of
   that frame turn in opposite directions at different speeds, the second
   mirrored and screened over the first, so the soft shapes orbit and flow
   through each other instead of sitting still. The layer is oversized so
   turning never shows a corner. */
.sc-mesh{position:absolute;inset:0;pointer-events:none}
.sc-mesh i{
  position:absolute;left:-40%;top:-40%;width:180%;height:180%;
  background-position:center;background-size:100% 100%;background-repeat:no-repeat;will-change:transform}
.sc-mesh i:nth-child(1){animation:scTurn 16s linear infinite}
.sc-mesh i:nth-child(2){mix-blend-mode:screen;opacity:.75;animation:scTurnBack 22s linear infinite}
.sc-row:nth-child(2) .sc-mesh i{animation-delay:-5s}
.sc-row:nth-child(3) .sc-mesh i{animation-delay:-11s}
@keyframes scTurn{
  0%{transform:rotate(0deg) scale(1)}
  50%{transform:rotate(180deg) scale(1.12)}
  100%{transform:rotate(360deg) scale(1)}}
@keyframes scTurnBack{
  0%{transform:scaleX(-1) rotate(0deg) scale(1.1)}
  50%{transform:scaleX(-1) rotate(180deg) scale(.95)}
  100%{transform:scaleX(-1) rotate(360deg) scale(1.1)}}
.sc-gl{position:absolute;inset:0;width:100%;height:100%;display:block}
.sc-panel.gl .sc-mesh,.ft-panel.gl .sc-mesh{display:none}
.sc-panel::after{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:radial-gradient(64% 56% at 50% 50%,rgba(10,10,10,.6),rgba(10,10,10,.15) 72%,rgba(10,10,10,0))}
.sc-pic{z-index:1}
.sc-pic{
  position:absolute;left:50%;top:50%;width:94%;height:auto;transform:translate(-50%,-48%) scale(.98);
  opacity:0;transition:opacity .5s var(--ease),transform .6s var(--ease)}
.sc-pic.on{opacity:1;transform:translate(-50%,-50%) scale(1)}
@media(max-width:900px){
  .sc-wrap{gap:96px}
  .sc-row{grid-template-columns:1fr;gap:32px}
  .sc-row.flip .sc-copy{order:0}
  .sc-copy{gap:36px}
  .sc-more{margin-top:-8px}
  .sc-panel{border-radius:24px}
}
@media(max-width:760px){
  .sc-head h2,.sc-head h3{font-size:32px}
}
@media(prefers-reduced-motion:reduce){
  .sc-body,.sc-body p,.sc-pic{transition:none}
  .sc-mesh i{animation:none}
}

/* ── Perks grid (Figma 741:8947) ──────────────────────────────────────── */
/* Left-aligned head, then a 3x2 grid of cards 32px apart. Each card is the
   design's soft gradient panel in the dark theme: no hard border, copy at
   the top, and the picture filling the lower half with a faint glow under
   it. */
.pk-head{max-width:860px;margin-bottom:48px}
.pk-pill{
  display:inline-flex;align-items:center;gap:10px;padding:6px 12px 6px 16px;margin-bottom:24px;
  border:1px solid var(--border);border-radius:999px;background:rgba(255,255,255,.03);font-size:13.5px;
  transition:border-color .2s}
.pk-pill:hover{border-color:rgba(255,255,255,.2)}
.pk-pill span{color:#fff;font-weight:500}
.pk-pill i{width:1px;height:14px;background:var(--border)}
.pk-pill strong{display:inline-flex;align-items:center;gap:4px;font-weight:500;color:var(--green)}
.pk-head h2{font-size:50px;font-weight:600;letter-spacing:-.03em;line-height:1.1}
.pk-head p{margin-top:16px;max-width:564px;font-size:17px;line-height:1.6;color:var(--muted)}
.pk-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:32px}
.pk-card{
  position:relative;overflow:hidden;display:flex;flex-direction:column;min-height:400px;padding:24px 24px 0;border-radius:24px;
  background:linear-gradient(160deg,rgba(255,255,255,.06),rgba(255,255,255,.015) 60%);
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.05);transition:box-shadow .25s}
.pk-card:hover{box-shadow:inset 0 0 0 1px rgba(255,255,255,.14)}
.pk-title{display:flex;align-items:center;gap:8px}
.pk-ic{display:inline-flex;width:24px;height:24px;align-items:center;justify-content:center;color:var(--blue)}
.pk-ic svg{width:20px;height:20px}
.pk-card h3{font-size:16px;font-weight:600;letter-spacing:-.01em}
.pk-card p{margin-top:16px;max-width:340px;font-size:14.5px;line-height:1.6;color:var(--muted)}
.pk-vis{position:relative;flex:1;display:flex;align-items:center;justify-content:center;margin:12px -24px 0;min-height:220px}
.pk-vis::before{
  content:"";position:absolute;left:15%;right:15%;bottom:6%;height:55%;border-radius:50%;
  background:radial-gradient(closest-side,rgba(80,136,253,.18),transparent);pointer-events:none}
.pk-vis img{position:relative;width:100%;height:auto;display:block;transition:transform .5s var(--ease)}
.pk-card:hover .pk-vis img{transform:translateY(-4px) scale(1.02)}
@media(max-width:1000px){
  .pk-grid{grid-template-columns:repeat(2,minmax(0,1fr));gap:20px}
}
@media(max-width:760px){
  .pk-head h2{font-size:40px}
  .pk-grid{grid-template-columns:1fr}
  .pk-card{min-height:0}
}

/* ── First report block (Figma 741:8947) ────────────────────────────── */
/* .ex-bg is a gradient, page colour at the top, brand blue at 70%, back to
   black at 75%, with two page-coloured quarter circles over its halves. What
   shows between their curved edges is a beam narrowing onto the folder, as
   on dropship.io. The folder is two tilted panels with the EasyQA mark
   between them; the front panel is frosted glass, so the mark sits in it. */
.ex{position:relative;padding:120px 0 72px;overflow:hidden}
/* Blurred so the arch's curved edges melt into the black instead of reading
   as hard arcs (product owner's request). */
.ex-bg{
  position:absolute;inset:0;max-width:1280px;margin:0 auto;display:flex;pointer-events:none;
  background:linear-gradient(#000,rgba(80,136,253,.42) 70%,#000 75%);filter:blur(28px)}
.ex-curve{flex:1;align-self:stretch;background:#000}
.ex-curve.is-left{border-top-right-radius:100%}
.ex-curve.is-right{border-top-left-radius:100%}
.ex-inner{position:relative;display:flex;flex-direction:column;align-items:center;gap:96px}
.ex-head{display:flex;flex-direction:column;align-items:center;text-align:center;max-width:560px}
/* Plain text like .sec-eyebrow in base.css; change the two together. */
.ex-pill{
  display:inline-flex;margin-bottom:20px;
  font-size:13px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--green)}
.ex-head h2{font-size:50px;font-weight:600;letter-spacing:-.03em;line-height:1.1}
.ex-head p{margin-top:16px;font-size:17px;line-height:1.6;color:var(--muted)}
.ex-cta{
  display:inline-flex;align-items:center;gap:8px;margin-top:28px;padding:12px 18px;border-radius:11px;
  background:var(--blue);color:#fff;font-size:15px;font-weight:600;transition:transform .2s var(--ease),filter .2s}
.ex-cta:hover{transform:translateY(-2px);filter:brightness(1.08)}
.ex-vis{position:relative;width:100%;max-width:340px;aspect-ratio:30/24;perspective:2000px}
.ex-file-bg{
  position:absolute;top:0;left:50%;width:90%;aspect-ratio:30/24;border-radius:32px;
  background:linear-gradient(#3f78f5,#5088FD 32%,#9fdcbf);
  outline:2px solid rgba(255,255,255,.3);outline-offset:-2px;box-shadow:inset 0 7px 13px rgba(255,255,255,.25);
  transform:translate(-50%) rotateX(-10deg)}
.ex-icon{
  position:absolute;z-index:1;left:35%;top:24%;width:50%;aspect-ratio:1;padding:9%;border-radius:28%;
  background:#fff;box-shadow:0 8px 20px rgba(0,0,0,.25);
  transform:rotate(30deg) translate(-50%,-50%)}
/* The logo sits in the middle of the tile and leans with it, at the tile's
   30deg (product owner's request). The tile sits a little higher than
   dropship.io's icon (top 24%, not 30%): deep in the folder, with the logo
   still above the glass. */
.ex-icon svg{display:block;transform:scale(.86)}
/* A dark fade over the folder's lower half, into the page black, so the
   glass blends into the background instead of ending on a hard edge. */
.ex-vis::after{
  content:"";position:absolute;z-index:3;left:-14%;right:-14%;top:30%;bottom:-20%;pointer-events:none;
  background:linear-gradient(to bottom,rgba(0,0,0,0),rgba(0,0,0,.7) 34%,#000 62%)}
.ex-file-fg{
  position:absolute;z-index:2;inset:0;border-radius:32px;
  background:rgba(255,255,255,.08);-webkit-backdrop-filter:blur(24px);backdrop-filter:blur(24px);
  outline:2px solid rgba(255,255,255,.35);outline-offset:-2px;box-shadow:inset 0 5px 5px rgba(129,182,255,.2);
  transform:rotateX(-40deg) translateY(16%)}
/* Hover (product owner, 2026-10-12): the folder opens a little, the back
   leaning away and the glass front tipping forward, and the EasyQA tile
   lifts out of it, straightens and catches a blue glow. Needs .fa-ring to let
   the pointer through (see "Feature arc"), or the hover never fires. */
.ex-icon,.ex-file-bg,.ex-file-fg{transition:transform .6s var(--ease),box-shadow .6s var(--ease)}
.ex-vis:hover .ex-icon{
  transform:rotate(10deg) translate(-50%,-82%) scale(1.06);
  box-shadow:0 18px 44px rgba(80,136,253,.55),0 8px 20px rgba(0,0,0,.25)}
.ex-vis:hover .ex-file-bg{transform:translate(-50%) rotateX(-20deg)}
.ex-vis:hover .ex-file-fg{transform:rotateX(-48deg) translateY(19%)}
@media(prefers-reduced-motion:reduce){.ex-icon,.ex-file-bg,.ex-file-fg{transition:none}}
@media(max-width:760px){
  .ex{padding:88px 0 48px}
  .ex-head h2{font-size:40px}
  .ex-inner{gap:88px}
  .ex-vis{max-width:65vw}
  .ex-file-bg,.ex-file-fg{border-radius:20px}
  .ex-curve{align-self:flex-end;height:80%}
}

/* ── Feature arc (home) ───────────────────────────────────────────────── */
/* Nine app-style tiles on a shallow arc (build.mjs S.featarc sets each one's
   --x, --y and --r from the circle). A tile is a rounded square in its own
   two-colour gradient with a light top edge and a soft drop shadow, so it
   reads as a glossy app icon. The lifted tile (.on) rises and brightens and
   its caption fades in underneath. The arc is laid out at 900px and scaled
   down as a whole on smaller screens. */
.fa-arc{--k:1;position:relative;width:900px;height:200px;margin:8px 0 0;left:50%;transform:translateX(-50%) scale(var(--k));transform-origin:50% 0}
.fa-tile{
  position:absolute;left:calc(50% + var(--x) - 48px);top:calc(40px + var(--y));width:96px;height:96px;padding:0;border:0;
  background:none;cursor:pointer;transform:rotate(var(--r));transition:transform .5s var(--ease)}
.fa-face{
  position:absolute;inset:0;display:grid;place-items:center;border-radius:18px;color:#fff;
  background:linear-gradient(160deg,var(--c1),var(--c2));
  box-shadow:inset 0 1.5px 0 rgba(255,255,255,.45),inset 0 -6px 14px rgba(0,0,0,.18),0 14px 28px rgba(0,0,0,.5),0 2px 6px rgba(0,0,0,.35);
  filter:saturate(.85) brightness(.82);transition:filter .4s,box-shadow .4s}
.fa-face svg{width:48px;height:48px;stroke-width:2.5;filter:drop-shadow(0 2px 3px rgba(0,0,0,.25))}
.fa-tile:hover .fa-face,.fa-tile.on .fa-face{filter:none}
.fa-tile.on{transform:rotate(var(--r)) translateY(-18px) scale(1.1)}
.fa-tile.on .fa-face{box-shadow:inset 0 1.5px 0 rgba(255,255,255,.5),inset 0 -6px 14px rgba(0,0,0,.15),0 22px 40px rgba(0,0,0,.55),0 0 40px -6px var(--c1)}
.fa-tile:focus-visible{outline:none}
.fa-tile:focus-visible .fa-face{outline:2px solid #fff;outline-offset:4px}
.fa-sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
/* The tiles rise into place, one after another, when the arc scrolls in. */
.fa-arc.armed .fa-tile{opacity:0;translate:0 40px}
.fa-arc.armed.in .fa-tile{opacity:1;translate:0 0;transition:transform .5s var(--ease),opacity .6s var(--ease) var(--d),translate .8s var(--ease) var(--d)}
.fa-cap{position:relative;max-width:520px;min-height:120px;margin:28px auto 0;text-align:center}
.fa-cap-i{position:absolute;inset:0;opacity:0;transform:translateY(8px);transition:opacity .35s,transform .45s var(--ease);pointer-events:none}
.fa-cap-i.on{opacity:1;transform:none;pointer-events:auto}
.fa-cap-i h3{font-size:22px;font-weight:600;letter-spacing:-.015em}
.fa-cap-i p{margin-top:10px;font-size:16px;line-height:1.6;color:var(--muted)}
@media(max-width:960px){.fa-arc{--k:.82;height:calc(200px * .82)}}
@media(max-width:760px){.fa-arc{--k:.6;height:calc(200px * .6)}.fa-cap{min-height:150px}}
@media(max-width:520px){.fa-arc{--k:.42;height:calc(200px * .42)}}
@media(prefers-reduced-motion:reduce){
  .fa-tile,.fa-cap-i{transition:none}
  .fa-arc.armed .fa-tile{opacity:1;translate:none}
}

/* ── Features around the folder (home) ────────────────────────────────── */
/* The merged features + first project section: an 860 x 560 stage with the
   folder at the bottom middle and the nine tiles on a shallow arc over it
   (build.mjs RING sets each tile's --x, --y and --r). The stage is scaled as a whole on smaller
   screens; the negative margin takes back the height the scale removes. */
.ex-stage{--k:1;position:relative;flex:none;width:860px;height:560px;
  transform:scale(var(--k));transform-origin:50% 0;margin-bottom:calc(560px * (var(--k) - 1))}
.ex-stage .ex-vis{position:absolute;left:50%;bottom:40px;width:340px;max-width:none;margin-left:-170px}
/* The ring covers the whole stage, folder included, so only the tiles take
   the pointer; otherwise the folder's hover never fires. */
.fa-ring{position:absolute;inset:0;width:auto;height:auto;margin:0;left:0;transform:none;pointer-events:none}
.fa-ring .fa-tile{pointer-events:auto}
.fa-ring .fa-tile{left:calc(50% + var(--x) - 48px);top:calc(var(--y) - 48px)}
.ex-inner:has(.ex-stage){gap:72px}
.ex-cap{width:100%;min-height:96px;margin-top:-120px}
.ex-inner:has(.ex-stage) .ex-head{max-width:720px}
.ex-foot{display:flex;justify-content:center;margin-top:-48px}
@media(max-width:960px){.ex-stage{--k:.8}}
/* Phones: the longest caption runs to four lines, so the caption keeps room
   for it and the button never sits on its text. */
@media(max-width:760px){.ex-stage{--k:.56}.ex-inner:has(.ex-stage){gap:48px}.ex-cap{margin-top:8px;min-height:150px}}
@media(max-width:520px){.ex-stage{--k:.44}}
/* More than nine tiles open the arc to about 1070px (build.mjs), so it scales
   down sooner and further, and the outer tiles never leave the screen. */
@media(max-width:1180px){.ex-stage.is-wide{--k:.88}}
@media(max-width:960px){.ex-stage.is-wide{--k:.76}}
@media(max-width:760px){.ex-stage.is-wide{--k:.54}}
@media(max-width:520px){.ex-stage.is-wide{--k:.34}}

/* ── Feature list (home) ──────────────────────────────────────────────── */
/* Editorial, not boxed: a split header, then three columns of features on
   hairline rules under a small numbered label. */
.fl-head{display:flex;justify-content:space-between;align-items:flex-end;gap:48px;margin-bottom:64px}
.fl-head h2{font-size:50px;font-weight:600;letter-spacing:-.03em;line-height:1.08}
.fl-head p{max-width:360px;font-size:17px;line-height:1.6;color:var(--muted)}
.fl-cols{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:48px}
.fl-label{
  display:flex;align-items:baseline;gap:12px;padding-bottom:16px;border-bottom:1px solid rgba(255,255,255,.22);
  font-size:13px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;color:#fff}
.fl-label span{font-variant-numeric:tabular-nums;color:var(--green)}
.fl-col ul{list-style:none}
.fl-col li{padding:22px 0;border-bottom:1px solid var(--border)}
.fl-col h4{font-size:17px;font-weight:600;letter-spacing:-.01em;color:#fff}
.fl-col li p{margin-top:6px;font-size:15px;line-height:1.55;color:var(--muted)}
@media(max-width:1000px){
  .fl-cols{grid-template-columns:1fr 1fr;gap:40px}
}
@media(max-width:760px){
  .fl-head{flex-direction:column;align-items:flex-start;gap:16px;margin-bottom:40px}
  .fl-head h2{font-size:40px}
  .fl-cols{grid-template-columns:1fr;gap:32px}
}

/* ── Proof strip (Figma 734:8913) ─────────────────────────────────────── */
/* Sits right under the hero video, so it is a slim band, not a full
   section: figures on the left, a quote on the right, right-aligned with
   its author, at the product owner's request. Stacked on small screens,
   everything reads from the left. */
.pf{padding:8px 0 72px}
.pf-row{display:flex;justify-content:space-between;align-items:flex-start;gap:48px}
.pf-stats{display:flex;gap:32px;flex:none}
.pf-stat{display:flex;align-items:center;gap:12px}
/* Brand green figures (product owner, 2026-10-12). */
.pf-num{font-size:44px;font-weight:500;letter-spacing:-.03em;line-height:1;color:var(--green)}
.pf-label{width:154px;font-size:14px;line-height:1.43;color:var(--muted)}
.pf-quote{max-width:560px;display:flex;flex-direction:column;gap:16px}
.pf-quote blockquote{font-size:16px;line-height:1.55;color:rgba(255,255,255,.72);text-align:right}
.pf-quote figcaption{display:flex;align-items:center;gap:14px;align-self:flex-end}
.pf-quote img{width:40px;height:40px;border-radius:50%;object-fit:cover;border:1px solid var(--border)}
.pf-quote figcaption span{display:flex;flex-direction:column;gap:3px}
.pf-quote strong{font-size:14px;font-weight:500;color:#fff}
.pf-quote figcaption span span{font-size:13px;color:var(--muted)}
@media(max-width:900px){
  .pf-row{flex-direction:column;gap:36px}
  .pf-quote blockquote{text-align:left}
  .pf-quote figcaption{align-self:flex-start}
}
@media(max-width:480px){
  .pf-stats{flex-direction:column;gap:20px}
}

/* ── Figures (Figma 733:1843) ─────────────────────────────────────────── */
/* Centred label and heading, then three cards in a 2:1:1 row, 28px
   apart, each 360px tall with 36px padding (roomier than the design's 288px
   and 24px, at the product owner's request), the number low. The
   design's corner art is left out at the product owner's request. */
.fg-head{display:flex;flex-direction:column;align-items:center;text-align:center;margin-bottom:64px}
.fg-head .sec-eyebrow{margin-bottom:20px}
/* The label is inline-flex, so it sat on the baseline of a text line taller
   than itself, which slipped about 11px of hidden space above every section
   heading and pushed the 120px section gap to about 131px. Pinning it to
   the top of its line removes that (product owner, 2026-10-12). */
.sec-eyebrow{vertical-align:top}
/* The button sits under the cards, at the product owner's request. */
.fg-foot{display:flex;justify-content:center;margin-top:56px}
.fg-head h2{font-size:50px;font-weight:600;letter-spacing:-.03em;line-height:1.1;text-wrap:balance}
.fg-row{display:grid;grid-template-columns:2fr 1fr 1fr;gap:28px}
.fg-card{
  position:relative;overflow:hidden;min-height:360px;padding:36px;border-radius:20px;
  display:flex;flex-direction:column;justify-content:flex-end;
  background:var(--card);border:1px solid var(--border);transition:border-color .25s}
.fg-card:hover{border-color:rgba(255,255,255,.18)}
.fg-num{font-size:48px;font-weight:600;letter-spacing:-.03em;line-height:1;margin-bottom:14px}
.fg-label{max-width:400px;min-height:4.5em;font-size:15px;line-height:1.5;color:var(--muted)}
/* Room for three lines on every label, so the numbers line up across the row as in the design. */
@media(max-width:900px){
  .fg-row{grid-template-columns:1fr 1fr}
  .fg-card.wide{grid-column:1 / -1}
}
@media(max-width:760px){
  .fg-head h2{font-size:40px}
  .fg-row{grid-template-columns:1fr}
  .fg-card{min-height:220px}
}

/* ── Figure card pictures ─────────────────────────────────────────────── */
/* Each sits in the empty top of its card (figVis in build.mjs), spans the
   card's full inner width, and plays once when the card is revealed (.in). Brand blue to green for "with
   EasyQA", grey for the old way. */
.fgv{position:absolute;top:36px;left:36px;right:36px}
.fgv-bars{display:flex;flex-direction:column;gap:14px}
.fgv-row{display:grid;grid-template-columns:110px 1fr;align-items:center;gap:12px;font-size:12.5px;color:var(--muted)}
.fgv-row i{display:block;height:10px;border-radius:999px;background:rgba(255,255,255,.05);overflow:hidden}
.fgv-row b{display:block;height:100%;width:0;border-radius:inherit;background:rgba(255,255,255,.22);transition:width 1.2s var(--ease) .2s}
.fgv-row.is-new span{color:#fff}
.fgv-row.is-new b{background:var(--grad);transition-delay:.55s;box-shadow:0 0 16px rgba(72,202,124,.35)}
.fg-card.in .fgv-row b{width:var(--w)}
.fgv-axis{display:flex;justify-content:space-between;margin-left:122px;font-size:11px;letter-spacing:.06em;text-transform:uppercase;color:var(--dim)}
.fgv-thread{display:flex;flex-direction:column;align-items:stretch;gap:8px}
.fgv-b{
  display:inline-flex;align-items:center;gap:6px;padding:6px 11px;border-radius:12px 12px 12px 4px;
  font-size:12.5px;line-height:1.2;background:rgba(255,255,255,.06);border:1px solid var(--border);color:rgba(255,255,255,.75);
  opacity:0;transform:translateY(6px);transition:opacity .4s var(--ease) var(--d),transform .5s var(--ease) var(--d),color .4s 1.6s}
.fgv-b.is-q{align-self:flex-start;width:74%}
.fgv-b.is-r{align-self:flex-end;border-radius:12px 12px 4px 12px}
.fgv-b.is-pin{width:100%}
.fgv-b.is-pin{color:#04120a;background:var(--green);border-color:transparent;font-weight:600}
.fg-card.in .fgv-b{opacity:1;transform:none}
.fg-card.in .fgv-b.is-q{color:rgba(255,255,255,.3);text-decoration:line-through;text-decoration-color:rgba(255,255,255,.35)}
.fgv-gauge{display:flex;flex-direction:column;align-items:flex-start}
/* The dial and its 1x / 3x labels share one box, capped by WIDTH: capping
   the height instead centred the dial inside a wider box, which pushed it
   past the card edge and away from its labels at some widths. */
.fgv-gauge{max-width:220px}
.fgv-gauge svg{display:block;overflow:visible;width:100%;height:auto}
.fgv-track{fill:none;stroke:rgba(255,255,255,.08);stroke-width:10;stroke-linecap:round}
.fgv-arc{fill:none;stroke:url(#fgvg);stroke-width:10;stroke-linecap:round;stroke-dasharray:100;stroke-dashoffset:100;transition:stroke-dashoffset 1.4s var(--ease) .3s}
.fg-card.in .fgv-arc{stroke-dashoffset:12}
.fgv-needle{transform-origin:80px 82px;transform:rotate(-90deg);transition:transform 1.4s var(--ease) .3s}
.fgv-needle line{stroke:#fff;stroke-width:3;stroke-linecap:round}
.fgv-needle circle{fill:#fff}
.fg-card.in .fgv-needle{transform:rotate(68deg)}
.fgv-ends{display:flex;justify-content:space-between;width:100%;margin-top:6px;font-size:11px;color:var(--dim)}
@media(prefers-reduced-motion:reduce){
  .fgv-row b,.fgv-b,.fgv-arc,.fgv-needle{transition:none}
}
/* Phones: the card is shorter than the picture plus the number, so the
   picture joins the flow above the number instead of sitting on top of it. */
@media(max-width:760px){
  .fg-card{min-height:0}
  .fgv{position:static;margin-bottom:28px}
  .fgv-row{grid-template-columns:112px 1fr;font-size:12px}
  .fgv-axis{margin-left:124px}
}

/* ── Globe (after dropship.io) ─────────────────────────────────────────── */
/* Only the top of the sphere shows; the mask fades its cut edge into the
   page. Before the script draws, the stage is simply empty black. */
.gb{overflow:hidden}
.gb .sec-head{margin-bottom:24px}
.gb-stage{
  position:relative;width:min(1100px,100%);margin:0 auto;aspect-ratio:1100/620;
  -webkit-mask-image:linear-gradient(#000 52%,transparent 96%);mask-image:linear-gradient(#000 52%,transparent 96%)}
.gb-canvas{position:absolute;inset:0;width:100%;height:100%;display:block}
.gb-pins{position:absolute;inset:0;pointer-events:none}
.gb-pin{position:absolute;left:0;top:0;will-change:transform}
.gb-pin i{
  position:absolute;left:-5px;top:-5px;width:10px;height:10px;border-radius:50%;
  background:var(--green);box-shadow:0 0 0 3px rgba(72,202,124,.25);
  transform:scale(0);transition:transform .45s var(--ease)}
.gb-pin i::after{
  content:"";position:absolute;inset:-7px;border-radius:50%;border:1.5px solid rgba(72,202,124,.6);
  opacity:0}
.gb-pin.on i{transform:scale(1)}
.gb-pin.on i::after{animation:gbPing 1.8s var(--ease) .2s infinite}
.gb-pin span{
  position:absolute;left:12px;bottom:12px;white-space:nowrap;padding:6px 10px;border-radius:9px;
  background:rgba(20,20,22,.92);border:1px solid rgba(255,255,255,.12);
  font-size:12.5px;font-weight:500;line-height:1;color:#fff;
  box-shadow:0 8px 24px rgba(0,0,0,.45);
  opacity:0;transform:translateY(6px) scale(.96);transform-origin:0 100%;
  transition:opacity .4s var(--ease),transform .45s var(--ease)}
.gb-pin.on span{opacity:1;transform:none;transition-delay:.12s}
@keyframes gbPing{0%{transform:scale(.4);opacity:.9}100%{transform:scale(1.6);opacity:0}}
@media(max-width:760px){
  .gb-stage{aspect-ratio:1/0.85}
  .gb-pin span{font-size:11.5px;padding:5px 8px}
}
@media(prefers-reduced-motion:reduce){
  .gb-pin i,.gb-pin span{transition:none}
  .gb-pin.on i::after{animation:none}
}

/* ── Persona links ────────────────────────────────────────────────────── */
/* Three across. With five personas that leaves a two-card final row,
   which sits better than the single orphan a four-column grid produced. */
/* A row list rather than another illustrated-card grid — problem, features
   and steps already use that shape, and repeating it here just reads as more
   of the same. */
/* Bento grid: two wide cards, then three narrower ones underneath — six
   tracks so "span 3" and "span 2" divide evenly into the two row shapes.
   Text sits at the top of each card, an icon in a lit, textured strip sits
   at the bottom — the reverse of the row list, and distinct from the flat
   illustration panels problem/features/steps use. */
/* One mixed grid — a text/brand cell alongside five persona cards, sized
   unevenly (a wide intro, one card running the full right-hand height, four
   even ones underneath) rather than a uniform repeating grid, so it reads as
   composed the way a mixed photo/copy/CTA bento does. Every cell keeps the
   same card language though (dark surface, brand-gradient icon badge) since
   all five items are the same kind of content, just arranged unevenly. */
/* A numbered accordion instead of a card grid — native <details>, the same
   pattern the FAQ already uses, so it expands with no JS. Only one persona
   open at a time isn't enforced (each <details> is independent), which is
   fine: nothing stops two being open together, it just means both stay
   readable rather than one forcibly collapsing the other. */
/* flex, not grid: with 5 cards the last row only has 2, and flex + justify-
   content:center lets that partial row centre itself instead of hugging the
   left edge the way an unfilled grid row would. flex-basis reproduces the
   same 3-per-row (then 2, then 1) widths a grid would have given at each
   breakpoint, so full rows still look identical to a grid layout. */
.who{display:flex;flex-wrap:wrap;justify-content:center;gap:20px}
.who-i{
  display:flex;flex-direction:column;flex:0 0 calc((100% - 40px) / 3);
  padding:14px 14px 26px;
  border:1px solid var(--border);border-radius:16px;background:var(--card);
  transition:border-color .25s,transform .25s var(--ease)}
.who-i:hover{border-color:rgba(255,255,255,.2);transform:translateY(-3px)}
.who-i .card-vis{margin-bottom:20px}
.who-i h3{padding:0 12px;font-size:17.5px;font-weight:600;letter-spacing:-.01em;margin-bottom:9px}
.who-i p{padding:0 12px;font-size:14.5px;line-height:1.66;color:var(--muted)}

/* ── FAQ (native disclosure, so it works without JS) ──────────────────── */
.faq-wrap{max-width:800px}
.faq-i{border-bottom:1px solid var(--border)}
.faq-i summary{
  display:flex;align-items:center;justify-content:space-between;gap:20px;
  padding:24px 2px;font-size:16.5px;font-weight:500;cursor:pointer;list-style:none}
.faq-i summary::-webkit-details-marker{display:none}
.faq-i summary svg{flex:none;color:var(--muted);transition:transform .25s var(--ease)}
.faq-i[open] summary svg{transform:rotate(45deg)}
/* site.js "FAQ open and close": the + turns back the moment a close starts. */
.faq-i.is-closing summary svg{transform:none}
.faq-i p{padding:0 2px 24px;font-size:15px;line-height:1.7;color:var(--muted);max-width:66ch}

/* ── Footer ───────────────────────────────────────────────────────────── */
footer{border-top:1px solid var(--border);padding:72px 0 36px;margin-top:0}
.foot-top{display:grid;grid-template-columns:minmax(0,1.1fr) minmax(0,2fr);gap:56px}
.foot-brand p{margin-top:18px;font-size:14px;line-height:1.66;color:var(--muted);max-width:34ch}
.foot-logo svg{height:26px;width:auto}
.foot-cols{display:grid;grid-template-columns:repeat(3,1fr);gap:32px}
.foot-col h3{font-size:12px;font-weight:600;letter-spacing:.1em;text-transform:uppercase;color:var(--dim);margin-bottom:16px}
.foot-col a{display:block;padding:5px 0;font-size:14px;color:var(--muted);transition:color .18s}
.foot-col a:hover{color:#fff}
.foot-bottom{
  display:flex;align-items:center;justify-content:space-between;gap:20px;flex-wrap:wrap;
  margin-top:56px;padding-top:26px;border-top:1px solid var(--border);font-size:13px;color:var(--dim)}
.foot-bottom a{color:var(--muted)}
.foot-bottom a:hover{color:#fff}
.foot-legal{display:flex;gap:20px}

/* ══ Hero story sequence ═══════════════════════════════════════════════════
   Five beats on one rail. Every beat carries `--n`; its delay is derived from
   that and `--beat`, so retiming the whole sequence is one number on the
   container. `--loop` is beat × 5 and must stay in step with the beat count. */
.st{position:relative;z-index:1;width:100%;max-width:960px;margin:60px auto 0;--loop:calc(var(--beat) * 5);animation:fadeUp 1s var(--ease) .42s both}
.st-svg{width:100%;height:auto;display:block;overflow:visible}

.st-rail{stroke:rgba(255,255,255,.1);stroke-width:2}
.st-fill{stroke:url(#stg);stroke-width:2;stroke-linecap:round;stroke-dasharray:1;stroke-dashoffset:1;
  animation:stFill var(--loop) linear infinite}
@keyframes stFill{0%{stroke-dashoffset:1}92%,100%{stroke-dashoffset:0}}

/* A beat is dim until its turn, then holds bright for one beat and settles
   back to a readable mid state — fully dimming it again would make the
   finished steps look undone. */
.st-b{--d:calc(var(--n) * var(--beat) - var(--loop));opacity:.3;
  animation:stOn var(--loop) linear infinite;animation-delay:var(--d)}
@keyframes stOn{0%{opacity:.3}6%{opacity:1}20%{opacity:1}30%,100%{opacity:.62}}

.st-card{fill:rgba(255,255,255,.04);stroke:var(--border);stroke-width:1}
.st-bar{fill:rgba(255,255,255,.05)}
.st-dot{fill:rgba(255,255,255,.22)}
.st-ln{fill:rgba(255,255,255,.14)}
.st-accent{fill:url(#stg);opacity:.75}
.st-node{fill:#0b0b0d;stroke:rgba(255,255,255,.22);stroke-width:2}
.st-b .st-node{animation:stNode var(--loop) linear infinite;animation-delay:var(--d)}
@keyframes stNode{0%{stroke:rgba(255,255,255,.22)}6%,100%{stroke:#48CA7C}}
.st-node-ok{fill:#48CA7C}
.st-lb{fill:rgba(255,255,255,.6);font:600 13px var(--font);text-anchor:middle;letter-spacing:.01em}
.st-mini-t{fill:rgba(255,255,255,.55);font:600 11px var(--font)}

/* beat 2 — the selection ring and the pin that drops onto it */
.st-sel{fill:none;stroke:#5088FD;stroke-width:1.5;stroke-dasharray:4 3;opacity:0;
  animation:stSel var(--loop) linear infinite;animation-delay:calc(1 * var(--beat) - var(--loop))}
@keyframes stSel{0%,4%{opacity:0}10%,30%{opacity:.9}42%,100%{opacity:.35}}
.st-pin{fill:#5088FD;opacity:0;transform-origin:331px 100px;
  animation:stPin var(--loop) var(--ease) infinite;animation-delay:calc(1 * var(--beat) - var(--loop))}
.st-pin-i{fill:#fff}
@keyframes stPin{0%,6%{opacity:0;transform:translateY(-14px) scale(.7)}14%{opacity:1;transform:none}100%{opacity:1;transform:none}}
.st-bub{fill:rgba(80,136,253,.16);stroke:rgba(80,136,253,.4);stroke-width:1;opacity:0;
  animation:stBub var(--loop) var(--ease) infinite;animation-delay:calc(1 * var(--beat) - var(--loop))}
.st-bub-ln{fill:rgba(255,255,255,.4);opacity:0;
  animation:stBub var(--loop) var(--ease) infinite;animation-delay:calc(1 * var(--beat) - var(--loop))}
@keyframes stBub{0%,12%{opacity:0;transform:translateY(5px)}20%{opacity:1;transform:none}100%{opacity:1;transform:none}}

/* beat 3 — rows filling in, the new comment landing last */
.st-st{fill:rgba(255,255,255,.2)}
.st-row:nth-child(6) .st-st{fill:#5088FD;animation:stLand var(--loop) var(--ease) infinite;animation-delay:calc(2 * var(--beat) - var(--loop))}
@keyframes stLand{0%,8%{opacity:0}16%{opacity:1}100%{opacity:1}}

/* beat 4 — progress bar running */
.st-prog-t{fill:rgba(255,255,255,.09)}
.st-prog{fill:url(#stg);transform-origin:612px 0;
  animation:stProg var(--loop) linear infinite;animation-delay:calc(3 * var(--beat) - var(--loop))}
@keyframes stProg{0%{transform:scaleX(.05)}22%{transform:scaleX(.72)}100%{transform:scaleX(.72)}}

/* beat 5 — the check drawing itself */
.st-ok-r{fill:rgba(72,202,124,.12);stroke:rgba(72,202,124,.45);stroke-width:1.5}
.st-ok{fill:none;stroke:#48CA7C;stroke-width:3.4;stroke-linecap:round;stroke-linejoin:round;
  stroke-dasharray:1;stroke-dashoffset:1;
  animation:stOk var(--loop) var(--ease) infinite;animation-delay:calc(4 * var(--beat) - var(--loop))}
@keyframes stOk{0%,4%{stroke-dashoffset:1}18%,100%{stroke-dashoffset:0}}

/* the comment travelling the rail, hidden while it sits on a beat */
.st-trav{fill:#8ef5c4;animation:stTrav var(--loop) linear infinite}
@keyframes stTrav{
  0%{transform:translateX(96px);opacity:0}
  16%{transform:translateX(96px);opacity:0}
  20%{opacity:1}
  36%{transform:translateX(288px);opacity:1}
  40%{transform:translateX(288px);opacity:0}
  56%{transform:translateX(480px);opacity:0}
  60%{opacity:1}
  76%{transform:translateX(672px);opacity:1}
  80%{transform:translateX(864px);opacity:0}
  100%{transform:translateX(864px);opacity:0}}

.st-mini{display:none;list-style:none;max-width:340px;margin:0 auto;text-align:left}
.st-mini li{display:flex;align-items:center;gap:13px;padding:13px 0;border-bottom:1px solid var(--border);font-size:14.5px;color:rgba(255,255,255,.8)}
.st-mini li:last-child{border-bottom:0}
.st-mini span{
  flex:none;width:23px;height:23px;border-radius:50%;display:grid;place-items:center;
  font-size:11px;font-weight:700;color:#04120a;background:var(--grad)}

/* ── Responsive ───────────────────────────────────────────────────────── */
@media(max-width:1000px){
  .stp{flex-basis:calc((100% - 22px) / 2)}
  .card{flex-basis:calc((100% - 20px) / 2)}
  .who-i{flex-basis:calc((100% - 20px) / 2)}
  .chk-inner{grid-template-columns:1fr;gap:36px}
  .foot-top{grid-template-columns:1fr;gap:44px}
}
@media(max-width:860px){
  .nav-links,.nav-right{display:none}
  .nav-burger{display:flex}
  .nav-drawer.open{display:block}
  .nav-drawer{
    position:absolute;top:100%;left:0;right:0;padding:16px 22px 24px;
    background:#0b0b0d;border-top:1px solid var(--border);border-bottom:1px solid var(--border);
    max-height:76vh;overflow-y:auto}
  .nav-drawer h4{font-size:11px;font-weight:600;letter-spacing:.1em;text-transform:uppercase;color:var(--dim);margin:18px 0 8px}
  .nav-drawer a{display:block;padding:10px 0;font-size:15px;color:rgba(255,255,255,.82);border-bottom:1px solid var(--border)}
  .nav-drawer .nav-drawer-cta{
    display:block;margin-top:20px;padding:13px;border-radius:11px;text-align:center;
    background:var(--grad-diag);color:#04120a;font-weight:700;border:0}
}
@media(max-width:760px){
  .st-svg{display:none}
  .st-mini{display:grid}
  .st{margin-top:44px}
  .sec-head h2,.prob-inner h2,.chk-copy h2{font-size:32px}
  .prob{padding:80px 0}
  .hero-compact h1{font-size:59px;max-width:none}
}
@media(max-width:620px){
  .stp,.card{flex-basis:100%}
  .who-i{flex-basis:100%}
  .foot-cols{grid-template-columns:1fr;gap:26px}
  .foot-bottom{flex-direction:column;align-items:flex-start;gap:14px}
}

/* Motion is decoration here; the sequence still reads as five labelled beats
   without it, so honour the preference completely rather than slowing it. */
@media(prefers-reduced-motion:reduce){
  .st-fill,.st-b,.st-sel,.st-pin,.st-bub,.st-bub-ln,.st-prog,.st-ok,.st-trav,
  .st-b .st-node,.st-row:nth-child(6) .st-st{animation:none!important}
  .st-b{opacity:1}
  .st-fill{stroke-dashoffset:0}
  .st-ok{stroke-dashoffset:0}
  .st-trav{opacity:0}
  .st-prog{transform:scaleX(.72)}
  .st-pin,.st-bub,.st-bub-ln,.st-sel{opacity:1}
}

/* ══ Media slots ═══════════════════════════════════════════════════════════
   Where real screenshots and video go. Until a `src` is supplied the block
   renders as an obvious placeholder carrying its own brief: what to shoot and
   at what size. It is styled to read as scaffolding, never as artwork, so a
   forgotten slot is impossible to miss on a review pass. */
.mwrap{padding:24px 0 88px}
.mwrap-wide .mfig{max-width:1170px}
.mfig{margin:0 auto;max-width:980px}
.mbox{
  display:block;width:100%;border-radius:16px;border:1px solid var(--border);
  background:var(--card);object-fit:cover;
  box-shadow:0 30px 80px rgba(0,0,0,.5)}
/* The hero recording carries a strip of black across the top of every frame.
   The box is sized to the content below that strip, so cover has to crop the
   difference — anchoring to the bottom spends that crop entirely on the strip
   instead of splitting it top and bottom and eating real content. */
video.mbox{object-position:50% 100%}
/* The hero video's controller (build.mjs VIDEO_BAR, site.js "Video
   controls"). A dark glass bar along the foot of the video; it shows on hover
   or keyboard focus, always while paused, and always on touch screens, which
   have no hover. */
.vp{position:relative}
.vp-bar{
  position:absolute;left:16px;right:16px;bottom:16px;z-index:2;
  display:flex;align-items:center;gap:4px;padding:6px 16px 6px 6px;border-radius:12px;
  background:rgba(10,10,14,.72);border:1px solid rgba(255,255,255,.12);
  -webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);
  opacity:0;transform:translateY(6px);transition:opacity .25s var(--ease),transform .25s var(--ease)}
.vp-bar[hidden]{display:none}
.vp:hover .vp-bar,.vp:focus-within .vp-bar,.vp:not(.is-playing) .vp-bar{opacity:1;transform:none}
@media(hover:none){.vp-bar{opacity:1;transform:none}}
.vp-btn{flex:none;width:38px;height:38px;border:0;border-radius:8px;background:transparent;color:#fff;
  display:flex;align-items:center;justify-content:center;cursor:pointer;transition:background .15s}
.vp-btn:hover{background:rgba(255,255,255,.1)}
.vp-btn:focus-visible{outline:2px solid var(--blue);outline-offset:1px}
.vp-btn svg{width:22px;height:22px}
.vp-play svg{width:20px;height:20px}
.vp-play .i-pause,.vp.is-playing .vp-play .i-play{display:none}
.vp.is-playing .vp-play .i-pause{display:block}
.vp-seek{
  flex:1;min-width:0;height:4px;margin:0 12px;border-radius:2px;cursor:pointer;
  -webkit-appearance:none;appearance:none;
  background:linear-gradient(90deg,var(--green) var(--p,0%),rgba(255,255,255,.2) var(--p,0%))}
.vp-seek::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;width:13px;height:13px;border-radius:50%;background:#fff;border:0;box-shadow:0 1px 4px rgba(0,0,0,.4)}
.vp-seek::-moz-range-thumb{width:13px;height:13px;border-radius:50%;background:#fff;border:0}
.vp-seek:focus-visible{outline:2px solid var(--blue);outline-offset:4px}
.vp-time{flex:none;font-size:12.5px;font-weight:500;color:rgba(255,255,255,.75);font-variant-numeric:tabular-nums;white-space:nowrap}
@media(max-width:560px){
  .vp-bar{left:8px;right:8px;bottom:8px;padding-right:12px}
  .vp-btn{width:34px;height:34px}
  .vp-time{display:none}
}
.mbox-ph{
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:9px;
  padding:34px;text-align:center;box-shadow:none;
  border:1px dashed rgba(255,255,255,.22);
  background:
    repeating-linear-gradient(45deg,rgba(255,255,255,.022) 0 12px,transparent 12px 24px),
    radial-gradient(120% 90% at 50% 0%,rgba(80,136,253,.10),transparent 62%),
    var(--card)}
.mph-kind{
  font-size:10.5px;font-weight:700;letter-spacing:.16em;padding:4px 10px;border-radius:999px;
  background:var(--grad-diag);color:#04120a}
.mph-label{font-size:18px;font-weight:600;letter-spacing:-.01em;color:#fff;max-width:30ch;text-wrap:balance}
.mph-shot{font-size:13.5px;line-height:1.6;color:var(--muted);max-width:62ch}
.mph-spec{
  margin-top:4px;font:500 11.5px ui-monospace,"SF Mono",monospace;letter-spacing:.02em;
  color:var(--dim);padding:5px 11px;border:1px solid var(--border);border-radius:7px}
.mfig-cap{margin-top:16px;text-align:center;font-size:13.5px;color:var(--muted)}
/* 1170px matches --max and .mwrap-wide, the widest measure the site already
   uses, so the hero video reads as large without inventing a width no other
   section has. .hero's own 28px side padding still keeps it off the edge. */
.hero-media{position:relative;z-index:1;width:100%;max-width:1170px;margin:56px auto 0;animation:fadeUp 1s var(--ease) .42s both}
.hero-media .mfig{max-width:none}
@media(max-width:760px){
  .mwrap{padding:12px 0 56px}
  .mbox-ph{padding:24px 18px;gap:7px}
  .mph-label{font-size:15.5px}
  .mph-shot{font-size:12.5px}
  .hero-media{margin-top:36px}
}

/* ── Section headings, 25% larger ─────────────────────────────────────── */
.sec-head h2{font-size:50px}
.prob-inner h2{font-size:52px}
.chk-copy h2{font-size:50px}
@media(max-width:760px){
  .sec-head h2,.prob-inner h2,.chk-copy h2{font-size:40px}
}

/* ══ Icons ═════════════════════════════════════════════════════════════════
   One tile treatment everywhere so a card, a persona and a step read as the
   same family. The glyph inherits currentColor and the tile carries the tint,
   which keeps the accent gradient reserved for the few places that earn it. */
.ic{width:20px;height:20px;display:block;flex:none}
.ic-tile{
  display:inline-grid;place-items:center;width:42px;height:42px;margin-bottom:18px;
  border-radius:10px;color:#cfe0ff;
  background:linear-gradient(150deg,rgba(80,136,253,.16),rgba(72,202,124,.12));
  border:1px solid rgba(255,255,255,.09);
  transition:color .25s,border-color .25s,transform .25s var(--ease)}
.card:hover .ic-tile,.who-i:hover .ic-tile{color:#fff;border-color:rgba(255,255,255,.22);transform:translateY(-1px)}

/* Steps put the number and the glyph on one line: the number carries sequence,
   the icon carries meaning, and neither has to do both jobs. */

.mph-glyph{color:rgba(255,255,255,.34)}
.mph-glyph .ic{width:26px;height:26px}

@media(max-width:620px){
  .ic-tile{width:38px;height:38px;margin-bottom:14px;border-radius:11px}
  .ic{width:18px;height:18px}
}

/* ══ Ribbon ════════════════════════════════════════════════════════════════
   Sits above the fixed nav, so the nav is offset by its height rather than
   the two overlapping. --ribbon-h is the single source of that offset: set it
   to 0 and every dependent rule collapses correctly, which is what dismissing
   the ribbon does. The class is applied by an inline script in <head> so a
   dismissed ribbon never flashes in and drags the page down as it is removed. */
:root{--ribbon-h:42px}
html.no-ribbon{--ribbon-h:0px}
.ribbon{
  position:fixed;top:0;left:0;right:0;height:42px;z-index:210;
  display:flex;align-items:center;justify-content:center;
  /* A softer, less uniform wash than the flat diagonal gradient: the accent
     is strongest at the two ends and eases through the middle, so the copy
     sits on the calmest part of the band rather than fighting full
     saturation. */
  background:
    radial-gradient(120% 300% at 0% 50%,rgba(80,136,253,.95),transparent 58%),
    radial-gradient(120% 300% at 100% 50%,rgba(72,202,124,.95),transparent 58%),
    linear-gradient(90deg,#4a80ea,#3fb488);
  color:#04120a}
html.no-ribbon .ribbon{display:none}
/* A hairline of light along the bottom edge separates the ribbon from the
   page without drawing an actual border line. */
.ribbon::after{
  content:"";position:absolute;left:0;right:0;bottom:0;height:1px;
  background:rgba(0,0,0,.18)}
.ribbon-in{
  display:flex;align-items:center;gap:14px;padding:0 14px;
  font-size:13.5px;font-weight:500;color:#04120a;line-height:1}
.ribbon-txt{letter-spacing:-.005em}
.ribbon-in strong{font-weight:700}
/* The supporting half recedes rather than competing with the claim. */
.ribbon-sub{color:rgba(4,18,10,.62)}

/* The button reads as a real button on the band: solid, not a tint of it. */
.ribbon-go{
  display:inline-flex;align-items:center;gap:7px;font-weight:600;font-size:12.5px;
  padding:6px 12px;border-radius:7px;background:#fff;color:#0d1117;
  box-shadow:0 1px 2px rgba(0,0,0,.18),0 4px 12px rgba(0,0,0,.12);
  transition:transform .18s var(--ease),box-shadow .18s}
.ribbon-go svg:first-child{width:14px;height:14px;flex:none}
.ribbon-arrow{opacity:.55;transition:transform .18s var(--ease)}
.ribbon-in:hover .ribbon-go{
  transform:translateY(-1px);
  box-shadow:0 2px 4px rgba(0,0,0,.2),0 8px 20px rgba(0,0,0,.18)}
.ribbon-in:hover .ribbon-arrow{transform:translateX(2px)}

.ribbon-x{
  position:absolute;right:10px;top:50%;transform:translateY(-50%);
  display:grid;place-items:center;width:26px;height:26px;border:0;border-radius:7px;
  background:transparent;color:rgba(0,0,0,.45);cursor:pointer;transition:background .16s,color .16s}
.ribbon-x:hover{background:rgba(0,0,0,.14);color:#04120a}

/* Everything pinned to the viewport top shifts by the ribbon height. */
nav{top:var(--ribbon-h)}
.hero{padding-top:calc(116px + var(--ribbon-h))}
.hero-compact{padding-top:calc(150px + var(--ribbon-h))}

@media(max-width:860px){
  :root{--ribbon-h:38px}
  .ribbon{height:38px}
  .ribbon-in{font-size:12.5px;gap:8px;padding-right:34px}
  .ribbon-in .ic{display:none}
}
@media(max-width:620px){
  .ribbon-in span:first-of-type{display:none}
  .ribbon-in{justify-content:center}
}

/* ══ Extension download ════════════════════════════════════════════════════ */
.dl{padding:104px 0;border-top:1px solid var(--border)}
.dl-inner{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:64px;align-items:center}
.dl-eyebrow{
  /* align-self, not just inline-flex: .dl-copy is a flex column, so this is a
     flex item and the default align-items:stretch pulled it to the full column
     width — which is why the pill ran to the right edge instead of hugging
     its label. Plain green text like every section label (.sec-eyebrow in
     base.css), at the product owner's request; change them together. */
  display:inline-flex;align-self:flex-start;
  align-items:center;gap:7px;margin-bottom:20px;
  font-size:13px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--green)}
.dl-eyebrow .ic{width:14px;height:14px}
/* The Chrome mark is a real logo, not a line icon: it ships at 18px and
   carries its own colours, so it needs its own size here or it overhangs the
   pill's cap height. flex:none stops it being squeezed by the label. */
.dl-eyebrow svg{width:14px;height:14px;flex:none}
.dl-copy h2{font-size:50px;font-weight:600;letter-spacing:-.03em;line-height:1.12;text-wrap:balance}
.dl-copy > p{margin-top:18px;font-size:17px;line-height:1.65;color:var(--muted);max-width:52ch}
.dl-actions{display:flex;flex-wrap:wrap;align-items:center;gap:12px;margin-top:32px}
.dl-meta{margin-top:16px;font-size:13px;color:var(--dim);max-width:46ch}
.dl-vis .mwrap{padding:0}
.dl-vis .mfig{max-width:none}

@media(max-width:1000px){
  .dl-inner{grid-template-columns:1fr;gap:44px}
  .dl{padding:80px 0}
}
@media(max-width:760px){
  .dl-copy h2{font-size:40px}
}

/* ══ Floating nav ══════════════════════════════════════════════════════════
   The header is an island rather than a full-width bar: <nav> stays a fixed,
   transparent full-width layer purely for positioning, and .nav-inner becomes
   the visible surface. base.css paints <nav> itself once scrolled, which would
   put a full-bleed bar behind the island, so that rule is neutralised here and
   the scrolled state is expressed on the island instead. */
nav{padding:14px 0;background:none;border-bottom:0;backdrop-filter:none;-webkit-backdrop-filter:none}
nav.scrolled{background:none;border-bottom:0;backdrop-filter:none;-webkit-backdrop-filter:none}
.nav-inner{
  max-width:1120px;padding:14px 14px 14px 26px;gap:18px;
  background:rgba(11,11,14,.96);
  border:1px solid rgba(255,255,255,.10);border-radius:16px;
  box-shadow:0 14px 44px rgba(0,0,0,.46),inset 0 1px 0 rgba(255,255,255,.05);
  transition:background .35s,border-color .35s,box-shadow .35s}
/* Over content the island needs more weight than it does over the hero. */
nav.scrolled .nav-inner{
  background:rgba(11,11,14,.92);border-color:rgba(255,255,255,.14);
  box-shadow:0 18px 54px rgba(0,0,0,.6),inset 0 1px 0 rgba(255,255,255,.06)}
.nav-logo svg{height:26px}
.nav-links{margin:0 auto}
.nav-cta{font-size:14px;padding:9px 18px}
.nav-login{font-size:14px}

/* The mega panel hangs off the island, so it clears the island's own edge
   rather than the viewport top. */
.nav-menu{top:calc(100% - 6px)}

/* Compact nav (site.js "Nav scroll"): scrolling down past the hero folds the
   island to its logo and buttons, scrolling up opens it again. Desktop only;
   under 861px the links already live in the burger drawer. .nav-links
   collapses by max-width with overflow hidden, which does not clip the mega
   panels: those hang off .nav-inner, outside the clipped box. */
/* One liquid motion (2026-10-12): the island and the links run on the same
   soft spring, with a slight settle at the end, and the links fold by their
   real width (--links-w, measured in site.js) so every frame of the fold is
   visible. The logo and buttons never shrink or wrap; only the links give
   way, which is what stopped "Log in" breaking onto two lines mid-fold. */
@media(min-width:861px){
  nav{--liquid:cubic-bezier(.34,1.18,.44,1)}
  .nav-inner{transition:background .35s,border-color .35s,box-shadow .35s,max-width .8s var(--liquid),padding .7s var(--liquid)}
  .nav-logo,.nav-right{flex-shrink:0}
  .nav-login,.nav-cta{white-space:nowrap}
  .nav-links{min-width:0;flex-shrink:1;max-width:var(--links-w,420px);overflow:hidden;
    transition:max-width .8s var(--liquid),opacity .4s ease .22s,visibility 0s}
  /* Width only: the padding stays as in the full bar, so the button keeps
     the same 14px to the island's edge on every side in both states. */
  nav.compact .nav-inner{max-width:540px}
  nav.compact .nav-links{max-width:0;opacity:0;visibility:hidden;pointer-events:none;
    transition:max-width .8s var(--liquid),opacity .22s ease,visibility 0s .8s}
}
@media(min-width:861px) and (prefers-reduced-motion:reduce){
  .nav-inner,.nav-links,nav.compact .nav-links{transition:none}
}

@media(max-width:860px){
  nav{padding:10px 0}
  .nav-inner{max-width:none;margin:0 14px;padding:11px 11px 11px 18px;border-radius:16px}
  /* The drawer becomes a second floating card under the island instead of a
     full-bleed sheet, which would not line up with it. */
  .nav-drawer{
    /* Matches the island's own 14px inset. Anchored to <nav>, which is
       full-width, so left/right have to repeat the inset rather than
       inherit it. */
    top:calc(100% + 10px);left:14px;right:14px;padding:14px 18px 20px;
    background:rgba(14,14,19,.82);
    -webkit-backdrop-filter:blur(48px) saturate(185%);backdrop-filter:blur(48px) saturate(185%);
    border:1px solid rgba(255,255,255,.10);border-top:1px solid rgba(255,255,255,.10);
    border-radius:16px;box-shadow:0 20px 60px rgba(0,0,0,.6)}
  .nav-drawer a:last-of-type{border-bottom:0}
}

/* ══ Corner language ═══════════════════════════════════════════════════════
   Two radii across the whole site: 8px on anything you press, 16px on any
   surface that holds content, including the floating nav island. Overridden here rather than edited into
   base.css so the original stylesheet stays a clean record of the homepage it
   shipped with.

   The primary CTA (btn-chrome / nav-cta) is set separately below, alongside
   its own hover-glow treatment, but lands on the same 8px. */
.btn-ghost,
.plan-btn,
.sv-install-btn,
.nav-drawer .nav-drawer-cta{border-radius:8px}

/* Content surfaces. .mbox covers both the real media and its placeholder, so
   an image dropped in later inherits the same corner as the card grid. */
.card,
.stp,
.mbox,
.pr-card,
.how-card{border-radius:16px}

/* ══ Testimonials ══════════════════════════════════════════════════════════
   A static row of cards, one per real Chrome Web Store review, each filled
   edge to edge with that reviewer's own photo.

   Known limitation: the source images are the 48x48 avatars the Chrome Web
   Store serves, and a card is roughly 370x400, so they run at a ~8x upscale
   and show visible pixel blocks. Rendering them sharp is a deliberate
   decision, not an oversight — swap in headshots of 800px or better and this
   rule needs no change.

   Replaces the horizontal marquee: base.css still defines .test-scroller and
   .test-track, but nothing renders them any more. Overriding the base
   .test-card here rather than editing base.css keeps the site's overrides in
   one file, which is the pattern the rest of this stylesheet follows. */
/* base.css drives the marquee: .test-track holds the three cards twice and
   travels exactly -50%, so the second set is mid-frame at the wrap and the
   loop is invisible. Only the sizing is set here — the duration is shortened
   from base's 46s because half as many cards means half the distance, which
   at the inherited timing would have crawled. */
.test-track{animation-duration:30s}
/* base.css fades both ends of the scroller into the page background with a
   120px gradient. Off here: the cards carry photographs now, and washing one
   out to black on the way past reads as a rendering fault rather than a
   soft edge. They clip on the scroller's own overflow instead. */
.test-scroller::before,.test-scroller::after{content:none}
.test-track .test-card{flex:0 0 380px;width:380px;margin-right:18px}
.test-card{
  position:relative;isolation:isolate;overflow:hidden;
  display:flex;flex-direction:column;gap:0;
  min-height:520px;padding:22px;border-radius:18px;
  border:1px solid rgba(255,255,255,.10);
  background:#0b0b0e;
  transition:transform .3s var(--ease),border-color .3s var(--ease)}
.test-photo{position:absolute;inset:0;z-index:-1;overflow:hidden;border-radius:inherit}
/* object-position favours the upper part of the frame: cover crops a 1:1
   avatar to this card's taller shape, and centring it would slice the top of
   the head off. */
.test-photo img{
  width:100%;height:100%;object-fit:cover;object-position:50% 28%;display:block;
  filter:saturate(1.25) contrast(1.05)}
/* Darkens towards the foot, where the quote and name sit, so their contrast
   holds no matter how light the photo underneath happens to be. */
.test-photo::after{
  content:"";position:absolute;inset:0;
  background:linear-gradient(180deg,
    rgba(10,10,13,.10) 0%,
    rgba(10,10,13,.55) 46%,
    rgba(10,10,13,.92) 100%)}
.test-card:hover{
  transform:translateY(-4px);border-color:rgba(255,255,255,.22)}
/* Sits where the reference puts a company logo. These reviewers are
   individuals with no company on record, so the slot carries the rating
   rather than inventing an employer for a named person. The source is stated
   once in the section subhead instead of repeated on all four cards. */
.test-src{display:flex;align-items:center}
.test-src .test-stars{display:flex;gap:3px;font-size:14px;color:#fff}
/* margin-top:auto is what anchors the quote and its attribution to the foot
   of the card, leaving the colour field open above them — the arrangement the
   reference gets by running a portrait down from the top. Putting the auto
   margin on .test-src instead only pushes the block that follows it, which
   left the quote riding up under the stars. */
.test-text{
  flex:none;
  margin:auto 0 20px;font-size:16px;line-height:1.55;font-weight:500;
  color:#fff;text-wrap:pretty}
.test-author{display:flex;align-items:center}
.test-meta{display:flex;flex-direction:column;gap:2px;min-width:0}
.test-name{font-size:14.5px;font-weight:600;color:#fff}
.test-date{font-size:13px;color:rgba(255,255,255,.62)}
.test-role{font-size:13px;color:rgba(255,255,255,.62)}
/* The track scrolls at every width, so the cards only need to get narrower —
   base.css already drops them to 300px under 640px; this shortens them to
   match so a tall card doesn't dominate a small screen. */
@media(max-width:640px){
  .test-card{min-height:440px}
}

/* ══ Pro badge ═════════════════════════════════════════════════════════════
   Matched to the supplied artwork: an outer gold pill with a thin, even
   surround, and an inner black ROUNDED RECTANGLE — not a second pill. That
   distinction is most of the character; a fully-rounded inner shape reads as
   a generic two-tone chip.

   Proportions are taken from the artwork rather than guessed: the black shape
   fills all but ~4% of the badge height, its corner radius is ~0.3 of its own
   height, and the wordmark is ~0.45 of it. Everything is driven by --pb-h so
   the badge scales as one object.

   Overridden automatically if tools/site/brand/pro-badge.* exists. */
.pro-badge{
  --pb-h:38px;
  display:inline-flex;align-items:center;
  height:var(--pb-h);padding:calc(var(--pb-h) * .085);
  border-radius:999px;
  background:linear-gradient(180deg,#eeb733 0%,#e5a929 100%);
  box-shadow:0 6px 20px rgba(224,164,25,.22)}
.pro-badge-mark{
  display:inline-flex;align-items:center;
  height:100%;padding:0 calc(var(--pb-h) * .42);
  border-radius:calc(var(--pb-h) * .30);
  background:#000;color:#fff;
  font-size:calc(var(--pb-h) * .45);font-weight:600;letter-spacing:-.015em;line-height:1}
.pro-badge-tag{
  padding:0 calc(var(--pb-h) * .40);
  font-size:calc(var(--pb-h) * .36);font-weight:800;letter-spacing:.04em;
  color:#1c1305;line-height:1}

/* ══ Pricing ═══════════════════════════════════════════════════════════════
   One split card, dark throughout. The two halves separate by weight rather
   than by inversion: the left recedes behind its artwork, the right sits
   forward on a lighter ground with a hairline between them.

   Both halves are tall on purpose — the card is the terminal object of the
   page, and giving it height is what stops it reading as another row. */
.price{position:relative;padding:110px 0;overflow:hidden}
.price::before{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:radial-gradient(56% 44% at 50% 4%,rgba(80,136,253,.10),transparent 70%)}
.price .wrap{position:relative;z-index:1}

.pplan{
  display:grid;grid-template-columns:minmax(0,0.9fr) minmax(0,1fr);
  max-width:1020px;margin:0 auto;border-radius:24px;overflow:hidden;
  border:1px solid rgba(255,255,255,.10)}

/* ── left: the argument ────────────────────────────────────────────────── */
/* The banner is the colour gradient and nothing else. The dark overlays that
   used to sit on top of it (a fade to black down the right edge and another
   across the top) are gone: they were there to echo the black areas of the
   source image, but over a full-height panel they just muddied it.

   Replaced wholesale if tools/site/brand/pricing-banner.* exists. */
.pplan-left{
  position:relative;display:flex;flex-direction:column;justify-content:flex-end;
  padding:44px;min-height:700px;overflow:hidden;
  /* Starts on blue, not on near-black. The first two stops used to run
     #0a1430 -> #14306a, which read as a black band across the top of the
     panel behind the badge. The ramp is now blue to mint end to end. */
  background:linear-gradient(180deg,
      #2c66c0 0%,
      #337ac9 14%,
      #3d93c5 30%,
      #43aeaa 45%,
      #47c193 58%,
      #5fd39b 70%,
      #86e4bd 83%,
      #a9edd6 93%,
      #bdf4e4 100%)}

/* A supplied file replaces all of it. cover + center keeps the composition
   intact at any panel size, and black stays underneath so an off-ratio image
   letterboxes into black rather than showing through. */
.pplan-left.has-art{background:var(--banner) center/cover no-repeat,#000}
/* The wireframe was drawn for a black panel. On the gradient it reads as
   noise, so it is dropped rather than restyled into something muddy. */
.pplan-art{display:none}
.pplan-copy{position:relative;z-index:1}
/* The copy sits at the bottom of the panel, which is the pale end of the
   gradient, so it inverts to near-black. White here would be unreadable —
   this is the whole reason the text colour is stated rather than inherited. */
.pplan-copy h2{font-size:44px;font-weight:600;letter-spacing:-.035em;line-height:1.05;color:#04231a}
.pplan-copy h2 strong{font-weight:600;color:#0a4d38;background:none;-webkit-text-fill-color:currentColor}
.pplan-copy p{margin-top:18px;font-size:14.5px;line-height:1.62;color:rgba(4,35,26,.72);max-width:36ch}

/* ── right: the transaction ────────────────────────────────────────────── */
.pplan-right{
  display:flex;flex-direction:column;padding:44px 40px;
  background:#0e0f14;border-left:1px solid rgba(255,255,255,.08)}
.pplan-right > *{flex:none}          /* nothing compresses when space is tight */
/* The badge sits top-left of the banner. margin-bottom:auto is what puts it
   there: the panel is a flex column justified to flex-end, so the auto margin
   absorbs the free space and pushes the headline block to the bottom. */
.pplan-left .pro-badge,
.pplan-left .pro-badge-img{position:relative;z-index:2;align-self:flex-start;margin-bottom:auto}

.pl-opts{display:grid;gap:10px}
/* The billing rows are selectable, not buttons in the CTA sense, so they keep
   an outline — but as an inset shadow so the row height does not change
   between selected and unselected. */
.pl-opt{
  display:grid;grid-template-columns:1fr auto auto;align-items:center;gap:11px;
  width:100%;padding:16px 17px;border-radius:12px;cursor:pointer;text-align:left;
  background:rgba(255,255,255,.03);border:0;
  box-shadow:inset 0 0 0 1.5px rgba(255,255,255,.10);
  font-family:inherit;transition:background .18s,box-shadow .18s}
.pl-opt:hover{background:rgba(255,255,255,.05);box-shadow:inset 0 0 0 1.5px rgba(255,255,255,.2)}
.pl-opt.active{
  background:rgba(72,202,124,.09);
  box-shadow:inset 0 0 0 1.5px rgba(72,202,124,.65),0 0 0 3px rgba(72,202,124,.10)}
.pl-opt-label{font-size:14px;font-weight:600;color:#fff}
.pl-save{
  padding:4px 9px;border-radius:6px;font-size:11.5px;font-weight:700;
  color:#8ef5c4;background:rgba(72,202,124,.16);white-space:nowrap}
.pl-rate{font-size:13.5px;color:var(--muted);white-space:nowrap;font-variant-numeric:tabular-nums}

/* The gap below the list is stated here rather than left to the CTA's auto
   margin: when the card runs short of spare space that margin computes to 0
   and the button lands flush against the last line. */
.pl-list{
  list-style:none;margin:28px 0 0;padding:24px 0 28px;
  border-top:1px solid rgba(255,255,255,.08);display:grid;gap:12px}
.pl-list li{display:flex;align-items:flex-start;gap:11px;font-size:14px;line-height:1.5;color:rgba(255,255,255,.82)}
.pl-list .ic{width:16px;height:16px;flex:none;margin-top:1px;color:var(--green)}

.pl-cta{
  display:block;margin-top:auto;padding:16px;border-radius:8px;text-align:center;
  font-size:14.5px;font-weight:700;color:#04120a;background:var(--grad-diag);
  box-shadow:0 10px 28px rgba(72,202,124,.24);
  transition:transform .2s var(--ease),box-shadow .2s}
.pl-cta:hover{transform:translateY(-1px);box-shadow:0 16px 36px rgba(72,202,124,.34)}
.pl-free{
  display:flex;align-items:baseline;justify-content:center;gap:8px;
  margin-top:12px;padding:13px;border-radius:8px;
  font-size:13.5px;font-weight:600;color:#fff;
  border:1px solid rgba(255,255,255,.12);transition:background .18s,border-color .18s}
.pl-free:hover{background:rgba(255,255,255,.06);border-color:rgba(255,255,255,.22)}
.pl-free span{font-weight:400;font-size:12.5px;color:var(--muted)}
.pl-fine{margin-top:18px;text-align:center;font-size:11.5px;line-height:1.6;color:var(--dim)}

@media(max-width:900px){
  .pplan{grid-template-columns:1fr;max-width:520px}
  .pplan-left{min-height:360px;padding:34px;justify-content:flex-end}
  .pplan-right{border-left:0;border-top:1px solid rgba(255,255,255,.08);padding:36px 26px}
  .pplan-copy h2{font-size:34px}
  .pplan-art{width:132%;top:-4%}
}
@media(max-width:560px){
  .price{padding:72px 0}
  .pl-opt{grid-template-columns:1fr auto;row-gap:6px}
  .pl-opt-label{grid-column:1 / -1}
  .pl-save,.pl-rate{grid-column:auto;justify-self:start}
}

/* ── Three-tier pricing: billing toggle + cards + comparison table ─────────── */
/* A real switch, not a two-tab pill: Monthly on the left, Yearly on the right,
   with a knob that slides. Either label or the switch itself flips it. */
.bill{display:flex;align-items:center;justify-content:center;gap:14px;margin:0 auto 34px}
.bill-label{display:inline-flex;align-items:center;gap:8px;font-size:14px;font-weight:600;
  color:var(--muted);cursor:pointer;user-select:none;transition:color .18s}
.bill-label.is-active{color:#fff}
.bill-switch{position:relative;flex:none;width:52px;height:30px;padding:0;border:1px solid var(--border);
  border-radius:999px;background:var(--card);cursor:pointer;transition:background .18s,border-color .18s}
.bill-switch::after{content:"";position:absolute;top:3px;left:3px;width:22px;height:22px;border-radius:50%;
  background:#fff;box-shadow:0 1px 3px rgba(0,0,0,.4);transition:transform .2s}
.bill-switch[aria-checked="true"]{background:var(--blue);border-color:transparent}
.bill-switch[aria-checked="true"]::after{transform:translateX(22px)}
.bill-switch:focus-visible{outline:2px solid var(--blue);outline-offset:2px}
.bill-save{font-size:11px;font-weight:700;padding:2px 8px;border-radius:999px;
  background:rgba(72,202,124,.16);color:var(--green,#48CA7C)}

.plans3{display:grid;grid-template-columns:repeat(3,1fr);gap:18px;max-width:1020px;margin:0 auto;align-items:start}
.plan3{position:relative;display:flex;flex-direction:column;padding:30px 26px;border:1px solid var(--border);
  border-radius:20px;background:var(--card)}
.plan3--pro{border-color:rgba(72,202,124,.55);background:
  linear-gradient(180deg,rgba(72,202,124,.08),transparent 55%),var(--card);
  box-shadow:0 24px 60px rgba(72,202,124,.16)}
.plan3-flag{position:absolute;top:-11px;left:50%;transform:translateX(-50%);white-space:nowrap;
  font-size:11px;font-weight:700;letter-spacing:.04em;text-transform:uppercase;padding:5px 13px;border-radius:999px;
  background:var(--green);color:#04120a}
.plan3-name{font-size:20px;font-weight:600;letter-spacing:-.01em;color:#fff}
.plan3-tag{margin-top:6px;font-size:13px;line-height:1.5;color:var(--muted);min-height:39px}
.plan3-price{margin-top:20px;display:flex;align-items:baseline;gap:2px;color:#fff;font-variant-numeric:tabular-nums}
.plan3-cur{font-size:22px;font-weight:600;align-self:flex-start;margin-top:6px}
.plan3-amt{font-size:46px;font-weight:600;letter-spacing:-.03em;line-height:1}
.plan3-per{font-size:15px;font-weight:500;color:var(--muted);margin-left:3px}
.plan3-sub{margin-top:8px;font-size:12.5px;color:var(--dim);min-height:18px}
.plan3-cta{display:flex;align-items:center;justify-content:center;margin-top:22px;padding:13px 18px;border-radius:11px;
  font-size:14.5px;font-weight:700;text-decoration:none;border:1px solid rgba(255,255,255,.14);
  color:#fff;background:rgba(255,255,255,.04);transition:transform .15s,box-shadow .2s,background .18s,border-color .18s}
.plan3-cta:hover{background:rgba(255,255,255,.08);border-color:rgba(255,255,255,.26)}
/* The featured plan's button is the site's main button: white, dark text,
   like every other primary action (brand audit, 2026-10-11). The others are
   the dark secondary style. */
.plan3-cta--solid{background:#fff;color:#000;border-color:transparent}
.plan3-cta--solid:hover{background:#fff;border-color:transparent;transform:translateY(-1px);box-shadow:0 14px 32px rgba(255,255,255,.14)}
.plan3-list{list-style:none;margin:24px 0 0;padding:24px 0 0;border-top:1px solid var(--border);
  display:flex;flex-direction:column;gap:12px}
.plan3-list li{display:flex;align-items:flex-start;gap:10px;font-size:13.5px;line-height:1.45;color:rgba(255,255,255,.84)}
.plan3-list .ic{width:16px;height:16px;flex:none;margin-top:1px;color:var(--green,#48CA7C)}

.cmp{margin:72px auto 0;max-width:900px}
.cmp-title{text-align:center;font-size:22px;font-weight:600;letter-spacing:-.02em;color:#fff;margin-bottom:24px}
.cmp-scroll{overflow-x:auto;border:1px solid var(--border);border-radius:16px}
.cmp-table{width:100%;border-collapse:collapse;min-width:600px}
.cmp-table th,.cmp-table td{padding:14px 18px;text-align:left;border-bottom:1px solid var(--border);font-size:14.5px}
.cmp-table thead th{font-size:14px;font-weight:600;color:#fff;background:var(--card);position:sticky;top:0}
.cmp-table th:first-child{width:40%}
.cmp-table th:not(:first-child),.cmp-table td:not(:first-child){text-align:center;width:20%}
.cmp-table tbody td:first-child{color:var(--muted)}
.cmp-table tbody tr:last-child td{border-bottom:0}
.cmp-col-pro{background:rgba(80,136,253,.06)}
.cmp-table thead .cmp-col-pro{background:rgba(80,136,253,.12)}
.cmp-y{display:inline-flex;color:var(--green,#48CA7C)}
.cmp-y .ic{width:18px;height:18px}
.cmp-n{color:var(--dim);font-weight:600}
.cmp-v{font-weight:600;color:#fff;font-variant-numeric:tabular-nums}

@media(max-width:820px){
  .plans3{grid-template-columns:1fr;max-width:440px;gap:22px}
  .plan3--pro{order:-1}
  .plan3-tag,.plan3-sub{min-height:0}
}

/* Supplied badge artwork, when tools/site/brand/pro-badge.* exists. Height is
   fixed and width follows, so swapping a wider or narrower file needs no CSS. */
.pro-badge-img{display:block;height:38px;width:auto}
@media(max-width:560px){.pro-badge-img{height:32px}}

/* ══ Extension panel ═══════════════════════════════════════════════════════
   Copy left, product window right, running off the panel's right edge. The
   crop is the whole idea: a window that continues past the frame reads as a
   screen you are looking into, where a contained thumbnail reads as a picture
   of one. overflow:hidden on the panel does the cutting, so the window is
   simply positioned wider than the space it has.

   The window chrome is drawn in CSS, not baked into the screenshot, so a new
   image can be dropped in without re-shooting the browser frame. */
.dl{padding:40px 0 110px;border-top:0}
.dl-panel{
  position:relative;overflow:hidden;min-height:560px;
  border:1px solid rgba(255,255,255,.09);border-radius:24px;
  background:
    radial-gradient(90% 120% at 8% 0%,rgba(80,136,253,.10),transparent 56%),
    linear-gradient(180deg,#0c0d12,#08080b)}
.dl-copy{
  position:relative;z-index:2;max-width:46%;padding:64px 0 64px 60px;
  display:flex;flex-direction:column;justify-content:center;min-height:560px}
.dl-copy h2{font-size:44px;font-weight:600;letter-spacing:-.034em;line-height:1.1;text-wrap:balance}
/* Second line recedes: the sentence keeps its shape while the emphasis lands
   on the first half, which is the reference's move. */
.dl-copy h2 span{color:rgba(255,255,255,.42)}
.dl-copy > p{margin-top:18px;font-size:16px;line-height:1.65;color:var(--muted);max-width:44ch}

/* ── the bleeding window ───────────────────────────────────────────────── */
.dl-win{
  position:absolute;left:52%;top:74px;width:64%;
  border-radius:14px 0 0 0;overflow:hidden;
  border:1px solid rgba(255,255,255,.12);border-right:0;border-bottom:0;
  background:#0b0c11;
  box-shadow:-30px 30px 80px rgba(0,0,0,.55)}
.dl-win-bar{
  display:flex;align-items:center;gap:7px;padding:0 14px;height:38px;
  background:#14161c;border-bottom:1px solid rgba(255,255,255,.07)}
.dl-dot{width:10px;height:10px;border-radius:50%;flex:none}
.dl-win-url{
  margin-left:12px;padding:4px 12px;border-radius:6px;
  background:rgba(255,255,255,.05);font-size:11.5px;color:var(--dim);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.dl-win-body{min-height:420px;display:flex}
.dl-win-body img{width:100%;height:auto;display:block}
.dl-ph{
  flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:9px;padding:40px 34px;text-align:center;
  background:repeating-linear-gradient(45deg,rgba(255,255,255,.022) 0 12px,transparent 12px 24px)}

/* Home page: the Chromium browsers the extension runs in, as round glass
   tiles like the Integrations tools (.ig-tool), in place of the window. */
.dl-browsers{
  position:absolute;left:50%;right:0;top:0;bottom:0;z-index:1;
  display:flex;flex-wrap:wrap;align-content:center;justify-content:center;gap:28px 32px;
  padding:48px 56px;list-style:none;margin:0}
.dl-browsers li{display:flex;flex-direction:column;align-items:center;gap:12px;width:96px}
.dl-br-ic{width:88px;height:88px;border-radius:50%;display:flex;align-items:center;justify-content:center;
  background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.12);box-shadow:0 12px 30px rgba(0,0,0,.3)}
.dl-br-ic img{width:44px;height:44px;object-fit:contain}
.dl-br-name{font-size:14px;font-weight:500;color:var(--muted)}

/* Home page only: about three quarters of the full panel's height. */
.dl-compact .dl-panel,.dl-compact .dl-copy{min-height:420px}
.dl-compact .dl-copy{padding:48px 0 48px 56px}
.dl-compact .dl-copy h2{font-size:36px}
.dl-compact .dl-win{top:56px}
.dl-compact .dl-win-body{min-height:320px}

@media(max-width:1080px){
  .dl-copy{max-width:52%;padding-left:44px}
  .dl-win{left:56%;width:70%}
}
@media(max-width:900px){
  .dl-panel{min-height:0}
  .dl-copy{max-width:none;min-height:0;padding:44px 32px 8px}
  .dl-win{position:relative;left:auto;top:auto;width:calc(100% - 32px);margin:28px 0 0 32px}
  .dl-win-body{min-height:300px}
  .dl-copy h2{font-size:34px}
  .dl-compact .dl-panel,.dl-compact .dl-copy{min-height:0}
  .dl-compact .dl-copy{padding:40px 32px 8px}
  .dl-compact .dl-copy h2{font-size:30px}
  .dl-browsers{position:relative;left:auto;padding:32px 32px 44px;justify-content:flex-start;gap:20px}
  .dl-browsers li{width:72px}
  .dl-br-ic{width:64px;height:64px}
  .dl-br-ic img{width:34px;height:34px}
}
@media(max-width:620px){
  .dl{padding:20px 0 72px}
  .dl-copy{padding:34px 22px 4px}
  .dl-win{width:calc(100% - 22px);margin-left:22px}
  .dl-win-body{min-height:230px}
}

/* ══ Card visuals ══════════════════════════════════════════════════════════
   Each feature card opens with an inset panel carrying a small illustration,
   the way the reference does. The panel is a recessed surface rather than
   another raised one, so the card still reads as a single object with a
   window cut into it.

   Every visual shares one 200x120 stage and this class vocabulary, so the
   palette lives here and no drawing carries a literal colour. */
.card{padding:14px 14px 26px;display:flex;flex-direction:column}
.card-vis{
  position:relative;overflow:hidden;border-radius:12px;margin-bottom:20px;
  background:
    radial-gradient(90% 80% at 50% 0%,rgba(80,136,253,.10),transparent 62%),
    #08080b;
  border:1px solid rgba(255,255,255,.055)}
.card-vis::after{               /* faint grid, the site's own texture */
  content:"";position:absolute;inset:0;pointer-events:none;
  background-image:radial-gradient(rgba(255,255,255,.05) 1px,transparent 1px);
  background-size:14px 14px}
.card h3{padding:0 12px;font-size:17.5px}
.card p{padding:0 12px}
.v{display:block;width:100%;height:auto;position:relative;z-index:1}

/* ── shared vocabulary ─────────────────────────────────────────────────── */
.v-panel{fill:rgba(255,255,255,.045);stroke:rgba(255,255,255,.09)}
.v-ln{fill:rgba(255,255,255,.16)}
.v-dim{fill:none;stroke:rgba(255,255,255,.22)}
.v-div{stroke:rgba(255,255,255,.12)}
.v-ac{fill:var(--blue)}
.v-ac2{fill:var(--green)}
.v-ac-t{fill:var(--blue)}
.v-chip{fill:rgba(72,202,124,.9)}
.v-chipbox{fill:rgba(255,255,255,.05);stroke:rgba(255,255,255,.08)}
.v-lbl{font:600 9px var(--font);fill:rgba(255,255,255,.62)}
.v-num{font:700 9px var(--font);fill:#fff}
.v-big{font:600 34px var(--font);fill:#fff;letter-spacing:-.03em}
.v-sel{fill:none;stroke:var(--blue);stroke-width:1.2;stroke-dasharray:3 2.5}
.v-bub{fill:rgba(80,136,253,.16);stroke:rgba(80,136,253,.34)}
.v-bub2{fill:rgba(72,202,124,.14);stroke:rgba(72,202,124,.30)}
.v-band{fill:rgba(72,202,124,.16)}
.v-shift{fill:rgba(80,136,253,.10);stroke:rgba(80,136,253,.4)}
.v-sw1{fill:#0d0f14;stroke:rgba(255,255,255,.10)}
.v-sw2{fill:var(--blue)}
.v-on-sw{fill:rgba(255,255,255,.9);font:600 15px var(--font)}
.v-pass{fill:rgba(72,202,124,.2)}
.v-pass-t{fill:#8ef5c4}
.v-open{fill:rgba(255,255,255,.28)}
.v-prog{fill:#f59e0b}
.v-tick{stroke:#04120a;stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round;fill:none}
.v-done{fill:rgba(72,202,124,.07);stroke:rgba(72,202,124,.28)}
.v-high{fill:#ef4444}
.v-med{fill:#f59e0b}
.v-low{fill:var(--blue)}
.v-av{fill:rgba(255,255,255,.14);stroke:#08080b;stroke-width:2}
.v-av2{fill:rgba(80,136,253,.5)}
.v-av3{fill:rgba(72,202,124,.5)}
.v-avplus{fill:rgba(255,255,255,.07);stroke:rgba(255,255,255,.14)}

/* The icon tile stays on personas and steps, where a full illustration would
   crowd a short label. */
.card .ic-tile{display:none}

/* Steps and persona cards take the same treatment as feature cards: one
   recessed visual panel, then the text. Personas moved to a numbered
   accordion instead, which keeps its own icon badge rather than hiding it. */
.stp{padding:14px 14px 26px}
.stp::before{display:none}          /* the old top hairline belonged to a flat card */
.stp h3{padding:0 12px}
.stp p{padding:0 12px}
.stp .ic-tile{display:none}


/* ══ Closing CTA heading ═══════════════════════════════════════════════════
   base.css never set a line-height here, so it fell through to `normal` —
   about 1.4 from this font's metrics, while every other display heading on
   the site is pinned near 1.13. At 73px that difference is very visible, and
   it was the only heading behaving differently.

   Weight goes to 500. BDO Grotesk ships a true Medium, and at this size the
   300 Light was thinning out against the dark ground. */
.cta-inner h2{line-height:1.14;font-weight:500}
.cta-inner h2 strong{font-weight:600}

/* ══ Rotating headline ═════════════════════════════════════════════════════
   The only animated element in the hero. "Give feedback where" never moves;
   the phrase after it slides up and fades between eight variants.

   No layout shift, by construction: every phrase occupies the SAME grid cell,
   so the cell sizes itself to the widest and tallest of them and stays that
   size forever. Nothing is hardcoded, so editing the list cannot break it.

   Timing per phrase: 500ms in, 2750ms hold, 400ms out, then a 100ms pause.
   That is a 3750ms slot; with eight phrases the loop is 30s, and the keyframe
   percentages below are those milliseconds expressed against that 30s. */
/* Selector matches base.css's own `.hero h1` specificity (0,1,1) — as a bare
   class it lost, and the headline silently kept the 105px / 940px rule, which
   wrapped the longest phrase and made the reserved box two lines tall. */
.hero h1.h1-rot-wrap{
  /* 12.635x is the measured width of the longest phrase, so 93px inside an
     1180px column keeps it on one line rather than leaving a hole under the
     short ones. */
  /* 25% up on the cap: 80px -> 100px, column widened to 1460px to hold it.
     Measured in place, "developers miss the difference." is 14.431x its
     font-size and the column is the viewport less 61px, so the largest size
     that still holds one line is (100vw - 61px) / 14.431 — about 6.39vw at
     780px, the tightest point. 6.3vw sits just under that across the range.

     So the full +25% applies from roughly 1590px of viewport, where the cap
     is reached; below that the headline is as large as one line allows. That
     is the trade: going bigger there would wrap the longest phrase, which
     makes the reserved cell two lines tall and leaves the short phrases
     floating in a hole.

     Then made about 15% smaller at the product owner's request: 100px -> 85px
     cap and 6.3vw -> 5.35vw, so it still holds one line everywhere. */
  font-size:clamp(34px,5.35vw,85px);max-width:1460px;line-height:1.06}
.h1-static{display:block;font-weight:300}
/* BDO Grotesk's glyph box is taller than a 1.06 line box, so at 100px the
   descenders of the phrase reach ~50px below the cell and were overrunning
   the subheadline. The padding is in em so it scales with the headline
   instead of needing a value per breakpoint. */
.h1-rot{display:grid;justify-items:center;align-items:start;padding-bottom:.04em}
.h1-p{
  grid-area:1/1;font-weight:600;
  /* background-clip:text paints only where the element's own background box
     overlaps the glyphs. With a 1.06 line-height the box stops above the
     descenders, so the tail of g/p/y got no paint and read as cut off. The
     padding extends the paint box below the baseline; it is on the phrase
     itself, not the grid cell, because the cell's padding is outside the
     background box and would not help. */
  padding-bottom:.10em;
  background:var(--grad);-webkit-background-clip:text;background-clip:text;color:transparent;
  opacity:0;transform:translateY(0.34em);
  /* duration and @keyframes are emitted per page by rotationCss(), because
     both depend on the phrase count. Only the slot length is fixed. */
  animation-name:h1Rot;animation-timing-function:var(--ease);
  animation-iteration-count:infinite;animation-fill-mode:both;
  animation-delay:calc(var(--i) * 3750ms)}

/* Reduced motion keeps the first phrase, permanently. The sentence a screen
   reader gets is the same one, because phrases two onward are aria-hidden. */
@media(prefers-reduced-motion:reduce){
  .h1-p{animation:none;opacity:0;transform:none}
  .h1-p:first-child{opacity:1}
}

@media(max-width:760px){
  .hero h1.h1-rot-wrap{font-size:clamp(36px,9.5vw,52px);line-height:1.08}
}

/* ══ Hero framing ══════════════════════════════════════════════════════════
   The copy is centred in the viewport on its own, and the media begins right
   after it — so a band of the video is always in view without the copy being
   pushed off-centre to make room. Previously the media was part of the same
   centred stack, which dragged the headline upward and buried the video. */
.hero:not(.hero-compact) .hero-sub{margin-top:10px}
.hero:not(.hero-compact) .hero-actions{margin-top:56px}

/* Scoped to the homepage. Inner pages use .hero-compact, which opens on a
   headline rather than a full-screen stage — giving them the 82vh centring
   too just left a large empty band under their nav. Without :not(), this rule
   won over .hero-compact's own padding purely by coming later in the file. */
.hero:not(.hero-compact){justify-content:flex-start;padding-top:calc(var(--ribbon-h) + 104px)}
.hero-copy{
  position:relative;z-index:1;width:100%;
  display:flex;flex-direction:column;align-items:center;justify-content:center}
.hero:not(.hero-compact) .hero-copy{
  /* 82vh, so the media's top edge lands at 82% of the viewport and roughly a
     fifth of it shows above the fold. */
  min-height:calc(82vh - var(--ribbon-h) - 104px)}
.hero-media{margin-top:0}

/* ══ Numbers (home), after Figma node 719:1291 ════════════════════════════
   The design's cards: 450px tall, radius 30, a darker card with a coloured
   panel inset from its top (27 / 32 / 23px, as in the design, so the three
   step slightly), a 56px number 60px down and an 18px label near the foot.
   In the site's theme: the card is a faint white glass on black, the panels
   are the brand's green, blue and pale cyan (the colours of the hero glow),
   and the heading is the site's own eyebrow and gradient title. */
.st{padding:40px 0 100px}
.st-head{margin-bottom:50px;text-align:left}
.st-head h2.sec-title{text-align:left;max-width:720px}
.st-row{display:flex;gap:20px}
.st-card{position:relative;flex:1 1 0;min-width:0;height:450px;border-radius:30px;background:rgba(255,255,255,.07);overflow:hidden}
.st-panel{position:absolute;left:0;right:0;bottom:0;top:var(--st-top);border-radius:30px;background:var(--st-c)}
.st-num{position:absolute;left:30px;top:60px;font-family:var(--font);font-weight:600;font-size:56px;line-height:64px;letter-spacing:-2px;color:#0b0b0d}
.st-label{position:absolute;left:30px;right:30px;bottom:30px;margin:0;max-width:325px;font-weight:600;font-size:18px;line-height:24px;letter-spacing:-.5px;color:#0b0b0d}
@media(max-width:860px){
  .st-row{flex-direction:column}
  .st-card{flex:none;height:260px}
}

/* ══ Quote banner (home, under How it works), after Figma node 718:860 ════
   The design's measurements (48/40 padding, 56 gap, 12 radius, a 568px
   quote, 40 between quote and name), recoloured for the black page: a faint
   glass card instead of #f3f4f6, white quote and name, muted role. The mark
   slot takes the design's 186.5px logo, or a round photo when there is no
   logo. */
.qb{padding:0 0 40px}
.qb-card{margin:0 auto;max-width:none;box-sizing:border-box;display:flex;align-items:center;gap:56px;padding:40px 48px;border-radius:12px;
  background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.08)}
.qb-mark{flex:none;width:186.5px;display:flex;justify-content:center}
.qb-logo{display:block;width:186.5px;height:45.895px;object-fit:contain}
.qb-photo{display:block;width:96px;height:96px;border-radius:50%;object-fit:cover;box-shadow:0 0 0 4px rgba(80,136,253,.18)}
/* Full container width at the product owner's request; the quote takes the
   rest of the row so it does not sit in a narrow column. */
.qb-body{display:flex;flex-direction:column;gap:40px;min-width:0;flex:1;max-width:820px;text-align:left}
.qb-quote{margin:0;font-family:var(--font);font-weight:500;font-size:20px;line-height:26px;color:#fff}
.qb-who{font-weight:500;font-size:16px;line-height:24px;color:rgba(255,255,255,.55)}
.qb-who strong{font-weight:600;color:#fff}
@media(max-width:760px){
  .qb-card{flex-direction:column;align-items:flex-start;gap:24px;padding:28px 24px}
  .qb-mark{width:auto}
  .qb-body{gap:20px}
}

/* ══ Integrations (home), after Figma node 730:1707 ═══════════════════════
   The illustration (a 440 x 311 frame, every piece at the design's own
   position) and the copy, 80px apart; the copy is 540px rather than the
   design's 440 so the site's larger two-line title holds two lines. In EasyQA's own look, at
   the product owner's request: the copy uses the site's section heading
   (.sec-eyebrow, .sec-title with a gradient line, .sec-sub, left-aligned here
   because the section is two columns) and its primary button (.btn-chrome);
   the comment and the tool circles are dark glass like the site's other cards,
   with the pin in the brand blue. The arrow keeps the design's own grey. */
.ig{padding:40px 0 120px}
.ig-row{display:flex;align-items:center;justify-content:center;gap:80px}
.ig-art{position:relative;flex:none;width:440px;height:311px}
.ig-bubble{position:absolute;left:0;top:0;box-sizing:border-box;width:439.5px;height:91.5px;display:flex;align-items:center;gap:16px;
  padding:0 19px;border-radius:16px;background:rgba(255,255,255,.05);border:1px solid rgba(255,255,255,.12);
  box-shadow:0 18px 40px rgba(0,0,0,.35);-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px)}
.ig-pin{flex:none;width:41.8px;height:41.8px;border-radius:50% 50% 50% 6px;background:#5088fd;color:#fff;display:flex;align-items:center;justify-content:center;
  font-size:17px;font-weight:600;box-shadow:0 0 0 4px rgba(80,136,253,.18)}
.ig-bubble-text{display:flex;flex-direction:column;gap:2px;min-width:0;text-align:left}
.ig-who{font-size:18px;line-height:24px;font-weight:600;color:#fff}
.ig-when{color:rgba(255,255,255,.45);font-weight:400;margin-left:6px;font-size:15px}
.ig-ask{font-size:18px;line-height:26px;color:rgba(255,255,255,.8);white-space:nowrap}
.ig-curve{position:absolute;left:27.2px;top:116px;width:41.2612px;height:94.001px;opacity:.55}
.ig-head{position:absolute;left:53.8px;top:192.3px;width:27.2553px;height:27.3999px;opacity:.55}
.ig-tool{position:absolute;box-sizing:border-box;width:75px;height:75px;border-radius:50%;
  background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.12);display:flex;align-items:center;justify-content:center;
  box-shadow:0 12px 30px rgba(0,0,0,.3)}
.ig-tool svg[stroke]{stroke:#fff}
.ig-copy{flex:none;width:540px;max-width:100%;text-align:left}
.ig-copy h2.sec-title,.ig-copy .sec-sub{text-align:left;margin-left:0}
.ig-copy .sec-sub{max-width:none}
.ig-note{margin:14px 0 0;font-size:14px;line-height:1.6;color:rgba(255,255,255,.45)}
.ig-cta{margin-top:28px}
@media(max-width:1020px){
  .ig-row{flex-direction:column;gap:40px}
  .ig-copy{text-align:center}
  .ig-copy h2.sec-title,.ig-copy .sec-sub{text-align:center;margin-left:auto;margin-right:auto}
}
@media(max-width:500px){
  .ig-art{transform:scale(.78);transform-origin:50% 0;margin-bottom:-68px}
  .ig-copy{width:auto}
}

/* ══ Reviews (home), after Figma node 718:870 ══════════════════════════════
   The design's measurements, recoloured for the black page (the design is
   light): cards are a faint white wash instead of #f5f5f5, text is white and
   muted white instead of navy, and the featured card's pastel wash is redone
   in the brand's blue and green. Three cards show at the 1160px container
   width, each (1160 - 2 x 16) / 3 = 376px, as in the design. */
.tq{padding:80px 0 176px}
.tq-feature{margin:64px 0 0;display:flex;align-items:center;gap:96px;padding:32px;border:1px solid rgba(255,255,255,.08);border-radius:12px;
  background:radial-gradient(60% 90% at 8% 100%,rgba(80,136,253,.2),transparent 70%),radial-gradient(45% 70% at 38% 100%,rgba(72,202,124,.12),transparent 70%),rgba(255,255,255,.02)}
.tq-feature-body{flex:1;min-width:0}
.tq-feature-quote{margin:0;font-weight:400;font-size:24px;line-height:32px;color:#fff;max-width:698px}
.tq-feature-who{padding-top:32px}
.tq-feature-photo{flex:none;width:300px;height:300px;border-radius:8px;object-fit:cover}
.tq-name{font-weight:600;font-size:18px;line-height:28px;color:#fff}
.tq-role{font-weight:500;font-size:14px;line-height:20px;color:rgba(255,255,255,.55);padding-top:2px}
.tq-carousel{padding-top:24px}
.tq-track{list-style:none;margin:0;padding:0;display:flex;gap:16px;overflow-x:auto;scroll-snap-type:x mandatory;scrollbar-width:none;outline:none}
.tq-track::-webkit-scrollbar{display:none}
.tq-track:focus-visible{outline:2px solid rgba(80,136,253,.7);outline-offset:4px;border-radius:12px}
.tq-card{flex:0 0 calc((100% - 32px) / 3);box-sizing:border-box;height:384px;padding:24px;border-radius:12px;background:rgba(255,255,255,.05);
  display:flex;flex-direction:column;justify-content:space-between;scroll-snap-align:start}
.tq-quote{margin:0;padding-bottom:16px;font-weight:400;font-size:18px;line-height:28px;color:rgba(255,255,255,.86)}
.tq-author{display:flex;align-items:center;gap:16px}
.tq-avatar{flex:none;width:64px;height:64px;border-radius:8px;object-fit:cover}
.tq-nav{display:flex;justify-content:center;gap:16px;margin-top:29px}
.tq-carousel.tq-fits .tq-nav{display:none}
.tq-btn{width:56px;height:56px;border-radius:50%;display:flex;align-items:center;justify-content:center;cursor:pointer;
  background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.14);color:#fff;box-shadow:0 2px 4px rgba(22,6,71,.05);transition:background .15s,opacity .15s}
.tq-btn:hover:not(:disabled){background:rgba(255,255,255,.1)}
.tq-btn:disabled{opacity:.35;cursor:default}
.tq-btn:focus-visible{outline:2px solid rgba(80,136,253,.8);outline-offset:2px}
/* Reviews: continuous scroll (site.js). The row glides right to left by one
   set of cards, then repeats; the sides fade into the page. Hover or focus
   pauses it. Without the tq-marquee class it is the plain carousel. */
.tq-marquee{overflow:hidden;
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 5%,#000 95%,transparent);
  mask-image:linear-gradient(90deg,transparent,#000 5%,#000 95%,transparent)}
.tq-marquee .tq-nav{display:none}
.tq-marquee .tq-track{overflow:visible;scroll-snap-type:none;width:max-content;animation:tqScroll var(--tq-dur,40s) linear infinite}
.tq-marquee .tq-card{flex:0 0 var(--tq-card-w)}
.tq-marquee:hover .tq-track,.tq-marquee:focus-within .tq-track{animation-play-state:paused}
@keyframes tqScroll{to{transform:translateX(calc(-1 * var(--tq-shift)))}}
@media(max-width:960px){
  .tq-feature{flex-direction:column-reverse;align-items:flex-start;gap:28px}
  .tq-feature-photo{width:100%;max-width:300px;height:auto;aspect-ratio:1}
  .tq-card{flex-basis:calc((100% - 16px) / 2)}
}
@media(max-width:600px){
  .tq{padding:56px 0 96px}
  .tq-feature{margin-top:40px;padding:24px}
  .tq-feature-quote{font-size:20px;line-height:30px}
  .tq-card{flex-basis:85%;height:auto;min-height:320px}
}

/* ══ Hero visual (arch, person, two cards) ═════════════════════════════════
   The home hero's visual under "Works with every major browser" (Figma:
   EasyQA, node 726:1564). The design is one 1764 x 736 frame; .hero-arch-art
   is that frame, with every piece at the design's own pixel position, and it
   is scaled as a whole (--s) to fit narrower screens. .hero-arch reserves the
   scaled height, so "Trusted by teams at" follows right after it.

   Adapted for the black page: the glow was drawn on light grey, where its
   faint outer tint shows; on black it needs a tighter blur (120px, not the
   design's 162px) to read, and its bottom edge fades out (mask) rather than
   being cut straight by the frame above the logos.

   The cards: they slide in from their own side when the visual scrolls into
   view (.armed is set by site.js, .in by its scroll observer), then float
   gently, out of step. On phones the frame is small, so the cards are scaled
   back up (--cs) to keep their text readable. Motion is off for people who
   ask for less of it. */
/* Pulled up 110px (scaled with the frame) into the empty glow above the
   person, at the product owner's request, so the visual sits closer to the
   browser row. z-index:-1 keeps the glow behind the row and buttons it now
   reaches under (.hero-copy is its stacking context). */
/* The home hero's copy starts a little lower than other heroes (+48px, +28px
   on phones), at the product owner's request: it sat close under the nav.
   :not(.hero-compact) matches, and beats, the shared rules in this file. */
/* 110px, down from 152px, so the arch photo can stay larger and still sit
   above the fold (see "Hero fit" in site.js, whose HEADLINE_LIFT matches the
   last 10px taken off here). */
.hero.hero-home:not(.hero-compact){padding-top:calc(var(--ribbon-h) + 110px)}
@media(max-width:760px){.hero.hero-home:not(.hero-compact){padding-top:calc(var(--ribbon-h) + 112px)}}
/* The headline block. On wider screens site.js ("Hero fit") shrinks the arch
   when needed so the person and both cards stay above the fold (product
   owner's request). */
.hero-top{display:flex;flex-direction:column;align-items:center;justify-content:center}
.hero-arch{--s:1;--cs:1;position:relative;z-index:-1;width:100%;height:calc(736px * var(--s));margin-top:calc(-110px * var(--s))}
.hero-arch-art{position:absolute;top:0;left:50%;width:1764px;height:736px;margin-left:-882px;
  transform:scale(var(--s));transform-origin:50% 0;text-align:left}
.hero-arch-glow{position:absolute;inset:0;overflow:hidden;pointer-events:none;
  -webkit-mask-image:linear-gradient(to bottom,#000 70%,transparent 100%);mask-image:linear-gradient(to bottom,#000 70%,transparent 100%)}
.hero-arch-bar{position:absolute;display:block;transform:rotate(45deg);filter:blur(120px)}
/* Each bar is placed by its centre, as in the design: left/top are the
   centre minus half the bar, in frame pixels. */
/* Wide bar: centre (1240.66, 1199.66), 1891.904 x 879. */
.hero-arch-bar--wide{left:294.708px;top:760.16px;width:1891.904px;height:879px;border-radius:149.057px;
  background:linear-gradient(90deg,#5088fd 0%,#48ca7c 46.635%,#112a4f 100%)}
/* Core bar: centre (1101.68, 1059.13), 1147.358 x 876.808. */
.hero-arch-bar--core{left:528.001px;top:620.726px;width:1147.358px;height:876.808px;border-radius:151.249px;
  background:linear-gradient(90deg,#5088fd 0%,#48ca7c 46.635%,#aef2ff 100%)}
/* The person: 948 x 534 at (447, 202), standing on the frame's bottom edge. */
.hero-arch-person{position:absolute;left:447px;top:202px;width:948px;height:534px;object-fit:cover;pointer-events:none}
/* Quote card: 360 wide at (447, 409). Stat card: 233 wide at (1066, 338). */
.hero-arch-card{position:absolute;scale:var(--cs)}
.hero-arch-quote{left:447px;top:409px;width:360px;transform-origin:0 50%;z-index:1}
.hero-arch-stat{left:1066px;top:338px;width:233px;transform-origin:100% 0;z-index:2}
.hero-arch-quote .hero-arch-float{box-sizing:border-box;padding:24px;border-radius:16px;background:#fff;box-shadow:0 4px 10px rgba(0,0,0,.1)}
.hero-arch-quote p{margin:0;font-family:var(--font);font-weight:500;font-size:20px;line-height:1.4;color:#000}
.hero-arch-stat .hero-arch-float{box-sizing:border-box;display:flex;flex-direction:column;gap:30px;padding:12px;border-radius:6px;background:linear-gradient(140deg,#3f74f2 0%,#2f8fd0 55%,#22a86c 100%);box-shadow:0 10px 30px rgba(47,143,208,.35);color:#fff}
.hero-arch-stat p{margin:0;font-family:var(--font);font-weight:600}
.hero-arch-stat-title{width:203px;font-size:16px;line-height:20px}
.hero-arch-stat-num{display:flex;align-items:flex-end;gap:6px;font-size:16px;line-height:20px}
.hero-arch-stat-num span{font-size:50px;line-height:56px;margin-bottom:-6px}

@keyframes heroArchInLeft{from{opacity:0;translate:-48px 12px}to{opacity:1;translate:0 0}}
@keyframes heroArchInRight{from{opacity:0;translate:48px 12px}to{opacity:1;translate:0 0}}
@keyframes heroArchFloat{0%,100%{transform:translateY(0)}50%{transform:translateY(-10px)}}
.hero-arch.armed:not(.in) .hero-arch-card{opacity:0}
.hero-arch.in .hero-arch-quote{animation:heroArchInLeft .9s var(--ease) .15s both}
.hero-arch.in .hero-arch-stat{animation:heroArchInRight .9s var(--ease) .35s both}
.hero-arch-quote .hero-arch-float{animation:heroArchFloat 6s ease-in-out 1.2s infinite}
.hero-arch-stat .hero-arch-float{animation:heroArchFloat 7s ease-in-out 2.4s infinite}
@media(prefers-reduced-motion:reduce){
  .hero-arch.armed:not(.in) .hero-arch-card{opacity:1}
  .hero-arch.in .hero-arch-card,.hero-arch-float{animation:none}
}

/* Smaller screens: the 948px-wide group (person and cards) is fitted to the
   screen; the glow around it is trimmed by the hero's overflow:hidden. */
/* Above 860px site.js may set --s inline to fit the first screen. */
@media(max-width:1000px){.hero-arch{--s:.85}}
@media(max-width:860px){.hero-arch{--s:.7}}
/* Phones: the cards are enlarged a little (--cs) so their text stays
   readable, and each grows AWAY from the person, toward its own screen edge,
   so neither covers his face. The sizes leave a margin on a 390px phone. */
@media(max-width:720px){
  .hero-arch{--s:.55;--cs:1.2}
  .hero-arch-quote{transform-origin:100% 50%}
  .hero-arch-stat{transform-origin:0 0}
}
@media(max-width:580px){.hero-arch{--s:.42;--cs:1.3}}
@media(max-width:440px){.hero-arch{--s:.34;--cs:1.3}}

/* Make it read as a video rather than an image slot. */
.mph-glyph.is-play{color:rgba(255,255,255,.5)}
.mph-glyph.is-play .ic{width:34px;height:34px}

@media(max-width:760px){
  .hero:not(.hero-compact){padding-top:calc(var(--ribbon-h) + 84px)}
  .hero:not(.hero-compact) .hero-copy{min-height:calc(78vh - var(--ribbon-h) - 84px)}
}

/* ══ Footer glow ═══════════════════════════════════════════════════════════
   The wash the original footer had, restored. It sits on .footer-wrap rather
   than on <footer>, because the SVG is wider than the page and needs clipping
   — overflow:hidden on the footer itself would also clip its content.

   The footer's own background is transparent so the glow reads through it;
   the border-top stays as the divider. */
/* No overflow:hidden here on purpose. Clipping the wrapper would cut the glow
   off at the footer's top edge and draw exactly the hard line this is meant to
   remove; letting it spill upward is what carries it under the CTA. The 130%
   width cannot cause a scrollbar because body already has overflow-x:hidden. */
/* Clipping stays: the glow is 130% of page width and unclipping it put up to
   170px of horizontal overflow on the document. The CTA now sits inside this
   wrapper, so there is room above the footer for the glow to spill into. */
.footer-wrap{position:relative;z-index:0;overflow:hidden}
/* Brighter, but pushed down so its hot core clears the link columns. At
   opacity .85 anchored to bottom:0 the peak landed directly behind the footer
   links and dropped their contrast to 1.3 — legible text matters more than
   the last bit of glow, so the intensity stays and the core moves instead. */
.footer-glow-img{
  position:absolute;bottom:-22%;left:50%;transform:translateX(-50%);
  width:140%;max-width:1720px;pointer-events:none;opacity:.85;z-index:0}
footer{position:relative;z-index:1;background:none;border-top:0}

/* The CTA is lifted above the glow's stacking level so its text stays legible
   while the wash passes behind it. Its background is transparent, so the glow
   still shows through around the type — which is what makes the two sections
   read as one continuous block instead of two stacked panels. */
.cta-section{position:relative;z-index:1;border-top:0}

@media(max-width:760px){
  .footer-glow-img{width:210%;opacity:.7;bottom:-16%}
}

/* Supplied screenshot in a card's visual panel. object-fit:contain rather than
   cover, because these are UI captures — cropping one cuts off the very
   control it is meant to show. The panel keeps its own background, so an image
   with a different aspect ratio sits on the texture instead of stretching. */
.card-img{
  display:block;width:100%;height:auto;position:relative;z-index:1;
  object-fit:contain}

/* ══ Button system ═════════════════════════════════════════════════════════
   One set of values for every button on the site: 16px regular, 12px vertical
   and 16px horizontal padding, 8px radius. Sizes were previously set per
   component (14px here, 14.5px there, 15px on the pricing CTA), which is how
   two buttons sitting side by side ended up different heights.

   line-height:1 keeps the box exactly 12+16+12 = 40px tall regardless of the
   font's own metrics, so the padding value is the height you actually get.
   box-sizing is already border-box globally. */
.btn-chrome,
.btn-ghost,
.nav-cta,
.nav-login,
.pl-cta,
.pl-free,
.pb-opt,
.plan-cta,
.plan-btn,
.sv-install-btn,
.nav-drawer .nav-drawer-cta{
  font-size:16px;
  font-weight:400;
  padding:12px 16px;
  border-radius:8px;
  line-height:1;
  /* base.css sets gap:8px/10px on these; with no icon left in most of them
     that gap only widened the box past the 16px side padding. */
  gap:8px;
  /* Every button carries a 1px border, transparent unless it is meant to
     show. Declaring it on all of them keeps them the same height: a border
     adds 2px to an intrinsically-sized box, so giving it only to the
     outlined ones would leave them 2px taller than the filled ones. */
  border:1px solid transparent}

/* base.css builds btn-chrome's outline from two pseudo-elements: ::before is
   a gradient rectangle bled 2px past the button, ::after is a white fill on
   top of it, leaving a 2px gradient ring. That pairing is replaced below —
   both are reused for the hover-glow fill and the travelling border light —
   so nothing here is switched off, only repurposed. */

/* A custom property is what lets the conic-gradient's angle below animate at
   all: browsers can only tween a <angle> smoothly between keyframes once it
   is registered as one. Unsupported browsers just keep the light static,
   which is a fine fallback. */
@property --btn-angle{syntax:'<angle>';inherits:false;initial-value:0deg}

/* Primary CTA: same 8px radius as every other button. The travelling border
   light runs by default rather than waiting for a hover — the ring sits at
   inset -2.5px, so it reads as a white comet against the dark page even
   while the button itself is still white. Hover adds the gradient fill and
   the arrow. */
.btn-chrome,.nav-cta{
  border-radius:8px;
  position:relative;
  isolation:isolate;
  box-shadow:
    0 1px 0 rgba(255,255,255,0) inset,
    0 10px 28px -6px rgba(80,136,253,0),
    0 0 46px -6px rgba(72,202,124,0);
  transition:color .45s var(--ease),transform .3s var(--ease),
             box-shadow .45s var(--ease);
}
.btn-chrome::before,.nav-cta::before{
  content:"";position:absolute;inset:0;z-index:-2;border-radius:inherit;
  background:linear-gradient(rgba(255,255,255,.30),transparent 55%),var(--grad);
  opacity:0;transition:opacity .45s var(--ease);
}
/* The travelling light: a conic-gradient ring, cut down to a ring by masking
   out everything but the padding box (the standard gradient-border trick),
   then spun by animating --btn-angle. A comet shape — soft build, bright
   head, hard cut — reads as motion much more clearly than a flat block of
   colour would, and the drop-shadow lets it bloom past its own 2.5px ring
   instead of staying a hairline. */
.btn-chrome::after,.nav-cta::after{
  content:"";position:absolute;inset:-2.5px;z-index:-1;border-radius:inherit;
  padding:2.5px;
  background:conic-gradient(from var(--btn-angle),
    transparent 0deg,
    transparent 255deg,
    rgba(255,255,255,.55) 300deg,
    #fff 328deg,
    #fff 335deg,
    transparent 345deg);
  -webkit-mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);
  -webkit-mask-composite:xor;mask-composite:exclude;
  opacity:1;
  animation:btn-border-loop 2.4s linear infinite;
}
.btn-chrome:hover,.nav-cta:hover{color:#fff;transform:scale(1.03)}
.btn-chrome:hover::before,.nav-cta:hover::before{opacity:1}
.btn-chrome:hover,.nav-cta:hover{
  box-shadow:
    0 1px 0 rgba(255,255,255,.35) inset,
    0 10px 28px -6px rgba(80,136,253,.55),
    0 0 46px -6px rgba(72,202,124,.5);
}
.btn-chrome:active,.nav-cta:active{transform:scale(.98)}
@keyframes btn-border-loop{to{--btn-angle:360deg}}

/* The arrow costs no space at rest: zero width, plus a negative margin that
   cancels the flex gap it would otherwise open beside the label. Hover
   animates both back, so the button grows into the arrow rather than holding
   an empty slot open for it. The slot clips, which is what lets the arrow
   inside run right off its own edge. */
.btn-chrome .btn-arrow,.nav-cta .btn-arrow{
  display:inline-flex;align-items:center;justify-content:center;
  width:0;height:16px;flex:none;overflow:hidden;margin-left:-8px;
  transition:width .28s var(--ease),margin-left .28s var(--ease);
}
.btn-chrome:hover .btn-arrow,.nav-cta:hover .btn-arrow,
.btn-chrome:focus-visible .btn-arrow,.nav-cta:focus-visible .btn-arrow{
  width:16px;margin-left:0;
}
/* Loops rather than settling: the arrow enters from the left, holds, then
   runs out to the right and vanishes before re-entering. Both ends of the
   keyframe sit at opacity 0, so the wrap-around is never seen as a jump. */
.btn-chrome .btn-arrow svg,.nav-cta .btn-arrow svg{
  width:16px;height:16px;flex:none;opacity:0;
}
.btn-chrome:hover .btn-arrow svg,.nav-cta:hover .btn-arrow svg,
.btn-chrome:focus-visible .btn-arrow svg,.nav-cta:focus-visible .btn-arrow svg{
  animation:btn-arrow-shuttle 1.25s var(--ease) infinite;
}
@keyframes btn-arrow-shuttle{
  0%,6%     {transform:translateX(-130%);opacity:0}
  28%,58%   {transform:translateX(0);opacity:1}
  86%,100%  {transform:translateX(130%);opacity:0}
}
@media(prefers-reduced-motion:reduce){
  .btn-chrome::after,.nav-cta::after{animation:none}
  .btn-chrome .btn-arrow,.nav-cta .btn-arrow{transition:none}
  .btn-chrome:hover .btn-arrow svg,.nav-cta:hover .btn-arrow svg,
  .btn-chrome:focus-visible .btn-arrow svg,.nav-cta:focus-visible .btn-arrow svg{
    animation:none;opacity:1;
  }
}

/* Hero pair only, 20% up from the site-wide button values (16px/12px+16px/
   8px radius/8px gap × 1.2), so the nav CTA and every other button on the
   site keep the shared size. */
.hero-actions .btn-chrome,
.hero-actions .btn-ghost{
  padding:14.4px 19.2px;
  border-radius:9.6px;
  gap:9.6px;
}

/* Full-width buttons keep the padding but stay centred rather than shrinking
   to their text. */
.pl-cta,.pl-free,.plan-cta{display:flex;align-items:center;justify-content:center;gap:8px}

/* The secondary line inside "Or start free" is deliberately smaller — it is a
   caption, not part of the label. */
.pl-free span{font-size:13px}

/* No borders on buttons. Secondary ones are separated by a faint fill instead,
   which also keeps every button at exactly 40px: a 1px border adds 2px to the
   box, since box-sizing only governs an explicitly set height, not an
   intrinsic one. The Chrome mark is pinned to 16px for the same reason — at
   18px it made its line box taller than the text beside it. */
/* Secondary buttons are outlined, not filled. */
.btn-ghost,
.pl-free,
.pb-opt{background:transparent;box-shadow:none;border-color:rgba(255,255,255,.20)}
.btn-ghost:hover,.pl-free:hover,.pb-opt:hover{
  background:transparent;border-color:rgba(255,255,255,.42);color:#fff}
.pb-opt.active{
  background:transparent;border-color:rgba(72,202,124,.85);color:#fff;box-shadow:none}

.btn-chrome svg,.nav-cta svg{width:16px;height:16px;flex:none}

/* The toolbar asset is a wide strip, not a page capture, so it is centred in
   the window body at its own scale rather than stretched to fill it. */
/* A full page capture fills the window; the toolbar strip is centred at its
   own scale instead, since stretching a 1232x353 strip to fill a 4:3 frame
   would blow it up past its native resolution. */
.dl-win-body{align-items:stretch}
.dl-shot{width:100%;height:auto;display:block;object-fit:cover;object-position:top center}
.dl-win-body:has(.dl-shot-alt){align-items:center;justify-content:center;padding:34px}
.dl-shot-alt{max-width:560px;object-fit:contain}

/* ── Compatibility table (pricing) ───────────────────────────────────────── */
.compat{padding:90px 0}
.compat .sec-head{margin-bottom:40px}
.compat-scroll{overflow-x:auto;max-width:820px;margin:0 auto;border:1px solid var(--border);border-radius:16px}
.compat-table{width:100%;border-collapse:collapse;min-width:560px}
.compat-table th,.compat-table td{padding:16px 20px;text-align:left;border-bottom:1px solid var(--border);font-size:15px}
.compat-table thead th{font-size:14px;font-weight:600;color:var(--text);vertical-align:top;background:var(--card)}
.compat-table thead th span{display:block;font-size:12px;font-weight:400;color:var(--dim);margin-top:3px}
.compat-table th:first-child{width:44%}
.compat-table td:nth-child(2),.compat-table td:nth-child(3),
.compat-table th:nth-child(2),.compat-table th:nth-child(3){text-align:center;width:28%}
.compat-table tbody td:first-child{color:var(--muted)}
.compat-table tbody tr:last-child td{border-bottom:none}
.compat-table td.y{color:var(--green);font-weight:600}
.compat-table td.n{color:var(--dim);font-weight:600}
.compat-note{max-width:680px;margin:22px auto 0;text-align:center;font-size:14px;line-height:1.7;color:var(--muted)}
@media(max-width:560px){ .compat-table th,.compat-table td{padding:13px 14px;font-size:14px} }


/* ══ Ambient depth ═════════════════════════════════════════════════════════
   The page was black from the hero down, section after section. Each band
   below gets a soft glow in the brand blue or green, placed differently so
   the eye keeps moving, and a few get the hero's dot grid, faded at the
   edges. A gradient hairline marks where some sections begin. All of it is
   pointer-events:none and sits behind the content (z-index:-1 inside a
   section that does not form a stacking context). */
#how,#teams,.fg,#faq,.cta-section,.pf{isolation:auto}
#how::before,#teams::before,.fg::before,#faq::before,.cta-section::before{
  content:"";position:absolute;pointer-events:none;z-index:-1}
#how::after,.fg::after,#faq::after{
  content:"";position:absolute;top:0;left:50%;width:min(1100px,90%);height:1px;transform:translateX(-50%);pointer-events:none;
  background:linear-gradient(90deg,transparent,rgba(80,136,253,.35) 30%,rgba(72,202,124,.35) 70%,transparent)}
/* How it works: blue glow up and left, on a faded dot grid. */
#how::before{inset:0;
  background:
    radial-gradient(40% 45% at 12% 18%,rgba(80,136,253,.16),transparent 70%),
    radial-gradient(rgba(255,255,255,.06) 1px,transparent 1.4px) 0 0/22px 22px;
  -webkit-mask-image:radial-gradient(70% 70% at 30% 35%,#000,transparent);mask-image:radial-gradient(70% 70% at 30% 35%,#000,transparent)}
/* Who it's for: green glow on the right. */
#teams::before{inset:0;background:radial-gradient(38% 50% at 88% 55%,rgba(72,202,124,.13),transparent 70%)}
/* The difference: a wide blue-to-green wash under the cards. */
.fg::before{left:0;right:0;top:30%;bottom:0;
  background:radial-gradient(45% 60% at 30% 60%,rgba(80,136,253,.13),transparent 70%),radial-gradient(40% 55% at 72% 62%,rgba(72,202,124,.11),transparent 70%);
  -webkit-mask-image:linear-gradient(#000 55%,transparent);mask-image:linear-gradient(#000 55%,transparent)}
/* FAQ: a quiet glow on the left and the dot grid. */
#faq::before{inset:0;
  background:radial-gradient(35% 50% at 15% 50%,rgba(72,202,124,.10),transparent 70%),
    radial-gradient(rgba(255,255,255,.05) 1px,transparent 1.4px) 0 0/22px 22px;
  -webkit-mask-image:radial-gradient(60% 70% at 50% 50%,#000,transparent);mask-image:radial-gradient(60% 70% at 50% 50%,#000,transparent)}
/* Closing call to action: the dot grid only, faded top and bottom. The
   blue and green aurora behind the buttons was removed on every page
   (product owner, 2026-10-17). */
.cta-section::before{inset:0;
  background:
    radial-gradient(rgba(255,255,255,.06) 1px,transparent 1.4px) 0 0/22px 22px;
  -webkit-mask-image:linear-gradient(transparent,#000 35%,#000 62%,transparent);mask-image:linear-gradient(transparent,#000 35%,#000 62%,transparent)}
/* Pricing and FAQ sit on a faint lighter band (base.css). Its flat edges
   read as hard lines on the black; fade it in and out instead. */
#pricing,#faq{background:linear-gradient(transparent,rgba(255,255,255,.014) 22%,rgba(255,255,255,.014) 78%,transparent)}

/* ══ Home page section rhythm ═════════════════════════════════════════════
   Every gap between two home sections is 120px (product owner, 2026-10-12):
   60px below one plus 60px above the next. Scoped to the sections after the
   home hero, and last in this file so it wins over each section's own
   padding. Phones use 40px each side, an 80px gap. */
.hero-home{padding-bottom:60px}
.hero-home ~ section,
.hero-home ~ .footer-wrap .cta-section{padding-top:60px;padding-bottom:60px}
/* A divider line counts as a section of its own: 120px above it and 120px
   below it. The line is drawn at the top edge of #how, .fg and #faq (the
   ::after hairline above), so those three get the full gap on top and the
   section before each one gets it underneath. #pricing counts too: its blue
   glow starts hard at its top edge, which reads as a divider (product owner,
   2026-10-12). */
.hero-home ~ #how,.hero-home ~ .fg,.hero-home ~ #pricing,.hero-home ~ #faq{padding-top:120px}
.hero-home ~ section:has(+ #how),
.hero-home ~ section:has(+ .fg),
.hero-home ~ section:has(+ #pricing),
.hero-home ~ section:has(+ #faq){padding-bottom:120px}
@media(max-width:760px){
  .hero-home{padding-bottom:40px}
  .hero-home ~ section,
  .hero-home ~ .footer-wrap .cta-section{padding-top:40px;padding-bottom:40px}
  .hero-home ~ #how,.hero-home ~ .fg,.hero-home ~ #pricing,.hero-home ~ #faq{padding-top:80px}
  .hero-home ~ section:has(+ #how),
  .hero-home ~ section:has(+ .fg),
  .hero-home ~ section:has(+ #pricing),
  .hero-home ~ section:has(+ #faq){padding-bottom:80px}
}

/* ══ No single word on a last line ════════════════════════════════════════
   Product owner, 2026-10-12: a heading or paragraph never ends on one word
   alone. Headings balance their lines; body text uses "pretty" wrapping.
   build.mjs (noWidows) also glues the last two words with a non-breaking
   space for browsers without text-wrap:pretty. */
h1,h2,h3,h4{text-wrap:balance}
p,li,blockquote,figcaption{text-wrap:pretty}

/* ══ Section reveal v2 ═════════════════════════════════════════════════════
   Home page, on trial (product owner, 2026-10-12). Only active when <html>
   has "mv2", which the build adds when SITE.homeMotion is true (content.mjs)
   and the visitor has not asked for reduced motion. site.js tags each block
   with data-fx and adds mv2-in when it scrolls into view, then mv2-done when
   the animation is over. The hidden look lives on :not(.mv2-in), so taking
   it away animates each element back to its normal style; the transitions
   live on :not(.mv2-done), so hover effects get their own back afterwards.
   Individual translate / scale / rotate are used, never transform, so
   nothing here fights an element's own transform. To undo: set homeMotion
   to false and rebuild (or delete this block and the site.js one).
   Not "fx": base.css already has a .fx diagram rule (max-width 1120px)
   that squeezed the whole page when it landed on <html>. */
/* The old fade-up stays out of the way inside a tagged block. */
html.mv2 [data-fx] .r,html.mv2 [data-fx].r{opacity:1;transform:none}

/* head: the label fades up, the heading wipes up, then the text and buttons
   follow. No blur, tracking or 3D tilt in any reveal: those repaint every
   frame and made scrolling lag (2026-10-17). Opacity, translate and scale
   only, which the GPU moves without repainting. */
html.mv2 [data-fx=head]:not(.mv2-done) :is(.sec-eyebrow,.ex-pill,.dl-eyebrow,.sc-tag){
  transition:opacity .7s var(--ease),translate .8s var(--ease)}
html.mv2 [data-fx=head]:not(.mv2-in) :is(.sec-eyebrow,.ex-pill,.dl-eyebrow,.sc-tag){opacity:0;translate:0 8px}
html.mv2 [data-fx=head]:not(.mv2-done) :is(h2,h3){
  clip-path:inset(-25% -6% -40% -6%);
  transition:clip-path 1.1s var(--ease) .12s,translate 1.1s var(--ease) .12s,opacity .7s ease .12s}
html.mv2 [data-fx=head]:not(.mv2-in) :is(h2,h3){clip-path:inset(0 0 100% 0);translate:0 .45em;opacity:0}
html.mv2 [data-fx=head]:not(.mv2-done) :is(p,.hero-actions,.dl-actions,.ex-cta,.ig-cta,.btn-chrome){
  transition:opacity .9s var(--ease) .4s,translate .9s var(--ease) .4s}
html.mv2 [data-fx=head]:not(.mv2-in) :is(p,.hero-actions,.dl-actions,.ex-cta,.ig-cta,.btn-chrome){opacity:0;translate:0 20px}

/* grid: children rise in turn, tipped back slightly in 3D. */
html.mv2 [data-fx=grid]:not(.mv2-done) > :not([data-fx]){
  transition:opacity .8s var(--ease),translate 1s var(--ease),scale 1s var(--ease);
  transition-delay:calc(var(--i,0) * 90ms + 120ms)}
html.mv2 [data-fx=grid]:not(.mv2-in) > :not([data-fx]){opacity:0;translate:0 40px;scale:.96}

/* panel: opens out of a rounded window and settles to full size. */
html.mv2 [data-fx=panel]:not(.mv2-done){
  clip-path:inset(-20% -20% -20% -20% round 0);
  transition:clip-path 1.3s var(--ease),scale 1.3s var(--ease),opacity .9s ease}
html.mv2 [data-fx=panel]:not(.mv2-in){clip-path:inset(14% 12% 14% 12% round 32px);scale:.92;opacity:0}

/* row: the Benefits copy slides in from its own side. */
html.mv2 [data-fx=row]:not(.mv2-done){transition:translate 1.1s var(--ease),opacity .9s ease}
html.mv2 [data-fx=row]:not(.mv2-in){translate:-64px 0;opacity:0}
html.mv2 .flip > [data-fx=row]:not(.mv2-in){translate:64px 0}

/* ══ Inner-page hero: split ═════════════════════════════════════════════
   The home hero is a centred stack. Inner pages used the same stack, and
   page after page of it felt repetitive (product owner, 2026-10-16), so an
   inner page with a picture opens on two columns instead: copy on the left,
   left-aligned, and the picture on the right. Below 980px the columns
   stack again, copy first, still left-aligned. */
.hero.hero-split{align-items:stretch;text-align:left;padding-bottom:88px}
/* Same content width as .wrap (max minus its 28px side padding): the hero
   already has 28px side padding of its own, so max-width alone would sit
   28px wider on each side than every section below it. */
.hero-split-grid{position:relative;z-index:1;width:100%;max-width:calc(var(--max) - 56px);margin:0 auto;
  display:grid;grid-template-columns:minmax(0,1.08fr) minmax(0,1fr);gap:56px;align-items:center}
.hero-split .hero-copy{align-items:flex-start;min-height:0}
.hero-split.hero-compact h1{font-size:60px;line-height:1.06;max-width:none}
.hero-split .hero-sub{max-width:540px}
.hero-split .hero-actions{justify-content:flex-start}
.hero-pic{position:relative;border-radius:22px;padding:8px;
  background:linear-gradient(135deg,rgba(80,136,253,.35),rgba(72,202,124,.25) 60%,rgba(255,255,255,.06));
  box-shadow:0 30px 80px -30px rgba(80,136,253,.45);animation:fadeUp 1s var(--ease) .32s both}
.hero-pic img{display:block;width:100%;height:auto;border-radius:15px;background:#0a0a0a}
/* Pictures keep their own shape; only photos are cropped, to one 4:3 frame. */
.hero-pic.is-photo img{aspect-ratio:4/3;object-fit:cover}
/* Solutions pages: two comments written for that audience take turns on
   the photo. Each pops in beside its pin, holds, and fades out while the
   other appears at its own spot; the 9s cycle loops for as long as the page
   is open. With reduced motion only the first one shows, still. */
.hero-pic-note{position:absolute;display:flex;align-items:center;gap:10px;
  padding:10px 14px 10px 10px;border-radius:14px;background:rgba(12,14,18,.92);border:1px solid rgba(255,255,255,.12);
  box-shadow:0 14px 40px rgba(0,0,0,.5);font-size:13px;line-height:1.35;color:var(--muted);white-space:nowrap;
  opacity:0;animation:heroNote 9s var(--ease) infinite both}
.hero-pic-note.n1{left:-22px;bottom:28px;transform-origin:left bottom}
.hero-pic-note.n2{right:-22px;top:30px;transform-origin:right top;animation-delay:4.5s}
.hero-pic-note b{display:block;color:#fff;font-weight:600}
.hero-pic-pin{flex:none;display:grid;place-items:center;width:28px;height:28px;border-radius:50%;
  background:#FF5A5F;border:2px solid #fff;color:#fff;font-size:13px;font-weight:600;
  animation:heroPin 9s var(--ease) infinite both;animation-delay:inherit}
.n2 .hero-pic-pin{background:#5088FD}
@keyframes heroNote{
  0%{opacity:0;transform:translateY(10px) scale(.92)}
  6%,44%{opacity:1;transform:none}
  50%,100%{opacity:0;transform:translateY(-6px) scale(.97)}}
@keyframes heroPin{
  0%,3%{transform:scale(.4)}
  8%{transform:scale(1.15)}
  12%,100%{transform:none}}
@media(prefers-reduced-motion:reduce){
  .hero-pic-note,.hero-pic-pin{animation:none}
  .hero-pic-note.n1{opacity:1}}
@media(max-width:1100px){.hero-split.hero-compact h1{font-size:50px}}
@media(max-width:980px){
  .hero-split-grid{grid-template-columns:1fr;gap:44px}
  .hero-pic{max-width:640px}
  .hero-pic-note.n1{left:12px;bottom:14px}
  .hero-pic-note.n2{right:12px;top:14px}
}
@media(max-width:760px){.hero-split.hero-compact h1{font-size:40px}}

/* ── Competitor prices (pricing) ─────────────────────────────────────────
   Shares the compatibility table's frame; our row is tinted so the eye
   finds it first. */
.compete{padding:90px 0 40px}
.compete .sec-head{margin-bottom:40px}
.compete-scroll{overflow-x:auto;max-width:980px;margin:0 auto;border:1px solid var(--border);border-radius:16px}
.compete-table{width:100%;border-collapse:collapse;min-width:680px}
.compete-table th,.compete-table td{padding:16px 20px;text-align:left;border-bottom:1px solid var(--border);font-size:15px;vertical-align:middle}
.compete-table thead th{font-size:13px;font-weight:600;color:var(--muted);background:var(--card)}
.compete-table tbody td{color:rgba(255,255,255,.78)}
.compete-table tbody td:first-child b{display:block;color:#fff;font-weight:600}
.compete-table tbody td:first-child span{display:block;font-size:12.5px;color:var(--dim);margin-top:2px}
.compete-table tbody tr:last-child td{border-bottom:none}
.compete-table tr.is-us td.y{color:var(--green)}
.compete-table td.n{color:var(--dim)}
.compete-table tr.is-us td{background:rgba(72,202,124,.07)}
.compete-table tr.is-us td:first-child{box-shadow:inset 3px 0 0 var(--green)}
.compete-table tr.is-us td:not(:first-child){color:#fff;font-weight:600}
@media(max-width:560px){ .compete-table th,.compete-table td{padding:13px 14px;font-size:14px} }

/* ── 404 page: ways out ──────────────────────────────────────────────── */
.lost{padding:30px 0 90px}
.lost .sec-head{margin-bottom:34px}
.lost-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:14px;max-width:960px;margin:0 auto}
.lost-i{display:block;padding:22px 22px 20px;border:1px solid var(--border);border-radius:16px;background:var(--card);
  transition:border-color .2s,transform .2s var(--ease)}
.lost-i:hover{border-color:rgba(72,202,124,.5);transform:translateY(-2px)}
.lost-i b{display:block;font-size:16px;font-weight:600;color:#fff}
.lost-i span{display:block;margin-top:6px;font-size:14px;line-height:1.5;color:var(--muted)}
@media(max-width:760px){.lost-grid{grid-template-columns:1fr 1fr}}
@media(max-width:480px){.lost-grid{grid-template-columns:1fr}}

/* Section headings keep their last two words together (no lone last word),
   and at 32px a long pair is wider than a 390px phone ("Capture,
   collaborate, resolve.", "arrives reproducible."), which scrolled the page
   sideways. 27px fits every heading on the site at 390px (measured). */
@media(max-width:430px){.sec-head h2{font-size:27px}}
/* Logo beside each tool's name in the price table. */
.compete-tool{display:flex;align-items:center;gap:12px}
.compete-logo{flex:none;width:32px;height:32px;border-radius:8px;object-fit:contain;background:#fff;padding:3px}
.compete-table tr.is-us .compete-logo{background:none;padding:0}

/* ══ Solutions story ════════════════════════════════════════════════════
   Five steps on one line. A gradient fills the line over the loop (--loop),
   and each step lights up as the fill reaches it, then stays lit until the
   loop starts over. Five fixed keyframe sets, one per step, because the
   story always has five. Reduced motion shows every step lit. */
.sy{padding:110px 0 40px;position:relative}
.sy-line{--loop:12s;position:relative;list-style:none;display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:18px;margin:0;padding:0}
.sy-line::before,.sy-fill{content:"";position:absolute;left:10%;right:10%;top:27px;height:2px;border-radius:2px}
.sy-line::before{background:rgba(255,255,255,.1)}
/* The gradient fill is a <span> in the list (build.mjs, S.story), placed
   absolutely so it takes no grid cell. That is also why the steps are
   counted with :nth-of-type, not :nth-child. */
.sy-fill{background:var(--grad);transform-origin:left;animation:syFill var(--loop) linear infinite}
@keyframes syFill{0%{transform:scaleX(0)}80%,100%{transform:scaleX(1)}}
.sy-beat{position:relative;z-index:1;display:flex;flex-direction:column;align-items:center;text-align:center;
  padding:0 6px;opacity:.38;animation:var(--k) var(--loop) var(--ease) infinite}
.sy-beat:nth-of-type(1){--k:sy0}.sy-beat:nth-of-type(2){--k:sy1}.sy-beat:nth-of-type(3){--k:sy2}.sy-beat:nth-of-type(4){--k:sy3}.sy-beat:nth-of-type(5){--k:sy4}
@keyframes sy0{0%,96%{opacity:1}100%{opacity:.38}}
@keyframes sy1{0%,19%{opacity:.38}22%,96%{opacity:1}100%{opacity:.38}}
@keyframes sy2{0%,39%{opacity:.38}42%,96%{opacity:1}100%{opacity:.38}}
@keyframes sy3{0%,59%{opacity:.38}62%,96%{opacity:1}100%{opacity:.38}}
@keyframes sy4{0%,79%{opacity:.38}82%,96%{opacity:1}100%{opacity:.38}}
.sy-node{display:grid;place-items:center;width:56px;height:56px;border-radius:16px;background:#0d0f13;
  border:1px solid rgba(255,255,255,.14);color:#fff;box-shadow:0 0 0 6px #000}
.sy-node svg{width:24px;height:24px}
.sy-beat:last-child .sy-node{color:#48CA7C;border-color:rgba(72,202,124,.55);background:#0b1510}
.sy-step{margin-top:18px;font-size:11.5px;font-weight:600;letter-spacing:.12em;text-transform:uppercase;color:var(--green)}
.sy-beat h3{margin-top:8px;font-size:18px;font-weight:600;letter-spacing:-.01em;color:#fff}
.sy-beat p{margin-top:8px;font-size:14px;line-height:1.55;color:var(--muted);max-width:220px}
/* The bit of interface each moment produces, popping in as its step lights. */
.sy-chip{margin-top:16px;padding:7px 12px;border-radius:999px;font-size:12.5px;font-weight:500;color:#fff;
  background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.14);white-space:nowrap}
.sy-beat:last-child .sy-chip{background:rgba(72,202,124,.14);border-color:rgba(72,202,124,.45);color:#8ef5c4}
@media(max-width:980px){.sy-beat p{font-size:13.5px}.sy-chip{white-space:normal}}
@media(max-width:760px){
  .sy{padding:80px 0 20px}
  .sy-line{grid-template-columns:1fr;gap:26px;max-width:420px;margin:0 auto}
  .sy-line::before,.sy-fill{left:27px;right:auto;top:28px;bottom:28px;width:2px;height:auto}
  .sy-fill{transform-origin:top;animation-name:syFillV}
  .sy-beat{display:grid;grid-template-columns:56px 1fr;column-gap:18px;align-items:start;text-align:left;padding:0}
  .sy-node{grid-row:1 / span 4}
  .sy-step{margin-top:2px}
  .sy-beat h3{margin-top:4px}
  .sy-beat p{max-width:none}
  .sy-chip{justify-self:start;margin-top:12px}
}
@keyframes syFillV{0%{transform:scaleY(0)}80%,100%{transform:scaleY(1)}}
@media(prefers-reduced-motion:reduce){
  .sy-beat,.sy-fill{animation:none}
  .sy-beat{opacity:1}
}

/* Closing call to action: the heading keeps its last two words together, and
   at 73px a pair like "decoding screenshots." is wider than the 720px box
   (base.css), so it spilled right and sat off centre. The box widens for the
   heading; the paragraph keeps its old measure. On narrow phones the heading
   drops to the same 27px as section headings and may use 14px of the box's
   side padding, which fits every page at 390px (measured). */
.cta-inner{max-width:960px}
.cta-inner > p{max-width:620px;margin-left:auto;margin-right:auto}
@media(max-width:430px){.cta-inner h2{font-size:27px;margin-left:-14px;margin-right:-14px}}

/* Pricing page without a hero (2026-10-16): the plans open the page, so
   their heading is the page's h1 and the section clears the fixed nav. The
   h1 takes the section-heading look at each width. */
.price-first{padding-top:150px}
.price-first .sec-head h1{font-size:40px;font-weight:600;letter-spacing:-.03em;line-height:1.14;text-wrap:balance}
@media(max-width:760px){.price-first{padding-top:120px}.price-first .sec-head h1{font-size:32px}}
@media(max-width:430px){.price-first .sec-head h1{font-size:27px}}

/* ══ Compare pages (2026-10-17) ═══════════════════════════════════════
   The hero shows the two marks instead of a picture; the table puts EasyQA
   first and tinted; "choose" gives each tool its honest column. */
.hero-vs{display:flex;align-items:center;justify-content:center;gap:28px;padding:56px 24px;aspect-ratio:942/530}
.vs-mark{display:grid;place-items:center;width:132px;height:132px;border-radius:30px;background:#fff;box-shadow:0 20px 50px rgba(0,0,0,.45)}
.vs-mark img{width:84px;height:84px;object-fit:contain}
.vs-mark.is-us{background:#0d0f13;border:1px solid rgba(255,255,255,.14)}
.vs-mark b{color:#111;font-size:18px}
.vs-x{font:600 15px var(--font);letter-spacing:.14em;text-transform:uppercase;color:var(--muted)}
.vs-table{min-width:560px}
.vs-table thead th:nth-child(2){color:#8ef5c4}
.vs-table td.vs-us{background:rgba(72,202,124,.07);color:#fff;font-weight:600}
.vs-table td:first-child{color:var(--muted);width:28%}
.choose{padding:70px 0 30px}
.choose-grid{display:grid;grid-template-columns:1fr 1fr;gap:16px;max-width:980px;margin:0 auto}
.choose-col{padding:26px 26px 22px;border:1px solid var(--border);border-radius:18px;background:var(--card)}
.choose-col.is-us{border-color:rgba(72,202,124,.45);background:rgba(72,202,124,.06)}
.choose-col h3{font-size:19px;font-weight:600;color:#fff}
.choose-col ul{list-style:none;margin:14px 0 0;padding:0;display:grid;gap:10px}
.choose-col li{position:relative;padding-left:22px;font-size:15px;line-height:1.5;color:rgba(255,255,255,.78)}
.choose-col li::before{content:"";position:absolute;left:2px;top:8px;width:8px;height:8px;border-radius:50%;background:rgba(255,255,255,.35)}
.choose-col.is-us li::before{background:var(--green)}
@media(max-width:760px){.choose-grid{grid-template-columns:1fr}.vs-mark{width:96px;height:96px;border-radius:22px}.vs-mark img{width:60px;height:60px}.hero-vs{gap:16px;padding:36px 16px}}

/* Text for search engines and screen readers only (the home hero's plain
   heading sentence). The standard clip pattern, so it is never shown. */
.sr-only{position:absolute!important;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}

/* ══ Features page: one feature per section (2026-10-17) ══════════════════
   After usepastel.com/features. A chapter heading (.fgp) opens each group;
   then each feature is its own row: copy on one side, the product capture
   on the gradient panel on the other, alternating. Features without a
   capture are a short text row with an icon. */
.fgp{padding:110px 0 10px}
.fgp .sec-head{margin-bottom:10px}
.ft{padding:44px 0}
/* Equal columns, so a panel on the left is the same size as one on the right. */
.ft-row{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:64px;align-items:center}
.ft.flip .ft-copy{order:2}
.ft-name{display:inline-block;font-size:12px;font-weight:600;letter-spacing:.12em;text-transform:uppercase;color:var(--green)}
.ft-copy h3,.ft-mini h3{margin-top:12px;font-size:32px;line-height:1.16;font-weight:600;letter-spacing:-.02em;color:#fff;text-wrap:balance}
.ft-copy p,.ft-mini p{margin-top:14px;font-size:16.5px;line-height:1.65;color:var(--muted);max-width:480px}
.ft-link{display:inline-flex;align-items:center;gap:8px;margin-top:20px;font-size:15px;font-weight:500;color:var(--green)}
.ft-link svg{transition:transform .2s var(--ease)}
.ft-link:hover svg{transform:translateX(3px)}
.ft-panel{position:relative;aspect-ratio:16/11;border-radius:28px;overflow:hidden;background:#0a0a0a;border:1px solid var(--border)}
/* Every picture is a trimmed copy fitted into the same box (80% x 70% of the
   panel), so the UI inside reads at the same size from row to row. */
.ft-panel > img{position:absolute;left:10%;top:15%;width:80%;height:70%;object-fit:contain;z-index:1}
.ft-text{padding:28px 0}
.ft-mini{display:grid;grid-template-columns:64px minmax(0,1fr);gap:24px;align-items:start;max-width:820px;margin:0 auto;
  padding:30px 34px;border:1px solid var(--border);border-radius:22px;background:var(--card)}
.ft-mini h3{margin-top:8px;font-size:26px}
.ft-mini p{max-width:none}
.ft-ic{display:grid;place-items:center;width:64px;height:64px;border-radius:18px;background:linear-gradient(135deg,rgba(80,136,253,.22),rgba(72,202,124,.22));border:1px solid rgba(255,255,255,.12);color:#fff}
.ft-ic svg{width:28px;height:28px}
@media(max-width:980px){
  .ft-row{grid-template-columns:1fr;gap:28px}
  .ft.flip .ft-copy{order:0}
  .ft-copy h3{font-size:28px}
}
@media(max-width:560px){
  .fgp{padding:80px 0 0}
  .ft{padding:30px 0}
  .ft-copy h3,.ft-mini h3{font-size:24px}
  .ft-mini{grid-template-columns:1fr;gap:16px;padding:24px 22px}
  .ft-panel{border-radius:20px}
}

/* Features page, Integrations row: the integration logos only, in a row,
   centred on the panel. Same round glass tiles as the home section. */
.ft-logos{position:absolute;inset:0;z-index:1;display:flex;align-items:center;justify-content:center;gap:22px}
.ft-logos .ig-tool{position:static;width:104px;height:104px}
.ft-logos .ig-tool svg{width:42px;height:42px}
@media(max-width:560px){.ft-logos{gap:14px}.ft-logos .ig-tool{width:74px;height:74px}.ft-logos .ig-tool svg{width:30px;height:30px}}

/* ══ Product hero (product pages, 2026-10-17) ═══════════════════════════
   Headline row (title left, intro and buttons right, aligned to the bottom),
   then a wide app window showing the page's picture on the moving gradient.
   Left-aligned to the same content width as the sections below. */
.hero.hero-product{align-items:stretch;text-align:left;padding-bottom:40px}
.hp-top{position:relative;z-index:1;width:100%;max-width:calc(var(--max) - 56px);margin:0 auto;
  display:grid;grid-template-columns:minmax(0,1.15fr) minmax(0,1fr);gap:64px;align-items:end}
.hp-head{display:flex;flex-direction:column;align-items:flex-start}
.hero-product.hero-compact h1{font-size:64px;line-height:1.04;max-width:none;margin:0}
.hp-side .hero-sub{margin-top:0;font-size:17.5px;max-width:none}
.hp-side .hero-actions{justify-content:flex-start;margin-top:26px}
.hp-side .hero-note{margin-top:16px}
.hp-shot{position:relative;z-index:1;width:100%;max-width:calc(var(--max) - 56px);margin:64px auto 0;animation:fadeUp 1s var(--ease) .3s both}
.hp-window{border-radius:20px;overflow:hidden;background:#0c0d10;border:1px solid rgba(255,255,255,.12);
  box-shadow:0 40px 120px -40px rgba(80,136,253,.5),0 20px 60px rgba(0,0,0,.5)}
.hp-bar{display:flex;align-items:center;gap:14px;padding:12px 16px;background:#141519;border-bottom:1px solid rgba(255,255,255,.08)}
.hp-dots{display:flex;gap:7px}
.hp-dots i{display:block;width:11px;height:11px;border-radius:50%;background:rgba(255,255,255,.18)}
.hp-dots i:nth-child(1){background:#ff5f57}.hp-dots i:nth-child(2){background:#febc2e}.hp-dots i:nth-child(3){background:#28c840}
.hp-url{flex:0 1 360px;margin:0 auto;padding:6px 14px;border-radius:8px;background:rgba(255,255,255,.06);
  font-size:13px;color:rgba(255,255,255,.55);text-align:center}
.hp-canvas{position:relative;aspect-ratio:16/7;overflow:hidden;
  background:
    radial-gradient(60% 70% at 50% 55%,rgba(80,136,253,.20),transparent 70%),
    radial-gradient(40% 50% at 78% 85%,rgba(72,202,124,.14),transparent 70%),
    radial-gradient(rgba(255,255,255,.07) 1px,transparent 1.4px) 0 0/22px 22px,
    #0a0b0e}
.hp-canvas > img{position:absolute;left:50%;top:12%;width:min(70%,640px);height:76%;transform:translateX(-50%);object-fit:contain;z-index:1;filter:drop-shadow(0 24px 50px rgba(0,0,0,.55))}
/* Capped at 640px so the 1x illustrations are not blown up. */
@media(max-width:1100px){.hero-product.hero-compact h1{font-size:52px}}
@media(max-width:900px){
  .hp-top{grid-template-columns:1fr;gap:22px}
  .hp-shot{margin-top:44px}
  .hp-canvas{aspect-ratio:16/10}
  .hp-canvas > img{top:10%;width:84%;height:80%}
}
@media(max-width:560px){
  .hero-product.hero-compact h1{font-size:40px}
  .hp-window{border-radius:14px}
  .hp-url{font-size:12px}
}

/* Story in detail (2026-10-17): rows reuse the feature-row layout (.ft). */
.sy-rows{list-style:none;margin:30px 0 0;padding:0}
.sy .sec-head{margin-bottom:10px}

/* Product hero with a real app screenshot: the window takes the capture's
   own 16:10 shape and shows it whole, edge to edge. */
.hp-canvas.is-shot{aspect-ratio:16/10;background:#0a0a0a}
.hp-canvas.is-shot > img,.hp-canvas.is-shot > video{position:absolute;left:0;top:0;width:100%;height:100%;transform:none;object-fit:cover;object-position:top;filter:none;z-index:1;display:block}
@media(max-width:900px){.hp-canvas.is-shot{aspect-ratio:16/10}.hp-canvas.is-shot > img{left:0;top:0;width:100%;height:100%}}

/* ══ Panel motions (2026-10-17) ═══════════════════════════════════════════
   The feature and story panels used one spin at one speed, so every card
   felt the same. Five motions now, handed out in turn (build.mjs, mv()):
   mv0 turns slowly, mv1 drifts across, mv2 breathes in and out, mv3 sways
   like a pendulum, mv4 orbits in a loose circle. All run about 20% slower
   than the old 16s/22s spin (40% slower, then sped up 20%), each starts at a different point, and the two
   layers of a panel move at different speeds so the colour keeps changing. */
.ft-panel .sc-mesh i{animation-timing-function:ease-in-out;left:-60%;top:-60%;width:220%;height:220%}
/* A larger layer than the home rows, so drifting and orbiting never bare a corner. */
.ft-panel.mv0 .sc-mesh i:nth-child(1){animation:mvTurn 22s linear infinite;animation-delay:-4s}
.ft-panel.mv0 .sc-mesh i:nth-child(2){animation:mvTurnBack 31s linear infinite;animation-delay:-11s}
.ft-panel.mv1 .sc-mesh i:nth-child(1){animation:mvDrift 26s ease-in-out infinite alternate;animation-delay:-7s}
.ft-panel.mv1 .sc-mesh i:nth-child(2){animation:mvDriftBack 36s ease-in-out infinite alternate;animation-delay:-19s}
.ft-panel.mv2 .sc-mesh i:nth-child(1){animation:mvBreathe 20s ease-in-out infinite;animation-delay:-2s}
.ft-panel.mv2 .sc-mesh i:nth-child(2){animation:mvBreatheBack 28s ease-in-out infinite;animation-delay:-14s}
.ft-panel.mv3 .sc-mesh i:nth-child(1){animation:mvSway 24s ease-in-out infinite alternate;animation-delay:-9s}
.ft-panel.mv3 .sc-mesh i:nth-child(2){animation:mvSwayBack 32s ease-in-out infinite alternate;animation-delay:-3s}
.ft-panel.mv4 .sc-mesh i:nth-child(1){animation:mvOrbit 29s linear infinite;animation-delay:-12s}
.ft-panel.mv4 .sc-mesh i:nth-child(2){animation:mvOrbitBack 39s linear infinite;animation-delay:-25s}
@keyframes mvTurn{to{transform:rotate(360deg)}}
@keyframes mvTurnBack{from{transform:scaleX(-1) rotate(0deg) scale(1.1)}to{transform:scaleX(-1) rotate(-360deg) scale(1.1)}}
@keyframes mvDrift{from{transform:translate(-14%,-6%) rotate(-8deg)}to{transform:translate(14%,6%) rotate(8deg)}}
@keyframes mvDriftBack{from{transform:scaleX(-1) translate(10%,8%) scale(1.05)}to{transform:scaleX(-1) translate(-12%,-8%) scale(1.15)}}
@keyframes mvBreathe{0%,100%{transform:scale(.92) rotate(0deg)}50%{transform:scale(1.22) rotate(25deg)}}
@keyframes mvBreatheBack{0%,100%{transform:scaleX(-1) scale(1.2) rotate(10deg)}50%{transform:scaleX(-1) scale(.95) rotate(-20deg)}}
@keyframes mvSway{from{transform:rotate(-38deg) scale(1.05)}to{transform:rotate(38deg) scale(1.05)}}
@keyframes mvSwayBack{from{transform:scaleX(-1) rotate(30deg) translateY(-6%)}to{transform:scaleX(-1) rotate(-30deg) translateY(6%)}}
@keyframes mvOrbit{0%{transform:translate(6%,0) rotate(0deg)}25%{transform:translate(0,6%) rotate(90deg)}50%{transform:translate(-6%,0) rotate(180deg)}75%{transform:translate(0,-6%) rotate(270deg)}100%{transform:translate(6%,0) rotate(360deg)}}
@keyframes mvOrbitBack{0%{transform:scaleX(-1) translate(0,5%) scale(1.1)}50%{transform:scaleX(-1) translate(0,-5%) scale(1.18) rotate(-180deg)}100%{transform:scaleX(-1) translate(0,5%) scale(1.1) rotate(-360deg)}}
@media(prefers-reduced-motion:reduce){.ft-panel .sc-mesh i{animation:none!important}}

/* Feature and story cards with the live gradient: the same soft dark centre
   as the home showcase panels (.sc-panel::after), so the UI picture stays
   the focus and colour gathers at the edges. */
.ft-panel.gl::after{content:"";position:absolute;inset:0;pointer-events:none;z-index:0;
  background:radial-gradient(64% 56% at 50% 50%,rgba(10,10,10,.6),rgba(10,10,10,.15) 72%,rgba(10,10,10,0))}

/* Feature and story rows: their copy sits one level deeper (.ft > .ft-row >
   .ft-copy), so the flipped rows slide in from the right like .sc-row does. */
html.mv2 .ft.flip .ft-copy[data-fx=row]:not(.mv2-in){translate:64px 0}

/* Integrations page cards: the tool's own logo, in the home section's round
   glass tile, centred on the card's dotted panel. */
.card-vis.card-tool{display:flex;align-items:center;justify-content:center;aspect-ratio:328/196;width:100%}
.card-tool .ig-tool{position:static;width:96px;height:96px}
.card-tool .ig-tool svg{width:42px;height:42px}

/* ══ Revi chat (home page, 2026-10-17) ═══════════════════════════════════ */
.revi{position:fixed;right:24px;bottom:24px;z-index:300;font-family:var(--font)}
.revi-ava{display:grid;place-items:center;flex:none}
.revi-ava svg{display:block}
.revi-face img{display:block;width:100%;height:100%;object-fit:contain}
.revi-btn .revi-face{animation:reviBob 4s ease-in-out infinite}
@keyframes reviBob{0%,100%{translate:0 0}50%{translate:0 -3px}}
.revi-btn{position:relative;display:flex;align-items:center;justify-content:center;width:64px;height:64px;border-radius:50%;
  border:1px solid rgba(255,255,255,.14);background:#0d0f13;cursor:pointer;box-shadow:0 12px 34px rgba(0,0,0,.55),0 0 0 6px rgba(79,135,252,.12);
  transition:transform .25s var(--ease),box-shadow .25s}
.revi-btn:hover{transform:translateY(-2px) scale(1.04);box-shadow:0 16px 40px rgba(0,0,0,.6),0 0 0 8px rgba(79,135,252,.18)}
.revi-btn:focus-visible{outline:2px solid #4f87fc;outline-offset:3px}
.revi-hi{position:absolute;right:76px;bottom:12px;white-space:nowrap;padding:10px 14px;border-radius:14px 14px 4px 14px;
  background:#fff;color:#0b0b0d;font-size:14px;font-weight:500;box-shadow:0 10px 30px rgba(0,0,0,.4);
  opacity:0;translate:8px 0;pointer-events:none;transition:opacity .3s,translate .3s var(--ease)}
.revi.greet .revi-hi{opacity:1;translate:0 0}
.revi.open .revi-hi{display:none}
.revi-panel{position:absolute;right:0;bottom:80px;width:370px;max-height:min(600px,calc(100vh - 130px));display:flex;flex-direction:column;
  border-radius:20px;overflow:hidden;background:#0e1014;border:1px solid rgba(255,255,255,.12);
  box-shadow:0 30px 80px rgba(0,0,0,.6);animation:reviIn .28s var(--ease)}
@keyframes reviIn{from{opacity:0;translate:0 12px;scale:.97}to{opacity:1;translate:0 0;scale:1}}
.revi-head{display:flex;align-items:center;gap:12px;padding:14px 14px 14px 16px;border-bottom:1px solid rgba(255,255,255,.08);
  background:linear-gradient(135deg,rgba(80,136,253,.18),rgba(72,202,124,.10))}
.revi-head .revi-face{width:38px;height:38px}
.revi-who{display:flex;flex-direction:column;min-width:0;flex:1}
.revi-who b{font-size:16px;color:#fff}
.revi-who span{font-size:12.5px;color:rgba(255,255,255,.6);display:flex;align-items:center;gap:6px}
.revi-dot{width:7px;height:7px;border-radius:50%;background:#48ca7c;display:inline-block}
.revi-x{display:grid;place-items:center;width:32px;height:32px;border-radius:9px;border:0;background:rgba(255,255,255,.06);color:#fff;cursor:pointer}
.revi-x:hover{background:rgba(255,255,255,.12)}
.revi-log{flex:1;min-height:150px;overflow-y:auto;padding:16px;display:flex;flex-direction:column;gap:10px}
.revi-msg{max-width:86%;padding:10px 13px;border-radius:14px;font-size:14px;line-height:1.5;word-wrap:break-word}
.revi-msg.bot{align-self:flex-start;background:#1b1e24;color:rgba(255,255,255,.88);border-bottom-left-radius:4px}
.revi-msg.me{align-self:flex-end;background:#4f87fc;color:#fff;border-bottom-right-radius:4px}
.revi-msg a{color:#8ef5c4;text-decoration:underline;text-underline-offset:2px}
.revi-msg b{color:#fff}
.revi-msg.typing{display:flex;gap:4px;padding:13px}
.revi-msg.typing i{width:6px;height:6px;border-radius:50%;background:rgba(255,255,255,.5);animation:reviDot 1s infinite}
.revi-msg.typing i:nth-child(2){animation-delay:.15s}.revi-msg.typing i:nth-child(3){animation-delay:.3s}
@keyframes reviDot{0%,60%,100%{opacity:.3;translate:0 0}30%{opacity:1;translate:0 -3px}}
.revi-chips{display:flex;flex-wrap:wrap;gap:6px;padding:0 16px 12px}
.revi-chip{padding:7px 11px;border-radius:999px;border:1px solid rgba(79,135,252,.45);background:rgba(79,135,252,.08);
  color:#cfe0ff;font:500 12.5px var(--font);cursor:pointer;transition:background .2s}
.revi-chip:hover{background:rgba(79,135,252,.2)}
.revi-form{display:flex;gap:8px;padding:12px;border-top:1px solid rgba(255,255,255,.08)}
.revi-form input{flex:1;min-width:0;padding:11px 13px;border-radius:12px;border:1px solid rgba(255,255,255,.12);background:#15181d;
  color:#fff;font:14px var(--font);outline:none}
.revi-form input:focus{border-color:#4f87fc}
.revi-form button{display:grid;place-items:center;width:42px;border-radius:12px;border:0;background:#4f87fc;color:#fff;cursor:pointer}
.revi-support{display:block;padding:11px 16px 13px;font-size:13px;color:rgba(255,255,255,.6);text-align:center;border-top:1px solid rgba(255,255,255,.06)}
.revi-support b{color:#8ef5c4;font-weight:600}
.revi-support:hover b{text-decoration:underline}
@media(max-width:560px){
  .revi{right:16px;bottom:16px}
  .revi-btn{width:58px;height:58px}
  .revi-panel{position:fixed;left:12px;right:12px;bottom:86px;width:auto;max-height:calc(100vh - 110px)}
  .revi-hi{display:none}
}
@media(prefers-reduced-motion:reduce){.revi-btn .revi-face,.revi-panel,.revi-msg.typing i,.revi-eye,.revi-eyes{animation:none!important}}
/* The panel's own display:flex beat the hidden attribute, so it showed while
   closed. And the suggestions sit in one row that scrolls sideways, so the
   conversation keeps the room. */
.revi-panel[hidden]{display:none}
.revi-chips{flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none;padding-bottom:12px;mask-image:linear-gradient(90deg,#000 85%,transparent);-webkit-mask-image:linear-gradient(90deg,#000 85%,transparent)}
.revi-chips::-webkit-scrollbar{display:none}
.revi-chip{flex:none;white-space:nowrap}
.revi-chips,.revi-head,.revi-form,.revi-support{flex:none}


/* ══ Revi expressions ══════════════════════════════════════════════════════
   The eyes sit where the artwork's eyes were (measured on the 478px cut-out:
   centres at 35.5% and 56% across, 39% down; 11.3% wide, 15.7% tall).
   States are classes on #revi, set by site.js ("Revi chat"):
   idle      blinks and glances side to side now and then
   is-think  looks up and to the side while the answer is "typed"
   is-happy  smiling eyes for a moment after answering, or on hover
   is-puzzled one eye smaller when Revi has no answer
   is-wink   a quick double blink with the greeting                                      */
.revi-face{position:relative;display:block;width:44px;height:44px}
.revi-eye{position:absolute;top:39.3%;width:11.3%;height:15.7%;margin:-7.85% 0 0 -5.65%;border-radius:999px;
  background:#08080a;box-shadow:0 2px 2px rgba(20,40,120,.25);
  transition:height .18s ease,margin .18s ease,border-radius .18s ease,translate .35s var(--ease),scale .2s ease,rotate .2s ease;
  animation:reviLook 11s infinite}
.revi-eye.l{left:35.46%}
.revi-eye.r{left:56.07%}
/* Both eyes sit in one group and the group blinks, so they can never close
   one after the other. It squashes around the eyes' line (39.3% down). */
.revi-eyes{position:absolute;inset:0;transform-origin:50% 39.3%;animation:reviBlink 5.5s infinite}
@keyframes reviBlink{0%,93%,100%{scale:1 1}96%{scale:1 .1}}
@keyframes reviLook{0%,38%,100%{translate:0 0}42%,52%{translate:-22% 0}57%,67%{translate:22% 0}72%{translate:0 0}}
/* thinking: glance up and to the right */
.revi.is-think .revi-eye{animation:none;translate:30% -26%;scale:.9 .9}
.revi.is-think .revi-eyes,.revi.is-happy .revi-eyes,.revi.is-puzzled .revi-eyes,.revi-btn:hover .revi-eyes{animation:none}
/* happy: the eyes become smiling arcs */
.revi.is-happy .revi-eye{animation:none;height:7%;margin-top:-5.5%;border-radius:999px 999px 3px 3px;
  background:transparent;box-shadow:inset 0 3px 0 0 #08080a}
.revi-head .revi.is-happy .revi-eye,.revi.is-happy .revi-head .revi-eye{box-shadow:inset 0 2.5px 0 0 #08080a}
/* puzzled: one eye smaller, a small tilt */
.revi.is-puzzled .revi-eye{animation:none}
.revi.is-puzzled .revi-eye.l{scale:.7 .7;translate:0 10%}
.revi.is-puzzled .revi-eye.r{rotate:12deg}
/* wink: the right eye closes once */
/* greeting: a quick double blink, both eyes together */
.revi.is-wink .revi-eyes{animation:reviDouble .9s ease}
@keyframes reviDouble{0%,30%,60%,100%{scale:1 1}15%,45%{scale:1 .1}}
.revi-btn:hover .revi-eye{animation:none;height:7%;margin-top:-5.5%;border-radius:999px 999px 3px 3px;background:transparent;box-shadow:inset 0 3px 0 0 #08080a}

/* No circle around Revi (product owner, 2026-10-17): the avatar itself is
   the button, a little larger, with a soft shadow so it still lifts off the
   page. */
.revi-btn{width:64px;height:64px;border:0;border-radius:0;background:none;box-shadow:none}
.revi-btn:hover{box-shadow:none;transform:translateY(-2px) scale(1.06)}
.revi-btn .revi-face{width:60px;height:60px;filter:drop-shadow(0 8px 18px rgba(0,0,0,.55)) drop-shadow(0 0 14px rgba(79,135,252,.35))}
.revi-btn:focus-visible{outline:2px solid #4f87fc;outline-offset:4px;border-radius:14px}
@media(max-width:560px){.revi-btn{width:58px;height:58px}.revi-btn .revi-face{width:54px;height:54px}}
.btn-ext-ic{display:inline-grid;place-items:center;width:22px;height:22px}.btn-ext-ic svg{width:22px;height:22px}

/* ══ Clean menus (2026-10-17, after Marker.io) ════════════════════════════
   Two labelled columns with a hairline between them, plain line icons in
   the brand green (no filled tiles), a title and one muted line, and a soft
   highlight on hover. */
.nav-menu-cols{display:grid;grid-template-columns:repeat(2,minmax(300px,1fr));padding:8px;gap:0}
.nav-col{display:flex;flex-direction:column;gap:2px;padding:14px 12px}
.nav-col + .nav-col{border-left:1px solid rgba(255,255,255,.08)}
.nav-col-t{padding:0 12px 10px;font-size:13px;font-weight:500;color:rgba(255,255,255,.5)}
.nav-menu-cols .nav-item{gap:14px;padding:11px 12px;border-radius:10px;align-items:flex-start}
.nav-menu-cols .nav-item::before{display:none}
.nav-menu-cols .nav-item:hover{background:rgba(255,255,255,.06)}
.nav-menu-cols .nav-item-ic{width:22px;height:22px;margin-top:2px;border:0;background:none;color:#48CA7C;border-radius:0}
.nav-menu-cols .nav-item:hover .nav-item-ic{color:#8ef5c4}
.nav-menu-cols .nav-item-ic .ic{width:20px;height:20px}
.nav-menu-cols .nav-menu-t{font-size:15px;font-weight:500}
.nav-menu-cols .nav-menu-d{font-size:13px;margin-top:4px;color:rgba(255,255,255,.5)}

/* Product hero, calmer (2026-10-17: "too tight and busy"). The app
   screenshot already has its own top bar, so it gets no extra browser bar;
   it sits in a thin gradient frame instead. More room between the headline
   row and the picture, a narrower intro, and a softer glow. */
.hero.hero-product{padding-top:calc(var(--ribbon-h) + 170px);padding-bottom:110px}
.hp-top{gap:96px;align-items:end}
.hp-side{max-width:470px;justify-self:end}
.hp-side .hero-sub{font-size:16.5px;line-height:1.7}
.hp-side .hero-actions{margin-top:30px}
.hp-shot{max-width:min(1060px,calc(var(--max) - 56px));margin-top:110px}
.hp-window{padding:10px;border-radius:26px;
  background:linear-gradient(140deg,rgba(80,136,253,.38),rgba(255,255,255,.06) 40%,rgba(72,202,124,.32));
  border:0;box-shadow:0 50px 120px -50px rgba(80,136,253,.45)}
.hp-canvas.is-shot{border-radius:17px;overflow:hidden}
@media(max-width:900px){
  .hero.hero-product{padding-top:calc(var(--ribbon-h) + 130px);padding-bottom:80px}
  .hp-top{gap:26px}
  .hp-side{justify-self:start;max-width:none}
  .hp-shot{margin-top:60px}
  .hp-window{padding:6px;border-radius:18px}
  .hp-canvas.is-shot{border-radius:13px}
}

/* Rows slide in from the side (Section reveal v2), so before they are shown
   their text sits up to 64px past the edge, and on phones the page could be
   dragged sideways. Clip the page's horizontal overflow; "clip" (not
   "hidden") keeps the sticky and fixed elements working. */
html,body{overflow-x:clip}

/* Product hero, take three (2026-10-17): "title area feels bad, the image
   does not fit the container, no shadow under it".
   - One left-aligned column: label, headline, intro, buttons. The split row
     had the right column starting above the headline and running past it.
   - The small note under the buttons is hidden here; it repeated the intro.
   - The screenshot is exactly the content width, the same edges as the
     headline and every section below, with no glow or shadow. */
.hp-top{display:flex;flex-direction:column;align-items:flex-start;gap:0}
.hp-head,.hp-side{max-width:760px;justify-self:auto}
.hp-side{max-width:600px}
.hp-side .hero-sub{margin-top:22px;font-size:18px;line-height:1.65}
.hp-side .hero-actions{margin-top:32px}
.hero-product .hero-note{display:none}
.hp-shot{max-width:calc(var(--max) - 56px);margin-top:72px}
.hp-window{padding:0;background:none;box-shadow:none;border:1px solid rgba(255,255,255,.1);border-radius:18px}
.hp-canvas.is-shot{border-radius:17px}
@media(max-width:900px){.hp-shot{margin-top:48px}.hp-window{border-radius:14px}.hp-canvas.is-shot{border-radius:13px}}
/* More air between the buttons and the screenshot (was 72px / 48px). */
.hp-shot{margin-top:120px}
@media(max-width:900px){.hp-shot{margin-top:72px}}

/* Problem sections, simplified (2026-10-17): a short heading, one plain
   sentence, and the answer in green. No divider, less space. */
.prob{padding:100px 0 40px}
.prob-inner{max-width:680px}
.prob-inner h2{font-size:40px}
.prob-body p{font-size:18px;line-height:1.6}
.prob-close{border-top:0;padding-top:0;margin-top:18px;color:var(--green);font-weight:500;font-size:18px}
@media(max-width:760px){.prob{padding:72px 0 24px}.prob-inner h2{font-size:30px}}
.prob{border-top:0}

/* "The problem" as one card: the problem on the left, the fix on the right. */
.prob{padding:24px 0 24px;border-top:0}
/* With no screenshot under it, the product hero keeps only a short gap. */
.hero-product:not(:has(.hp-shot)){padding-bottom:40px}
.prob-card{display:grid;grid-template-columns:1fr 1fr;
  border:1px solid rgba(255,255,255,.10);border-radius:24px;overflow:hidden;
  background:rgba(255,255,255,.025)}
.prob-before,.prob-after{padding:44px 48px;display:flex;flex-direction:column;justify-content:flex-start;gap:14px}
.prob-before{background:linear-gradient(135deg,rgba(255,99,99,.07),transparent 60%)}
.prob-after{position:relative;isolation:isolate}
.prob-tag{font-size:12px;font-weight:600;letter-spacing:.12em;text-transform:uppercase}
.prob-tag.neg{color:#ff7a7a}
.prob-tag.pos{color:var(--green)}
.prob-card .prob-h{font-size:34px;font-weight:600;letter-spacing:-.03em;line-height:1.15;text-wrap:balance;margin:0}
.prob-before p,.prob-after p{font-size:17px;line-height:1.6;color:var(--muted);margin:0}
@media(max-width:760px){
  .prob{padding:48px 0 16px}
  .prob-card{grid-template-columns:1fr;border-radius:20px}
  .prob-before,.prob-after{padding:28px 24px}
  .prob-card .prob-h{font-size:26px}
}

/* Problem card motion. On reveal: the problem slides in from the left, the
   divider draws down, the arrow pops on it, then the green fix side sweeps
   in. The tags' dots breathe slowly afterwards. All of it is off for people
   who ask for reduced motion. */
.prob-card{position:relative;transition:border-color .4s ease,transform .4s ease,box-shadow .4s ease}
.prob-card:hover{border-color:rgba(74,222,128,.22);transform:translateY(-3px);box-shadow:0 24px 60px -30px rgba(74,222,128,.35)}
.prob-after::after{content:"";position:absolute;inset:0;z-index:-1;
  background:linear-gradient(135deg,rgba(74,222,128,.12),rgba(74,222,128,.02));
  transform-origin:left;transition:transform .9s cubic-bezier(.2,.7,.2,1) .55s,opacity .4s ease}
.prob-card:hover .prob-after::after{background:linear-gradient(135deg,rgba(74,222,128,.17),rgba(74,222,128,.03))}
.prob-after::before{content:"";position:absolute;left:0;top:0;bottom:0;width:1px;
  background:linear-gradient(180deg,rgba(255,255,255,.04),rgba(74,222,128,.45),rgba(255,255,255,.04));
  transform-origin:top;transition:transform .7s cubic-bezier(.2,.7,.2,1) .3s}
.prob-arrow{position:absolute;left:0;top:50%;z-index:2;width:40px;height:40px;margin:-20px 0 0 -20px;
  display:grid;place-items:center;border-radius:50%;color:var(--green);
  background:#0b120d;border:1px solid rgba(74,222,128,.35);
  box-shadow:0 0 0 6px rgba(0,0,0,.6),0 0 24px rgba(74,222,128,.25);
  transition:transform .55s cubic-bezier(.3,1.6,.5,1) .75s,opacity .3s ease .75s}
.prob-arrow svg{transition:transform .35s ease}
.prob-card:hover .prob-arrow svg{transform:translateX(3px)}
.prob-before > *,.prob-after > :not(.prob-arrow){transition:opacity .6s ease,transform .7s cubic-bezier(.2,.7,.2,1)}
.prob-before > :nth-child(1){transition-delay:.05s}.prob-before > :nth-child(2){transition-delay:.15s}.prob-before > :nth-child(3){transition-delay:.25s}
.prob-after > :nth-child(2){transition-delay:.85s}.prob-after > :nth-child(3){transition-delay:.95s}.prob-after > :nth-child(4){transition-delay:1.05s}
.prob-card:not(.in) .prob-before > *{opacity:0;transform:translateX(-18px)}
.prob-card:not(.in) .prob-after > :not(.prob-arrow){opacity:0;transform:translateX(18px)}
.prob-card:not(.in) .prob-after::after{transform:scaleX(0)}
.prob-card:not(.in) .prob-after::before{transform:scaleY(0)}
.prob-card:not(.in) .prob-arrow{opacity:0;transform:scale(.4) rotate(-45deg)}
.prob-tag{display:inline-flex;align-items:center;gap:8px}
.prob-tag::before{content:"";width:6px;height:6px;border-radius:50%;background:currentColor;box-shadow:0 0 0 0 currentColor}
.prob-card.in .prob-tag.pos::before{animation:probPulse 2.4s ease-out 1.6s infinite}
@keyframes probPulse{0%{box-shadow:0 0 0 0 rgba(74,222,128,.55)}70%,100%{box-shadow:0 0 0 7px rgba(74,222,128,0)}}
@media(max-width:760px){
  .prob-after::before{left:0;right:0;bottom:auto;width:auto;height:1px;transform-origin:left;
    background:linear-gradient(90deg,rgba(255,255,255,.04),rgba(74,222,128,.45),rgba(255,255,255,.04))}
  .prob-card:not(.in) .prob-after::before{transform:scaleX(0)}
  .prob-arrow{left:50%;top:0;margin:-20px 0 0 -20px}
  .prob-arrow svg{transform:rotate(90deg)}
  .prob-card:hover .prob-arrow svg{transform:rotate(90deg) translateY(-3px)}
  .prob-card:not(.in) .prob-before > *,.prob-card:not(.in) .prob-after > :not(.prob-arrow){transform:translateY(14px)}
}
@media(prefers-reduced-motion:reduce){
  .prob-card,.prob-card *,.prob-card *::before,.prob-card *::after{transition:none!important;animation:none!important}
  .prob-card:not(.in) .prob-before > *,.prob-card:not(.in) .prob-after > *,.prob-card:not(.in) .prob-arrow{opacity:1;transform:none}
  .prob-card:not(.in) .prob-after::after,.prob-card:not(.in) .prob-after::before{transform:none}
  .prob-card:hover{transform:none}
}

/* Page changes cross-fade instead of blinking white-to-dark, and the menu
   bar stays put (2026-10-17: "moving one page to another feels choppy").
   Browsers without cross-page view transitions just load normally. */
@view-transition{navigation:auto}
#nav{view-transition-name:site-nav}
/* The old page fades out and lifts a little; the new one fades in and
   settles from just below. Only opacity and transform, so the GPU does it. */
::view-transition-old(root){animation:eqaPageOut .28s cubic-bezier(.4,0,1,1) both}
::view-transition-new(root){animation:eqaPageIn .5s cubic-bezier(.16,1,.3,1) .06s both}
::view-transition-group(site-nav){animation-duration:0s}
@keyframes eqaPageOut{to{opacity:0;transform:translateY(-12px)}}
@keyframes eqaPageIn{from{opacity:0;transform:translateY(18px)}}
html{background:#000}
/* Browsers without page transitions (Firefox) still get a soft fade in.
   Opacity only: a transform on body would unpin the fixed menu bar.
   html.vt is set in the head where page transitions exist, so those
   browsers do not fade twice. */
html:not(.vt) body{animation:eqaFadeIn .4s ease both}
@keyframes eqaFadeIn{from{opacity:0}}
@media(prefers-reduced-motion:reduce){
  @view-transition{navigation:none}
  html:not(.vt) body{animation:none}
}

/* The dropdown menus are solid now (product owner, 2026-10-17: "remove the
   transparency"); the page behind no longer shows through. */
.nav-menu{background:#0c0c11;-webkit-backdrop-filter:none;backdrop-filter:none}
