/* ZephyrAB — one stylesheet for the marketing site.
 *
 * WHY THIS FILE EXISTS
 * The palette used to be copy-pasted into 13 pages. Changing an accent meant
 * 13 edits, so in practice it never changed and the pages slowly diverged —
 * the same failure the navigation had. One file, one set of tokens.
 *
 * It is same-origin, not a CDN. The marketing pages deliberately load nothing
 * from a third party: no font service, no icon kit, no script host. That is a
 * privacy property (no visitor is announced to anyone else) and an
 * availability one, and it is why the type below is a system stack rather than
 * a webfont.
 *
 * ORDER: tokens, reset, type, layout, components, navigation, footer, motion.
 */

/* ---------------------------------------------------------------- tokens */
:root{
  /* Ground. Deeper and less blue than the old navy, so product screenshots
     sit ON the page and lift away from it rather than blending in. */
  --bg:        #07080e;
  --bg-2:      #0b0d15;
  --surface:   #0f1119;
  --surface-2: #141724;
  --line:      rgba(255,255,255,.075);
  --line-2:    rgba(255,255,255,.14);

  /* Ink. Four steps, no more — every extra grey is a decision somebody has to
     make again later.
     The three that carry TEXT are measured against the DARKEST thing they can
     sit on. --faint was #6b7590 and came out at 4.35:1, which looks fine and
     fails AA; the browser contrast gate is what said so. Whenever one of these
     moves, re-run `node deploy/gate/site.js` rather than eyeballing it. */
  --ink:   #e9edf7;   /* 16.4:1 on --bg */
  --muted: #98a2b8;   /*  7.8:1 */
  --faint: #7b86a3;   /*  5.5:1 on --bg, 5.2:1 on --surface */
  /* NOT A TEXT COLOUR. Too dark to meet AA anywhere, deliberately — it is for
     rules, inactive markers and the decorative address in a screenshot frame.
     Using it for a label is what made the footer headings 2.67:1. */
  --dim:   #4b5470;

  /* Accent. TWO, not three. The old teal/violet/pink ran all three at equal
     weight, which is why nothing on the page felt primary. Violet leads,
     cyan supports and carries data, and the third hue is retired. */
  --v:   #7c6cff;
  --v-2: #9b8dff;
  --c:   #22d3ee;
  --c-2: #67e8f9;
  --ok:  #34d399;
  --warn:#fbbf24;
  --bad: #fb7185;

  /* The gradient is a BRAND MARK, not a decoration. It belongs on the
     wordmark and the single primary action, and nowhere else — a page where
     everything is gradient has no emphasis at all. */
  --grad: linear-gradient(115deg, var(--c) 0%, var(--v) 55%, #b06cff 100%);
  --grad-soft: linear-gradient(115deg, rgba(34,211,238,.14), rgba(124,108,255,.14));

  --maxw: 1180px;
  --maxw-prose: 760px;
  --r: 14px;
  --r-lg: 22px;

  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;

  --shadow: 0 24px 60px -22px rgba(0,0,0,.85);
  --shadow-lg: 0 40px 90px -30px rgba(0,0,0,.95);

  /* --- names the older pages already use -------------------------------
   * pricing, download, releases and compare were each written with their own
   * copy of the palette. Aliasing the old names here lets their page CSS keep
   * working unchanged while the VALUES come from one place — which is the
   * whole point of the move. Prefer the names above in anything new; these
   * exist to be deleted once nothing references them. */
  --bg2:       var(--bg-2);
  --panel:     var(--surface);
  --panel-brd: var(--line);
  --a1:        var(--c);      /* was teal   */
  --a2:        var(--v);      /* was violet */
  --a3:        var(--v-2);    /* was pink — retired; folds onto violet */
  --amber:     var(--warn);
}

/* ----------------------------------------------------------------- reset */
*{ box-sizing:border-box }
html{ scroll-behavior:smooth }
@media (prefers-reduced-motion: reduce){ html{ scroll-behavior:auto } }
body{
  margin:0; background:var(--bg); color:var(--ink);
  font-family:var(--font); line-height:1.65;
  -webkit-font-smoothing:antialiased; -moz-osx-font-smoothing:grayscale;
  overflow-x:hidden;
}
img{ max-width:100%; height:auto; display:block }
a{ color:var(--c-2); text-decoration:none }
a:hover{ text-decoration:underline }
/* A link INSIDE running text must be told apart from the text by something
   other than its colour (WCAG 1.4.1) — axe reports this as
   `link-in-text-block`, and it is a real problem for anyone who cannot see the
   difference between grey and cyan. Links that stand alone (nav, footer,
   buttons, cards) are identifiable by position and are left clean. */
p a, li a, td a, dd a, blockquote a{ text-decoration:underline; text-underline-offset:2px }
:focus-visible{ outline:2px solid var(--c); outline-offset:3px; border-radius:6px }

/* ------------------------------------------------------------------ type */
/* Fluid, so a headline is confident on a laptop without overflowing a phone.
   Tracking tightens as size grows — large text set at body tracking reads
   loose and amateurish. */
h1,h2,h3,h4{ margin:0 0 .4em; font-weight:750; letter-spacing:-.02em; line-height:1.12 }
h1{ font-size:clamp(2.4rem, 1.4rem + 3.6vw, 4.3rem); letter-spacing:-.035em; font-weight:800 }
h2{ font-size:clamp(1.7rem, 1.2rem + 1.7vw, 2.6rem); letter-spacing:-.028em }
h3{ font-size:clamp(1.1rem, 1rem + .4vw, 1.35rem); letter-spacing:-.015em }
p{ margin:0 0 1em }

.lead{ color:var(--muted); font-size:clamp(1.02rem, .97rem + .35vw, 1.2rem); max-width:62ch }
.muted{ color:var(--muted) }
.faint{ color:var(--faint); font-size:.88rem }
.mono{ font-family:var(--mono) }

/* The eyebrow. Small mono caps above a heading — it is the single cheapest
   device that makes a page read "engineering" rather than "brochure". */
.eyebrow{
  font-family:var(--mono); font-size:.74rem; letter-spacing:.16em;
  text-transform:uppercase; color:var(--c); margin:0 0 .8em; font-weight:600;
}
.grad-text{
  background:var(--grad); -webkit-background-clip:text; background-clip:text;
  color:transparent;
}
/* A gradient headline at display size loses contrast through its middle. Where
   a whole heading must be legible, tint it instead of gradienting it. */
.tint{ color:var(--v-2) }

/* ---------------------------------------------------------------- layout */
.wrap{ max-width:var(--maxw); margin:0 auto; padding:0 24px }
.prose{ max-width:var(--maxw-prose) }
section{ padding:clamp(64px, 7vw, 120px) 0; position:relative }
.section-head{ max-width:66ch; margin:0 0 clamp(28px,3.4vw,52px) }

.grid{ display:grid; gap:18px }
.g-2{ grid-template-columns:repeat(2,1fr) }
.g-3{ grid-template-columns:repeat(3,1fr) }
.g-4{ grid-template-columns:repeat(4,1fr) }
@media(max-width:900px){ .g-3,.g-4{ grid-template-columns:repeat(2,1fr) } }
@media(max-width:620px){ .g-2,.g-3,.g-4{ grid-template-columns:1fr } }

/* Bento: a feature grid where the cells are deliberately unequal, so the eye
   is given an order to read them in instead of five identical boxes. */
.bento{ display:grid; grid-template-columns:repeat(6,1fr); gap:16px }
.bento > *{ grid-column:span 2 }
.bento > .wide{ grid-column:span 3 }
.bento > .full{ grid-column:span 6 }
@media(max-width:900px){
  .bento{ grid-template-columns:repeat(2,1fr) }
  .bento > *,.bento > .wide,.bento > .full{ grid-column:span 2 }
}

/* ------------------------------------------------------------ components */
.card{
  background:var(--surface); border:1px solid var(--line);
  border-radius:var(--r-lg); padding:24px;
  transition:border-color .22s, transform .22s, background .22s;
}
.card:hover{ border-color:var(--line-2); background:var(--surface-2); transform:translateY(-2px) }
.card h3{ margin:0 0 .35em }
.card p{ color:var(--muted); margin:0; font-size:.95rem }
.card .ico{
  width:38px; height:38px; border-radius:11px; display:grid; place-items:center;
  background:var(--grad-soft); border:1px solid var(--line); margin-bottom:14px;
  font-size:1.05rem;
}

.btn{
  display:inline-flex; align-items:center; gap:9px; padding:13px 24px;
  border-radius:999px; font-weight:650; font-size:.97rem; cursor:pointer;
  border:1px solid transparent; font-family:inherit;
  transition:transform .2s, box-shadow .2s, background .2s, border-color .2s;
}
.btn:hover{ text-decoration:none }
.btn-primary{ background:var(--grad); color:#07080e; box-shadow:0 12px 34px -14px rgba(124,108,255,.85) }
.btn-primary:hover{ transform:translateY(-2px); box-shadow:0 18px 44px -14px rgba(124,108,255,.95) }
.btn-ghost{ background:transparent; border-color:var(--line-2); color:var(--ink) }
.btn-ghost:hover{ background:rgba(255,255,255,.05); border-color:var(--ink) }

.pill{
  display:inline-flex; align-items:center; gap:9px; padding:7px 15px;
  border-radius:999px; border:1px solid var(--line-2); background:rgba(255,255,255,.03);
  font-size:.84rem; color:var(--muted);
}
.pill .dot{ width:7px; height:7px; border-radius:50%; background:var(--ok);
  box-shadow:0 0 0 4px rgba(52,211,153,.16) }

/* Stat: a real measured number, with the thing it measures under it. The
   number is the point, so it gets the size and the tabular figures. */
.stat .n{ font-size:clamp(1.9rem,1.4rem + 1.6vw,2.7rem); font-weight:800;
  letter-spacing:-.035em; font-variant-numeric:tabular-nums; line-height:1 }
.stat .l{ color:var(--faint); font-size:.86rem; margin-top:8px }

/* Browser chrome around a product screenshot. Without a frame a screenshot
   reads as a stray image; with one it reads as software. */
.frame{
  border:1px solid var(--line-2); border-radius:var(--r-lg); overflow:hidden;
  background:var(--surface); box-shadow:var(--shadow-lg);
}
.frame-bar{
  display:flex; align-items:center; gap:7px; padding:11px 15px;
  background:var(--surface-2); border-bottom:1px solid var(--line);
}
.frame-bar i{ width:11px; height:11px; border-radius:50%; background:#2c3242; display:block }
.frame-bar .addr{
  margin-left:12px; font-family:var(--mono); font-size:.74rem; color:var(--dim);
  background:rgba(0,0,0,.3); padding:4px 12px; border-radius:6px; flex:1;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.frame img{ display:block; width:100% }

/* Ambient light. Two soft pools rather than the old three orbs — fewer,
   larger and dimmer reads as depth; more and brighter reads as decoration. */
.glow{ position:fixed; inset:0; pointer-events:none; z-index:0; overflow:hidden }
.glow::before,.glow::after{
  content:""; position:absolute; border-radius:50%; filter:blur(110px); opacity:.5;
}
.glow::before{ width:60vw; height:60vw; left:-18vw; top:-24vw; background:rgba(124,108,255,.22) }
.glow::after{ width:52vw; height:52vw; right:-16vw; top:8vw; background:rgba(34,211,238,.13) }
body > *:not(.glow){ position:relative; z-index:1 }

.rule{ border:0; border-top:1px solid var(--line); margin:0 }

table{ width:100%; border-collapse:collapse; font-size:.93rem }
th,td{ text-align:left; padding:11px 12px; border-bottom:1px solid var(--line); vertical-align:top }
th{ color:var(--faint); font-weight:600; font-size:.76rem; text-transform:uppercase; letter-spacing:.1em }
td.num,th.num{ text-align:right; font-variant-numeric:tabular-nums }
.tablewrap{ overflow-x:auto }

pre{
  background:#05060b; border:1px solid var(--line); border-radius:var(--r);
  padding:15px 17px; overflow-x:auto; font-family:var(--mono);
  font-size:.85rem; line-height:1.6;
}
code{ font-family:var(--mono); font-size:.9em }

.panel{ background:var(--surface); border:1px solid var(--line);
  border-radius:var(--r-lg); padding:22px 24px; margin:18px 0 }

/* ------------------------------------------------------------ navigation */
header.nav{
  position:sticky; top:0; z-index:50; backdrop-filter:blur(16px);
  background:rgba(7,8,14,.78); border-bottom:1px solid var(--line);
}
.nav-in{ display:flex; align-items:center; justify-content:space-between; height:66px }
.brand{ display:flex; align-items:center; gap:11px; font-weight:800; font-size:1.08rem;
  color:var(--ink); letter-spacing:-.02em }
.brand:hover{ text-decoration:none }
.brand svg{ width:27px; height:27px }

.nav-links{ display:flex; gap:26px; align-items:center }
.nav-links > a,.menu-btn{
  color:var(--muted); font-size:.93rem; font-weight:500; margin-left:0;
  background:none; border:0; padding:0; font-family:inherit; cursor:pointer;
  display:inline-flex; align-items:center; gap:5px;
}
.nav-links > a:hover,.menu-btn:hover,.menu-btn[aria-expanded="true"]{ color:var(--ink); text-decoration:none }
.caret{ width:0; height:0; border-left:4px solid transparent; border-right:4px solid transparent;
  border-top:5px solid currentColor; opacity:.7; transition:transform .18s }
.menu-btn[aria-expanded="true"] .caret{ transform:rotate(180deg) }
.menu{ position:relative }
.dropdown{
  display:none; position:absolute; top:calc(100% + 12px); left:-14px; min-width:216px;
  background:var(--surface-2); border:1px solid var(--line-2); border-radius:var(--r);
  padding:8px; box-shadow:var(--shadow); z-index:60;
}
.menu:hover .dropdown,.dropdown.open{ display:block }
/* Bridges the gap between button and panel so the pointer does not cross dead
   space and close it on the way down. */
.menu:hover::after{ content:""; position:absolute; left:0; right:0; top:100%; height:14px }
.dropdown a{ display:block; padding:9px 12px; border-radius:9px; color:var(--muted);
  font-size:.9rem; white-space:nowrap }
.dropdown a:hover{ background:rgba(255,255,255,.06); color:var(--ink); text-decoration:none }
.nav-links a[aria-current="page"]{ color:var(--ink) }
.dropdown a[aria-current="page"]{ background:rgba(255,255,255,.06) }

/* `.nav-links > a` is (0,1,1) and out-specifies a bare `.nav-cta` (0,1,0) —
   its `background:none` once painted this button away entirely, leaving
   near-black text on a dark bar while `isVisible()` still returned true.
   Matched at (0,2,1) so it wins. */
.nav-links > a.nav-cta{
  padding:10px 19px; border-radius:999px; background:var(--grad);
  color:#07080e; font-weight:650;
}
.nav-links > a.nav-cta:hover{ text-decoration:none; opacity:.93 }

.navtoggle{ display:none; background:none; border:0; cursor:pointer; padding:10px; margin:-10px -6px -10px 0 }
.navtoggle span,.navtoggle span::before,.navtoggle span::after{
  display:block; width:22px; height:2px; background:var(--ink); border-radius:2px;
  transition:transform .2s, opacity .2s;
}
.navtoggle span::before,.navtoggle span::after{ content:""; position:relative }
.navtoggle span::before{ top:-7px } .navtoggle span::after{ top:5px }
.navtoggle[aria-expanded="true"] span{ background:transparent }
.navtoggle[aria-expanded="true"] span::before{ transform:translateY(7px) rotate(45deg) }
.navtoggle[aria-expanded="true"] span::after{ transform:translateY(-5px) rotate(-45deg) }

@media(max-width:900px){
  .navtoggle{ display:block }
  /* This was `display:none`, which left a phone with NO navigation at all. */
  .nav-links{
    display:none; position:absolute; top:66px; left:0; right:0; flex-direction:column;
    align-items:stretch; gap:2px; padding:14px 24px 22px; background:var(--bg-2);
    border-bottom:1px solid var(--line); max-height:calc(100vh - 66px); overflow-y:auto;
  }
  .nav-links.open{ display:flex }
  .nav-links > a,.menu-btn{ padding:11px 2px; font-size:1rem }
  .menu{ position:static }
  /* Both groups sit open on a phone: a nested toggle inside a toggle is more
     taps and more to get wrong than showing six short links. */
  .dropdown{ display:block; position:static; border:0; box-shadow:none; background:none;
    padding:0 0 8px 12px; min-width:0 }
  .menu-btn{ pointer-events:none; color:var(--faint); font-size:.76rem;
    text-transform:uppercase; letter-spacing:.1em; font-family:var(--mono) }
  .menu-btn .caret{ display:none }
  .nav-links > a.nav-cta{ text-align:center; justify-content:center; margin-top:10px; padding:13px }
}

/* ---------------------------------------------------------------- footer */
footer.site{ border-top:1px solid var(--line); margin-top:clamp(56px,6vw,96px);
  padding:44px 0 40px; color:var(--faint); font-size:.89rem }
footer.site .cols{ display:grid; grid-template-columns:1.6fr 1fr 1fr 1fr; gap:28px; margin-bottom:34px }
@media(max-width:760px){ footer.site .cols{ grid-template-columns:1fr 1fr } }
footer.site h4{ font-size:.74rem; text-transform:uppercase; letter-spacing:.13em;
  color:var(--faint); font-family:var(--mono); font-weight:600; margin:0 0 12px }
footer.site a{ color:var(--muted); display:block; padding:4px 0; font-size:.9rem }
footer.site a:hover{ color:var(--ink); text-decoration:none }
footer.site .base{ display:flex; justify-content:space-between; gap:18px; flex-wrap:wrap;
  padding-top:22px; border-top:1px solid var(--line) }

/* ---------------------------------------------------------------- motion */
.reveal{ opacity:0; transform:translateY(22px);
  transition:opacity .7s cubic-bezier(.2,.7,.2,1), transform .7s cubic-bezier(.2,.7,.2,1) }
.reveal.in{ opacity:1; transform:none }
@media (prefers-reduced-motion: reduce){
  .reveal{ opacity:1; transform:none; transition:none }
  .card:hover,.btn:hover{ transform:none }
}
