/* Public marketing site (templates/site_base.html).
   Linked rather than inlined: this file is ~11KB, a third of it rules for a
   waitlist form most pages never render, and inlining it re-sent all of it on
   every page. Linked with ?v=asset_version(), which is what earns the year of
   `immutable` that finance/web/caching.py stamps on versioned /static URLs, so
   the second page view costs nothing.

   Per-page CSS still ships inline through site_base's {% block style %} hook.
   Do not move page-specific rules here; they belong to their page. */

/* Geist and Fira Code, self-hosted. Served from /static/fonts rather than
   fonts.googleapis.com: the Google stylesheet was the only third-party
   request the public site made, it was render blocking, and these are the
   pages whose privacy policy tells the reader nothing third party loads.
   Both faces are OFL.

   Variable RANGES, not a list of instances. The single variable file renders
   font-weight: 640, 650 and 660 as authored. Requested as discrete weights,
   the served files were one face per value and every heading the design sets
   between 600 and 700 snapped up to the 700 face, so the whole site rendered
   a weight heavier than it was written.

   Latin subset only. The site is US only and English, and the wider subsets
   are bytes no reader here spends.

   font-display: swap, so text paints in the fallback stack immediately and
   reflows once the file lands. The Geist file is preloaded from site_base's
   <head>; Fira Code is not, because it paints only inline code and figures. */
@font-face {
  font-family: "Geist";
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url("/static/fonts/geist-latin-variable.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Fira Code";
  font-style: normal;
  font-weight: 400 500;
  font-display: swap;
  src: url("/static/fonts/fira-code-latin-variable.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
  --bg: #ffffff; --surface: #f6f8fa; --ink-1: #1a1d21; --ink-2: #3d434b;
  --ink-3: #5b6470; --line: #e3e8ee; --accent: #2563eb; --accent-soft: #eff4ff;
  --btn-ink: #ffffff;
  /* The waitlist form's own tokens. They live at THIS level, not in the
     landing page's extended palette, because the form is no longer the
     landing page's: every calculator carries it. A token defined only in
     one caller's block renders as an empty value on the other, and an
     undefined custom property fails silently rather than loudly. */
  /* The quietest ink. It was #97a1b0, which measures 2.61:1 on --bg and
     2.45:1 on --surface, and it does not paint decoration: it carries
     field hints on the calculators, the qualifier under every row of the
     plan matrix, table footnotes, the input placeholder, and the labels
     inside the product mockups. At #6b7280 it clears 4.5:1 on all three
     grounds and is still the bottom rung of the ladder. Defined once
     here; the pages that used to restate it verbatim no longer do. */
  --ink-4: #6b7280;
  --pos: #059669; --pos-soft: #d9f5e8; --pos-ink: #047352; --neg: #be123c;
  /* Rule 3 in EMBER-DESIGN.md: mono on any digit a reader scans. Defined
     as a token because more than one surface needs it now (inline code,
     the legal pages' dates and section numbers) and a second literal copy
     of the stack is how the two drift. Ligatures are switched off at each
     use site, per the same rule. */
  --font-mono: "Fira Code", ui-monospace, SFMono-Regular, Menlo, monospace;
}
@media (prefers-color-scheme: dark) {
  :root {
    --bg: #0e1116; --surface: #161b22; --ink-1: #e6e9ed; --ink-2: #c3c9d2;
    --ink-3: #9aa4b2; --line: #272d36; --accent: #60a5fa; --accent-soft: #14243d;
    --btn-ink: #0e1116;
    --ink-4: #7b8494;
    --pos: #34d399; --pos-soft: rgba(52,211,153,.14); --pos-ink: #6ee7b7;
    --neg: #fb7185;
  }
}
* { box-sizing: border-box; }
/* Smooth scrolling is decoration, and a reader who has asked their OS to
   reduce motion has asked for it not to happen. Wrapped in
   no-preference so the default is a jump, not an animation, for anyone
   whose setting is unknown. */
@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}
/* The top bar is sticky on every public page, so an in-page anchor
   (#waitlist-hero, a legal section, a docs heading) would otherwise land
   under it. scroll-padding-top reserves the bar's height plus a little
   air on the scroll container, which fixes every target at once,
   including the one a Shift+Tab moves focus to. The two values track the
   measured bar: 67px on desktop, 93px once it wraps to two rows below
   620px. Per-element scroll-margin-top is no longer needed and was
   removed from the waitlist form and its confirmation. */
html { scroll-padding-top: 84px; }
body {
  margin: 0; background: var(--bg); color: var(--ink-2);
  font-family: "Geist", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  font-size: 16px; line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}
a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }
/* One focus ring for the whole public site, drawn outside the element so
   it never depends on the element's own colours. The email input used to
   replace its outline with a 22% accent glow, which measures 1.36:1
   against the page: a keyboard reader could not find the field they were
   standing in. :focus-visible rather than :focus, so a pointer click does
   not paint a ring nobody asked for. */
a:focus-visible, button:focus-visible, .btn:focus-visible, .wl-input:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 2px;
}
/* Skip link. Six tab stops sat in front of the content on every page.
   First child of <body>, off screen until it takes focus, and it moves
   focus to the wrapper around each page's own <main>. */
.skip-link {
  position: absolute; left: 16px; top: 10px; z-index: 20;
  transform: translateY(-200%);
  padding: 9px 15px; border-radius: 7px; font-size: 14px; font-weight: 600;
  color: var(--accent); background: var(--bg); border: 1px solid var(--accent);
}
.skip-link:focus { transform: translateY(0); text-decoration: none; }
#main-content:focus { outline: none; }
code, kbd {
  font-family: var(--font-mono);
  font-variant-ligatures: none; font-size: .86em;
  background: var(--surface); border-radius: 4px; padding: .12em .35em;
}
h1, h2, h3 { color: var(--ink-1); line-height: 1.2; letter-spacing: -0.02em; }

/* Brand mark: the one sanctioned gradient artifact (matches .side-mark).
   These pages have no theme toggle, so the variant swaps on the media
   query rather than on [data-theme] the way the app does. */
.mark {
  display: inline-block; width: 22px; height: 22px;
  background: url("/static/ember-mark.svg") center / contain no-repeat;
  flex-shrink: 0; vertical-align: middle;
}
@media (prefers-color-scheme: dark) {
  .mark { background-image: url("/static/ember-mark-dark.svg"); }
}
.wordmark { font-weight: 600; font-size: 17px; color: var(--ink-1); letter-spacing: -0.02em; }
.wordmark sup { font-weight: 400; color: var(--ink-3); font-size: 10px; margin-left: 3px; }

header.topbar {
  position: sticky; top: 0; z-index: 10; background: var(--bg);
  border-bottom: 1px solid var(--line);
  display: flex; align-items: center;
  gap: 20px; padding: 13px 24px;
}
.topbar .brand { display: flex; align-items: center; gap: 9px; color: inherit; }
.topbar .brand:hover { text-decoration: none; }
.topbar nav { display: flex; gap: 20px; align-items: center; margin-left: auto; }
.topbar .cta { flex-shrink: 0; }
/* Touch targets. The link text is 22px tall, which is under any touch
   minimum, so each link carries padding that grows the hit area and an
   equal negative margin that hands the space back to the layout. The
   target is 40px tall; the bar is the height it always was. Horizontal
   padding stays under half the smallest gap, so two neighbours never
   overlap, and vertical padding stays under the bar's own 11px so the
   target never crosses the bottom hairline. */
.topbar nav a {
  color: var(--ink-3); font-size: 14px; font-weight: 500;
  padding: 9px 6px; margin: -9px -6px;
}
.topbar nav a:hover { color: var(--ink-1); text-decoration: none; }
.topbar nav a.active { color: var(--ink-1); }
/* The nav items plus the brand do not fit on one phone-width line, and
   a topbar that overflows makes the WHOLE page scroll sideways. Let the
   bar wrap: the brand and the one button share the first row, and the
   text links drop to a second, centred row beneath. Two rows, never
   three. An earlier layout put the button inside the nav, so on a phone
   it wrapped to a third row of its own and the sticky bar covered 15% of
   every screen. Centred rather than spread, because a wrapped
   `space-between` row strands its last item against one margin.

   The column gap is 10px, not 14px, because the five links measure
   44+72+32+89+43 = 280px and the bar's own padding takes 32px: at 14px
   gaps the row needed 368px and a 360px phone put it back on three rows.
   At 10px it needs 352px and holds two rows down to 360. The row gap is
   20px so that on anything narrower, where the links do wrap, the 40px
   touch targets meet rather than overlap. */
@media (max-width: 620px) {
  header.topbar { flex-wrap: wrap; gap: 8px 12px; padding: 11px 16px; }
  html { scroll-padding-top: 108px; }
  .topbar .cta { order: 2; margin-left: auto; }
  .topbar nav { order: 3; gap: 20px 10px; width: 100%; justify-content: center; flex-wrap: wrap; margin-left: 0; }
  .topbar nav a { font-size: 13.5px; }
}

.btn {
  display: inline-flex; align-items: center; gap: .5em;
  padding: 9px 18px; border-radius: 7px; font-weight: 600; font-size: 14.5px;
  border: 1px solid var(--line); color: var(--ink-1); background: var(--bg);
  text-decoration: none; white-space: nowrap;
}
.btn:hover { text-decoration: none; background: var(--surface); }
.btn.primary { background: var(--accent); border-color: var(--accent); color: var(--btn-ink); }
.btn.primary:hover { filter: brightness(1.07); background: var(--accent); }
.topbar .btn { padding: 7px 14px; }

main { max-width: 1000px; margin: 0 auto; padding: 0 24px 96px; }

/* ---- Waitlist signup (templates/_waitlist.html) ----
   Shared chrome, because the form is shared: the landing hero, the
   landing closer, and every /tools/* calculator render the same macro.
   These rules used to live in the landing page's own style block, which
   is why they are here now rather than there.
   .btn is styled for an <a> above, so the submit <button> restates the
   font and cursor: neither is inherited. */
.wl-form {
  display: flex; gap: 10px; flex-wrap: wrap; justify-content: center;
  max-width: 470px; margin: 0 auto;
}
.wl-input {
  flex: 1 1 230px; min-width: 0; padding: 12px 14px;
  font-family: inherit; font-size: 15.5px; line-height: 1.2;
  color: var(--ink-1); background: var(--bg);
  border: 1px solid var(--line); border-radius: 7px;
}
.wl-input::placeholder { color: var(--ink-4); }
/* The border carries the state for a pointer user; the shared
   :focus-visible outline above carries it for a keyboard one. The 22%
   accent glow that used to stand in for the outline is gone: it measured
   1.36:1 against the page. */
.wl-input:focus { border-color: var(--accent); }
.wl-form .btn {
  padding: 12px 22px; font-size: 15.5px;
  font-family: inherit; cursor: pointer;
}
.btn.primary.glow { box-shadow: 0 10px 30px -10px color-mix(in oklab, var(--accent) 70%, transparent); }
/* Confirmation panel, rendered in place of the form after ?waitlist=ok. */
.wl-done {
  display: flex; align-items: center; gap: 11px; text-align: left;
  max-width: 470px; margin: 0 auto; padding: 14px 18px;
  font-size: 15px; color: var(--pos-ink); background: var(--pos-soft);
  border: 1px solid color-mix(in oklab, var(--pos) 34%, transparent);
  border-radius: 9px;
}
.wl-done svg { color: var(--pos); flex-shrink: 0; }
.wl-done b { color: inherit; font-weight: 640; }
.wl-error {
  max-width: 470px; margin: 12px auto 0; font-size: 14px; color: var(--neg);
}
/* Two spans on their own lines rather than a <br>: the break is layout,
   not content, so it can collapse to one line if a translation is short
   and it doesn't strand a lone link fragment on a phone. */
.wl-note {
  font-size: 14px; color: var(--ink-3); line-height: 1.55;
  margin: 16px auto 0; max-width: 460px;
}
.wl-note span { display: block; }
.wl-note a { color: var(--ink-2); text-decoration: underline; text-underline-offset: 2px; }
.wl-note a:hover { color: var(--accent); }
/* Visually hidden but read by screen readers: each input needs a label,
   and the placeholder is not one. */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
/* Below the input's flex basis the button wraps to its own line, where a
   content-width button next to a full-width input reads as broken. Stack
   both and let the button fill instead.

   The flex-basis reset is load bearing, not tidying. `flex: 1 1 230px`
   sizes the MAIN axis, and turning the row into a column turns that main
   axis vertical: the 230px that was the input's minimum WIDTH becomes its
   height, and every phone narrower than this breakpoint gets a 230px-tall
   email box. Any change to the row's flex shorthand has to be mirrored
   here. */
@media (max-width: 470px) {
  .wl-form { flex-direction: column; }
  .wl-form .wl-input { flex: 0 0 auto; }
  .wl-form .btn { justify-content: center; }
}

footer.site-foot {
  border-top: 1px solid var(--line); margin-top: 0;
  padding: 28px 24px 40px; font-size: 13.5px; color: var(--ink-3);
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; flex-wrap: wrap;
}
footer.site-foot .links { display: flex; gap: 18px; flex-wrap: wrap; }
/* Same padding-plus-negative-margin trick as the top bar: a 36px touch
   target on 22px of text, without moving the footer's spacing. */
footer.site-foot a { color: var(--ink-3); padding: 7px 5px; margin: -7px -5px; }
footer.site-foot a:hover { color: var(--ink-1); }
