/* =====================================================================
   Nevo Money — Nevo 2.0 design layer
   ---------------------------------------------------------------------
   Loads LAST (6th sheet) so it wins ties against components.css/home.css
   without a single !important.

   Everything here is namespaced `nvx-`. That prefix is unused anywhere
   else in css/, so this layer can never collide with the existing
   `feature-`, `hero-`, `scroll-`, `nevo-` (the .nevo-card family) or
   bare-word classes.

   Colours are lifted verbatim from the Flutter app (packages/nevo_shared
   theme/app_colors.dart) so the site and the product read as one object.
   ===================================================================== */

:root {
  /* --- Brand triad. The app's ColorScheme primary/secondary/tertiary. --- */
  --nvx-primary: #64afff;
  --nvx-secondary: #81c784;
  --nvx-tertiary: #c7a3ff;

  /* Money semantics. costColors.green / .red — the exact hues the forecast
     line changes to when a projected balance crosses zero. */
  --nvx-green: #69f0ae;
  --nvx-red: #ff5252;
  --nvx-amber: #ffb300;

  /* Surfaces + ink. */
  --nvx-ink: #edf3fa;
  --nvx-ink-dim: #c7d1da;
  --nvx-surface: #161b25;
  --nvx-surface-hi: #242c3a;
  --nvx-outline: #3f4858;

  /* The app's scaffold gradient, which is also the site body background. */
  --nvx-void-top: #0a1128;
  --nvx-void-bottom: #050810;

  /* Card recipe — NevoCard: radius 28, 1px outlineVariant @ .24, a diagonal
     white sheen at .06, elevation 6. */
  --nvx-card-radius: 28px;
  --nvx-card-bg: rgba(22, 27, 37, 0.72);
  --nvx-card-border: rgba(63, 72, 88, 0.55);
  --nvx-card-sheen: rgba(255, 255, 255, 0.06);
  --nvx-card-shadow: 0 3px 6px rgba(0, 0, 0, 0.28), 0 24px 60px -28px rgba(0, 0, 0, 0.7);

  /* Glow strengths differ per theme: dark composites additively and can
     carry a lot more bloom before it turns to mud. */
  --nvx-glow-a: 0.5;
  --nvx-glow-b: 0.22;
  --nvx-grid-line: rgba(237, 243, 250, 0.05);

  /* Motion — MotionTokens, plus the Flutter-exact bezier for easeOutCubic.
     (Note: Flutter's easeOutCubic is 0.215,0.61,0.355,1 — NOT the
     easings.net curve of the same name. Using the wrong one visibly drifts
     against the app.) */
  --nvx-dur-short: 120ms;
  --nvx-dur-med: 200ms;
  --nvx-dur-long: 300ms;
  /* 420ms, not 720. At a normal 1400px/s reading scroll a 720ms fade plus a
     480ms stagger left the last tile of a 9-up grid fully off-screen before
     it finished arriving, so the grid was read with holes and scanned as
     "content did not load". */
  --nvx-dur-reveal: 420ms;
  --nvx-ease-emph: cubic-bezier(0.215, 0.61, 0.355, 1);
  --nvx-ease-std: cubic-bezier(0.42, 0, 0.58, 1);
  --nvx-ease-out: cubic-bezier(0, 0, 0.58, 1);
  --nvx-ease-back: cubic-bezier(0.175, 0.885, 0.32, 1.275);
  /* NevoSpring.gentle, sampled from the real spring simulation. */
  --nvx-spring: linear(
    0, 0.1919 4%, 0.5726 8%, 0.9208 12%, 1.1313 16%, 1.1966 20%, 1.1628 24%,
    1.0887 28%, 1.019 32%, 0.9758 36%, 0.9614 40%, 0.9672 44%, 0.9816 48%,
    0.9956 52%, 1.0044 56%, 1.0076 60%, 1.0066 64%, 1.0038 68%, 1.001 72%,
    0.9992 76%, 0.9985 80%, 0.9987 84%, 0.9992 88%, 0.9998 92%, 1.0001 96%, 1
  );

  /* Layout. The existing container is 1100px; the demo and the deck need
     more air without becoming a different site. */
  --nvx-wide: 1240px;
  --nvx-gutter: 24px;
  /* One vertical rhythm, shared with the older .section/.scroll-story
     classes so the page does not alternate between two ladders. */
  --nvx-band-pad: 104px;

  /* z-index: the audit found 3–9 completely unoccupied between .container
     (2) and .apple-nav (999). Stay inside it. */
  --nvx-z-behind: 0;
  --nvx-z-base: 3;
  --nvx-z-raised: 5;
  --nvx-z-float: 8;
}

body.light-mode,
.theme-light {
  --nvx-primary: #1e40af;
  /* Re-derived for a pale ground. #4caf50 (Material 500) was carried over
     from the dark theme untouched while primary and tertiary were properly
     darkened, and it measured 2.45:1 against the page — it alone caused the
     locked positioning line to drop to 2.84:1 mid-gradient, the primary CTA
     to hit 3.37:1 on hover as the ramp pans onto the green stop, and the
     read/write capability badges to invert their own pairing (2.34:1 green
     against 5.6:1 purple).
     Money green and red are darkened for the same reason: 14px bold is not
     "large text", so the amounts in the demo need the full 4.5:1. Splitting
     brand-green from money-green also restores the separation the dark
     theme has, so a status pill never reads as an amount. */
  --nvx-secondary: #2e7d32;
  --nvx-tertiary: #5e35b1;

  --nvx-green: #1b5e20;
  --nvx-red: #c62828;
  --nvx-amber: #b45309;

  --nvx-ink: #1c2233;
  --nvx-ink-dim: #434b5e;
  --nvx-surface: #f7f9fc;
  --nvx-surface-hi: #e3e8f3;
  --nvx-outline: #c7cdda;

  --nvx-void-top: #eaeff8;
  --nvx-void-bottom: #dde4f0;

  --nvx-card-bg: rgba(255, 255, 255, 0.78);
  --nvx-card-border: rgba(199, 205, 218, 0.9);
  --nvx-card-sheen: rgba(255, 255, 255, 0.55);
  --nvx-card-shadow: 0 2px 6px rgba(15, 23, 42, 0.06), 0 24px 60px -34px rgba(15, 23, 42, 0.28);

  --nvx-glow-a: 0.28;
  --nvx-glow-b: 0.12;
  --nvx-grid-line: rgba(28, 34, 51, 0.06);
}

/* =====================================================================
   1. Motion utilities (paired with js/nevo-motion.js)
   ===================================================================== */

/* Nothing is hidden by default. An inline <script> in each page's <head>
   adds `nvx-js` to <html>, so a browser with JavaScript switched off never
   enters the hidden state at all and simply reads a fully visible page.
   Hiding first and hoping a script arrives to un-hide is how content
   disappears; this way the failure mode is "no animation", not "no site". */
html.nvx-js [data-nvx-reveal] {
  opacity: 0;
  transform: translate3d(0, 22px, 0);
  transition:
    opacity var(--nvx-dur-reveal) var(--nvx-ease-emph),
    transform var(--nvx-dur-reveal) var(--nvx-ease-emph);
  will-change: opacity, transform;
}
html.nvx-js [data-nvx-reveal].is-nvx-in {
  opacity: 1;
  transform: none;
}
/* Variants — same timing, different arrival vector. */
html.nvx-js [data-nvx-reveal='scale'] { transform: translate3d(0, 18px, 0) scale(0.96); }
html.nvx-js [data-nvx-reveal='left'] { transform: translate3d(-26px, 0, 0); }
html.nvx-js [data-nvx-reveal='right'] { transform: translate3d(26px, 0, 0); }
html.nvx-js [data-nvx-reveal='blur'] { filter: blur(10px); transition-property: opacity, transform, filter; }
html.nvx-js [data-nvx-reveal='blur'].is-nvx-in { filter: none; }

/* The remaining hole: JS is ON (so we hid everything) but js/nevo-motion.js
   itself never loaded, leaving nobody to reveal it. The engine announces
   itself with `nvx-motion-ready` the moment it boots; if that has not
   happened two seconds in, unhide the lot. Gating on the engine's own class
   rather than merely on `nvx-js` is what stops this failsafe from firing on
   a healthy page and force-revealing every section at once. */
@keyframes nvx-failsafe { to { opacity: 1; transform: none; filter: none; } }
html.nvx-js:not(.nvx-motion-ready) [data-nvx-reveal] {
  animation: nvx-failsafe 1ms linear 2s forwards;
}

/* =====================================================================
   2. Atmosphere — the aurora field behind the whole page
   ---------------------------------------------------------------------
   <body> already paints a FIXED navy gradient. This adds slow-drifting
   brand-hued light on top of it, fixed to the viewport for the same
   reason: the page should feel like it is moving through a space, not
   scrolling a texture.
   ===================================================================== */

.nvx-aurora {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  overflow: hidden;
  contain: strict;
}
.nvx-aurora span {
  position: absolute;
  display: block;
  border-radius: 50%;
  filter: blur(90px);
  opacity: var(--nvx-glow-b);
  mix-blend-mode: plus-lighter;
  will-change: transform;
}
.light-mode .nvx-aurora span,
.theme-light .nvx-aurora span {
  /* plus-lighter on a near-white page just blows out to flat white. */
  mix-blend-mode: normal;
  filter: blur(110px);
}
.nvx-aurora .nvx-aur-1 {
  width: 62vw; height: 62vw; min-width: 460px; min-height: 460px;
  top: -22vw; left: -12vw;
  background: radial-gradient(circle, var(--nvx-primary) 0%, transparent 68%);
  animation: nvx-drift-a 34s var(--nvx-ease-std) infinite alternate;
}
.nvx-aurora .nvx-aur-2 {
  width: 52vw; height: 52vw; min-width: 380px; min-height: 380px;
  top: 22vh; right: -18vw;
  background: radial-gradient(circle, var(--nvx-tertiary) 0%, transparent 68%);
  animation: nvx-drift-b 42s var(--nvx-ease-std) infinite alternate;
}
.nvx-aurora .nvx-aur-3 {
  width: 44vw; height: 44vw; min-width: 320px; min-height: 320px;
  bottom: -16vw; left: 22vw;
  background: radial-gradient(circle, var(--nvx-secondary) 0%, transparent 70%);
  opacity: calc(var(--nvx-glow-b) * 0.75);
  animation: nvx-drift-c 50s var(--nvx-ease-std) infinite alternate;
}
@keyframes nvx-drift-a { to { transform: translate3d(8vw, 6vh, 0) scale(1.14); } }
@keyframes nvx-drift-b { to { transform: translate3d(-7vw, -8vh, 0) scale(1.1); } }
@keyframes nvx-drift-c { to { transform: translate3d(6vw, -5vh, 0) scale(1.18); } }

/* A hairline grid, the ledger under everything. Very nearly invisible by
   design — you should feel it more than see it. */
.nvx-aurora::after {
  content: '';
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(var(--nvx-grid-line) 1px, transparent 1px),
    linear-gradient(90deg, var(--nvx-grid-line) 1px, transparent 1px);
  background-size: 88px 88px;
  mask-image: radial-gradient(ellipse 90% 70% at 50% 20%, #000 0%, transparent 78%);
  -webkit-mask-image: radial-gradient(ellipse 90% 70% at 50% 20%, #000 0%, transparent 78%);
}

/* Everything on the page must sit above the aurora. */
body > main,
body > nav,
body > footer { position: relative; z-index: var(--nvx-z-base); }

/* =====================================================================
   2c. Retiring the older layer onto this one
   ---------------------------------------------------------------------
   `.section` and `.scroll-story` predate this file and were never brought
   onto its scale. Left alone they produce the whole "two design systems"
   seam: a different container width, a section padding that never steps
   down on mobile (so the OLD sections ended up breathing MORE than the new
   ones on a phone — the rhythm inverted), a second headline voice, and a
   second reveal curve. Everything below aliases the old classes onto the
   nvx values. No markup changed; the old sections keep their own class
   names and their data-i18n keys.
   ===================================================================== */

/* One vertical rhythm for both systems. */
.nvx-band,
.section,
.scroll-story { padding: var(--nvx-band-pad) 0; }
.nvx-band-tight { padding: calc(var(--nvx-band-pad) / 2) 0; }

/* The trust strip sat 40px under the hero — three times tighter than any
   other boundary on the page, in the first screenful. */
.trust-strip-shell { padding: var(--nvx-band-pad) 0; }

/* The old headline and eyebrow, in the nvx voice. */
.section-title {
  font-size: clamp(2.05rem, 1.45rem + 2.3vw, 3.15rem);
  line-height: 1.06;
  letter-spacing: -0.028em;
}
.section-eyebrow,
.showcase-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.24em;
  color: var(--nvx-primary);
}
.section-eyebrow::before,
.showcase-eyebrow::before {
  content: '';
  width: 22px;
  height: 1px;
  background: currentColor;
  opacity: 0.55;
}
/* Centred headers put the eyebrow in the middle, where a leading dash
   reads as a stray mark rather than a rule. */
.section-header .section-eyebrow { justify-content: center; }

/* Single-word orphans on the last line, across both systems. */
.section-title,
.hero-title,
.plan-v2-name,
.faq-title,
.nvx-proof-l { text-wrap: balance; }

/* Both reveal engines on one curve. The old rule animated `all`, which
   also transitioned colour and shadow on hover for anything inside it. */
.reveal-on-scroll {
  transform: translate3d(0, 22px, 0);
  transition:
    opacity var(--nvx-dur-reveal) var(--nvx-ease-emph),
    transform var(--nvx-dur-reveal) var(--nvx-ease-emph);
}
.reveal-on-scroll.visible { transform: none; }

/* One gutter. The old container held 24px while the new one stepped to
   20px on a phone, so the page's edge moved as you scrolled. */
.container { padding: 0 var(--nvx-gutter); }

/* =====================================================================
   3. Shared section furniture
   ===================================================================== */

.nvx-band {
  position: relative;
  scroll-margin-top: calc(var(--nav-height) + 24px);
}
.nvx-wrap {
  width: min(var(--nvx-wide), 100%);
  margin: 0 auto;
  padding: 0 var(--nvx-gutter);
  position: relative;
  z-index: var(--nvx-z-base);
}

/* A tonal slab that reads as a distinct chapter without a hard edge. */
.nvx-band-tonal::before {
  content: '';
  position: absolute;
  inset: 0;
  background:
    radial-gradient(ellipse 70% 100% at 50% 0%, color-mix(in srgb, var(--nvx-primary) 9%, transparent), transparent 70%),
    color-mix(in srgb, var(--nvx-surface) 55%, transparent);
  mask-image: linear-gradient(180deg, transparent, #000 12%, #000 88%, transparent);
  -webkit-mask-image: linear-gradient(180deg, transparent, #000 12%, #000 88%, transparent);
  pointer-events: none;
}

.nvx-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  margin: 0 0 14px;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--nvx-primary);
}
.nvx-eyebrow::before {
  content: '';
  width: 22px;
  height: 1px;
  background: currentColor;
  opacity: 0.55;
}
.nvx-eyebrow-center { justify-content: center; }

.nvx-h2 {
  margin: 0 0 16px;
  font-size: clamp(2.05rem, 1.45rem + 2.3vw, 3.15rem);
  font-weight: 700;
  line-height: 1.06;
  letter-spacing: -0.028em;
  color: var(--nvx-ink);
  text-wrap: balance;
}
.nvx-lead {
  margin: 0;
  max-width: 56ch;
  font-size: 1.09rem;
  line-height: 1.62;
  color: var(--nvx-ink-dim);
}
.nvx-head-center { max-width: 760px; margin: 0 auto 56px; text-align: center; }
.nvx-head-center .nvx-lead { margin-inline: auto; }

/* The gradient rule the app uses on its brand button, reused as a
   section-closing flourish. */
.nvx-rule {
  height: 1px;
  border: 0;
  margin: 0;
  background: linear-gradient(90deg, transparent, var(--nvx-card-border) 18%, var(--nvx-card-border) 82%, transparent);
}

/* =====================================================================
   4. Cards — the NevoCard recipe, ported
   ===================================================================== */

.nvx-card {
  position: relative;
  border-radius: var(--nvx-card-radius);
  background: var(--nvx-card-bg);
  border: 1px solid var(--nvx-card-border);
  box-shadow: var(--nvx-card-shadow);
  backdrop-filter: blur(18px) saturate(1.2);
  -webkit-backdrop-filter: blur(18px) saturate(1.2);
  overflow: hidden;
  isolation: isolate;
}
/* The diagonal highlight sheen. topLeft -> bottomRight, white @ .06 dark,
   .12 light — this is what stops the glass looking like flat grey. */
.nvx-card::before {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(135deg, var(--nvx-card-sheen), transparent 58%);
  pointer-events: none;
  z-index: 0;
}
.nvx-card > * { position: relative; z-index: 1; }

.nvx-card-lift {
  transition:
    transform var(--nvx-dur-long) var(--nvx-ease-emph),
    border-color var(--nvx-dur-long) var(--nvx-ease-emph),
    box-shadow var(--nvx-dur-long) var(--nvx-ease-emph);
}
.nvx-card-lift:hover {
  transform: translateY(-6px);
  border-color: color-mix(in srgb, var(--nvx-primary) 42%, var(--nvx-card-border));
  box-shadow: var(--nvx-card-shadow), 0 0 0 1px color-mix(in srgb, var(--nvx-primary) 12%, transparent);
}
/* Pointer-tracked glow, fed by --nvx-mx/--nvx-my from NevoMotion. */
.nvx-card-glow::after {
  content: '';
  position: absolute;
  inset: -1px;
  border-radius: inherit;
  background: radial-gradient(
    260px circle at calc(var(--nvx-mx, 0.5) * 100%) calc(var(--nvx-my, 0.5) * 100%),
    color-mix(in srgb, var(--nvx-primary) 18%, transparent),
    transparent 62%
  );
  opacity: 0;
  transition: opacity var(--nvx-dur-long) var(--nvx-ease-emph);
  pointer-events: none;
  z-index: 0;
}
.nvx-card-glow:hover::after { opacity: 1; }

/* =====================================================================
   5. Buttons — BrandGradientButton, ported
   ===================================================================== */

.nvx-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  min-height: 52px;
  padding: 0 28px;
  border: 0;
  border-radius: 20px;
  font: inherit;
  font-size: 1rem;
  font-weight: 700;
  letter-spacing: -0.005em;
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
  transition:
    transform var(--nvx-dur-med) var(--nvx-ease-emph),
    box-shadow var(--nvx-dur-med) var(--nvx-ease-emph),
    filter var(--nvx-dur-med) var(--nvx-ease-emph);
}
.nvx-btn:active { transform: translateY(1px) scale(0.99); }

/* The signature CTA: primary -> tertiary -> secondary, left to right. */
.nvx-btn-brand {
  position: relative;
  color: #0b1020;
  background: linear-gradient(90deg, var(--nvx-primary) 0%, var(--nvx-tertiary) 50%, var(--nvx-secondary) 100%);
  background-size: 220% 100%;
  background-position: 0% 50%;
  box-shadow: 0 10px 30px -14px color-mix(in srgb, var(--nvx-primary) 70%, transparent);
  transition:
    transform var(--nvx-dur-med) var(--nvx-ease-emph),
    box-shadow var(--nvx-dur-med) var(--nvx-ease-emph),
    background-position 620ms var(--nvx-ease-std);
}
.light-mode .nvx-btn-brand,
.theme-light .nvx-btn-brand { color: #fff; }
.nvx-btn-brand:hover {
  background-position: 100% 50%;
  transform: translateY(-2px);
  box-shadow: 0 18px 44px -16px color-mix(in srgb, var(--nvx-primary) 80%, transparent);
}

.nvx-btn-ghost {
  color: var(--nvx-ink);
  background: color-mix(in srgb, var(--nvx-ink) 6%, transparent);
  border: 1px solid var(--nvx-card-border);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
}
.nvx-btn-ghost:hover {
  transform: translateY(-2px);
  border-color: color-mix(in srgb, var(--nvx-primary) 50%, var(--nvx-card-border));
  background: color-mix(in srgb, var(--nvx-ink) 10%, transparent);
}

.nvx-btn-text {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--nvx-primary);
  font-weight: 600;
  font-size: 0.98rem;
  text-decoration: none;
}
.nvx-btn-text .nvx-chev {
  transition: transform var(--nvx-dur-med) var(--nvx-ease-emph);
}
.nvx-btn-text:hover .nvx-chev { transform: translateX(4px); }

.nvx-cta-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 14px 20px;
}
.nvx-cta-center { justify-content: center; }

/* =====================================================================
   6. Hero
   ===================================================================== */

.nvx-hero {
  position: relative;
  padding: calc(var(--nav-height) + 76px) 0 40px;
  overflow: hidden;
}
.nvx-hero-inner {
  display: grid;
  /* The copy column may never fall below 600px in two-column mode. Below
     that the locked positioning line breaks into four one-word lines, with
     "See" alone at 80px type, across 981-1180px: iPad landscape and any
     13" laptop at default scaling. */
  grid-template-columns: minmax(min(600px, 100%), 1.02fr) minmax(0, 0.98fr);
  align-items: center;
  gap: clamp(24px, 4vw, 64px);
}

/* --- the release pill --- */
.nvx-pill {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 7px 8px 7px 7px;
  margin-bottom: 24px;
  border-radius: 999px;
  border: 1px solid var(--nvx-card-border);
  background: color-mix(in srgb, var(--nvx-surface) 70%, transparent);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  font-size: 0.84rem;
  color: var(--nvx-ink-dim);
  text-decoration: none;
  transition: border-color var(--nvx-dur-med) var(--nvx-ease-emph), transform var(--nvx-dur-med) var(--nvx-ease-emph);
}
.nvx-pill:hover {
  transform: translateY(-1px);
  border-color: color-mix(in srgb, var(--nvx-primary) 55%, var(--nvx-card-border));
}
.nvx-pill b {
  padding: 3px 10px;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--nvx-primary), var(--nvx-tertiary));
  color: #0b1020;
  font-size: 0.74rem;
  font-weight: 700;
  letter-spacing: 0.04em;
}
.light-mode .nvx-pill b,
.theme-light .nvx-pill b { color: #fff; }
.nvx-pill .nvx-chev { color: var(--nvx-ink-dim); }

.nvx-hero-title {
  margin: 0 0 20px;
  font-size: clamp(2.9rem, 1.9rem + 4.4vw, 4.5rem);
  font-weight: 700;
  line-height: 1.02;
  letter-spacing: -0.035em;
  color: var(--nvx-ink);
  text-wrap: balance;
}
/* The locked positioning line's second half carries the brand ramp. */
/* No animation. A 14s ramp is far too slow to register as motion, so it
   bought nothing while guaranteeing the single most important sentence on
   the site was a different colour every time anyone looked at it — passing
   through a near-grey at t=7s (saturation 0.16) and the product's own
   "safe" green at t=14s. The words are locked; the colour should be too. */
.nvx-grad {
  background: linear-gradient(96deg, var(--nvx-primary) 4%, var(--nvx-tertiary) 52%, var(--nvx-secondary) 96%);
  background-size: 200% 100%;
  background-position: 0% 50%;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.nvx-hero-sub {
  margin: 0 0 30px;
  max-width: 46ch;
  font-size: clamp(1.02rem, 0.98rem + 0.3vw, 1.16rem);
  line-height: 1.6;
  color: var(--nvx-ink-dim);
}

/* --- the three-up proof rail --- */
.nvx-proof {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px;
  margin-top: 38px;
  padding-top: 30px;
  border-top: 1px solid var(--nvx-card-border);
}
.nvx-proof-n {
  display: block;
  font-size: clamp(1.4rem, 1.1rem + 1vw, 1.9rem);
  font-weight: 700;
  line-height: 1.1;
  letter-spacing: -0.02em;
  color: var(--nvx-ink);
  font-variant-numeric: tabular-nums;
}
.nvx-proof-l {
  display: block;
  margin-top: 6px;
  font-size: 0.85rem;
  line-height: 1.4;
  color: var(--nvx-ink-dim);
}

/* --- hero media column --- */
.nvx-hero-media {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 520px;
}
/* Stacks the device over its own caption/replay control. */
.nvx-media-col { flex-direction: column; }

/* =====================================================================
   7. The Nevo star (canvas glow + the app-icon mark on top)
   ===================================================================== */

.nvx-star {
  position: relative;
  width: min(420px, 78vw);
  aspect-ratio: 1 / 1.24;
  display: grid;
  place-items: center;
}
/* The canvas BLEEDS past this box so the nebula has room to fall off
   rather than hitting an edge. js/nevo-star.js owns those insets:
   it sets them inline, and its scene scale and centre anchor are
   derived to match. Do not add overflow:hidden to the host. */
/* The mark sits at 35% of the box height — the same anchor the painter
   uses for the halo centre, so the ring orbits the icon and not a point
   above it. */
.nvx-star-mark {
  position: absolute;
  top: 35%;
  left: 50%;
  width: 112px;
  height: 112px;
  transform: translate(-50%, -50%);
  /* 30/112 = 0.268 — the launch cinematic's own tile ratio
     (nevo_logo.dart:653-654), deliberately rounder than the shared
     NevoLogoMark 0.2237 used by the nav lockup. As a percentage so the
     silhouette survives the mobile size-down. */
  border-radius: 26.8%;
  box-shadow: 0 0 66px 2px color-mix(in srgb, var(--nvx-primary) 35%, transparent);
  animation: nvx-float 2600ms var(--nvx-ease-std) infinite alternate;
}
.light-mode .nvx-star-mark,
.theme-light .nvx-star-mark {
  box-shadow: 0 12px 34px rgba(0, 0, 0, 0.22);
}
@keyframes nvx-float { from { transform: translate(-50%, calc(-50% - 4px)); } to { transform: translate(-50%, calc(-50% + 4px)); } }

/* The star's caption: the assistant's own name + subtitle, exactly as the
   app's chat header shows them. */
.nvx-star-cap {
  position: absolute;
  left: 50%;
  bottom: 6%;
  transform: translateX(-50%);
  width: max-content;
  max-width: 92%;
  text-align: center;
}
.nvx-star-cap b {
  display: block;
  font-size: 1.5rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--nvx-ink);
}
.nvx-star-cap span {
  display: block;
  margin-top: 4px;
  font-size: 0.92rem;
  color: var(--nvx-ink-dim);
}

/* =====================================================================
   8. Prompt chips — the assistant's real starter questions, on a marquee
   ===================================================================== */

.nvx-marquee {
  position: relative;
  overflow: hidden;
  mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}
.nvx-marquee-track {
  display: flex;
  width: max-content;
  gap: 14px;
}
.nvx-marquee.is-nvx-running .nvx-marquee-track {
  animation: nvx-marquee var(--nvx-marquee-dur, 38s) linear infinite;
}
.nvx-marquee:hover .nvx-marquee-track { animation-play-state: paused; }
@keyframes nvx-marquee { to { transform: translate3d(-50%, 0, 0); } }

.nvx-chip {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 11px 18px;
  border-radius: 999px;
  border: 1px solid var(--nvx-card-border);
  background: color-mix(in srgb, var(--nvx-surface) 62%, transparent);
  color: var(--nvx-ink);
  font-size: 0.94rem;
  white-space: nowrap;
}
.nvx-chip svg { color: var(--nvx-primary); flex: none; }

/* =====================================================================
   9. Assistant section — the phone + the answer rail
   ===================================================================== */

.nvx-assist {
  display: grid;
  grid-template-columns: minmax(0, 0.92fr) minmax(0, 1.08fr);
  align-items: center;
  gap: clamp(28px, 4.5vw, 72px);
}
.nvx-assist-copy { max-width: 30rem; }

.nvx-points { display: grid; gap: 20px; margin: 30px 0 34px; padding: 0; list-style: none; }
.nvx-point { display: grid; grid-template-columns: 42px minmax(0, 1fr); gap: 16px; align-items: start; }
.nvx-point-ic {
  display: grid;
  place-items: center;
  width: 42px;
  height: 42px;
  border-radius: 13px;
  color: var(--nvx-primary);
  background: color-mix(in srgb, var(--nvx-primary) 14%, transparent);
  border: 1px solid color-mix(in srgb, var(--nvx-primary) 30%, transparent);
}
.nvx-point h3 { margin: 2px 0 5px; font-size: 1.04rem; font-weight: 600; color: var(--nvx-ink); }
.nvx-point p { margin: 0; font-size: 0.96rem; line-height: 1.55; color: var(--nvx-ink-dim); }

/* A quote slab for the approval promise — the single most important
   trust claim on the page, so it gets its own object. */
.nvx-vow {
  position: relative;
  margin: 0;
  padding: 26px 28px;
  border-radius: 22px;
  border: 1px solid var(--nvx-card-border);
  background: linear-gradient(135deg, color-mix(in srgb, var(--nvx-primary) 12%, transparent), transparent 62%);
  font-size: 1.08rem;
  line-height: 1.55;
  color: var(--nvx-ink);
}
.nvx-vow b { color: var(--nvx-primary); font-weight: 700; }
.nvx-vow::before {
  content: '';
  position: absolute;
  inset-inline-start: 0;
  top: 22px;
  bottom: 22px;
  width: 3px;
  border-radius: 3px;
  background: linear-gradient(180deg, var(--nvx-primary), var(--nvx-tertiary));
}

/* =====================================================================
   10. Device frame
   ===================================================================== */

.nvx-device {
  position: relative;
  width: min(392px, 88vw);
  margin: 0 auto;
  border-radius: 54px;
  padding: 11px;
  background: linear-gradient(160deg, #2b3446, #0d1119 46%, #232b3b);
  box-shadow:
    0 2px 0 rgba(255, 255, 255, 0.09) inset,
    0 40px 90px -40px rgba(0, 0, 0, 0.85),
    0 0 0 1px rgba(255, 255, 255, 0.05);
}
/* In light mode the device used to be a pale frame around a pale screen on
   a pale page: the screen measured 1.02:1 against the background, so the
   demo, which is the centrepiece of the section, barely read as a device at
   all. The frame goes dark in BOTH themes. A phone is a dark object; making
   it pale to "match" a light page is what erased it. */
.light-mode .nvx-device,
.theme-light .nvx-device {
  background: linear-gradient(160deg, #3b4557, #171c26 46%, #2c3444);
  box-shadow:
    0 2px 0 rgba(255, 255, 255, 0.12) inset,
    0 30px 70px -34px rgba(15, 23, 42, 0.55),
    0 0 0 1px rgba(15, 23, 42, 0.12);
}
.nvx-device-screen {
  position: relative;
  border-radius: 44px;
  overflow: hidden;
  background: linear-gradient(180deg, var(--nvx-void-top), var(--nvx-void-bottom));
  aspect-ratio: 392 / 800;
  display: flex;
  flex-direction: column;
}
/* The app's own light scaffold, but seated inside a dark bezel so the screen
   edge is a real edge rather than a 1.02:1 guess. */
.light-mode .nvx-device-screen,
.theme-light .nvx-device-screen {
  background: linear-gradient(180deg, #f4f7fc, #e6ecf7);
  box-shadow: inset 0 0 0 1px rgba(15, 23, 42, 0.08);
}

/* The pill cutout. Cosmetic, but a phone without one reads as a mockup. */
.nvx-device-notch {
  position: absolute;
  top: 9px;
  left: 50%;
  transform: translateX(-50%);
  width: 104px;
  height: 26px;
  border-radius: 999px;
  background: #05070d;
  z-index: 6;
}
/* The notch belongs to the bezel, not the screen, so it stays the bezel's
   colour in both themes. Painted ink-on-light it read as a black blob. */
.light-mode .nvx-device-notch,
.theme-light .nvx-device-notch { background: #12161f; }

/* The glow the device casts on the page. */
.nvx-device-halo {
  position: absolute;
  inset: 6% 2%;
  border-radius: 50%;
  background: radial-gradient(ellipse at 50% 50%, color-mix(in srgb, var(--nvx-primary) 34%, transparent), transparent 66%);
  filter: blur(60px);
  z-index: -1;
  pointer-events: none;
}

/* =====================================================================
   11. What's New — the 2.0 deck, as a web object
   ===================================================================== */

.nvx-deck {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: 20px;
}
.nvx-deck-card {
  display: flex;
  flex-direction: column;
  padding: 28px;
  min-height: 260px;
}
.nvx-deck-card h3 {
  margin: 0 0 10px;
  font-size: 1.32rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.18;
  color: var(--nvx-ink);
}
.nvx-deck-card p { margin: 0; font-size: 0.98rem; line-height: 1.58; color: var(--nvx-ink-dim); }
.nvx-deck-card .nvx-deck-tag {
  align-self: flex-start;
  margin-bottom: 18px;
  padding: 5px 11px;
  border-radius: 999px;
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--nvx-primary);
  background: color-mix(in srgb, var(--nvx-primary) 13%, transparent);
  border: 1px solid color-mix(in srgb, var(--nvx-primary) 26%, transparent);
}
.nvx-deck-card .nvx-deck-art { margin-top: auto; padding-top: 24px; }

.nvx-span-7 { grid-column: span 7; }
.nvx-span-5 { grid-column: span 5; }
.nvx-span-6 { grid-column: span 6; }
.nvx-span-4 { grid-column: span 4; }
.nvx-span-12 { grid-column: span 12; }

/* --- release timeline (whats-new page) --- */
.nvx-tl { position: relative; display: grid; gap: 12px; }
.nvx-tl::before {
  content: '';
  position: absolute;
  inset-inline-start: 11px;
  top: 14px;
  bottom: 14px;
  width: 2px;
  background: linear-gradient(180deg, var(--nvx-primary), color-mix(in srgb, var(--nvx-tertiary) 60%, transparent), transparent);
  opacity: 0.5;
}
.nvx-tl-row {
  position: relative;
  display: grid;
  grid-template-columns: 24px minmax(0, 1fr);
  gap: 22px;
  padding: 18px 0;
  align-items: start;
}
.nvx-tl-dot {
  position: relative;
  z-index: 1;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--nvx-void-bottom);
  border: 2px solid color-mix(in srgb, var(--nvx-primary) 55%, transparent);
}
.light-mode .nvx-tl-dot,
.theme-light .nvx-tl-dot { background: var(--nvx-void-top); }
.nvx-tl-dot i {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--nvx-primary);
}
.nvx-tl-row.is-major .nvx-tl-dot {
  border-color: transparent;
  background: linear-gradient(135deg, var(--nvx-primary), var(--nvx-tertiary));
  box-shadow: 0 0 0 5px color-mix(in srgb, var(--nvx-primary) 16%, transparent);
}
.nvx-tl-row.is-major .nvx-tl-dot i { background: #fff; }
.nvx-tl-ver {
  display: inline-block;
  margin-bottom: 8px;
  font-size: 0.74rem;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--nvx-primary);
}
.nvx-tl-row h3 { margin: 0 0 8px; font-size: 1.2rem; font-weight: 600; color: var(--nvx-ink); }
.nvx-tl-row ul { margin: 10px 0 0; padding: 0; list-style: none; display: grid; gap: 8px; }
.nvx-tl-row li {
  position: relative;
  padding-inline-start: 22px;
  font-size: 0.96rem;
  line-height: 1.55;
  color: var(--nvx-ink-dim);
}
.nvx-tl-row li::before {
  content: '';
  position: absolute;
  inset-inline-start: 4px;
  top: 0.68em;
  width: 5px; height: 5px;
  border-radius: 50%;
  background: color-mix(in srgb, var(--nvx-primary) 70%, transparent);
}

/* --- the tiny fake exchange used as deck-card art ------------------- */
.nvx-mini {
  display: grid;
  gap: 8px;
  padding: 14px;
  border-radius: 16px;
  border: 1px solid color-mix(in srgb, var(--nvx-outline) 45%, transparent);
  background: color-mix(in srgb, var(--nvx-surface) 70%, transparent);
}
.nvx-mini span { font-size: 0.9rem; line-height: 1.4; }
.nvx-mini-q {
  justify-self: end;
  max-width: 82%;
  padding: 9px 13px;
  border-radius: 14px 14px 4px 14px;
  background: color-mix(in srgb, var(--nvx-primary) 12%, transparent);
  color: var(--nvx-ink);
}
.nvx-mini-a { max-width: 84%; color: var(--nvx-ink); font-weight: 600; }
.nvx-mini-a::before {
  content: '';
  display: inline-block;
  width: 7px; height: 7px;
  margin-inline-end: 8px;
  border-radius: 50%;
  background: var(--nvx-secondary);
  vertical-align: 1px;
}

/* =====================================================================
   11b. Capability columns + the honest-limits slab
   ===================================================================== */

.nvx-cap { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 20px; }
.nvx-cap-col { padding: 30px; }
.nvx-cap-col header { margin-bottom: 20px; }
.nvx-cap-col h3 { margin: 12px 0 0; font-size: 1.2rem; font-weight: 700; letter-spacing: -0.015em; color: var(--nvx-ink); }
.nvx-cap-badge {
  display: inline-block;
  padding: 5px 11px;
  border-radius: 999px;
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}
/* Read tools run immediately; write tools always stop for a yes. The two
   colours carry that distinction before anyone reads a word. */
.nvx-cap-badge.is-read {
  color: var(--nvx-secondary);
  background: color-mix(in srgb, var(--nvx-secondary) 14%, transparent);
  border: 1px solid color-mix(in srgb, var(--nvx-secondary) 30%, transparent);
}
.nvx-cap-badge.is-write {
  color: var(--nvx-tertiary);
  background: color-mix(in srgb, var(--nvx-tertiary) 14%, transparent);
  border: 1px solid color-mix(in srgb, var(--nvx-tertiary) 32%, transparent);
}
.nvx-cap-col ul { margin: 0; padding: 0; list-style: none; display: grid; gap: 12px; }
.nvx-cap-col li {
  position: relative;
  padding-inline-start: 26px;
  font-size: 0.97rem;
  line-height: 1.5;
  color: var(--nvx-ink-dim);
}
.nvx-cap-col li::before {
  content: '';
  position: absolute;
  inset-inline-start: 2px;
  top: 0.42em;
  width: 12px;
  height: 7px;
  border-inline-start: 2px solid var(--nvx-primary);
  border-bottom: 2px solid var(--nvx-primary);
  transform: rotate(-45deg);
  border-radius: 1px;
}

.nvx-limits {
  margin-top: 24px;
  padding: 34px;
  border-radius: 26px;
  border: 1px dashed color-mix(in srgb, var(--nvx-outline) 80%, transparent);
  background: color-mix(in srgb, var(--nvx-surface) 40%, transparent);
}
.nvx-limits h3 {
  margin: 0 0 20px;
  font-size: 1.2rem;
  font-weight: 700;
  letter-spacing: -0.015em;
  color: var(--nvx-ink);
}
.nvx-limits ul { margin: 0; padding: 0; list-style: none; display: grid; gap: 14px; }
.nvx-limits li {
  position: relative;
  padding-inline-start: 26px;
  font-size: 0.97rem;
  line-height: 1.55;
  color: var(--nvx-ink-dim);
}
.nvx-limits li::before {
  content: '';
  position: absolute;
  inset-inline-start: 3px;
  top: 0.58em;
  width: 10px;
  height: 2px;
  border-radius: 2px;
  background: color-mix(in srgb, var(--nvx-ink-dim) 70%, transparent);
}
.nvx-limits b { color: var(--nvx-ink); font-weight: 600; }

/* =====================================================================
   12. Feature mosaic
   ===================================================================== */

.nvx-mosaic {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 20px;
}
.nvx-tile { padding: 30px; display: flex; flex-direction: column; gap: 14px; }
.nvx-tile-ic {
  display: grid;
  place-items: center;
  width: 48px; height: 48px;
  border-radius: 15px;
  color: var(--nvx-primary);
  background: linear-gradient(150deg, color-mix(in srgb, var(--nvx-primary) 22%, transparent), color-mix(in srgb, var(--nvx-tertiary) 14%, transparent));
  border: 1px solid color-mix(in srgb, var(--nvx-primary) 26%, transparent);
}
.nvx-tile h3 { margin: 0; font-size: 1.1rem; font-weight: 600; color: var(--nvx-ink); }
.nvx-tile p { margin: 0; font-size: 0.96rem; line-height: 1.56; color: var(--nvx-ink-dim); }

/* =====================================================================
   13. Step rail
   ===================================================================== */

.nvx-steps { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 20px; counter-reset: nvxstep; }
.nvx-step { position: relative; padding: 30px 28px 28px; }
/* On h3, NOT on the card. `.nvx-step` is also `.nvx-card`, whose ::before
   is the glass sheen at position:absolute;inset:0 — both rules landed on one
   pseudo-element, so the numeral painted across the card's border box, over
   its own heading, clipped by the rounded corner, and the card lost its
   sheen. On the heading it returns to flow and the sheen comes back. */
.nvx-step h3::before {
  counter-increment: nvxstep;
  content: '0' counter(nvxstep);
  display: block;
  margin-bottom: 16px;
  font-size: 2.4rem;
  font-weight: 700;
  line-height: 1;
  letter-spacing: -0.04em;
  background: linear-gradient(140deg, var(--nvx-primary), var(--nvx-tertiary));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  opacity: 0.85;
}
.nvx-step h3 { margin: 0 0 8px; font-size: 1.08rem; font-weight: 600; color: var(--nvx-ink); }
.nvx-step p { margin: 0; font-size: 0.96rem; line-height: 1.56; color: var(--nvx-ink-dim); }

/* =====================================================================
   14. Closing CTA
   ===================================================================== */

.nvx-final {
  position: relative;
  padding: clamp(48px, 6vw, 82px) clamp(24px, 5vw, 68px);
  text-align: center;
  border-radius: 36px;
  overflow: hidden;
}
.nvx-final::after {
  content: '';
  position: absolute;
  inset: -40% -10% auto;
  height: 120%;
  background: radial-gradient(ellipse at 50% 0%, color-mix(in srgb, var(--nvx-primary) 22%, transparent), transparent 62%);
  pointer-events: none;
  z-index: 0;
}
.nvx-final > * { position: relative; z-index: 1; }
.nvx-final .nvx-h2 { max-width: 18ch; margin-inline: auto; }
.nvx-final .nvx-lead { margin-inline: auto; text-align: center; }
.nvx-fine {
  margin: 22px auto 0;
  max-width: 60ch;
  font-size: 0.85rem;
  line-height: 1.55;
  color: color-mix(in srgb, var(--nvx-ink-dim) 82%, transparent);
}

/* =====================================================================
   15. Trust row
   ===================================================================== */

.nvx-trust { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 18px; }
.nvx-trust-item { padding: 24px; display: grid; gap: 10px; }
.nvx-trust-item svg { color: var(--nvx-primary); }
.nvx-trust-item h3 { margin: 0; font-size: 0.99rem; font-weight: 600; color: var(--nvx-ink); }
.nvx-trust-item p { margin: 0; font-size: 0.9rem; line-height: 1.5; color: var(--nvx-ink-dim); }

/* =====================================================================
   16. Responsive
   ===================================================================== */

@media (max-width: 1080px) {
  .nvx-deck-card { min-height: 0; }
  .nvx-span-7, .nvx-span-5 { grid-column: span 6; }
}

@media (max-width: 980px) {
  :root { --nvx-band-pad: 80px; }
  .nvx-hero { padding-top: calc(var(--nav-height) + 52px); }
  .nvx-hero-inner { grid-template-columns: minmax(0, 1fr); gap: 44px; }
  /* Stacked, the copy comes FIRST. The positioning line is the message;
     leading with the star pushed it below the fold on a phone. */
  .nvx-hero-media { min-height: 380px; }
  .nvx-hero-sub { max-width: 62ch; }
  .nvx-assist { grid-template-columns: minmax(0, 1fr); gap: 44px; }
  .nvx-assist-copy { max-width: none; }
  .nvx-mosaic, .nvx-steps { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .nvx-trust { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .nvx-span-7, .nvx-span-5, .nvx-span-6, .nvx-span-4 { grid-column: span 12; }
}

@media (max-width: 734px) {
  :root { --nvx-gutter: 20px; --nvx-band-pad: 62px; }
  .nvx-head-center { margin-bottom: 38px; }
  .nvx-proof { grid-template-columns: minmax(0, 1fr); gap: 16px; margin-top: 30px; padding-top: 24px; }
  .nvx-proof li { display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: baseline; gap: 12px; }
  .nvx-proof-l { margin-top: 0; }
  .nvx-mosaic, .nvx-steps, .nvx-trust { grid-template-columns: minmax(0, 1fr); }
  .nvx-hero-media { min-height: 320px; }
  .nvx-star { width: min(290px, 78vw); }
  .nvx-star-mark { width: 84px; height: 84px; }
  .nvx-star-cap b { font-size: 1.28rem; }
  .nvx-star-cap span { font-size: 0.86rem; }
  .nvx-btn { width: 100%; }
  .nvx-cta-row { gap: 12px; }
  .nvx-cta-row .nvx-btn-text { width: 100%; justify-content: center; }
  .nvx-tl-row { grid-template-columns: 20px minmax(0, 1fr); gap: 16px; }
  .nvx-tl::before { inset-inline-start: 9px; }
  .nvx-tl-dot { width: 20px; height: 20px; }
  .nvx-final { border-radius: 26px; }
  .nvx-vow { padding: 22px 20px; font-size: 1rem; }
}

/* =====================================================================
   17. Reduced motion — render the settled frame, never a shortened one
   ===================================================================== */

@media (prefers-reduced-motion: reduce) {
  [data-nvx-reveal] { opacity: 1 !important; transform: none !important; filter: none !important; transition: none !important; }
  .nvx-aurora span,
  .nvx-star-mark,
  .nvx-grad,
  .nvx-marquee-track { animation: none !important; }
  .nvx-card-lift, .nvx-btn, .nvx-pill { transition: none !important; }
  .nvx-card-lift:hover, .nvx-btn:hover, .nvx-pill:hover { transform: none !important; }
  /* backdrop-filter is dropped too: the app drops its blur under reduced
     motion, and it is also the single biggest scroll-jank source. */
  .nvx-card, .nvx-btn-ghost, .nvx-pill, .nvx-chip {
    backdrop-filter: none !important;
    -webkit-backdrop-filter: none !important;
  }
}

/* whats-new page responsive tail */
@media (max-width: 980px) {
  .nvx-cap { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 734px) {
  .nvx-cap-col, .nvx-limits { padding: 24px 20px; }
}

/* =====================================================================
   18. Fixed-count rails: grid, not flex-wrap
   ---------------------------------------------------------------------
   Three rails used `flex: 1 1 Npx; max-width: Mpx` under
   `justify-content: center`. With a fixed number of cards that always
   orphans the last row AT A DIFFERENT SIZE: a full row compresses toward
   the flex-basis while a short row grows to the max-width cap, so the
   five-card trust strip rendered four at 253x163 then one at 300x101,
   centred, aligned to nothing. A grid gives every card one width and the
   last row simply ends.
   ===================================================================== */

.trust-strip {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 14px;
}
.trust-strip > * { flex: none; max-width: none; }

.feature-moats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 16px;
}
.feature-moats > * { flex: none; max-width: none; }

/* Eight thumbs at 136px + seven 12px gaps need 1172px, but the rail was
   capped at 1040 — so "Credit" sat alone on row two at every width from
   1280 up. Four-up by two is the only clean factorisation of eight. */
.showcase-thumbs {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 12px;
  width: min(var(--nvx-wide), 100%);
}
.showcase-thumb { max-width: none; }

@media (max-width: 980px) {
  .trust-strip { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .showcase-thumbs { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 734px) {
  .trust-strip { grid-template-columns: minmax(0, 1fr); }
  .showcase-thumbs { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* A12: the release bullets ran to 155 characters while the intro paragraph
   in the same row was correctly capped at 74. */
.nvx-tl-row li { max-width: 560px; }

/* /about's Mission lead ran to 125 characters and then a 13-character stub,
   while the Founder note on the same page is capped at 559px. Match it. */
.about-mission .section-lead { max-width: 560px; }

/* =====================================================================
   19. Mobile: reading order and touch targets
   ===================================================================== */

/* A13. Stacked, the COPY comes first. The markup puts the device before
   the copy so the two-column desktop layout reads phone-left/words-right,
   but stacked that meant a phone frame with a silent scripted conversation
   arrived ~730px before any heading explained what it was. */
@media (max-width: 980px) {
  .nvx-assist { display: flex; flex-direction: column; }
  .nvx-assist > .nvx-assist-copy { order: 0; }
  .nvx-assist > .nvx-hero-media,
  .nvx-assist > *:not(.nvx-assist-copy) { order: 1; }
}

/* A14. Touch targets. Everything below measured under 44px on a 390px
   viewport: the open nav's links were 16px tall, the language flags 26px,
   the theme toggle 34px and the hamburger 38px. These are the controls a
   phone visitor uses to get anywhere. */
@media (max-width: 900px) {
  .apple-nav .nav-items > a {
    display: flex;
    align-items: center;
    min-height: 44px;
  }
}
@media (max-width: 980px) {
  .lang-btn {
    min-width: 44px;
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }
  .theme-toggle,
  .nav-toggle {
    min-width: 44px;
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }
  .nav-cta { min-height: 44px; display: inline-flex; align-items: center; }
  .nvx-demo-ctl { min-height: 44px; }

  /* Standalone links, not links inside a sentence. WCAG exempts inline
     links in flowing text from the target minimum; none of these are that
     — they are the section CTAs and the whole footer nav. */
  .btn-apple-link,
  .footer-nav a,
  .brand-lockup,
  .nvx-pill,
  .nvx-replay-intro,
  .nvx-btn-text {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
  }
  .cookie-btn { min-height: 44px; }
}

/* A15. The mid-page CTA. Deliberately a slim two-column slab rather than a
   third full-height callout: the page already closes on one, and a second
   tall centred block in the middle would read as the end of the page. */
.nvx-midcta {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: clamp(24px, 4vw, 56px);
  padding: clamp(28px, 4vw, 44px) clamp(24px, 4vw, 48px);
}
.nvx-midcta-title {
  margin: 0 0 10px;
  font-size: clamp(1.55rem, 1.2rem + 1.4vw, 2.1rem);
  font-weight: 700;
  line-height: 1.12;
  letter-spacing: -0.025em;
  color: var(--nvx-ink);
  text-wrap: balance;
}
.nvx-midcta .nvx-lead { font-size: 1rem; max-width: 52ch; }
@media (max-width: 860px) {
  .nvx-midcta { grid-template-columns: minmax(0, 1fr); }
  .nvx-midcta .nvx-cta-row { width: 100%; }
}

/* The slim mid-page CTA. One row, one action, no card chrome — it punctuates
   the long story run without pretending to be a section of its own. */
.nvx-ctaslim {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 20px 32px;
  padding: 26px clamp(22px, 3vw, 34px);
  border-radius: 22px;
  border: 1px solid var(--nvx-card-border);
  background: linear-gradient(100deg, color-mix(in srgb, var(--nvx-primary) 12%, transparent), transparent 62%);
}
.nvx-ctaslim p {
  margin: 0;
  font-size: clamp(1.08rem, 0.98rem + 0.5vw, 1.35rem);
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: -0.018em;
  color: var(--nvx-ink);
  max-width: 30ch;
}
@media (max-width: 640px) {
  .nvx-ctaslim { flex-direction: column; align-items: stretch; text-align: center; }
  .nvx-ctaslim p { max-width: none; }
}

/* =====================================================================
   20. B-group: light-mode surfaces, chart ink, and layout corrections
   ===================================================================== */

/* B2. The /features comparison's "them" card measured 1.01:1 against the
   light page — the column read as loose text while its partner read as an
   object, so a two-sided comparison landed as a one-sided claim. This is
   the recurring sub-0.6 light-mode fill failure. */
body.light-mode .vs-card.vs-them,
.theme-light .vs-card.vs-them {
  background: rgba(255, 255, 255, 0.62);
  border-color: rgba(160, 170, 195, 0.9);
}
body.light-mode .vs-label,
.theme-light .vs-label,
body.light-mode .testimonial-attr,
.theme-light .testimonial-attr { color: #33394a; }

/* B15. The star's caption was anchored to the box (bottom:6%) while the
   mark was anchored to the painter centre (top:35%), so the two drifted
   185px apart at every width and the caption read as an unrelated block.
   One grid, two rows, a real gap; the canvas keeps its own absolute bleed. */
.nvx-star {
  display: grid;
  grid-template-rows: auto auto;
  justify-items: center;
  align-content: center;
  gap: 26px;
  aspect-ratio: auto;
  min-height: 420px;
}
.nvx-star-mark {
  position: relative;
  top: auto;
  left: auto;
  transform: none;
  grid-row: 1;
}
.nvx-star-cap {
  position: relative;
  left: auto;
  bottom: auto;
  transform: none;
  grid-row: 2;
}
@keyframes nvx-float-rel { from { transform: translateY(-4px); } to { transform: translateY(4px); } }
.nvx-star-mark { animation: nvx-float-rel 2600ms var(--nvx-ease-std) infinite alternate; }

/* B16. `.nvx-assist-copy{max-width:30rem}` capped the copy at 480px inside a
   609px column, so the whole composition sat 33px left of every other
   section's centre while the same class in the narrower column had almost
   no slack. Even columns, and the cap only where it is not the constraint. */
.nvx-assist { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
.nvx-assist-copy { max-width: 34rem; }

/* B18. Right for a 9-tile mosaic, wrong for a 3-card numbered sequence:
   at 900px it ran two cards then one with a card-width of empty grid. */
@media (max-width: 980px) {
  .nvx-steps { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 14px; }
}
@media (max-width: 734px) {
  .nvx-steps { grid-template-columns: minmax(0, 1fr); }
}

/* B19. Stacked, the story copy stayed left-aligned in a 560px block while
   the phone centred below it — 348px of dead gutter beside every heading,
   six times in a row. Pick one alignment. */
@media (max-width: 980px) {
  .scroll-story-inner { justify-items: center; }
  .scroll-copy { margin-inline: auto; max-width: 640px; }
  .scroll-media { justify-self: center; }
}

/* B21. `.lang-btn{opacity:.45}` multiplied the UA focus ring down to 2.0:1,
   so a keyboard user lost the cursor exactly at the language switcher while
   the neighbouring toggle sat at 7.56:1. Restoring opacity is the
   load-bearing half of this. */
.lang-btn:focus-visible {
  opacity: 1;
  outline: 2px solid var(--nvx-primary);
  outline-offset: 2px;
}

/* B17. /features hero: the three cards are identical boxes, but
   `align-content: end` bottom-aligned their contents, so a 2/3/2-line
   heading difference staggered the eyebrows across three baselines 45px
   apart — a visible staircase across a row of equal cards. */
.feature-hero-card,
.features-hero .feature-moat-card { align-content: start; }

/* B8 note: the two screenshots the gallery uniquely carried were briefly
   rehomed into mosaic tiles here. That was wrong and is reverted: these are
   1320x2868 phone captures, and cropping one into a 322x210 slot shows the
   status bar and nothing else. The tiles are text cards and read better
   without art. Those two screens live on /features, in real phone frames. */

/* B11. The store badges, lifted into the hero. install.css owns their look
   and this page does not load it, so the shell they need lives here. */
.nvx-hero-badges {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 26px;
}
.nvx-hero-badges .store-badge {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  min-height: 52px;
  padding: 0 18px;
  border-radius: 14px;
  border: 1px solid var(--nvx-card-border);
  background: color-mix(in srgb, var(--nvx-surface) 68%, transparent);
  color: var(--nvx-ink);
  text-decoration: none;
  transition: transform var(--nvx-dur-med) var(--nvx-ease-emph), border-color var(--nvx-dur-med) var(--nvx-ease-emph);
}
.nvx-hero-badges .store-badge:hover {
  transform: translateY(-2px);
  border-color: color-mix(in srgb, var(--nvx-primary) 50%, var(--nvx-card-border));
}
.nvx-hero-badges .badge-icon svg { width: 24px; height: 24px; display: block; }
.nvx-hero-badges .badge-meta { display: grid; line-height: 1.15; }
.nvx-hero-badges .badge-subtitle { font-size: 0.66rem; letter-spacing: 0.06em; text-transform: uppercase; color: var(--nvx-ink-dim); }
.nvx-hero-badges .badge-title { font-size: 1rem; font-weight: 600; }

/* B9. The band was 200px tall carrying 48px of ink, with no heading, so it
   read as a section that had failed to load. A label gives it a reason to
   exist and the padding stops it floating. The chips lost their leading
   plus icon in the markup: styled as the app's tappable suggestion pills,
   they invited a tap they could not answer. */
.nvx-marquee-band { padding: calc(var(--nvx-band-pad) / 2.6) 0; }
.nvx-marquee-label {
  margin: 0 0 18px;
  text-align: center;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--nvx-ink-dim);
}
.nvx-chip { cursor: default; }

/* B12. The price anchor. The homepage named Core and Premium four times
   before defining either, and carried no dollar figure outside the demo's
   own chart, so the plan names read as bare jargon. */
.nvx-price-anchor {
  margin: 26px auto 0;
  max-width: 62ch;
  font-size: 0.98rem;
  line-height: 1.6;
  color: var(--nvx-ink-dim);
}
.nvx-price-anchor strong { color: var(--nvx-ink); font-weight: 600; }
.nvx-price-note {
  margin: 8px auto 0;
  max-width: 56ch;
  font-size: 0.85rem;
  line-height: 1.5;
  color: color-mix(in srgb, var(--nvx-ink-dim) 82%, transparent);
}

/* =====================================================================
   21. C-group
   ===================================================================== */

/* C1. The middle of the type scale had collapsed: card headings came in
   four sizes for one role (21.1 / 17.6 / 17.3 / 16.6px) and `.nvx-point h3`
   sat only 8% above the body beneath it, so the assistant section's three
   benefit blocks scanned as one grey mass. One ramp, and every card heading
   on the same step. */
:root {
  --nvx-t-xs: 0.82rem;
  --nvx-t-sm: 0.94rem;
  --nvx-t-base: 1rem;
  --nvx-t-md: 1.12rem;
  --nvx-t-lg: 1.32rem;
  --nvx-t-xl: clamp(1.55rem, 1.2rem + 1.4vw, 2.1rem);
  --nvx-t-2xl: clamp(2.05rem, 1.45rem + 2.3vw, 3.15rem);
}
.nvx-tile h3,
.nvx-point h3,
.nvx-step h3,
.nvx-cap-col h3,
.nvx-trust-item h3 {
  font-size: var(--nvx-t-md);
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: -0.012em;
}
.nvx-deck-card h3 { font-size: var(--nvx-t-lg); }
.nvx-tile p,
.nvx-point p,
.nvx-step p { font-size: var(--nvx-t-sm); }

/* C3. The nvx layer shipped no focus styles at all, so its controls fell
   back to Chrome's ring while the older layer used a branded 2px one. The
   ring changed colour and thickness several times down a single page. */
.nvx-btn:focus-visible,
.nvx-btn-text:focus-visible,
.nvx-pill:focus-visible,
.nvx-chip:focus-visible,
.nvx-card a:focus-visible,
.nvx-replay-intro:focus-visible,
.nvx-cine-skip:focus-visible,
.nvx-hero-badges .store-badge:focus-visible {
  outline: 2px solid var(--nvx-primary);
  outline-offset: 3px;
  border-radius: 6px;
}

/* C4. forced-colors strips `background`, and the brand button's entire shape
   came from one. "Get the App" rendered as bare text while the SECONDARY
   ghost button kept its border, inverting the hierarchy. A transparent
   border is free normally and is promoted to a system colour there. */
.nvx-btn-brand { border: 1px solid transparent; }
@media (forced-colors: active) {
  .nvx-btn-brand { border-color: ButtonText; }
  .nvx-card { border: 1px solid CanvasText; }
}

/* C5. 62 layers stayed permanently promoted after their entrance finished.
   The measured cost is small (59.5fps vs 60.0 at 6x throttle) but it is free
   to give back, and low-end Android is where it is not free. */
html.nvx-js [data-nvx-reveal].is-nvx-in { will-change: auto; }

/* C6. At 1024px the 3-up mosaic squeezed body copy to 26-34 characters per
   line: a seven-line paragraph averaging 29 characters in the Break-Even
   tile. Two columns from 1180 down. The steps rail keeps its own three. */
@media (max-width: 1180px) {
  .nvx-mosaic { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* C7. Centred leads broke long-then-stub (73 characters, then 21). Note the
   `ch` trap: in Inter, 56ch renders about 73 characters, so the cap has to
   be tighter than the number suggests. */
.nvx-lead { text-wrap: pretty; }
.nvx-head-center .nvx-lead { text-wrap: balance; max-width: 46ch; }
.nvx-fine { text-wrap: pretty; max-width: 56ch; }

/* C8. 600-734px was getting phone styling: a 694px-wide "Get the App" and a
   one-column proof rail with ~430px of trailing space per stat. Full-bleed
   belongs to actual phones. */
@media (min-width: 521px) and (max-width: 734px) {
  .nvx-btn { width: auto; }
  .nvx-proof { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .nvx-cta-row .nvx-btn-text { width: auto; }
}

/* =====================================================================
   22. Pricing: the paywall first, and a way back to it
   ---------------------------------------------------------------------
   The plans used to sit below a full screen of hero and a trust strip
   already shown on the homepage, so a visitor who came here for a number
   scrolled past everything before seeing one. Plans now come first, and
   everything below can point back at a SPECIFIC plan rather than at the
   top of the page.
   ===================================================================== */

.pricing-hero-tight { padding-top: calc(var(--nav-height) + 44px); padding-bottom: 0; }
.pricing-hero-tight .hero-title { margin-bottom: 0; }

.nvx-planjump {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px 12px;
  margin-top: 24px;
  /* min-width:0 so the row can never establish a min-content width wider
     than its parent. Dropped into a centred CTA slab it did exactly that,
     widening the card's content box and shoving the headline off the right
     edge. A rail like this must always be able to shrink and wrap. */
  min-width: 0;
  max-width: 100%;
}
.nvx-planjump-center { justify-content: center; margin-inline: auto; }
.nvx-planjump-label {
  font-size: 0.86rem;
  color: var(--nvx-ink-dim);
  margin-inline-end: 4px;
}
.nvx-planjump-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 40px;
  padding: 0 16px;
  border-radius: 999px;
  border: 1px solid var(--nvx-card-border);
  background: color-mix(in srgb, var(--nvx-surface) 64%, transparent);
  color: var(--nvx-ink);
  font-size: 0.9rem;
  font-weight: 600;
  text-decoration: none;
  transition: transform var(--nvx-dur-med) var(--nvx-ease-emph), border-color var(--nvx-dur-med) var(--nvx-ease-emph);
}
.nvx-planjump-btn::after { content: '\2191'; opacity: 0.6; font-weight: 400; }
.nvx-planjump-btn:hover {
  transform: translateY(-1px);
  border-color: color-mix(in srgb, var(--nvx-primary) 55%, var(--nvx-card-border));
}

/* Landing on a plan has to be legible, or the jump feels like nothing
   happened. The card announces itself once and settles. */
.plan-card-v2 { scroll-margin-top: calc(var(--nav-height) + 28px); }
.plan-card-v2:focus { outline: none; }
.plan-card-v2.is-nvx-target {
  animation: nvx-plan-land 1400ms var(--nvx-ease-emph) both;
}
@keyframes nvx-plan-land {
  0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--nvx-primary) 55%, transparent); }
  22%  { box-shadow: 0 0 0 4px color-mix(in srgb, var(--nvx-primary) 45%, transparent); }
  100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--nvx-primary) 0%, transparent); }
}
@media (prefers-reduced-motion: reduce) {
  .plan-card-v2.is-nvx-target { animation: none; box-shadow: 0 0 0 2px var(--nvx-primary); }
}

/* =====================================================================
   23. Scroll-story phones: shorter than the viewport
   ---------------------------------------------------------------------
   These rendered 420x913 from a 1320x2868 capture, so a single screenshot
   was taller than a 900px viewport. Six of them, each sticky, meant long
   runs of empty column beside a phone you could never see whole. Narrower,
   and cropped from the TOP so the part that carries the headline's claim
   is the part you keep. The fade makes the crop deliberate rather than a
   cut, and only the bottom is masked so nothing important is softened.
   ===================================================================== */
.scroll-story .phone-frame { max-width: 340px; }
.scroll-story .phone-frame img {
  max-height: 560px;
  object-fit: cover;
  object-position: top center;
  -webkit-mask-image: linear-gradient(180deg, #000 78%, transparent 100%);
  mask-image: linear-gradient(180deg, #000 78%, transparent 100%);
}
@media (max-width: 980px) {
  .scroll-story .phone-frame { max-width: 300px; }
  .scroll-story .phone-frame img { max-height: 460px; }
}
