/* LITEMODE shared stylesheet.
   One file, cached across every page. No framework, no build step — the pages
   that sell speed should not ship a render-blocking CSS-in-JS bundle. */

:root{
  --ink:#0C1222;
  --muted:#5A6478;
  /* White, chrome, colour. The page is white; the colour comes from the streak
     field and the motes, not from a grey wash. Cards sit on white too, so the
     hairline and the shadow have to do the separating — hence the slightly
     stronger --line than a grey background would need. */
  --ice:#FFFFFF;
  --surface:#FFFFFF;
  --line:rgba(12,18,34,.13);
  /* the faintest possible tint, for alternating sections — barely a shade */
  --alt:#FAFBFD;

  --c1:#FF3D8A;
  --c2:#7C3AED;
  --c3:#21D4FD;
  --ramp:linear-gradient(120deg,var(--c1),var(--c2) 55%,var(--c3));

  --ease:cubic-bezier(.16,1,.3,1);
  --wrap:1080px;
}

*,*::before,*::after{ box-sizing:border-box; }
html{ scroll-behavior:smooth; -webkit-text-size-adjust:100%; }
body{
  margin:0; background:var(--ice); color:var(--ink);
  font-family:'Inter',system-ui,-apple-system,'Segoe UI',sans-serif;
  font-size:17px; line-height:1.7; -webkit-font-smoothing:antialiased;
  overflow-x:hidden;
}
img{ max-width:100%; height:auto; display:block; }
a{ color:inherit; }

@font-face{
  font-family:'Inter'; font-weight:100 900; font-display:swap;
  src:url('/brand_assets/fonts/Inter-Variable-latin.woff2') format('woff2');
}

.wrap{ max-width:var(--wrap); margin:0 auto; padding:0 20px; }
.narrow{ max-width:760px; }

/* ---------- type ---------- */
h1,h2,h3{ font-family:'Chakra Petch',sans-serif; font-weight:700; letter-spacing:-.02em; margin:0; }
h1{ font-size:clamp(2.1rem,6vw,3.6rem); font-style:italic; line-height:1.05; }
h2{ font-size:clamp(1.5rem,3.4vw,2.1rem); line-height:1.2; margin-bottom:.6rem; }
h3{ font-size:1.15rem; line-height:1.35; margin-bottom:.35rem; }
p{ margin:0 0 1.1rem; }
.lede{ font-size:1.16rem; color:var(--muted); max-width:56ch; }
.eyebrow{
  font-family:'JetBrains Mono',ui-monospace,monospace; font-size:11.5px;
  letter-spacing:.16em; text-transform:uppercase; color:var(--muted); margin:0 0 14px;
}
.grad{ background:var(--ramp); -webkit-background-clip:text; background-clip:text; color:transparent; }
.muted{ color:var(--muted); }
.small{ font-size:14.5px; }

/* Gradient rule under every h2 on the marketing pages. Opt-in via body.lp so
   the logo/widget labs keep their plain headings. */
.lp h2{ position:relative; }
.lp h2::after{
  content:""; display:block; width:38px; height:3px; margin-top:.5rem; border-radius:2px;
  background:var(--ramp);
}
.lp .cta h2::after{ display:none; }              /* the CTA block carries its own ramp edge */
.lp.calm h2::after{ width:22px; height:2px; opacity:.5; }   /* legal pages stay quiet */

/* Figures: the ramp belongs on the number, not the sentence around it. */
.figure{ letter-spacing:-.035em; }

/* ---------- logo ---------- */
.lm-logo{
  --thick:.17em; --h:.74em; --lean:-13deg; --gap:.11em; --pair:.45em;
  --lm-phase:-.28em;                 /* = thick + gap: keeps the ramp continuous across the pair */
  font-family:'Inter',sans-serif; font-weight:900; letter-spacing:-.02em;
  display:inline-flex; align-items:center; line-height:1; white-space:nowrap;
  text-decoration:none;
}
.lm-slashes{ display:inline-flex; align-items:center; gap:var(--gap); margin-right:.21em; }
.lm-slash{
  display:block; width:var(--thick); height:var(--h); transform:skewX(var(--lean));
  position:relative; overflow:hidden;
}

/* ---------- logo shimmer ----------
   Each stroke becomes a window and a tiled ramp travels behind it. The only
   animated property is translateX on an absolutely-positioned pseudo element,
   so the stroke's own box never changes: no reflow, and the nav bar itself is
   never repainted — the moving layer composites on its own.

   The tile mirrors about its midpoint —
     pink -> purple -> cyan -> YELLOW -> cyan -> purple -> pink
   so frame 100% is pixel-identical to frame 0 and the 4s loop has no seam.
   Purple and cyan appear twice per tile, so their bands are cut narrow to
   compensate: the four colours hold 28 / 28 / 28 / 16 of the tile's width,
   which keeps the yellow a dash rather than a third of the mark. */
.lm-slash::before{
  content:""; position:absolute; top:0; left:0; height:100%; width:1.8em;
  will-change:transform;
  background-image:linear-gradient(90deg,
    #FF3D8A 0%,  #FF3D8A 8%,
    #7C3AED 20%, #7C3AED 22%,
    #21D4FD 34%, #21D4FD 39%,
    #FFB454 45%, #FFB454 55%,
    #21D4FD 61%, #21D4FD 66%,
    #7C3AED 78%, #7C3AED 80%,
    #FF3D8A 92%, #FF3D8A 100%);
  background-size:.9em 100%; background-repeat:repeat-x;
  animation:lmShimmer 4s linear infinite;
}
.lm-slash:nth-child(2)::before{ left:var(--lm-phase); }
@keyframes lmShimmer{ from{ transform:translateX(0) } to{ transform:translateX(-.9em) } }
.lm-word{
  background:linear-gradient(176deg,#46536A 0%,#0C1222 26%,#5D6A80 46%,#0C1222 54%,#3A4557 76%,#0C1222 100%);
  -webkit-background-clip:text; background-clip:text; color:transparent;
}

/* ---------- nav ---------- */
.nav{
  position:sticky; top:0; z-index:50; background:rgba(247,249,252,.88);
  backdrop-filter:blur(12px); border-bottom:1px solid var(--line);
}
.nav-inner{ max-width:var(--wrap); margin:0 auto; padding:0 20px; height:62px;
  display:flex; align-items:center; justify-content:space-between; gap:16px; }
.nav-links{ display:flex; align-items:center; gap:18px; }
.nav-links a{
  display:inline-block;
  font-family:'JetBrains Mono',ui-monospace,monospace; font-size:11px;
  letter-spacing:.12em; text-transform:uppercase; color:var(--muted);
  text-decoration:none; transition:color .2s ease, transform .3s var(--ease);
}
.nav-links a:hover{ color:var(--ink); transform:translateY(-1px) }
.nav-links a:active{ transform:translateY(0) scale(.97) }
.nav-links a:focus-visible{ outline:2px solid var(--c2); outline-offset:3px; border-radius:4px }
/* a ramp seam under the sticky bar */
.lp .nav:after{
  content:""; position:absolute; left:0; right:0; bottom:-1px; height:1px; pointer-events:none;
  background:linear-gradient(90deg,
    transparent, rgba(255,61,138,.5) 20%, rgba(124,58,237,.55) 52%, rgba(33,212,253,.5) 84%, transparent);
}
@media (max-width:620px){ .nav-links .hide-sm{ display:none } }

/* ---------- buttons ---------- */
.btn{
  display:inline-block; border-radius:999px; padding:14px 26px; font-weight:500;
  text-decoration:none; font-size:16px; border:0; cursor:pointer;
  transition:transform .3s var(--ease), box-shadow .3s var(--ease), filter .2s ease;
}
.btn-primary{
  background:linear-gradient(135deg,var(--c1),var(--c2) 52%,var(--c3)); color:#fff;
  box-shadow:0 1px 2px rgba(12,18,34,.2), 0 12px 28px -12px rgba(124,58,237,.55);
}
.btn-primary:hover{ transform:translateY(-2px); filter:saturate(1.12) brightness(1.05); }
.btn-primary:active{ transform:translateY(0) scale(.99); filter:none; }
.btn-ghost{ border:1px solid var(--line); background:rgba(255,255,255,.7); color:var(--muted); }
.btn-ghost:hover{ transform:translateY(-2px); border-color:var(--ink); color:var(--ink); }
.btn-ghost:active{ transform:translateY(0) scale(.99); }
.btn:focus-visible{ outline:2px solid var(--c2); outline-offset:3px; }
.btn-row{ display:flex; flex-wrap:wrap; gap:12px; align-items:center; margin-top:26px; }

/* ---------- background layers ----------
   Two clipping rules matter throughout. `.has-fx` clips, and each layer clips
   again, so anything drifting past the right edge can never widen the document
   at 390px. */
.has-fx{ position:relative; overflow:hidden; }
/* .fx-layer is the opt-out for per-page hero grounds (the Dublin map, the
   trades ground, and whatever comes next). Without it this rule forces
   position:relative on them and their inset:0 collapses to zero height. */
.has-fx > :not(.motes):not(.orbs):not(.streaks):not(.fx-layer){ position:relative; z-index:1; }

/* ---------- floating motes ----------
   Small points of brand colour on their own slow paths — dust catching light,
   not a gradient wash. 5–13px, soft halo, low opacity. Transform and opacity
   are the only animated properties, and the layer composites on its own. */
.motes{ position:absolute; inset:0; z-index:0; overflow:hidden; pointer-events:none; }
.motes > i{
  position:absolute; display:block;
  width:var(--s,8px); height:var(--s,8px); border-radius:50%;
  background:var(--col,#7C3AED);
  box-shadow:0 0 calc(var(--s,8px) * 1.8) calc(var(--s,8px) * .22) var(--col,#7C3AED);
  opacity:var(--o,.5); will-change:transform,opacity;
  animation:
    moteDrift var(--dur,28s) var(--ease) var(--delay,0s) infinite alternate,
    moteGlow  var(--gdur,7s) ease-in-out var(--delay,0s) infinite alternate;
}
@keyframes moteDrift{
  from{ transform:translate3d(0,0,0); }
  to{ transform:translate3d(var(--dx,20px), var(--dy,-34px), 0); }
}
@keyframes moteGlow{
  from{ opacity:calc(var(--o,.5) * var(--om,1) * .4); }
  to{ opacity:calc(var(--o,.5) * var(--om,1)); }
}

/* Placement is a contrast decision, not a decorative one. A 9px dot of pink at
   .5 alpha sitting under 15.5px --muted copy drops it to about 3.5:1, so no
   mote is ever put in the copy column: the default field lives in the right
   third, alongside the streaks, where the 56ch measure never reaches. */
.motes > i:nth-child(1) { left:64%; top:24%; --s:9px;  --col:var(--c1); --o:.5;  --dx:28px;  --dy:-32px; --dur:27s; --gdur:6s; }
.motes > i:nth-child(2) { left:88%; top:52%; --s:7px;  --col:var(--c3); --o:.62; --dx:-34px; --dy:26px;  --dur:31s; --gdur:8s;  --delay:-3s; }
.motes > i:nth-child(3) { left:74%; top:80%; --s:6px;  --col:var(--c2); --o:.45; --dx:22px;  --dy:-26px; --dur:24s; --gdur:5.5s; --delay:-7s; }
.motes > i:nth-child(4) { left:95%; top:14%; --s:12px; --col:var(--c2); --o:.4;  --dx:-24px; --dy:34px;  --dur:34s; --gdur:9s;  --delay:-1s; }
.motes > i:nth-child(5) { left:66%; top:62%; --s:7px;  --col:var(--c3); --o:.55; --dx:32px;  --dy:-20px; --dur:29s; --gdur:6.5s; --delay:-5s; }
.motes > i:nth-child(6) { left:83%; top:8%;  --s:5px;  --col:var(--c1); --o:.6;  --dx:-20px; --dy:30px;  --dur:22s; --gdur:4.5s; --delay:-2s; }
.motes > i:nth-child(7) { left:94%; top:88%; --s:10px; --col:var(--c1); --o:.36; --dx:-30px; --dy:-24px; --dur:36s; --gdur:10s; --delay:-8s; }
.motes > i:nth-child(8) { left:70%; top:40%; --s:6px;  --col:var(--c2); --o:.5;  --dx:26px;  --dy:22px;  --dur:26s; --gdur:7s;  --delay:-4s; }
.motes > i:nth-child(9) { left:97%; top:36%; --s:5px;  --col:var(--c3); --o:.5;  --dx:-18px; --dy:-28px; --dur:30s; --gdur:5s;  --delay:-6s; }
.motes > i:nth-child(10){ left:79%; top:68%; --s:8px;  --col:var(--c3); --o:.45; --dx:-26px; --dy:-30px; --dur:33s; --gdur:8.5s; --delay:-9s; }
.motes > i:nth-child(11){ left:96%; top:64%; --s:6px;  --col:var(--c2); --o:.42; --dx:24px;  --dy:34px;  --dur:28s; --gdur:6s;  --delay:-3.5s; }
.motes > i:nth-child(12){ left:61%; top:12%; --s:5px;  --col:var(--c1); --o:.46; --dx:-22px; --dy:26px;  --dur:25s; --gdur:5.5s; --delay:-10s; }

/* Sections whose content is one full-width opaque block (a price band, the CTA)
   have no right-hand clearing, so the field moves into the gutters and the
   padding strips above and below the block. */
.motes-edge > i:nth-child(1){ left:2%;  top:18%; }
.motes-edge > i:nth-child(2){ left:97%; top:30%; }
.motes-edge > i:nth-child(3){ left:4%;  top:72%; }
.motes-edge > i:nth-child(4){ left:95%; top:82%; }
.motes-edge > i:nth-child(5){ left:44%; top:3%;  }
.motes-edge > i:nth-child(6){ left:68%; top:96%; }
.motes-edge > i:nth-child(7){ left:1%;  top:46%; }
.motes-edge > i:nth-child(8){ left:98%; top:60%; }
.motes-edge > i:nth-child(9){ left:22%; top:97%; }

/* On a phone the copy runs the full width and there is no right-hand third to
   hide in, so only the motes hugging the 20px gutter survive. --om is a
   multiplier, so the per-mote --o values still do their work underneath it. */
@media (max-width:700px){
  .motes{ --om:.8; }
  .motes > i{ display:none; }
  .motes > i:nth-child(4),
  .motes > i:nth-child(7),
  .motes > i:nth-child(9),
  .motes > i:nth-child(11){ display:block; }
  .motes-edge > i{ display:none; }
  .motes-edge > i:nth-child(2),
  .motes-edge > i:nth-child(4),
  .motes-edge > i:nth-child(5),
  .motes-edge > i:nth-child(6),
  .motes-edge > i:nth-child(7),
  .motes-edge > i:nth-child(9){ display:block; }
}

/* ---------- warp streaks ----------
   The homepage's signature background, cut down (see /assets/streaks.js).
   The mask keeps the field around its vanishing point and fades it out before
   it reaches the copy column, so the colour can run at an alpha that actually
   reads without touching body-text contrast. */
.streaks{
  position:absolute; inset:0; z-index:0; width:100%; height:100%; pointer-events:none;
  -webkit-mask-image:radial-gradient(78% 40% at 99% 1%, #000 0%, #000 42%, rgba(0,0,0,.5) 66%, rgba(0,0,0,0) 86%);
          mask-image:radial-gradient(78% 40% at 99% 1%, #000 0%, #000 42%, rgba(0,0,0,.5) 66%, rgba(0,0,0,0) 86%);
}
@media (min-width:900px){
  .streaks{
    /* 26% of the width puts the outer edge of the field at roughly x=780 on a
       1440 viewport — clear of the 56ch copy column, which is what stops a
       saturated streak running through the lede. */
    -webkit-mask-image:radial-gradient(26% 132% at 80% 44%, #000 0%, #000 40%, rgba(0,0,0,.45) 72%, rgba(0,0,0,0) 100%);
            mask-image:radial-gradient(26% 132% at 80% 44%, #000 0%, #000 40%, rgba(0,0,0,.45) 72%, rgba(0,0,0,0) 100%);
  }
}

/* ---------- soft wash ----------
   Kept for one job only: bleeding colour out from under the dark CTA block.
   Restrained on purpose — the pages are white and chrome, not tie-dye. */
.orbs{ position:absolute; inset:0; z-index:0; overflow:hidden; pointer-events:none; }
.orbs > i{
  position:absolute; display:block; border-radius:50%;
  background:radial-gradient(circle at 42% 38%, var(--tint,rgba(124,58,237,.16)), transparent 70%);
  filter:blur(var(--blur,64px)); will-change:transform;
  animation:orbDrift var(--dur,20s) var(--ease) infinite alternate;
}
@keyframes orbDrift{
  from{ transform:translate3d(0,0,0) scale(1); }
  to{ transform:translate3d(var(--dx,30px), var(--dy,-40px), 0) scale(var(--ds,1.1)); }
}
.orbs-cta > i:nth-child(1){ width:26rem; height:26rem; bottom:-15rem; left:4%;
  --tint:rgba(124,58,237,.2); --dx:34px; --dy:-26px; --dur:20s; }
.orbs-cta > i:nth-child(2){ width:20rem; height:20rem; top:-12rem; right:2%;
  --tint:rgba(33,212,253,.16); --dx:-30px; --dy:30px; --ds:1.12; --dur:24s; }

/* ---------- sections ---------- */
section{ padding:56px 0; }
section.tight{ padding:36px 0; }
.hero{ padding:64px 0 44px; }
.rule{ border:0; border-top:1px solid var(--line); margin:0; }

/* An alternating surface so the page is not one flat grey top to bottom.
   Cooler and a shade deeper than the ice, not lighter — white cards have to
   keep popping off it. The ramp tint is a few percent, a wash not a slab. */
/* On a white page an alternating section can no longer be "the grey one". The
   separation now comes from the hairline rules and the faintest colour wash —
   enough to feel a change of chapter, not enough to read as a grey band. */
.sec-alt{
  background:
    linear-gradient(180deg, rgba(124,58,237,.035), rgba(33,212,253,.025) 58%, rgba(255,61,138,.02)),
    var(--alt);
  border-top:1px solid var(--line);
  border-bottom:1px solid var(--line);
}
.sec-alt + .sec-alt{ border-top:0; }

/* ramp hairline for section boundaries — the colour is a seam, not a slab */
.rule-ramp{
  border:0; height:1px; margin:0;
  background:linear-gradient(90deg,
    transparent, rgba(255,61,138,.55) 18%, rgba(124,58,237,.6) 50%, rgba(33,212,253,.55) 82%, transparent);
}

/* ---------- cards ---------- */
.grid{ display:grid; gap:14px; }
@media (min-width:640px){ .g2{ grid-template-columns:repeat(2,1fr) } }
@media (min-width:900px){ .g3{ grid-template-columns:repeat(3,1fr) } .g4{ grid-template-columns:repeat(4,1fr) } }
.card{
  position:relative; overflow:hidden;
  background:var(--surface); border:1px solid var(--line); border-radius:13px; padding:20px;
  box-shadow:0 1px 2px rgba(12,18,34,.04), 0 12px 24px -20px rgba(12,18,34,.22);
  transition:transform .35s var(--ease), border-color .25s ease, box-shadow .35s var(--ease);
}
/* the ramp is a wipe along the top edge, revealed on hover — scaleX only */
.card::before{
  content:""; position:absolute; left:0; right:0; top:0; height:2px; background:var(--ramp);
  transform:scaleX(0); transform-origin:left;
  transition:transform .45s var(--ease);
}
a.card{ text-decoration:none; display:block; }
/* every card lifts, not just the ones that happen to be links */
.card:hover, .card:focus-within{
  transform:translateY(-3px);
  border-color:rgba(124,58,237,.34);
  box-shadow:
    0 1px 2px rgba(12,18,34,.05),
    0 10px 20px -14px rgba(255,61,138,.26),
    0 24px 42px -26px rgba(124,58,237,.45);
}
.card:hover::before, .card:focus-within::before{ transform:scaleX(1); }
a.card:active{ transform:translateY(-1px) scale(.994); }
a.card:focus-visible{ outline:2px solid var(--c2); outline-offset:3px; }
.card p{ margin:0; color:var(--muted); font-size:14.5px; line-height:1.6; }
.card h3{ margin-bottom:.3rem; font-size:1.02rem; }

/* price line inside a card */
.price{ font-family:'JetBrains Mono',ui-monospace,monospace; font-size:13px; color:var(--ink); }

/* ---------- price band ---------- */
.band{
  position:relative; overflow:hidden;
  background:var(--surface); border:1px solid var(--line); border-radius:16px; padding:26px;
  box-shadow:0 1px 2px rgba(12,18,34,.04), 0 24px 50px -34px rgba(124,58,237,.35);
  transition:transform .4s var(--ease), border-color .25s ease, box-shadow .4s var(--ease);
}
/* ramp edge sits at a third by default and runs the full width on hover */
.band::before{
  content:""; position:absolute; left:0; right:0; top:0; height:3px; background:var(--ramp);
  transform:scaleX(.32); transform-origin:left;
  transition:transform .55s var(--ease);
}
.band:hover, .band:focus-within{
  transform:translateY(-3px);
  border-color:rgba(124,58,237,.3);
  box-shadow:
    0 1px 2px rgba(12,18,34,.05),
    0 14px 26px -18px rgba(255,61,138,.24),
    0 34px 60px -36px rgba(124,58,237,.5);
}
.band:hover::before, .band:focus-within::before{ transform:scaleX(1); }
.band .figure{ font-family:'Chakra Petch',sans-serif; font-style:italic; font-weight:700;
  font-size:3rem; line-height:1; }

/* ---------- list ---------- */
.ticks{ list-style:none; margin:0; padding:0; }
.ticks li{
  position:relative; padding:0 0 11px 27px; color:var(--muted); font-size:15.5px; line-height:1.6;
  transition:transform .3s var(--ease);
}
.ticks li:before{
  content:""; position:absolute; left:0; top:.55em; width:13px; height:8px;
  border-left:2px solid var(--c2); border-bottom:2px solid var(--c2);
  transform:rotate(-45deg);
  transition:transform .3s var(--ease);
}
/* the ramp walks down the list rather than painting every tick one colour */
.ticks li:nth-child(3n+1):before{ border-color:var(--c1); }
.ticks li:nth-child(3n+3):before{ border-color:var(--c3); }
.ticks li:hover{ transform:translateX(3px); color:var(--ink); }
.ticks li:hover:before{ transform:rotate(-45deg) scale(1.2); }
.ticks strong{ color:var(--ink); font-weight:600; }

/* ---------- FAQ ---------- */
.faq{ border-bottom:1px solid var(--line); }
.faq summary{
  list-style:none; cursor:pointer; padding:17px 40px 17px 0; position:relative;
  font-weight:600; font-size:16.5px;
  transition:transform .3s var(--ease);
}
.faq summary::-webkit-details-marker{ display:none }
/* tint sits on a pseudo element so the hover is an opacity fade, not a
   background-color transition */
.faq summary::before{
  content:""; position:absolute; inset:-2px -12px; z-index:-1; border-radius:10px;
  background:linear-gradient(90deg, rgba(255,61,138,.08), rgba(124,58,237,.07) 55%, rgba(33,212,253,.06));
  opacity:0; transition:opacity .3s var(--ease);
}
.faq summary:hover{ color:var(--c2); transform:translateX(3px) }
.faq summary:hover::before, .faq summary:focus-visible::before{ opacity:1 }
.faq summary:active{ transform:translateX(3px) scale(.995) }
.faq summary:focus-visible{ outline:2px solid var(--c2); outline-offset:3px; border-radius:6px }
.faq[open] summary{ color:var(--ink) }
.faq summary:after{
  content:""; position:absolute; right:6px; top:50%; width:10px; height:10px;
  border-right:2px solid var(--muted); border-bottom:2px solid var(--muted);
  transform:translateY(-70%) rotate(45deg); transition:transform .28s var(--ease);
}
.faq[open] summary:after{ transform:translateY(-30%) rotate(-135deg) }
.faq-body{ padding:0 8px 18px 0; color:var(--muted); font-size:15.5px; }
.faq-body strong{ color:var(--ink); font-weight:600 }

/* ---------- CTA block ---------- */
.cta{
  background:var(--ink); color:#fff; border-radius:18px; padding:54px 26px 50px; text-align:center;
  position:relative; overflow:hidden;
  box-shadow:
    0 2px 4px rgba(12,18,34,.2),
    0 26px 50px -40px rgba(255,61,138,.5),
    0 44px 84px -52px rgba(124,58,237,.75);
}
/* ramp edge along the top of the block */
.cta:after{
  content:""; position:absolute; left:0; right:0; top:0; height:3px; background:var(--ramp);
}
.cta:before{
  content:""; position:absolute; inset:0; pointer-events:none;
  background:
    radial-gradient(30rem 18rem at 50% 118%, rgba(124,58,237,.5), transparent 64%),
    radial-gradient(20rem 14rem at 88% -12%, rgba(33,212,253,.28), transparent 60%),
    radial-gradient(18rem 12rem at 6% 8%, rgba(255,61,138,.3), transparent 60%);
}
.cta > *{ position:relative }
.cta h2{ font-style:italic; margin-bottom:.5rem }
.cta p{ color:rgba(255,255,255,.72); max-width:46ch; margin:0 auto 22px }

/* ---------- footer ---------- */
.foot{ border-top:1px solid var(--line); padding:26px 0 40px; }
.foot-inner{ display:flex; flex-wrap:wrap; gap:14px; align-items:center; justify-content:space-between;
  font-size:14px; color:var(--muted); }
.foot a{ color:var(--muted); text-decoration:none; display:inline-block;
  transition:transform .3s var(--ease), color .2s ease }

/* ---------- footer CTA ----------
   "Build a quote" is the last thing on every page, so it gets the // cast —
   the same recipe as the logo. Two stacked backgrounds clipped to the text:
   the ink underneath so it is always readable, and a // shaped gradient
   sweeping across on top. The strokes do not move; the gradient does. */
.foot-links a.foot-cta{
  /* Same weight as its neighbours — at 14px, 600 against 400 reads as a
     different typeface rather than emphasis. The // sweep is the distinction. */
  font-weight:inherit;
  background-image:
    linear-gradient(103deg,
      transparent 0 41%,
      #FF3D8A 42.6%, #7C3AED 45.4%,
      transparent 46.6% 48.4%,
      #7C3AED 49.6%, #21D4FD 52.4%,
      transparent 53.6% 100%),
    linear-gradient(var(--ink), var(--ink));
  background-size:320% 100%, 100% 100%;
  background-repeat:no-repeat;
  -webkit-background-clip:text; background-clip:text;
  color:transparent;
  animation:footRun 4.5s linear infinite;
}
@keyframes footRun{
  from{ background-position:215% 0, 0 0 }
  to  { background-position:-115% 0, 0 0 }
}
.foot-links a.foot-cta:hover{ animation-duration:1.6s }
@media (prefers-reduced-motion: reduce){
  .foot-links a.foot-cta{ animation:none; background-position:50% 0, 0 0 }
}

/* ---------- nav CTA ----------
   "Build your quote" is the conversion action on every page, so it should not
   look identical to a section anchor sitting beside it. */
/* Copied verbatim from the homepage .btn-primary — same 135deg ramp, same two
   easings, same two-layer shadow, same hover and active. It is the button that
   works, so it should not be reinvented per page. */
.nav-links a.nav-cta{
  display:inline-flex; align-items:center;
  padding:9px 18px; border-radius:9999px;
  background:linear-gradient(135deg,#FF3D8A,#7C3AED 52%,#21D4FD); color:#fff;
  /* .nav-links a sets JetBrains Mono uppercase for the text links. Inheriting
     it here put bold monospace inside a gradient pill, which looked wrong. The
     button takes the body face, exactly like the homepage one. */
  font-family:'Switzer',system-ui,-apple-system,sans-serif;
  font-size:14px; font-weight:600; letter-spacing:normal; text-transform:none;
  white-space:nowrap;
  box-shadow:0 1px 2px rgba(12,18,34,.2), 0 12px 28px -12px rgba(124,58,237,.55);
  transition:transform .35s cubic-bezier(.3,1,.4,1),
             box-shadow .35s cubic-bezier(.16,1,.3,1),
             filter .25s ease;
}
.nav-links a.nav-cta:hover{
  transform:translateY(-2px); filter:saturate(1.15) brightness(1.06);
  box-shadow:0 2px 4px rgba(124,58,237,.3), 0 18px 40px -12px rgba(255,61,138,.5);
}
.nav-links a.nav-cta:active{ transform:translateY(0) scale(.985); filter:none }
.nav-links a.nav-cta:focus-visible{ outline:2px solid #7C3AED; outline-offset:3px }
@media (max-width:520px){ .nav-links a.nav-cta{ padding:8px 14px; font-size:13px } }

/* ---------- header wordmark shimmer ----------
   The white PNG logo can't shimmer alone, so a masked overlay carries a brand
   ramp band that sweeps left -> right across the logo, resting off-screen
   between passes. Only background-position animates. */
.logo-shine{ position:relative; display:inline-flex; line-height:0; }
.logo-shine img{ height:24px; width:auto; display:block; }
.logo-shine__gleam{
  position:absolute; inset:0; pointer-events:none;
  -webkit-mask:url(/assets/litemode-wordmark-white.png) center/contain no-repeat;
          mask:url(/assets/litemode-wordmark-white.png) center/contain no-repeat;
  background-image:linear-gradient(105deg,
    transparent 44%, #FF3D8A 47%, #7C3AED 50%, #21D4FD 53%, transparent 56%);
  background-repeat:no-repeat; background-size:300% 100%;
  background-position:100% 0; opacity:1;
  animation:logoShine 4s ease-in-out infinite;
}
@keyframes logoShine{ 0%,18%{ background-position:100% 0 } 58%,100%{ background-position:0% 0 } }
@media (prefers-reduced-motion: reduce){ .logo-shine__gleam{ animation:none; opacity:0 } }

/* ---------- nav dropdown ----------
   Kept in the DOM and hidden with opacity/visibility rather than display, so
   the panel can transition and its links stay crawlable. */
.nav-drop{ position:relative }
/* Matches the sibling text links exactly — same mono face, size, tracking and
   case — so the nav reads as one row rather than a sans item dropped among
   monospace ones. */
.nav-drop > button{
  display:inline-flex; align-items:center; gap:.4rem;
  padding:0; border:0; background:none; cursor:pointer;
  font-family:'JetBrains Mono',ui-monospace,monospace; font-size:11px;
  letter-spacing:.12em; text-transform:uppercase; color:var(--muted);
  transition:color .2s ease, transform .3s var(--ease);
}
.nav-drop > button:hover,
.nav-drop[data-open="true"] > button{ color:var(--ink); transform:translateY(-1px) }
.nav-drop > button:active{ transform:translateY(0) scale(.97) }
.nav-drop > button:focus-visible{ outline:2px solid var(--c2); outline-offset:3px; border-radius:4px }
.nav-drop > button svg{ transition:transform .22s var(--ease) }
.nav-drop[data-open="true"] > button svg{ transform:rotate(180deg) }

.nav-panel{
  position:absolute; top:calc(100% + .7rem); left:50%;
  width:17rem; padding:.4rem; z-index:60;
  border:1px solid var(--line); border-radius:1rem;
  background:rgba(255,255,255,.9); backdrop-filter:blur(14px);
  box-shadow:0 1px 2px rgba(12,18,34,.05),
             0 18px 34px -18px rgba(124,58,237,.34),
             0 12px 26px -20px rgba(33,212,253,.30);
  opacity:0; visibility:hidden;
  transform:translate(-50%,-.35rem) scale(.98);
  transition:opacity .2s var(--ease),
             transform .24s cubic-bezier(.16,1.1,.3,1),
             visibility 0s linear .24s;
}
.nav-drop[data-open="true"] .nav-panel{
  opacity:1; visibility:visible; transform:translate(-50%,0) scale(1);
  transition-delay:0s,0s,0s;
}
/* The landing-page nav sets mono + uppercase + letter-spacing on its links.
   That is right for three nav items and wrong for a panel of sentences, so the
   panel resets to the body face explicitly rather than inheriting. */
.nav-panel a{
  position:relative; display:block; padding:.5rem .7rem .5rem .78rem;
  border-radius:.6rem; overflow:hidden; text-decoration:none;
  font-family:inherit; font-size:.8125rem; font-weight:400;
  line-height:1.4; letter-spacing:normal; text-transform:none;
  color:var(--muted);
  transition:color .16s var(--ease), transform .16s var(--ease);
}
.nav-panel a span{ display:block; font-size:.75rem; letter-spacing:normal; text-transform:none }
/* Gradient hover: a ramp rail slides in from the left and the title picks up
   the ramp. Only transform and opacity animate — the rail is pre-painted. */
.nav-panel a::before{
  content:''; position:absolute; left:0; top:6px; bottom:6px; width:2px;
  border-radius:99px; background:var(--ramp);
  opacity:0; transform:scaleY(.4); transform-origin:center;
  transition:opacity .18s var(--ease), transform .22s cubic-bezier(.16,1.1,.3,1);
}
.nav-panel a::after{
  content:''; position:absolute; inset:0; border-radius:.6rem;
  background:linear-gradient(90deg, rgba(255,61,138,.09), rgba(124,58,237,.07) 55%, rgba(33,212,253,.06));
  opacity:0; transition:opacity .18s var(--ease);
}
.nav-panel a:hover, .nav-panel a:focus-visible{ color:var(--ink); transform:translateX(2px) }
.nav-panel a:hover::before, .nav-panel a:focus-visible::before{ opacity:1; transform:scaleY(1) }
.nav-panel a:hover::after,  .nav-panel a:focus-visible::after{ opacity:1 }
.nav-panel a:hover b, .nav-panel a:focus-visible b{
  background:var(--ramp); -webkit-background-clip:text; background-clip:text; color:transparent;
}
.nav-panel a:focus-visible{ outline:2px solid var(--c2); outline-offset:-2px }
.nav-panel a:active{ transform:translateX(1px) }
.nav-panel a b{
  position:relative; z-index:1; display:block; margin-bottom:1px;
  font-family:inherit; font-size:.8125rem; font-weight:600;
  letter-spacing:normal; text-transform:none; color:var(--ink);
}
.nav-panel a span{ position:relative; z-index:1; color:var(--muted) }
.nav-panel .np-label{
  padding:.55rem .7rem .3rem; margin:0;
  font-family:'JetBrains Mono',ui-monospace,monospace;
  font-size:.5625rem; letter-spacing:.18em; text-transform:uppercase; color:#8A93A6;
}
.nav-panel hr{ margin:.35rem .7rem; border:0; border-top:1px solid rgba(12,18,34,.07) }

/* ---------- mobile navigation ----------
   Under 760px the dropdown used to be hidden outright, which left every page
   with a logo and one button and no way to reach anything else. Instead the
   trigger becomes a burger and the panel becomes a full-width sheet, so the
   same markup serves both. */
@media (max-width:760px){
  .nav-drop > button{ gap:0; padding:6px; width:36px; height:36px; justify-content:center }
  .nav-drop > button svg{ display:none }               /* chevron off */
  /* label replaced by three rules drawn from the button's own box */
  .nav-drop > button{ font-size:0; position:relative }
  .nav-drop > button::before,
  .nav-drop > button::after,
  .nav-drop > button > span.bar{
    content:''; position:absolute; left:8px; right:8px; height:2px; border-radius:2px;
    background:currentColor;
    transition:transform .24s cubic-bezier(.16,1.1,.3,1), opacity .18s var(--ease);
  }
  .nav-drop > button::before{ top:11px }
  .nav-drop > button > span.bar{ top:17px }
  .nav-drop > button::after{ top:23px }
  .nav-drop[data-open="true"] > button::before{ transform:translateY(6px) rotate(45deg) }
  .nav-drop[data-open="true"] > button > span.bar{ opacity:0 }
  .nav-drop[data-open="true"] > button::after{ transform:translateY(-6px) rotate(-45deg) }

  .nav-panel{
    position:fixed; left:12px; right:12px; top:64px; width:auto;
    max-height:calc(100vh - 84px); overflow-y:auto;
    transform:translate(0,-.4rem) scale(1);
    padding:.5rem;
    /* Opaque here. The translucent desktop panel is small and elegant; at full
       sheet width the page bleeding through it is just noise. */
    background:#fff;
    box-shadow:0 1px 2px rgba(12,18,34,.06),
               0 24px 48px -20px rgba(12,18,34,.28);
  }
  .nav-drop[data-open="true"] .nav-panel{ transform:translate(0,0) scale(1) }
  .nav-panel a{ padding:.7rem .8rem }
  .nav-panel a b{ font-size:.875rem }
}
@media (prefers-reduced-motion: reduce){
  .nav-panel, .nav-drop > button svg, .nav-panel a,
  .nav-panel a::before, .nav-panel a::after{ transition-duration:.01ms !important }
}

/* ---------- touch targets ----------
   Nav, breadcrumb and footer links sit at 14–15px, so their boxes come out
   around 19–24px tall — well under the ~44px a thumb needs. Padding would
   reflow all three rows, so the hit area is extended with a pseudo-element
   instead: nothing moves, the tappable box grows. */
@media (max-width: 860px){
  /* .crumb and .crumbs both exist across the landing pages — cover both. */
  .nav-links a, .foot a, .crumbs a, .crumb a{ position:relative }
  .nav-links a::after, .foot a::after, .crumbs a::after, .crumb a::after{
    content:''; position:absolute; left:-6px; right:-6px;
    top:50%; height:44px; transform:translateY(-50%);
  }
  /* Neighbouring links would otherwise overlap each other's grown hit boxes. */
  .nav-links{ gap:18px }
  .foot-links{ gap:16px 18px }
  /* The crumb row sits directly under the header, so its 44px band was being
     occluded from above. Give it clearance rather than shrinking the band. */
  .crumbs, .crumb{ line-height:2; margin-top:10px; margin-bottom:6px }
}
.foot a:hover{ color:var(--ink); transform:translateY(-1px) }
.foot a:active{ transform:translateY(0) scale(.97) }
.foot a:focus-visible{ outline:2px solid var(--c2); outline-offset:3px; border-radius:4px }
.foot-links{ display:flex; flex-wrap:wrap; gap:16px }

/* ---------- breadcrumb ---------- */
.crumb{ font-size:13px; color:var(--muted); padding-top:18px }
.crumb a{ text-decoration:none; display:inline-block; transition:transform .3s var(--ease), color .2s ease }
.crumb a:hover{ color:var(--c2); transform:translateY(-1px) }
.crumb a:active{ transform:translateY(0) scale(.97) }
.crumb a:focus-visible{ outline:2px solid var(--c2); outline-offset:3px; border-radius:4px }

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{ animation-duration:.01ms !important; transition-duration:.01ms !important }
  html{ scroll-behavior:auto }
  /* Shimmer settles on the one frame of the loop whose slice of the tile
     reproduces the original static lockup — a solid pink first stroke and a
     purple-into-cyan second stroke. Killed outright rather than crushed to
     .01ms, because an infinite loop at .01ms would thrash. */
  .lm-slash::before{ animation:none !important; transform:translateX(-.82em); }

  /* Motes and washes settle into the end frame of their drift rather than
     running an infinite loop at .01ms, which would thrash the compositor.
     The streak field paints one static frame and stops (see streaks.js). */
  .orbs > i{
    animation:none !important;
    transform:translate3d(var(--dx,30px), var(--dy,-40px), 0) scale(var(--ds,1.1));
  }
  .motes > i{
    animation:none !important;
    transform:translate3d(var(--dx,20px), var(--dy,-34px), 0);
    opacity:var(--o,.5);
  }
}
