/*
 * Inter, declared here because this is now the only stylesheet every page loads.
 *
 * It used to come from site-shell.css, which carried the @font-face for the
 * whole site. Removing that shell took the declaration with it, so ten pages --
 * the home page among them -- asked for "Inter" against a font nobody had
 * registered and quietly fell back to Segoe UI. The wordmark is where that is
 * most obvious, but it was every character on those pages.
 *
 * Copied verbatim from site-shell.css: one variable file covering 100-900, and
 * font-display: swap so the text is readable while it loads.
 */
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("/assets/fonts/inter-latin-var.woff2") format("woff2");
}

/*
 * The light home page.
 *
 * Everything else on this site is one pinned dark theme -- data-theme="dark" is
 * a static attribute on <html> and several tests assert it. This page is the
 * exception, so it does not borrow the shared shell's tokens: site-shell.css
 * defines its palette on .hd and .ft, and a light page pulling those in would
 * be fighting a dark variable set for every colour it wanted. The header and
 * footer here are their own components under an hx- prefix, which is also what
 * keeps test/header-navigation.test.js and tools/sync-site-shell.py away from
 * them -- they find pages by class="hd-nav", and this page has none.
 *
 * The hero is the mockup. Every section below it is the live home page's
 * content, so the job of the rest of this file is to say the same things in a
 * light palette: the same two-column blocks, the same five- and four-card
 * runs, the same big dashboard figure, the same numbered lists.
 *
 * Fonts: Inter is self-hosted and already on the site. The display serif and
 * the handwritten accents come from Google Fonts, which the CSP allows
 * (style-src fonts.googleapis.com, font-src fonts.gstatic.com). Both have real
 * fallbacks, because a headline is not worth a blank page.
 */

/*
 * Declared on every root the chrome can hang from, not just .hx. The home page
 * is .hx from <body> down; on the other pages only the header, the footer, the
 * utility strip and the search dialog are hx components, and each has to be
 * able to resolve these on its own.
 */
.hx,
.hx-util,
.hx-hd,
.hx-backdrop,
.hx-ft,
.hx-search,
.hx-sticky-cta,
/* The upgrade confirmation is appended to <body> by pricing.js. On the home
   page that is inside .hx, but a <dialog> is cheap to declare here and this is
   the same lesson as .hx-to-top below -- one page moving the section would
   otherwise leave the sheet resolving its surface and ink to nothing. */
.hx-upgrade,
/* The back-to-top button is a child of <body>, outside every wrapper above.
   On the home page that is still inside .hx, but on the pages whose body is
   .support-page or .doc-page it is not -- and there it resolved --hx-green-deep
   and --hx-mint-line to nothing, so the button wore the page's own ink and lost
   its shadow entirely. */
.hx-to-top {
  /* Ground and ink. The off-white is warm and slightly green rather than grey,
     which is what stops a page this empty reading as unfinished. */
  --hx-ground: #f4f7f1;
  --hx-ground-2: #eef3ea;
  --hx-surface: #fff;
  --hx-ink: #16241c;
  --hx-ink-2: #2c3f34;
  --hx-body: #47574e;
  /* 4.88:1 on the ground and 5.28:1 on white. It was #6b7a71, which measured
     4.14 against the mint-soft card fill and 4.18 against the ground -- under
     the 4.5 that 13px captions, figure captions and the footer's small print
     need, and those are most of what this token colours. */
  --hx-muted: #616f67;

  --hx-green: #0a8a45;
  --hx-green-deep: #06753a;
  --hx-green-dark: #17381f;
  --hx-green-darker: #102817;
  --hx-green-bright: #45e39a;
  --hx-mint: #e4f1e8;
  --hx-mint-soft: #eff7f1;
  --hx-mint-line: #d4e7da;
  --hx-line: #e1e8df;
  /*
   * A frame for a screenshot, which --hx-line cannot be.
   *
   * --hx-line is a divider between two tinted surfaces and is right for that.
   * Around a screenshot it fails: several of these are captures with a white
   * or near-white background sitting on a white card, so the border measured
   * 1.18:1 against the image own corner pixel and the picture bled into the
   * card with no edge at all. This is the same hue, dark enough to read as a
   * hairline at 1px without becoming a rule in its own right.
   */
  --hx-frame: #c2d1c6;
  --hx-line-soft: #ecf1ea;

  --hx-shadow-card: 0 12px 34px -20px rgba(18, 52, 34, .26);
  --hx-shadow-lift: 0 24px 60px -28px rgba(18, 52, 34, .3);
  --hx-shadow-pill: 0 14px 40px -22px rgba(18, 52, 34, .34);

  /*
   * Four display steps, because there were nine.
   *
   * Every heading carried its own clamp() and they landed within a few pixels
   * of each other: h2 at 46, 48, 50 and 52, h3 at 24, 36, 37 and 39. Sizes
   * that close do not read as a hierarchy -- they read as the same size drawn
   * slightly wrong. These are the four steps that were actually in use, named
   * once so a heading picks a level rather than inventing one.
   */
  --hx-h-section: clamp(34px, 3.6vw, 54px);  /* the six section heads */
  --hx-h-band: clamp(30px, 3.2vw, 46px);     /* privacy, about, the closing call */
  --hx-h-sub: clamp(27px, 2.7vw, 38px);      /* photo blocks, the video, plan names */
  --hx-h-card: 24px;                         /* inside a card */
  --hx-sans: "Inter", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  /*
   * The same family as the body, self-hosted, no second request.
   *
   * This was a display serif -- Instrument, then Fraunces -- which is a look
   * this design no longer wants. One typeface across the page is the minimal
   * position, and the hierarchy comes from size and weight instead of from a
   * change of voice. It also drops a render-blocking Google Fonts stylesheet:
   * Inter is already preloaded as a woff2 on every page, so the headline now
   * paints in its final face rather than swapping into one.
   */
  --hx-display: "Inter", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --hx-script: "Caveat", "Segoe Script", "Bradley Hand", cursive;

  color: var(--hx-body);
  font-family: var(--hx-sans);
  font-size: 16px;
  line-height: 1.6;
}
/* Only a page that is entirely this design paints the ground. Elsewhere the
 * page's own stylesheet owns its background, and the chrome sits on top. */
.hx { background: var(--hx-ground); }
:where(.hx, .hx-util, .hx-hd, .hx-ft, .hx-search, .hx-sticky-cta, .hx-upgrade) *,
:where(.hx, .hx-util, .hx-hd, .hx-ft, .hx-search, .hx-sticky-cta, .hx-upgrade) *::before,
:where(.hx, .hx-util, .hx-hd, .hx-ft, .hx-search, .hx-sticky-cta, .hx-upgrade) *::after { box-sizing: border-box; }
/*
 * Every base reset is wrapped in :where(), and this is the whole reason.
 *
 * Written as ".hx p", ".hx figure", ".hx ul", ".hx h1" these are a class plus a
 * type -- specificity (0,1,1) -- and a component class is (0,1,0). The reset
 * won every time, so a component could not set its own margin at all:
 *
 *   .hx-month-art { margin: 54px auto 0 }   ->  0, so the figure sat hard left
 *   .hx-steps-art { margin: 54px auto 0 }   ->  0, off-centre by 365px
 *   .hx-card-art  { margin-bottom: 18px }   ->  0, image touching its own text
 *   .hx-hero-lead, .hx-trust, .hx-hero-note, .hx-client-list, .hx-steps,
 *   .hx-life-list, .hx-plans-note, .hx-watch-note  -> all 0
 *
 * Eleven of twelve margins on the page, which is why the vertical rhythm read
 * as broken and the two big screenshots looked misplaced. The headings had the
 * same problem in a quieter way: .hx-display asks for weight 500 and a 1.06
 * line, and ".hx h1, .hx h2..." was holding them at 600 and 1.1.
 *
 * :where() contributes nothing to specificity, so these land at (0,0,1) -- still
 * ahead of the browser's own stylesheet, which is all a reset needs to beat,
 * and now behind every component class, which is what a reset should be.
 */
/*
 * The browser keeps an 8px margin on <body> unless something says otherwise,
 * and nothing here did. The utility strip, the header and the footer are all
 * full-bleed, so that margin showed as a pale gutter down both sides of the
 * dark bar and a pale band above it -- the page looked inset by 8px on three
 * sides.
 *
 * It belongs in this file rather than on .hx because the chrome is on all
 * twenty-four pages while only two of them are .hx, and this is the only
 * stylesheet every one of them loads.
 */
body { margin: 0; }

:where(.hx, .hx-util, .hx-hd, .hx-ft, .hx-search, .hx-sticky-cta) img { display: block; max-width: 100%; }
/*
 *
 * As ".hx a" this was specificity (0,1,1) -- a class and a type -- and every
 * single-class component rule below is (0,1,0), so the reset won. The visible
 * result was that every button written as a link took the body's ink instead
 * of its own colour: the hero's call to action and all three pricing buttons
 * rendered #47574e on #17381f, which is 1.69:1 and effectively unreadable.
 * The <button> versions of the same component were white, so the two looked
 * like different components.
 *
 * :where() contributes nothing to specificity, leaving just the type selector
 * at (0,0,1). Plain links still inherit; anything with a class now wins.
 */
:where(.hx, .hx-util, .hx-hd, .hx-ft, .hx-search, .hx-sticky-cta) a { color: inherit; text-decoration: none; }
/*
 * The shared chrome defends its own links.
 *
 * The reset above is deliberately :where(), so it lands at (0,0,1) and sits
 * behind every component that styles a link. The cost is that it also sits
 * behind whatever the surrounding page declares, and six pages that host this
 * header carry a global link rule written for their own body copy:
 *
 *   support.html  inline   a:hover { text-decoration: underline }   (0,1,1)
 *   docs-legal.css         .doc-page a:hover { ... }                (0,2,1)
 *   page-base.css          a:hover { ... }                          (0,1,1)
 *
 * All of them outrank (0,0,1), so on /support, /about, /mcp-docs, /privacy,
 * /terms and /manny-guide the wordmark and every nav item grew an underline on
 * hover -- styling from a page bleeding into shared furniture that is supposed
 * to look identical everywhere.
 *
 * These are (0,2,1): high enough to beat a page's global rule, low enough that
 * any chrome component can still style its own hover.
 */
.hx-util a:hover,
.hx-hd a:hover,
.hx-ft a:hover,
.hx-search a:hover,
.hx-sticky-cta a:hover { text-decoration: none; }
/* The one chrome link that should underline: a real mailto, where the underline
   is what says so. (0,3,1), to clear the rule immediately above. */
.hx-ft a.hx-ft-email:hover { text-decoration: underline; }
:where(.hx, .hx-util, .hx-hd, .hx-ft, .hx-search, .hx-sticky-cta) h1,
:where(.hx, .hx-util, .hx-hd, .hx-ft, .hx-search, .hx-sticky-cta) h2,
:where(.hx, .hx-util, .hx-hd, .hx-ft, .hx-search, .hx-sticky-cta) h3,
:where(.hx, .hx-util, .hx-hd, .hx-ft, .hx-search, .hx-sticky-cta) h4 { margin: 0; color: var(--hx-ink); font-weight: 600; letter-spacing: -.02em; line-height: 1.1; }
:where(.hx, .hx-util, .hx-hd, .hx-ft, .hx-search, .hx-sticky-cta) p { margin: 0; }
:where(.hx, .hx-util, .hx-hd, .hx-ft, .hx-search, .hx-sticky-cta) ul,
:where(.hx, .hx-util, .hx-hd, .hx-ft, .hx-search, .hx-sticky-cta) ol { margin: 0; padding: 0; list-style: none; }
:where(.hx, .hx-util, .hx-hd, .hx-ft, .hx-search, .hx-sticky-cta) svg { fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
:where(.hx, .hx-util, .hx-hd, .hx-ft, .hx-search, .hx-sticky-cta) figure { margin: 0; }

/*
 * One focus ring, for a component set that had none.
 *
 * Nothing here styled :focus-visible, so every button and link fell back to
 * the browser's own ring. On a set of dark pills and rounded cards that is a
 * gamble twice over: the default is drawn in the UA's colour, which has no
 * relationship to this palette, and an outline is clipped by an ancestor's
 * overflow -- .hx-card, .hx-final and .hx-watch-frame all clip, and the links
 * and buttons inside them are exactly the ones a keyboard reader lands on.
 *
 * So: an explicit ring, in the palette, offset far enough to read and not far
 * enough to reach a clipping edge. The colour flips to white wherever the
 * thing being focused sits on one of the dark greens, because a green ring on
 * dark green is not a ring.
 */
:where(.hx, .hx-util, .hx-hd, .hx-ft, .hx-search, .hx-sticky-cta) :focus-visible {
  outline: 3px solid var(--hx-green-deep);
  outline-offset: 2px;
}
.hx-btn:focus-visible,
.hx-util :focus-visible,
.hx-privacy :focus-visible,
.hx-final :focus-visible,
.hx-plan.is-featured :focus-visible { outline-color: #fff; }
/* The ghost button is a light surface even inside the dark sections. */
.hx-btn-ghost:focus-visible { outline-color: var(--hx-green-deep); }
.hx-privacy .hx-btn-ghost:focus-visible,
.hx-final .hx-btn:focus-visible { outline-color: #fff; }
/* The poster fills its frame to the edge, so its ring goes inside or the
 * frame's own overflow clips it away entirely. */
.hx-watch-play:focus-visible { outline-offset: -5px; }

.hx-shell { width: min(1490px, calc(100% - 64px)); margin-inline: auto; }

.hx-skip {
  position: absolute;
  top: -60px;
  left: 16px;
  z-index: 200;
  padding: 13px 18px;
  border-radius: 0 0 10px 10px;
  background: var(--hx-green-dark);
  color: #fff;
  font: 700 15px/1.2 var(--hx-sans);
  transition: top .16s ease;
}
.hx-skip:focus { top: 0; }

/* -------------------------------------------------------------- utility bar */

/*
 * The strip above the header. Two claims the page makes everywhere else in
 * prose, said once in small type where a reader looking for the catch will
 * look first. It scrolls away; the header does not.
 */
.hx-util { background: var(--hx-green-darker); color: rgba(255, 255, 255, .82); font-size: 13.2px; }
.hx-util-in { display: flex; align-items: center; justify-content: space-between; gap: 24px; min-height: 46px; }
.hx-util p { display: flex; align-items: center; gap: 8px; margin: 0; }
.hx-util-right { display: flex; align-items: center; gap: 22px; }
.hx-util b { color: #fff; font-weight: 500; }
.hx-util svg { flex: none; color: var(--hx-green-bright); stroke-width: 1.7; }
/* 28px rather than 20: WCAG 2.2 asks for 24x24 on a target that is not a
 * word inside a sentence, and this one is a standalone link in a 46px bar
 * with the room to spare. */
.hx-util-more { display: inline-flex; align-items: center; gap: 7px; padding-block: 4px; color: #fff; font-weight: 600; white-space: nowrap; }
.hx-util-more svg { color: currentColor; transition: transform .16s ease; }
.hx-util-more:hover svg { transform: translateX(3px); }

/* ------------------------------------------------------------------ header */

/*
 * A floating card rather than a bar across the page.
 *
 * It is sticky, so it has to read as a separate object from the moment it
 * detaches -- a full-width white band over a white page has nothing to
 * separate it but a shadow, and the pill has its own edges. The top padding is
 * what makes it float; when stuck it tightens rather than disappearing, so the
 * thing that moves is the gap and not the height.
 */
.hx-hd { position: sticky; top: 0; z-index: 60; padding: 18px 0; transition: padding .2s ease; }
.hx-hd.is-stuck { padding: 10px 0; }
.hx-hd-card {
  position: relative;
  display: flex;
  align-items: center;
  gap: 28px;
  height: 76px;
  padding: 0 14px 0 26px;
  border: 1px solid var(--hx-line);
  border-radius: 44px;
  background: var(--hx-surface);
  box-shadow: var(--hx-shadow-card);
  transition: box-shadow .2s ease;
}
.hx-hd.is-stuck .hx-hd-card { box-shadow: var(--hx-shadow-lift); }

.hx-brand { display: flex; align-items: center; gap: 12px; flex: none; }
.hx-brand img { width: 36px; height: 36px; }
.hx-brand span { color: var(--hx-ink); font-size: 22px; font-weight: 700; letter-spacing: -.3px; white-space: nowrap; }
/*
 * "Money" states its own weight.
 *
 * <b> carries the browser default font-weight: bolder, and bolder is relative
 * to the parent -- against the 700 on .hx-brand span that resolves to 900. So
 * the first word of the wordmark was two steps heavier than the second, in the
 * header and the footer, without anything asking for it. The <i> next to it
 * needed the same treatment for font-style, which is why that line already
 * exists; this is the missing half of the pair.
 */
.hx-brand b { font-weight: 600; }
.hx-brand i { color: var(--hx-green); font-style: normal; }

.hx-nav { display: flex; align-items: center; gap: 34px; margin-inline: auto; }
.hx-nav a {
  position: relative;
  color: var(--hx-ink-2);
  font-size: 15.4px;
  font-weight: 500;
  white-space: nowrap;
  transition: color .16s ease;
}
.hx-nav a::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -7px;
  height: 2px;
  border-radius: 2px;
  background: var(--hx-green);
  transform: scaleX(0);
  transition: transform .18s ease;
}
.hx-nav a:hover,
.hx-nav a[aria-current="page"] { color: var(--hx-green-deep); }
.hx-nav a:hover::after,
.hx-nav a[aria-current="page"]::after { transform: scaleX(1); }

.hx-hd-act { display: flex; align-items: center; gap: 14px; flex: none; }
.hx-search-open,
.hx-burger {
  display: grid;
  place-items: center;
  flex: none;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 1px solid var(--hx-line);
  border-radius: 50%;
  background: var(--hx-mint-soft);
  color: var(--hx-ink-2);
  cursor: pointer;
  transition: background .16s ease, color .16s ease;
}
.hx-search-open:hover,
.hx-burger:hover { background: var(--hx-mint); color: var(--hx-green-deep); }
.hx-signin { color: var(--hx-ink); font-size: 15.4px; font-weight: 600; white-space: nowrap; }
.hx-signin:hover { color: var(--hx-green-deep); }
.hx-avatar {
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--hx-green);
  color: #fff;
  font-size: 13px;
  font-weight: 700;
}
.hx-signin.is-signed-in { display: inline-flex; align-items: center; gap: 9px; }
.hx-signin.is-signed-in .hx-name { max-width: 130px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hx-burger { display: none; }
/* The call to action says less as the pill narrows. Both labels are in the
 * markup rather than swapped by script, so the shorter one is right on the
 * first paint instead of after it. */
.hx-cta-short { display: none; }

/* ----------------------------------------------------------------- buttons */

.hx-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  height: 54px;
  padding: 0 26px;
  border: 1px solid transparent;
  border-radius: 999px;
  background: var(--hx-green-dark);
  color: #fff;
  font-family: var(--hx-sans);
  font-size: 15.6px;
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
  transition: background .16s ease, transform .16s ease, box-shadow .16s ease;
}
.hx-btn:hover { background: var(--hx-green-darker); box-shadow: var(--hx-shadow-pill); transform: translateY(-1px); }
.hx-btn svg { stroke-width: 2; transition: transform .16s ease; }
.hx-btn:hover svg { transform: translate(3px, -3px); }
.hx-btn-sm { height: 46px; padding: 0 20px; font-size: 14.8px; }
.hx-btn-lg { height: 60px; padding: 0 32px; font-size: 16.4px; }
.hx-btn-ghost {
  border-color: var(--hx-line);
  background: var(--hx-surface);
  color: var(--hx-ink);
  box-shadow: var(--hx-shadow-card);
}
.hx-btn-ghost:hover { border-color: var(--hx-mint-line); background: var(--hx-surface); color: var(--hx-green-deep); }
.hx-btn-ghost .hx-play {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  margin-left: -10px;
  border-radius: 50%;
  background: var(--hx-green-dark);
  color: #fff;
}
.hx-btn-ghost .hx-play svg { fill: currentColor; stroke: none; transform: none; }
.hx-btn-ghost small { color: var(--hx-muted); font-size: 13.4px; font-weight: 500; }

.hx-link {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  color: var(--hx-green-deep);
  font-size: 15px;
  font-weight: 600;
}
.hx-link svg { transition: transform .16s ease; }
.hx-link:hover svg { transform: translate(3px, -3px); }

/* --------------------------------------------------------------- type parts */

/*
 * ".hx .hx-eyebrow", not ".hx-eyebrow".
 *
 * Both labels on this page are paragraphs, and every container that holds one
 * also styles its own paragraphs: .hx-head > p, .hx-block-copy > p,
 * .hx-watch-head p, .hx-life-copy > p, .hx-privacy p. Those are a class plus a
 * type, (0,1,1), and a lone class is (0,1,0) -- so the container won and
 * eleven of the twelve eyebrows rendered at 16-17px in body grey instead of
 * 11.8px green. They kept their uppercase and letter-spacing, so they did not
 * look unstyled; they looked like shouting.
 *
 * The fix is on this side rather than on the containers'. Wrapping those in
 * :where() would drop them to (0,0,1), and the base ".hx p { margin: 0 }"
 * reset is (0,1,1) -- it would start winning, and the FAQ answers would lose
 * their indent. Raising the label to (0,2,0) touches nothing else.
 */
:where(.hx, .hx-util, .hx-hd, .hx-ft, .hx-search, .hx-sticky-cta) .hx-eyebrow,
.hx-eyebrow.hx-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 8px 16px 8px 13px;
  border: 1px solid var(--hx-mint-line);
  border-radius: 999px;
  background: var(--hx-mint);
  color: var(--hx-green-deep);
  font-size: 11.8px;
  font-weight: 700;
  letter-spacing: .12em;
  line-height: 1.35;
  text-transform: uppercase;
}
.hx-eyebrow svg { flex: none; color: var(--hx-green); stroke-width: 1.9; }

/* The small line above a card's heading. The live page calls it an eyebrow
 * too, but inside a card a pill is too much furniture, so it is plain.
 *
 * Scoped like the eyebrow above, and for the same reason: .hx-card-body > p
 * and .hx-inset p are (0,1,1) and were overriding all nine of these to body
 * size and body colour. */
:where(.hx, .hx-util, .hx-hd, .hx-ft, .hx-search, .hx-sticky-cta) .hx-kicker,
.hx-kicker.hx-kicker {
  color: var(--hx-green-deep);
  font-size: 11.6px;
  font-weight: 700;
  letter-spacing: .11em;
  text-transform: uppercase;
}

/*
 * Negative tracking, because the display face is now a sans.
 *
 * The rule here used to be the opposite, and said so: tracking sat at "normal"
 * because a high-contrast display serif arrives already fitted, and pulling it
 * 2.5% tighter jammed the round letters together -- "conversations" read as
 * badly spaced rather than as a headline.
 *
 * That reasoning ended with the serif. The same note also recorded the other
 * half of the rule -- tight tracking is a sans habit, and Inter is drawn loose
 * and tightens well -- so setting the display in Inter puts -.028em back on the
 * right side of the argument.
 */
.hx-display {
  font-family: var(--hx-display);
  /*
   * 600, not the 400 the serif used.
   *
   * A display serif carries its presence in stroke contrast; a neutral sans has
   * none to trade on, so at 400 a 104px headline reads thin and unset rather
   * than quiet. 600 is the weight that gives it back, and Inter is a real
   * variable font here, so this is a drawn weight and not a synthesised one.
   */
  font-weight: 600;
  letter-spacing: -.028em;
  line-height: 1.04;
}
/*
 * The second line is accented, not italicised.
 *
 * Sixteen of the twenty-seven display headings put their second line in an
 * <em>, and the serif answered that with a true italic. The self-hosted Inter
 * is one upright file -- font-style: normal, no italic companion -- so asking
 * for italic here would not select a second design, it would make the browser
 * shear the upright one. A faux oblique on a 104px headline is the single most
 * obvious way to make a typeface look cheap.
 *
 * So the emphasis moves from slant to colour, which is the more minimal device
 * anyway: same face, same weight, brand green. The markup does not change.
 */
.hx-display em { font-style: normal; font-weight: 600; color: var(--hx-green-deep); }
/*
 * The same accent, inverted for the dark bands.
 *
 * --hx-green-deep is chosen to sit on the light ground, where it measures
 * 5.37:1. On the closing band's #102817 it measures 2.70:1 -- under the 3.0
 * that large text needs, and the darker of the two greens is the wrong way to
 * go against a dark ground. The bright green is the same accent read the other
 * direction. Scoped to the band, so the light sections keep the deep green.
 */
.hx-final-content .hx-display em { color: var(--hx-green-bright); }
.hx-hero h1 em,
.hx-head h2 em { display: block; }

/*
 * A pen, not a brush.
 *
 * The viewBox is 300x12 and it is stretched to the width of the line with
 * preserveAspectRatio="none", so a plain stroke-width is scaled by however
 * much the box had to grow -- at 420px wide a width of 6 rendered as a band
 * about 9px thick that crossed into the paragraph below. non-scaling-stroke
 * takes the stroke out of that transform, so 2.5 is 2.5 at every size, and the
 * rule can then sit where a hand would have drawn it.
 */
.hx-underline { position: relative; display: inline-block; }
.hx-underline svg {
  position: absolute;
  left: 1%;
  top: calc(100% - 4px);
  width: 97%;
  height: 12px;
  color: var(--hx-green);
  stroke-width: 2.5;
  vector-effect: non-scaling-stroke;
  opacity: .5;
}

/*
 * The handwritten notes in the margins. Decorative, and the reader loses
 * nothing by not seeing them, but they are real text rather than an image so
 * they scale and can be read out.
 */
.hx-script {
  color: var(--hx-green-deep);
  font-family: var(--hx-script);
  font-size: 27px;
  font-weight: 500;
  line-height: 1.14;
}
.hx-script-arrow { flex: none; color: var(--hx-green); opacity: .5; stroke-width: 1.7; }

/* -------------------------------------------------------------------- hero */

.hx-hero { position: relative; padding: 26px 0 90px; }
.hx-hero-in {
  display: grid;
  grid-template-columns: minmax(0, .92fr) minmax(0, 1.08fr);
  align-items: center;
  gap: 56px;
}
/* Room under the last line for the drawn rule, which is positioned out of
 * flow and would otherwise be overlapped by whatever follows the heading. */
.hx-hero h1 { margin: 26px 0 0; padding-bottom: 14px; font-size: clamp(46px, 5.1vw, 74px); }
.hx-hero h1 .hx-lead-line { display: block; }
.hx-hero-lead { max-width: 58ch; margin-top: 26px; color: var(--hx-body); font-size: 17.6px; line-height: 1.62; }
.hx-hero-cta { display: flex; flex-wrap: wrap; align-items: center; gap: 16px; margin-top: 36px; }

.hx-trust { display: flex; flex-wrap: wrap; gap: 14px 34px; margin-top: 42px; }
.hx-trust li { display: flex; align-items: center; gap: 12px; }
.hx-trust-ico {
  display: grid;
  place-items: center;
  flex: none;
  width: 42px;
  height: 42px;
  border: 1px solid var(--hx-mint-line);
  border-radius: 50%;
  background: var(--hx-mint);
  color: var(--hx-green-deep);
}
.hx-trust b { display: block; color: var(--hx-ink); font-size: 14.8px; font-weight: 600; }
.hx-trust span span { color: var(--hx-muted); font-size: 13.2px; }

/*
 * The second hand-written note, now under the photograph rather than under the
 * copy column's trust row.
 *
 * margin-left: auto pushes it to the far edge of the caption, so the two notes
 * read as separate marginalia on the picture instead of one run-on line. Its
 * own items sit on the note's baseline, which is what the old .hx-hero-note
 * did -- the caption itself aligns to flex-start for the other note's arrow,
 * which has to meet the image.
 */
/*
 * Each note keeps its arrow; the caption keeps them apart.
 *
 * space-between on the caption rather than an auto margin on the second note,
 * because it does the right thing in both states: on one row the two are pushed
 * to opposite ends of the picture, and once they wrap each sits at the start of
 * its own row. The auto margin only handled the first of those, and had to be
 * switched off below 1180 -- which left the pair 10px apart on a tablet, close
 * enough that the eye read straight across them.
 */
.hx-hero-cap-note { display: flex; align-items: flex-start; gap: 10px; }
.hx-hero-cap-end { align-items: flex-end; }
.hx-hero-cap-end .hx-script-arrow { margin-bottom: 4px; }

.hx-hero-art { position: relative; }
.hx-hero-art > img { width: 100%; height: auto; border-radius: 30px; box-shadow: var(--hx-shadow-lift); }
.hx-hero-art figcaption { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: flex-start; gap: 14px 28px; margin-top: 18px; padding-left: 6%; }
.hx-hero-art figcaption .hx-script { font-size: 25px; }

/*
 * The card lifted off the photo.
 *
 * It is markup rather than part of the image, so its words are real text that
 * can be read, translated and corrected -- something baked into a photograph
 * cannot be any of those. Hidden from assistive technology because the
 * photograph's own alt text already says what it shows.
 */
.hx-float {
  position: absolute;
  z-index: 2;
  padding: 15px 18px;
  border: 1px solid var(--hx-line);
  border-radius: 18px;
  background: rgba(255, 255, 255, .94);
  box-shadow: var(--hx-shadow-lift);
  backdrop-filter: blur(6px);
}
.hx-float-tip {
  right: 2%;
  bottom: 16%;
  width: 224px;
  border-color: transparent;
  background: var(--hx-green-dark);
  color: rgba(255, 255, 255, .9);
  font-size: 14px;
  line-height: 1.45;
}
.hx-float-tip b { color: #fff; font-weight: 600; }

/* ----------------------------------------------------------- section frame */

/*
 * Anchored sections clear the sticky header.
 *
 * Without this the browser scrolls the section's own top edge to y=0, which is
 * 112px behind the header: the band's colour change is hidden entirely and the
 * eyebrow clears by four pixels, so "Features" in the navigation lands on
 * something that looks like the middle of a section. scroll-margin-top moves
 * only the scroll target, not the layout.
 */
[id] { scroll-margin-top: 136px; }

.hx-section { padding: 96px 0; }
.hx-section-white { background: var(--hx-surface); }
.hx-head { max-width: 820px; }
.hx-head.is-centred { margin-inline: auto; text-align: center; }
.hx-head.is-centred .hx-eyebrow { justify-content: center; }
.hx-head h2 { margin-top: 22px; font-size: var(--hx-h-section); }
/*
 * A cap on the measure, in ch so it follows the font size.
 *
 * These ran to 96 characters a line on a 1440px viewport -- comfortably past
 * the 45-75 a reader tracks without losing the line, and worse for being
 * centred, because a long centred line gives the eye no fixed left edge to
 * return to.
 */
.hx-head > p { max-width: 68ch; margin-top: 20px; color: var(--hx-body); font-size: 17px; }
.hx-head.is-centred > p { margin-inline: auto; }

/* ----------------------------------------------------------------- clients */

.hx-client-list {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 12px 14px;
  margin-top: 30px;
}
.hx-client-list li {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 9px 16px;
  border: 1px solid var(--hx-line);
  border-radius: 999px;
  background: var(--hx-ground);
  color: var(--hx-ink-2);
  font-size: 14.6px;
  font-weight: 600;
}
.hx-client-list img { width: 22px; height: 22px; border-radius: 6px; }
.hx-fineprint { margin-top: 18px; color: var(--hx-muted); font-size: 12.6px; }

/*
 * The two alternating blocks. Copy one side, photograph the other, and the
 * second one reversed -- the live page's .v2-block / .v2-block-flip pair.
 */
.hx-block {
  display: grid;
  grid-template-columns: minmax(0, .88fr) minmax(0, 1.12fr);
  align-items: center;
  gap: 56px;
  margin-top: 86px;
}
/*
 * The flip swaps the tracks, not just the items.
 *
 * "order: 2" on the copy moved it to the right, but the columns stayed
 * .88fr / 1.12fr -- so on the flipped block the copy landed in the wide track
 * and the photograph in the narrow one. The two blocks rendered their photos
 * at 722px and 567px, which reads as a mistake rather than as a rhythm, and
 * the copy stretched to 87 characters a line. Mirroring the tracks keeps the
 * photograph wide in both and the measure where it belongs.
 */
.hx-block-flip { grid-template-columns: minmax(0, 1.12fr) minmax(0, .88fr); }
.hx-block-flip .hx-block-copy { order: 2; }
.hx-block-copy h3 { margin: 20px 0 18px; font-size: var(--hx-h-sub); }
.hx-block-copy > p { max-width: 58ch; color: var(--hx-body); font-size: 16.6px; }
.hx-block-copy .hx-btn { margin-top: 26px; }
.hx-block-art img { width: 100%; height: auto; border-radius: 26px; box-shadow: var(--hx-shadow-lift); }
.hx-block-art figcaption,
.hx-card-art figcaption,
.hx-month-art figcaption { margin-top: 14px; color: var(--hx-muted); font-size: 13.4px; }
.hx-block-art figcaption { text-align: center; }

/*
 * The foldable under the client list: one money layer, two assistants.
 *
 * Deliberately not .hx-block-art. That rule rounds the corners and drops a
 * lifted shadow, and both assume a rectangular screenshot sitting on a card.
 * This is a cutout on transparency, so the radius would clip nothing and the
 * shadow would trace the bounding box instead of the phone -- a rectangle of
 * shade drawn around a pair of hands.
 *
 * 880px because that is the widest the master stays sharp at: the source is
 * 1448 across, so a 2x screen still has 1.65x of real pixels to draw with.
 */
.hx-clients-art { max-width: 880px; margin: 52px auto 0; }
.hx-clients-art img { display: block; width: 100%; height: auto; }
.hx-clients-art figcaption {
  margin-top: 16px;
  color: var(--hx-muted);
  font-size: 13.4px;
  text-align: center;
}

/* ------------------------------------------------------------------- cards */

/*
 * Two columns with rows that line up.
 *
 * This was a downward-filling multicol, copied from the live page, where it
 * works because that design separates cards with rules rather than boxes -- a
 * column ending short of its neighbour is invisible when there is no box edge
 * to notice. Here the cards are shadowed surfaces, and the Features run left
 * the right column finishing about 340px above the left, which read as ragged
 * rather than as masonry.
 *
 * So: a real grid. Cards in a row stretch to the taller of the two, so their
 * bottom edges align. The five-card run's odd one out is the note card, which
 * has no image and spans both columns -- it closes the set instead of being
 * stranded in a half-width cell.
 */
.hx-cards {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 24px;
  margin-top: 54px;
}
.hx-card-note { grid-column: 1 / -1; }
.hx-card {
  /* A column, so the body can take the slack the row's height gives it and
     keep a call to action on the bottom edge. */
  display: flex;
  flex-direction: column;
  padding: 22px;
  border: 1px solid var(--hx-line);
  border-radius: 26px;
  background: var(--hx-surface);
  box-shadow: var(--hx-shadow-card);
  transition: transform .18s ease, box-shadow .18s ease;
}
.hx-section-white .hx-card { background: var(--hx-ground); }
.hx-card:hover { box-shadow: var(--hx-shadow-lift); transform: translateY(-3px); }
/*
 * The screenshots are shown whole.
 *
 * These were edge-to-edge with "height: 232px; object-fit: cover", which is
 * the right treatment for a photograph and the wrong one for a document: every
 * one of these is a dense dashboard screenshot, and cropping it to a 232px
 * band left a horizontal sliver of unreadable interface. A card whose whole
 * job is "look at this screen" was showing about a fifth of it.
 *
 * So: natural aspect ratio, and the image sits inside the card's padding with
 * its own border and shadow, which is what the live page does -- it reads as a
 * framed object rather than as a banner the card was cut from. Card heights
 * then vary with the images, which is exactly what the two-column flow is for.
 */
.hx-card-art { margin-bottom: 18px; }
/*
 * No frame on a card screenshot.
 *
 * It had a 1px border, which read as a box drawn around a picture that is
 * already a box. The soft shadow is enough to lift it off the card, and the
 * corner radius is enough to say it is a screen. The month figure below keeps
 * its frame: that one is a standalone figure on an open section rather than an
 * object inside a card.
 */
.hx-card-art img {
  width: 100%;
  height: auto;
  border-radius: 16px;
  background: var(--hx-surface);
  box-shadow: var(--hx-shadow-card);
}
.hx-card-art figcaption {
  margin-top: 12px;
  color: var(--hx-muted);
  font-size: 11.6px;
  font-weight: 600;
  letter-spacing: .08em;
  text-align: center;
  text-transform: uppercase;
}
/* A grid rather than a column flex: inside a multicol the card has no
 * definite height, so "flex: 1" and "margin-top: auto" had nothing to measure
 * against and the link simply sat under the copy anyway. This says that. */
.hx-card-body { display: flex; flex-direction: column; align-items: flex-start; flex: 1; gap: 12px; }
.hx-card-body h3 { font-size: var(--hx-h-card); }
/* 60ch rather than the full 607px a card gets in the two-column flow, which
 * was 80 characters a line. */
.hx-card-body > p { max-width: 60ch; color: var(--hx-body); font-size: 15.2px; }
/* Pinned to the bottom of the card, which a stretched row now gives a
 * definite height to measure against. */
.hx-card-body .hx-link { margin-top: auto; padding-top: 6px; }

/*
 * What the sentence turns into.
 *
 * The logging card's screenshot is landscape where its neighbour's is portrait
 * -- 370px against 714px -- so the stretched row left it with 332px of empty
 * surface above a link pinned to the bottom edge. That was the one place on
 * the page where a shadowed card showed as a void.
 *
 * Filled with the thing the paragraph above is describing rather than with
 * more paragraph: the sentences somebody actually types on the left, and the
 * amount and category taken out of them on the right. The claim is the card's
 * own -- "works out the amount, the category and the date" -- shown instead of
 * asserted a second time.
 *
 * width: 100% because .hx-card-body aligns its children to flex-start, so a
 * list left to its own intrinsic width sits narrower than the copy above it.
 */
.hx-says {
  display: grid;
  gap: 10px;
  width: 100%;
  margin: 2px 0 0;
  padding: 0;
  list-style: none;
}
.hx-says li {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 4px 14px;
  padding: 13px 16px;
  border: 1px solid var(--hx-mint-line);
  border-radius: 14px;
  background: var(--hx-mint-soft);
}
.hx-says-in { color: var(--hx-ink); font-size: 14.8px; line-height: 1.4; }
.hx-says-out {
  flex: none;
  /* --hx-green measured 4.06:1 against the mint fill these rows sit on, which
     is under the 4.5 that 11.8px text needs. The deep green is the same hue a
     step darker and clears it. */
  color: var(--hx-green-deep);
  font-size: 11.8px;
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
}

/*
 * A tick list ends a card, so it sits on the bottom edge like the link does.
 *
 * The four #features cards pair screenshots of different natural heights --
 * 417px against 546px in the top row -- and the shorter card took the whole
 * difference as blank surface underneath its ticks. Same slack either way; the
 * question is only where it falls. Above the list it reads as breathing room
 * between copy and claims, and the tick blocks line up across the row; below
 * it, it read as the card having run out.
 *
 * Only when nothing else is already claiming the space: a card with a link
 * has .hx-link { margin-top: auto } for exactly this, and the first auto
 * margin in a column takes the slack, so the two never fight.
 */
.hx-card-body .hx-ticks { margin-top: auto; padding-top: 4px; }

.hx-ticks { display: grid; gap: 10px; }
.hx-ticks li { display: flex; gap: 10px; color: var(--hx-body); font-size: 14.8px; line-height: 1.45; }
.hx-ticks svg { flex: none; margin-top: 4px; color: var(--hx-green); stroke-width: 2.4; }

/* The last card in the run carries no photograph -- three claims and a boxed
 * note, as on the live page. */
/* Spanning the row, so its three claims and the boxed note sit side by side
 * rather than stacked down a half-width column. */
.hx-card-note { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr); align-items: center; gap: 28px; }
.hx-inset {
  display: grid;
  gap: 10px;
  padding: 22px;
  border: 1px solid var(--hx-mint-line);
  border-radius: 18px;
  background: var(--hx-mint-soft);
}
.hx-inset h4 { font-size: var(--hx-h-card); }
.hx-inset p { max-width: 56ch; color: var(--hx-body); font-size: 14.6px; }

/* ------------------------------------------------------------------- video */

.hx-watch { margin-top: 74px; text-align: center; }
.hx-watch-head { max-width: 720px; margin-inline: auto; }
.hx-watch-head h3 { margin: 20px 0 14px; font-size: var(--hx-h-sub); }
.hx-watch-head p { max-width: 62ch; margin-inline: auto; color: var(--hx-body); font-size: 16.4px; }
.hx-watch-frame {
  position: relative;
  max-width: 980px;
  margin: 34px auto 0;
  overflow: hidden;
  border: 1px solid var(--hx-line);
  border-radius: 26px;
  background: var(--hx-ground-2);
  box-shadow: var(--hx-shadow-lift);
}
.hx-watch-frame iframe { display: block; width: 100%; aspect-ratio: 16 / 9; border: 0; }
.hx-watch-play { display: block; width: 100%; padding: 0; border: 0; background: none; cursor: pointer; }
.hx-watch-play img { width: 100%; height: auto; }
.hx-watch-mark {
  position: absolute;
  left: 50%;
  top: 50%;
  display: grid;
  place-items: center;
  width: 78px;
  height: 78px;
  border-radius: 50%;
  background: rgba(23, 56, 31, .88);
  color: #fff;
  transform: translate(-50%, -50%);
  transition: transform .18s ease, background .18s ease;
}
.hx-watch-mark svg { fill: currentColor; stroke: none; margin-left: 4px; }
.hx-watch-play:hover .hx-watch-mark { background: var(--hx-green-darker); transform: translate(-50%, -50%) scale(1.06); }
.hx-watch-note { margin-top: 16px; color: var(--hx-muted); font-size: 13px; }

/* ------------------------------------------------------------ month figure */

/*
 * The one image on the page that is a document rather than a photograph: a
 * whole month of dashboard. It gets its own width and no crop, because
 * object-fit on this would cut off the half of it the caption promises.
 */
.hx-month-art { max-width: 1180px; margin: 54px auto 0; text-align: center; }
.hx-month-art img {
  width: 100%;
  height: auto;
  border: 1px solid var(--hx-frame);
  border-radius: 26px;
  background: var(--hx-surface);
  box-shadow: var(--hx-shadow-lift);
}

/* ------------------------------------------------------------------- steps */

.hx-steps { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 20px; margin-top: 54px; }
.hx-step {
  padding: 30px;
  border: 1px solid var(--hx-mint-line);
  border-radius: 24px;
  background: var(--hx-mint-soft);
}
.hx-section-white .hx-step { background: var(--hx-ground); }
.hx-step-num {
  display: grid;
  place-items: center;
  width: 46px;
  height: 46px;
  margin-bottom: 22px;
  border-radius: 50%;
  background: var(--hx-green-dark);
  color: #fff;
  font-size: 15px;
  font-weight: 700;
}
.hx-step h3 { margin-bottom: 9px; font-size: 20px; }
.hx-step p { color: var(--hx-body); font-size: 14.8px; }
.hx-steps-foot { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 16px; margin-top: 34px; }
.hx-steps-foot p { color: var(--hx-muted); font-size: 14px; }

.hx-steps-art { max-width: 760px; margin: 54px auto 0; text-align: center; }
.hx-steps-art img { width: 100%; height: auto; border-radius: 26px; box-shadow: var(--hx-shadow-lift); }
.hx-steps-art figcaption {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  margin-top: 18px;
  color: var(--hx-ink-2);
  font-size: 13.6px;
  font-weight: 600;
}
/* The arrow between "Receipt in" and "Clear record out". */
.hx-steps-art figcaption i {
  width: 46px;
  height: 1px;
  background: var(--hx-mint-line);
}

/* -------------------------------------------------------- built for real life */

.hx-life-in {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, .9fr);
  align-items: center;
  gap: 64px;
}
.hx-life-art img { width: 100%; height: auto; border-radius: 28px; box-shadow: var(--hx-shadow-lift); }
.hx-life-copy h2 { margin: 20px 0 18px; font-size: var(--hx-h-band); }
.hx-life-copy > p { max-width: 58ch; color: var(--hx-body); font-size: 16.6px; }
.hx-life-list { display: grid; margin-top: 30px; border-top: 1px solid var(--hx-line); }
.hx-life-list li { display: grid; grid-template-columns: 46px minmax(0, 1fr); gap: 16px; padding: 20px 0; border-bottom: 1px solid var(--hx-line); }
.hx-life-num { color: var(--hx-green-deep); font-size: 12px; font-weight: 700; letter-spacing: .1em; }
.hx-life-list b { display: block; margin-bottom: 5px; color: var(--hx-ink); font-size: 16px; }
.hx-life-list p { color: var(--hx-body); font-size: 14.6px; }
.hx-life-copy .hx-link { margin-top: 26px; }

/* ----------------------------------------------------------------- privacy */

.hx-privacy { background: var(--hx-green-darker); color: rgba(255, 255, 255, .82); }
.hx-privacy-in { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 40px; padding: 76px 0; }
.hx-privacy .hx-eyebrow { border-color: rgba(255, 255, 255, .2); background: rgba(255, 255, 255, .09); color: #a7e9c3; }
.hx-privacy .hx-eyebrow svg { color: #a7e9c3; }
.hx-privacy h2 { margin: 22px 0 16px; color: #fff; font-size: var(--hx-h-band); }
.hx-privacy p { max-width: 64ch; font-size: 16.4px; }
.hx-privacy .hx-btn-ghost { border-color: rgba(255, 255, 255, .26); background: transparent; color: #fff; box-shadow: none; }
.hx-privacy .hx-btn-ghost:hover { background: rgba(255, 255, 255, .1); color: #fff; }

/* ----------------------------------------------------------------- pricing */

.hx-plans { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 20px; margin-top: 54px; }
.hx-plan {
  display: flex;
  flex-direction: column;
  padding: 32px;
  border: 1px solid var(--hx-line);
  border-radius: 26px;
  background: var(--hx-surface);
}
.hx-section-white .hx-plan { background: var(--hx-ground); }
.hx-plan.is-featured { border-color: var(--hx-green-dark); background: var(--hx-green-dark); color: rgba(255, 255, 255, .84); }
.hx-plan.is-featured h3,
.hx-plan.is-featured strong { color: #fff; }
.hx-plan > span { color: var(--hx-muted); font-size: 11.8px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase; }
.hx-plan.is-featured > span { color: #a7e9c3; }
/*
 * The plan name and the price carry the display weight, like every other
 * heading. Both said font-weight: 400, which was not a choice -- it was the
 * only weight the display serif had. With a sans in that slot these two were
 * the only headings on the page still at 400, and a 42px price set lighter
 * than the 24px card headings above it is the wrong thing to under-emphasise.
 * Tracking matches .hx-display for the same reason.
 */
.hx-plan h3 { margin: 14px 0 10px; font-family: var(--hx-display); font-size: var(--hx-h-sub); font-weight: 600; letter-spacing: -.028em; }
.hx-plan-price { display: flex; align-items: baseline; gap: 8px; padding-bottom: 24px; border-bottom: 1px solid var(--hx-line); }
.hx-plan.is-featured .hx-plan-price { border-color: rgba(255, 255, 255, .2); }
.hx-plan-price strong { color: var(--hx-ink); font-family: var(--hx-display); font-size: 42px; font-weight: 600; letter-spacing: -.028em; }
.hx-plan-price span { color: var(--hx-muted); font-size: 14px; }
.hx-plan.is-featured .hx-plan-price span { color: rgba(255, 255, 255, .7); }
.hx-plan ul { display: grid; gap: 12px; margin: 24px 0 28px; }
.hx-plan li { display: flex; gap: 11px; font-size: 14.8px; }
.hx-plan li svg { flex: none; margin-top: 4px; color: var(--hx-green); stroke-width: 2.4; }
.hx-plan.is-featured li svg { color: #7fe0ab; }
.hx-plan .hx-btn { width: 100%; margin-top: auto; }
.hx-plan.is-featured .hx-btn { background: #fff; color: var(--hx-green-dark); }
.hx-plan.is-featured .hx-btn:hover { background: var(--hx-mint); }
.hx-plans-note { max-width: 62ch; margin: 22px auto 0; color: var(--hx-muted); font-size: 14px; text-align: center; }
.hx-plans-note .hx-link { justify-content: center; }

/*
 * The states pricing.js introduces, in this theme's own materials.
 *
 * The three cards shipped as three identical offers, so the section had no way
 * to say "this one is already yours" and no button that could start a checkout
 * -- a signed-in reader was shown the same trial link as a stranger. These are
 * the light theme's half of that; home.css carries the same states for the
 * older card on /pricing.
 */
.hx-plan.is-current { border-color: var(--hx-green); box-shadow: var(--hx-shadow-card); }
.hx-plan.is-featured.is-current { border-color: var(--hx-green-bright); }
/*
 * Two classes on purpose. `.hx-plan > span` is the eyebrow rule at (0,1,1), and
 * the badge is a direct-child span too -- at (0,1,0) it lost, and the badge
 * rendered as a second line of uppercase grey directly above the real eyebrow.
 */
.hx-plan .hx-plan-badge {
  align-self: flex-start;
  margin-bottom: 12px;
  padding: 5px 11px;
  border-radius: 999px;
  background: var(--hx-mint);
  color: var(--hx-green-deep);
  font-size: 11.4px;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
}
.hx-plan.is-featured .hx-plan-badge { background: rgba(255, 255, 255, .16); color: #a7e9c3; }
/* A limit the plan does not carry gets a dash, not a faded tick. A tick means
   yes, and dimming one is not a way to say no. */
.hx-plan li.is-off { color: var(--hx-muted); }
.hx-plan li.is-off svg { color: var(--hx-frame); }
.hx-plan.is-featured li.is-off { color: rgba(255, 255, 255, .6); }
.hx-plan.is-featured li.is-off svg { color: rgba(255, 255, 255, .42); }
/* Present and inert rather than absent: the card keeps its height and the row
   of three buttons keeps one baseline. */
.hx-btn.is-disabled { background: var(--hx-mint); box-shadow: none; color: var(--hx-green-deep); pointer-events: none; }
.hx-plan.is-featured .hx-btn.is-disabled { background: rgba(255, 255, 255, .16); color: #fff; }
/*
 * The eyebrow rule again, and the reason it is worth a second note: the inert
 * button and the note below it are direct-child spans too, so `.hx-plan > span`
 * reached both. The current plan's button came out at the eyebrow's 11.8px
 * uppercase while the two live buttons beside it were 15.6px sentence case --
 * the one card a reader is looking for was the one with the wrong button on it.
 */
.hx-plan .hx-btn.is-disabled { font-size: 15.6px; font-weight: 600; letter-spacing: normal; text-transform: none; }
.hx-plan .hx-plan-note {
  margin-top: auto;
  padding-top: 10px;
  color: var(--hx-muted);
  font-size: 13.4px;
  font-weight: 600;
  letter-spacing: normal;
  text-transform: none;
}

/* ------------------------------------------------------- the upgrade sheet */

/*
 * Shown before anybody is sent to Stripe, so the price, the interval and what
 * changes are all stated once more on this site rather than first appearing on
 * a payment page. A real <dialog>, so the top layer, the focus trap and Escape
 * are the platform's job -- the same bargain .hx-search makes, and it borrows
 * that dialog's entrance for the same reason.
 */
.hx-upgrade {
  width: min(460px, calc(100vw - 32px));
  margin: auto;
  padding: 0;
  border: 0;
  background: none;
}
.hx-upgrade::backdrop { background: rgba(16, 40, 23, .42); backdrop-filter: blur(3px); }
.hx-upgrade[open] { animation: hx-search-open .19s cubic-bezier(.2, .8, .3, 1) both; }
.hx-upgrade[open]::backdrop { animation: hx-search-veil .22s ease-out both; }
.hx-upgrade .upgrade-sheet {
  padding: 30px;
  border: 1px solid var(--hx-line);
  border-radius: 26px;
  background: var(--hx-surface);
  box-shadow: 0 40px 90px -40px rgba(18, 52, 34, .5);
}
.hx-upgrade .upgrade-kicker { margin: 0 0 10px; color: var(--hx-green); font-size: 11.4px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase; }
.hx-upgrade h2 { margin: 0; color: var(--hx-ink); font-family: var(--hx-display); font-size: 30px; font-weight: 600; letter-spacing: -.028em; }
.hx-upgrade .upgrade-line { display: flex; align-items: baseline; gap: 8px; margin: 10px 0 22px; padding-bottom: 20px; border-bottom: 1px solid var(--hx-line); }
.hx-upgrade .upgrade-line strong { color: var(--hx-ink); font-family: var(--hx-display); font-size: 34px; font-weight: 600; letter-spacing: -.028em; }
.hx-upgrade .upgrade-line span { color: var(--hx-muted); font-size: 14px; }
.hx-upgrade .upgrade-what { margin: 0 0 12px; color: var(--hx-muted); font-size: 11.4px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; }
.hx-upgrade .upgrade-gets { display: grid; gap: 10px; margin: 0 0 20px; padding: 0; list-style: none; }
.hx-upgrade .upgrade-gets li { position: relative; padding-inline-start: 24px; color: var(--hx-ink-2); font-size: 14.8px; line-height: 1.5; }
.hx-upgrade .upgrade-gets li::before { content: "\2713"; position: absolute; inset-inline-start: 0; color: var(--hx-green); font-weight: 800; }
.hx-upgrade .upgrade-small { margin: 0 0 20px; color: var(--hx-muted); font-size: 13.2px; line-height: 1.6; }
.hx-upgrade .upgrade-actions { display: grid; gap: 10px; }
.hx-upgrade .upgrade-actions .hx-btn { width: 100%; }
.hx-upgrade .upgrade-cancel {
  height: 46px;
  border: 1px solid var(--hx-line);
  border-radius: 999px;
  background: none;
  color: var(--hx-muted);
  font-family: var(--hx-sans);
  font-size: 14.8px;
  font-weight: 600;
  cursor: pointer;
}
.hx-upgrade .upgrade-cancel:hover { border-color: var(--hx-mint-line); color: var(--hx-ink); }
@media (max-width: 560px) {
  .hx-upgrade .upgrade-sheet { padding: 22px; }
  .hx-upgrade h2 { font-size: 26px; }
}

/* --------------------------------------------------------------------- faq */

.hx-faq-in { display: grid; grid-template-columns: minmax(0, .8fr) minmax(0, 1.2fr); gap: 64px; }
.hx-faq-link { margin-top: 20px; }
.hx-faq-list { border-top: 1px solid var(--hx-line); }
.hx-faq details { border-bottom: 1px solid var(--hx-line); }
.hx-faq summary {
  display: grid;
  grid-template-columns: 42px minmax(0, 1fr) 28px;
  align-items: center;
  gap: 10px;
  padding: 24px 0;
  color: var(--hx-ink);
  font-size: 17.4px;
  font-weight: 600;
  cursor: pointer;
  list-style: none;
}
.hx-faq summary::-webkit-details-marker { display: none; }
.hx-faq summary:hover { color: var(--hx-green-deep); }
.hx-faq summary span { color: var(--hx-green-deep); font-size: 12px; font-weight: 700; letter-spacing: .1em; }
.hx-faq summary i { position: relative; width: 26px; height: 26px; border: 1px solid var(--hx-line); border-radius: 50%; }
.hx-faq summary i::before,
.hx-faq summary i::after { content: ""; position: absolute; left: 7px; right: 7px; top: 12px; height: 1.5px; border-radius: 2px; background: currentColor; }
.hx-faq summary i::after { transform: rotate(90deg); transition: transform .18s ease; }
.hx-faq details[open] summary i::after { transform: none; }
/* The script holds a closing panel open until it has finished shrinking, so
 * [open] is still true while the answer slides away. This is what turns the
 * marker back into a plus at the moment of the click instead of after it.
 * Same specificity as the rule above and placed after it, deliberately. */
.hx-faq details.is-shut summary i::after { transform: rotate(90deg); }
.hx-faq details > p { margin: -6px 0 24px 52px; max-width: 68ch; color: var(--hx-body); font-size: 15.4px; }

/* --------------------------------------------------------------- final cta */

/*
 * The photograph is the section, with the copy over it -- the live page's
 * .final-cta. The overlay is a sibling div rather than a pseudo-element so it
 * can sit between the image and the text without a z-index fight.
 */
/* The dark ground is on the section as well as on the overlay. The overlay
 * paints it in practice, but the white text over it should not depend on one
 * absolutely-positioned div having laid itself out. */
.hx-final { position: relative; isolation: isolate; overflow: hidden; background: var(--hx-green-darker); }
.hx-final-photo { position: absolute; inset: 0; z-index: -1; }
.hx-final-photo img { width: 100%; height: 100%; object-fit: cover; }
.hx-final-photo div { position: absolute; inset: 0; background: linear-gradient(180deg, rgba(10, 26, 16, .78), rgba(10, 26, 16, .92)); }
.hx-final-content {
  display: grid;
  justify-items: center;
  gap: 18px;
  width: min(760px, calc(100% - 64px));
  margin-inline: auto;
  padding: 104px 0;
  color: rgba(255, 255, 255, .84);
  text-align: center;
}
.hx-final-content img { width: 54px; height: 54px; }
.hx-final-content > p { font-size: 16.4px; }
.hx-final-content h2 { color: #fff; font-size: var(--hx-h-band); }
.hx-final-content .hx-btn { margin-top: 10px; background: #fff; color: var(--hx-green-dark); }
.hx-final-content .hx-btn:hover { background: var(--hx-mint); }
.hx-final-content small { color: rgba(255, 255, 255, .64); font-size: 13.4px; }

/* -------------------------------------------------------------- sticky cta */

/*
 * The phone-only bar that appears once the reader is past the hero and goes
 * away again over the final call, which already asks for the same thing. The
 * live page has the same element; it is hidden until the script decides, so it
 * never flashes on a page that has not scrolled.
 */
.hx-sticky-cta {
  position: fixed;
  left: 12px;
  right: 12px;
  bottom: 12px;
  z-index: 50;
  display: none;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 12px 12px 12px 18px;
  border: 1px solid var(--hx-line);
  border-radius: 18px;
  background: rgba(255, 255, 255, .96);
  box-shadow: var(--hx-shadow-lift);
  backdrop-filter: blur(8px);
}
.hx-sticky-cta[hidden] { display: none; }

/*
 * Back to the top.
 *
 * Fixed and hidden until the page has scrolled. A static one only arrives once
 * you have already reached the bottom, which is the single moment it is no
 * longer useful -- and that is exactly what these pages were shipping: markup
 * for a button the retired shell used to style and drive, sitting in the flow
 * below the footer in the browser's default chrome, bound to nothing.
 *
 * home-v3.js toggles .is-up from an IntersectionObserver on .hx-sentinel, so
 * showing it costs no scroll handler and no layout read per frame.
 *
 * visibility, not opacity alone: a transparent button is still a focus stop,
 * and tabbing to something nobody can see is worse than not offering it.
 *
 * Its own box-sizing and svg rules because it is a child of <body>, outside
 * every .hx wrapper -- the shell's :where() resets do not reach it, and on the
 * pages whose body is not .hx the arrow would otherwise paint as a black
 * filled shape rather than a stroked one.
 */
.hx-to-top {
  position: fixed;
  right: 20px;
  bottom: 20px;
  z-index: 45;
  box-sizing: border-box;
  display: grid;
  place-items: center;
  width: 46px;
  height: 46px;
  padding: 0;
  border: 1px solid var(--hx-mint-line);
  border-radius: 50%;
  background: rgba(255, 255, 255, .94);
  color: var(--hx-green-deep);
  box-shadow: var(--hx-shadow-lift);
  backdrop-filter: blur(8px);
  cursor: pointer;
  visibility: hidden;
  opacity: 0;
  translate: 0 8px;
  transition: opacity .2s ease, translate .2s ease, visibility .2s;
}
.hx-to-top svg { fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.hx-to-top.is-up { visibility: visible; opacity: 1; translate: none; }
.hx-to-top:hover { border-color: var(--hx-green); background: #fff; }
.hx-sticky-cta span { display: grid; gap: 2px; }
.hx-sticky-cta b { color: var(--hx-ink); font-size: 14.6px; font-weight: 700; }
.hx-sticky-cta small { color: var(--hx-muted); font-size: 12.2px; }

/* ------------------------------------------------------------------ footer */

.hx-ft { padding: 76px 0 0; border-top: 1px solid var(--hx-line); background: var(--hx-surface); }
.hx-ft-top { display: grid; grid-template-columns: 1.4fr repeat(3, 1fr); gap: 40px; }
/*
 * The brand block: tagline, the registered company and its address, the
 * support address, and the social row. Copied from the live footer rather than
 * rewritten -- a postal address is not the sort of thing to paraphrase.
 */
.hx-ft-brand .hx-brand img { width: 44px; height: 44px; }
.hx-ft-note { max-width: 330px; margin-top: 22px; color: var(--hx-body); font-size: 15.6px; line-height: 1.6; }
.hx-ft-address {
  margin-top: 14px;
  color: var(--hx-muted);
  font-size: 14px;
  /* <address> is italic by default in every browser, and this is a postal
     address rather than an aside. */
  font-style: normal;
  line-height: 1.6;
}
.hx-ft-address strong { color: var(--hx-ink); font-weight: 600; }
/*
 * The company name, linked to the company site.
 *
 * It keeps the surrounding colour -- the shell's link reset gives it
 * `color: inherit` and the name should not turn green in the middle of an
 * address or a copyright line. The underline on hover is the whole affordance,
 * so it needs the same (0,3,1) the footer's mailto uses: the chrome's own
 * `.hx-ft a:hover { text-decoration: none }` sits at (0,2,1) and would
 * otherwise leave these two looking like plain text that happens to be
 * clickable.
 */
.hx-ft a.hx-ft-org:hover { text-decoration: underline; }
.hx-ft-email { display: inline-block; margin-top: 10px; color: var(--hx-green-deep); font-weight: 600; }
.hx-ft-email:hover { text-decoration: underline; }

.hx-ft-social { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 20px; }
.hx-ft-social a {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border: 1px solid var(--hx-line);
  border-radius: 12px;
  background: var(--hx-surface);
  /* Each brand sets --social-color below; the fallback keeps an unknown one
     legible rather than invisible. */
  color: var(--social-color, var(--hx-ink-2));
  transition: transform .16s ease, border-color .16s ease, background .16s ease;
}
.hx-ft-social a:hover { transform: translateY(-2px); border-color: var(--social-color, var(--hx-mint-line)); background: var(--hx-mint-soft); }
.hx-social-instagram { --social-color: #c13584; }
.hx-social-threads { --social-color: #101010; }
.hx-social-x { --social-color: #101010; }
.hx-social-tiktok { --social-color: #010101; }
.hx-social-linkedin { --social-color: #0a66c2; }
.hx-social-facebook { --social-color: #1877f2; }
.hx-social-email { --social-color: var(--hx-green-deep); }
.hx-ft h2 { margin-bottom: 18px; color: var(--hx-ink); font-size: 13px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase; }
.hx-ft-col li + li { margin-top: 13px; }
.hx-ft-col a { color: var(--hx-body); font-size: 14.8px; }
.hx-ft-col a:hover { color: var(--hx-green-deep); }
.hx-ft-base {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  margin-top: 56px;
  padding: 26px 0;
  border-top: 1px solid var(--hx-line);
  color: var(--hx-muted);
  font-size: 13.8px;
}
.hx-ft-base ul { display: flex; gap: 20px; }

/* ------------------------------------------------------------------ search */

/*
 * Search over the pages, not over anybody's money.
 *
 * The index is a static file built from the pages themselves by
 * scripts/build-search-index.mjs and fetched on first open, so nothing is
 * typed anywhere but this browser and there is no query string to leak. The
 * dialog is a real <dialog>: it gets the top layer, the focus trap and the
 * Escape key from the platform rather than from script.
 */
.hx-search[open] {
  display: flex;
  /* Entrance, in the site's own motion language. "both" so the opening frame
     is held before the first tick rather than flashing the end state. */
  animation: hx-search-open .19s cubic-bezier(.2, .8, .3, 1) both;
}
.hx-search {
  flex-direction: column;
  width: min(680px, calc(100vw - 32px));
  max-height: min(74vh, 620px);
  margin: 11vh auto auto;
  padding: 0;
  overflow: hidden;
  border: 1px solid var(--hx-line);
  border-radius: 22px;
  background: var(--hx-surface);
  box-shadow: 0 40px 90px -40px rgba(18, 52, 34, .5);
  color: var(--hx-body);
  font-family: var(--hx-sans);
}
.hx-search::backdrop { background: rgba(16, 40, 23, .42); backdrop-filter: blur(3px); }
.hx-search[open]::backdrop { animation: hx-search-veil .22s ease-out both; }

@keyframes hx-search-open { from { opacity: 0; transform: translateY(-10px) scale(.985); } }
@keyframes hx-search-veil { from { opacity: 0; } }

/* ----------------------------------------------------------------- the bar */

.hx-search-bar { display: flex; align-items: center; gap: 12px; padding: 16px 17px; border-bottom: 1px solid var(--hx-line); }
/*
 * The glass takes the accent rather than the muted grey. It is the one mark in
 * the panel that says what the panel is, and at 19px in #616f67 it read as
 * another piece of chrome.
 */
.hx-search-glass { flex: none; color: var(--hx-green-deep); stroke-width: 2; }
.hx-search-bar input {
  flex: 1;
  min-width: 0;
  border: 0;
  background: none;
  color: var(--hx-ink);
  font-family: inherit;
  font-size: 17px;
  font-weight: 500;
}
/* WebKit draws its own clear affordance on type="search"; this panel draws a
   better one that is the same on every browser. */
.hx-search-bar input::-webkit-search-cancel-button { -webkit-appearance: none; appearance: none; }
/*
 * The field keeps a ring.
 *
 * This said "outline: none" with nothing in its place: a reader who tabs from
 * the ESC button back to the input had no way to tell where they were. The
 * ring is drawn inside, because the bar is flush to the dialog's edge.
 */
.hx-search-bar input:focus-visible { outline: 2px solid var(--hx-green-deep); outline-offset: 3px; border-radius: 5px; }
.hx-search-bar input::placeholder { color: var(--hx-muted); font-weight: 400; }
/*
 * Both bar buttons are at least 30px square, over the 24px WCAG 2.2 asks of a
 * pointer target. The old ESC pill was 22px tall.
 */
.hx-search-clear,
.hx-search-close {
  display: grid;
  place-items: center;
  flex: none;
  min-width: 30px;
  height: 30px;
  padding: 0 8px;
  border: 1px solid var(--hx-line);
  border-radius: 9px;
  background: var(--hx-mint-soft);
  color: var(--hx-muted);
  font-family: inherit;
  cursor: pointer;
  transition: background .15s ease, color .15s ease;
}
/*
 * The script hides the clear button with the hidden attribute, and the
 * display: grid above was quietly winning: the UA's [hidden] { display: none }
 * loses to any author rule that sets display, so the button sat there on an
 * empty field offering to clear nothing.
 */
.hx-search-clear[hidden] { display: none; }
.hx-search-clear:hover,
.hx-search-close:hover { background: var(--hx-mint); color: var(--hx-ink); }
.hx-search-close kbd { border: 0; background: none; font-size: 11.6px; font-weight: 700; }

/* ------------------------------------------------------------- the results */

.hx-search-out {
  overflow-y: auto;
  /* The page behind must not start scrolling when the list reaches its end. */
  overscroll-behavior: contain;
  padding: 6px 8px 10px;
  scrollbar-width: thin;
  scrollbar-color: var(--hx-mint-line) transparent;
}
.hx-search-out::-webkit-scrollbar { width: 10px; }
.hx-search-out::-webkit-scrollbar-thumb {
  border: 3px solid transparent;
  border-radius: 99px;
  background: var(--hx-mint-line);
  background-clip: content-box;
}
.hx-search-group {
  padding: 12px 12px 7px;
  color: var(--hx-muted);
  font-size: 11.2px;
  font-weight: 700;
  letter-spacing: .11em;
  text-transform: uppercase;
}
.hx-result {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  column-gap: 12px;
  row-gap: 3px;
  padding: 11px 13px;
  border-radius: 13px;
  transition: background .13s ease;
}
.hx-result-head { grid-column: 1; display: flex; align-items: center; gap: 9px; min-width: 0; }
.hx-result b { color: var(--hx-ink); font-size: 15.4px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/*
 * What kind of page a row is.
 *
 * Twelve titles in a column give a reader no way to tell an article from a
 * reference page or a legal one, and several of this site's titles are long
 * enough to be cut before the part that would have said so. The script reads
 * the kind off the URL, so there is no new field to keep in step.
 */
.hx-result-kind {
  flex: none;
  padding: 2px 7px;
  border-radius: 6px;
  background: var(--hx-mint);
  color: var(--hx-green-deep);
  font-size: 10.2px;
  font-weight: 700;
  letter-spacing: .07em;
  text-transform: uppercase;
}
.hx-result-snip {
  grid-column: 1;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
  color: var(--hx-muted);
  font-size: 13.4px;
  line-height: 1.45;
}
/* The return glyph, shown only on the row Enter would actually open. */
.hx-result-go { grid-column: 2; grid-row: 1 / -1; color: var(--hx-green-deep); font-size: 15px; opacity: 0; }
.hx-result:hover { background: var(--hx-mint-soft); }
/*
 * A focused row gets the ring as well as the tint.
 *
 * The tint alone was the indicator, and mint-soft on white is about 1.06:1 --
 * under the 3:1 a non-text indicator needs, and invisible in practice. The
 * ring is inset so the row's own rounded corners do not clip it.
 */
.hx-result:focus-visible { background: var(--hx-mint); outline: 2px solid var(--hx-green-deep); outline-offset: -2px; }
/* The keyboard's row is marked twice over: the fill, and a bar down its lead
   edge that does not ask anyone to tell two pale greens apart. */
.hx-result[aria-selected="true"] { background: var(--hx-mint); box-shadow: inset 3px 0 0 var(--hx-green); }
.hx-result[aria-selected="true"] .hx-result-go { opacity: 1; }
.hx-result mark { padding: 0 1px; border-radius: 3px; background: #cdecd9; color: var(--hx-green-deep); font-weight: 600; }

.hx-search-empty { padding: 34px 16px 38px; text-align: center; }
.hx-search-empty b { display: block; color: var(--hx-ink); font-size: 15.4px; font-weight: 600; }
.hx-search-empty span { display: block; margin-top: 7px; color: var(--hx-muted); font-size: 13.8px; }
/*
 * Waiting for the index.
 *
 * The first keystroke arrives before the index has been fetched, and the panel
 * used to answer it with "nothing on the site matches" -- a wrong answer, and
 * then a correction a moment later. These are the shape of the answer while it
 * is still on its way.
 */
.hx-search-load { display: grid; gap: 8px; padding: 10px 5px; }
.hx-search-load i {
  height: 46px;
  border-radius: 13px;
  background: linear-gradient(90deg, var(--hx-mint-soft) 25%, var(--hx-mint) 50%, var(--hx-mint-soft) 75%) 0 0 / 240% 100%;
  animation: hx-search-shimmer 1.1s linear infinite;
}
@keyframes hx-search-shimmer { to { background-position: -240% 0; } }

/* ---------------------------------------------------------------- the foot */

.hx-search-foot {
  display: flex;
  align-items: center;
  gap: 7px 16px;
  flex-wrap: wrap;
  padding: 10px 16px;
  border-top: 1px solid var(--hx-line);
  color: var(--hx-muted);
  font-size: 12.4px;
}
.hx-search-count { font-weight: 600; }
.hx-search-count:empty { display: none; }
.hx-search-keys { display: flex; align-items: center; gap: 5px; margin-left: auto; }
.hx-search-keys em { font-style: normal; opacity: .45; }
.hx-search-private { display: inline-flex; align-items: center; gap: 6px; }
.hx-search-private svg { flex: none; color: var(--hx-green-deep); stroke-width: 1.7; }
.hx-search-foot kbd {
  display: inline-grid;
  place-items: center;
  min-width: 19px;
  height: 19px;
  padding: 0 5px;
  border: 1px solid var(--hx-line);
  /* A thicker bottom edge is the whole of the keycap illusion. */
  border-bottom-width: 2px;
  border-radius: 5px;
  background: var(--hx-mint-soft);
  color: var(--hx-ink-2);
  font-family: inherit;
  font-size: 11.2px;
  font-weight: 600;
}

@media (prefers-reduced-motion: reduce) {
  .hx-search[open],
  .hx-search[open]::backdrop { animation: none; }
  .hx-search-load i { animation: none; }
  .hx-result { transition: none; }
  /* Listed here rather than in the .hx-scoped block below: the button is a
     child of <body>, and on the pages whose body is not .hx that block's
     ".hx *" would never reach it. */
  .hx-to-top { transition: none; translate: none; }
}

/*
 * On a phone the panel is most of the screen, sits closer to the top so the
 * keyboard does not push it off, and drops the key legend -- there are no
 * arrow keys to press. 16px on the field is what stops iOS zooming the page in
 * the moment it takes focus.
 */
@media (max-width: 640px) {
  .hx-search { width: calc(100vw - 20px); max-height: 84vh; margin: 6vh auto auto; border-radius: 18px; }
  .hx-search-bar { padding: 14px; }
  .hx-search-bar input { font-size: 16px; }
  .hx-search-keys { display: none; }
  .hx-search-private { margin-left: auto; }
  /*
   * Titles wrap here rather than ending in an ellipsis. On a wide panel the
   * cut is the right trade -- one tidy line beats a title that runs to three.
   * At 337px it was eating the last word of even a short label, and two short
   * lines read better than a sentence stopped mid-word.
   */
  .hx-result-head { align-items: baseline; }
  .hx-result b { overflow: visible; white-space: normal; }
}

/* ------------------------------------------------------------ mobile sheet */

.hx-sheet {
  position: absolute;
  left: 0;
  right: 0;
  top: calc(100% - 6px);
  z-index: 70;
  padding: 22px;
  border: 1px solid var(--hx-line);
  border-radius: 26px;
  background: var(--hx-surface);
  box-shadow: var(--hx-shadow-lift);
}
.hx-sheet[hidden] { display: none; }
.hx-sheet h2 { margin: 0 0 10px; color: var(--hx-green-deep); font-size: 11.6px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase; }
.hx-sheet-more { margin-top: 18px; }
.hx-sheet-links { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.hx-sheet-links a {
  display: flex;
  align-items: center;
  min-height: 46px;
  padding: 0 14px;
  border-radius: 12px;
  background: var(--hx-mint-soft);
  color: var(--hx-ink);
  font-size: 14.8px;
  font-weight: 600;
}
.hx-sheet-links a:hover { background: var(--hx-mint); color: var(--hx-green-deep); }
.hx-sheet-act { display: grid; grid-template-columns: 1fr 1.4fr; gap: 10px; margin-top: 18px; padding-top: 18px; border-top: 1px solid var(--hx-line); }
.hx-sheet-act .hx-signin { display: flex; align-items: center; justify-content: center; min-height: 50px; border: 1px solid var(--hx-line); border-radius: 999px; }
.hx-backdrop { position: fixed; inset: 0; z-index: 55; background: rgba(16, 40, 23, .34); }
.hx-backdrop[hidden] { display: none; }

/* -------------------------------------------------------------- responsive */

@media (max-width: 1320px) {
  .hx-nav { gap: 24px; }
  .hx-hd-card { gap: 20px; }
}

@media (max-width: 1180px) {
  .hx-hero-in { grid-template-columns: minmax(0, 1fr); gap: 46px; }
  .hx-hero h1 { font-size: clamp(42px, 7vw, 62px); }
  .hx-hero-lead { max-width: 640px; }
  /*
   * The headline wraps to the measure it has, rather than to the one it had.
   *
   * The breaks are set in the markup for the two-column hero, where the copy
   * column is 660px and neither sentence fits on a line. On one column the
   * measure is the whole shell -- 945px at 1024 -- where both fit whole, 879px
   * and 759px. Keeping the breaks there stacked four short lines down the left
   * of a column twice their width, which is the hole that showed on tablets.
   *
   * The <em> keeps its own line, so the two sentences still separate; only the
   * breaks inside each one are given back to the browser. At narrow widths it
   * wraps to the same places the markup was forcing anyway.
   */
  .hx-hero h1 .hx-lead-line { display: inline; }
  /*
   * Balanced, because the natural break is not always the good one: at 820 the
   * first sentence wrapped to "Know where your money / goes." and left two
   * words alone on a line. balance asks the browser to even the lines out,
   * which is the judgement the hardcoded breaks used to supply. Unsupported
   * browsers ignore it and get the plain wrap, which is what they had.
   */
  .hx-hero h1 { text-wrap: balance; }
  /* Wrapping and separation are on the base rule now, so both states are right
     at every width and there is nothing to switch off here. */
  .hx-block,
  .hx-life-in { grid-template-columns: minmax(0, 1fr); gap: 36px; }
  /* The photograph leads on one column: reading a caption about a picture that
     is still below the fold is worse than the alternating rhythm is worth. */
  .hx-block-flip .hx-block-copy { order: 0; }
  .hx-block-art { order: -1; }
  .hx-life-art { order: -1; }
  .hx-faq-in { grid-template-columns: minmax(0, 1fr); gap: 34px; }
  .hx-privacy-in { grid-template-columns: minmax(0, 1fr); }
}

@media (max-width: 1080px) {
  .hx-nav { display: none; }
  /* The pill's own Sign in, not the sheet's copy of it. Written as a
   * descendant rather than :not(.hx-sheet .hx-signin), which is a complex
   * :not() argument and silently drops the whole rule in older Safari. */
  .hx-hd-act .hx-signin { display: none; }
  .hx-burger { display: grid; }
  .hx-hd-card { justify-content: space-between; }
  .hx-hd { position: relative; }
  .hx-steps,
  .hx-plans { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .hx-ft-top { grid-template-columns: 1fr 1fr; }
}

@media (max-width: 900px) {
  /* Phones get the bar; a laptop already has the header's own button in view. */
  .hx-sticky-cta:not([hidden]) { display: flex; }
  /* Above that bar, which owns the bottom of the viewport at this width: it is
     72px tall on a 12px inset, so it reaches 84px up. 96 clears it by the same
     12px it holds off the viewport edge -- at 84 the two were exactly flush. */
  .hx-to-top { right: 16px; bottom: 96px; }
}

@media (max-width: 820px) {
  .hx-shell { width: min(1490px, calc(100% - 36px)); }
  .hx-section { padding: 68px 0; }
  .hx-block { margin-top: 58px; }
  /* One column of cards. Two columns of 300px is the floor at which the
     screenshots still read; below it they are thumbnails. */
  .hx-cards { grid-template-columns: minmax(0, 1fr); }
  .hx-card-note { grid-template-columns: minmax(0, 1fr); align-items: start; gap: 20px; }
  .hx-float-tip { width: 190px; font-size: 13.2px; }
  .hx-final-content { width: min(760px, calc(100% - 36px)); padding: 76px 0; }
  .hx-util-in { min-height: 42px; font-size: 12.4px; }
  .hx-util p span { display: none; }
  .hx-watch { margin-top: 54px; }
  .hx-watch-mark { width: 62px; height: 62px; }
}

@media (max-width: 680px) {
  .hx-cta-full { display: none; }
  .hx-cta-short { display: inline; }
  .hx-steps,
  .hx-plans,
  .hx-ft-top { grid-template-columns: minmax(0, 1fr); }
  .hx-hd-card { height: 68px; padding: 0 10px 0 16px; border-radius: 34px; }
  .hx-brand span { font-size: 19px; }
  .hx-brand img { width: 32px; height: 32px; }
  .hx-hero-cta .hx-btn { width: 100%; }
  .hx-trust { gap: 14px; }
  .hx-sheet-links { grid-template-columns: minmax(0, 1fr); }
  .hx-util-right .hx-util-hide { display: none; }
  .hx-script { font-size: 23px; }
  .hx-faq summary { grid-template-columns: 34px minmax(0, 1fr) 26px; font-size: 16.2px; }
  .hx-faq details > p { margin-left: 34px; }
  .hx-card-art img { height: 200px; }
}

@media (max-width: 560px) {
  /*
   * The wordmark goes and the mark stays.
   *
   * Below here the pill holds the brand, search, the call to action and the
   * menu, and "Money Copilot AI" is the one of the four that is already said
   * by the logo beside it. Keeping it pushed the button past the right edge
   * and gave the whole page a horizontal scrollbar -- and it is scoped to the
   * header, because the footer's copy of the brand has all the room it needs.
   */
  .hx-hd-card .hx-brand span { display: none; }
  .hx-hd-card { gap: 12px; }
  .hx-hd-act { gap: 10px; }
}

@media (max-width: 430px) {
  .hx-float-tip { display: none; }
  .hx-hero-art > img { border-radius: 22px; }
  .hx-sticky-cta small { display: none; }
}

/*
 * Finger-sized targets where there are fingers.
 *
 * The standalone links measured 24 to 30px tall, which clears the 24px
 * minimum and is still a poor thing to hit on a phone. Scoped to coarse
 * pointers so the desktop layout keeps its density -- padding on an
 * inline-flex link grows the hit area without moving the text.
 */
@media (pointer: coarse) {
  .hx-link { min-height: 44px; }
  .hx-ft-col a,
  .hx-ft-base a { padding-block: 8px; }
}

@media (prefers-reduced-motion: reduce) {
  .hx *,
  .hx *::before,
  .hx *::after { transition: none !important; animation: none !important; }
  .hx-btn:hover,
  .hx-card:hover { transform: none; }
  .hx-watch-play:hover .hx-watch-mark { transform: translate(-50%, -50%); }
}


/* ==========================================================================
 * The two pages still built on home.css
 *
 * home.css is one dark palette with no light underneath, so pricing and manny
 * did not flip when the dark pin came off -- they sat dark beneath a white
 * header. It is entirely token-driven, so this remaps the tokens rather than
 * restyling the pages, and then fixes the handful of components that pair a
 * token with a hardcoded colour, which a remap cannot reach.
 *
 * Scoped to a body class: --ink, --line and --muted are each declared by three
 * stylesheets on this site, so a :root override would reach pages that never
 * asked for one.
 * ========================================================================== */
.hx-legacy-light {
  --ink: #f4f7f1;          /* the page ground; home.css sets body's background from it */
  --ink-soft: #eef3ea;
  --surface: #fff;
  /* Missed on the first pass and the reason the plan cards stayed dark:
     home.css declares five surfaces, not one. */
  --surface-2: #fff;
  --surface-3: #f7faf6;
  --paper: #16241c;        /* body text, and the reason the page read as dark */
  --muted: #616f67;        /* 4.88:1 on the ground, like the rest of the light design */
  --line: #e1e8df;
  --line-strong: #d4e7da;
  --mint: #e4f1e8;         /* a fill on 25 of its 31 uses; the text uses are below */
  --mint-bright: #eff7f1;
  --accent-text: #06753a;
  --green: #0a8a45;
  --green-dark: #17381f;
  --shadow: 0 24px 60px -28px rgba(18, 52, 34, .3);
}

/*
 * .button hardcodes color:#07110d against a --mint fill, so remapping the
 * token alone would have left a pale mint call to action. It takes the light
 * design's button instead: dark green, white label.
 */
.hx-legacy-light .button {
  border-color: var(--hx-green-dark, #17381f);
  background: var(--hx-green-dark, #17381f);
  color: #fff;
}
.hx-legacy-light .button:hover {
  background: var(--hx-green-darker, #102817);
  box-shadow: 0 14px 40px -22px rgba(18, 52, 34, .34);
}
/* The inverse button was a near-white fill for use on a dark section. On a
 * light one it is a white rectangle, so it becomes the outlined variant. */
.hx-legacy-light .button-light {
  border-color: var(--line-strong);
  background: #fff;
  color: var(--paper);
}

/*
 * The three places --mint is a colour rather than a fill: a badge, the tick in
 * the upgrade list and the tick in the comparison table. Pale mint text on a
 * light ground is invisible, so these take the accent instead.
 */
.hx-legacy-light .price-badge,
.hx-legacy-light .upgrade-gets li::before,
.hx-legacy-light .plan-yes { color: var(--accent-text); }

/*
 * Manny keeps its dark chips.
 *
 * They are a glass panel floating over a photograph rather than over the page,
 * so the surface was always meant to be dark -- it is their text that came from
 * --paper and --muted and turned dark with everything else, leaving dark on
 * dark at 1.14:1. Light text, stated rather than inherited.
 */
.hx-legacy-light .mny-chip-label { color: rgba(255, 255, 255, .74); }
.hx-legacy-light .mny-chip-value,
.hx-legacy-light .mny-chip-ask { color: #fff; }
.hx-legacy-light .mny-chip-note { color: #7fe0ab; }

/* --mint as a colour once more, here on a light pill. */
.hx-legacy-light .mny-delta { color: var(--accent-text); }


/* ==========================================================================
 * Meeting the shared motion system
 *
 * assets/motion.css was written for the dark shell, and two of its defaults
 * are wrong against a light page.
 * ========================================================================== */

/*
 * The focus ring's colour.
 *
 * motion.css paints it "var(--motion-focus, #45e39a)" and its selector,
 * html.motion-enabled .motion-interactive:focus-visible, outruns this page's
 * own focus rule. That mint is built for a near-black background; on white it
 * is about 1.9:1 and barely a ring at all. The token exists precisely so a
 * page can answer this, so this page answers it.
 */
.hx,
.hx-util,
.hx-hd,
.hx-ft,
.hx-search,
.hx-sticky-cta { --motion-focus: #06753a; }

/*
 * One lift per element, not two.
 *
 * .hx-card and .hx-btn already raise themselves on hover with transform, and
 * motion.css raises .motion-interactive again with the translate property.
 * They are different properties, so they compose rather than override: the card
 * would travel 3px of its own plus 4px of the system's. The components keep
 * their own movement and give up the system's, which is the pattern motion.css
 * already uses for the header's controls.
 */
html.motion-enabled .hx-card.motion-interactive:hover,
html.motion-enabled .hx-btn.motion-interactive:hover,
html.motion-enabled .hx-use.motion-interactive:hover,
html.motion-enabled .hx-plan.motion-interactive:hover { translate: none; }
