/* Snapi landing page — scoped styles.
   All class names live under .snapi-landing-v2 to avoid colliding with Chakra
   or the authenticated app styles. */

/* Weight-matched fallback for the serif headings. Lustria is Latin-only (no
   latin-ext), so non-English locales hit glyphs it doesn't have — e.g. Romanian
   ă/ț/ș — and fall back to the local serif. Lustria itself ships ONLY weight 400,
   so the headings (600/800) are already faux-bold; the fallback's *real* bold
   then rendered much heavier, making those few characters stand out. This alias
   declares the local serif at weight 400 ONLY, so the browser synthesises bold
   from it too — a faux-bold that matches Lustria's. Sits right after 'Lustria'
   in the stack, so it only affects glyphs Lustria can't render.
   (Cross-platform note: relies on a local serif being present — Georgia/Times on
   macOS/Windows. Where neither exists the system serif still applies its own
   bold; a full-coverage webfont would be the robust multilingual answer.) */
@font-face {
  font-family: 'LustriaFallback';
  src: local('Georgia'), local('Times New Roman'), local('Times');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

.snapi-landing-v2 {
  /* The --sl-* palette is now sourced from the Chakra theme (semanticTokens in
     src/theme/index.ts) — this block is the single bridge point. The Chakra vars
     carry their own light/dark values keyed off <html data-theme>, the same flag
     this file's [data-theme="dark"] rules use, so no manual dark flip is needed
     for the promoted vars (see the slimmed dark block below). */
  /* Landing background wash — warm cream (founder 2026-09-17). Light mode only;
     the [data-theme="dark"] block below restores the slate canvas. */
  --sl-bg: #fefaed;
  --sl-bg-gradient-tint: #fffdf6;
  --sl-fg: var(--chakra-colors-ink-base);
  --sl-fg-muted: var(--chakra-colors-ink-muted);
  --sl-fg-soft: var(--chakra-colors-ink-soft);
  --sl-primary: var(--chakra-colors-primary-base);
  --sl-primary-hover: var(--chakra-colors-primary-hover);
  --sl-border: var(--chakra-colors-stroke-base);
  --sl-surface: var(--chakra-colors-panel-base);
  --sl-surface-alt: var(--chakra-colors-panel-alt);
  --sl-card-bg: var(--chakra-colors-panel-card);
  /* Landing-local — not reused elsewhere, so kept here with a manual dark flip. */
  --sl-dark: #0f172a;
  --sl-darker: #020617;
  --sl-shadow-color: 15, 23, 42;

  min-height: 100vh;
  /* Extremely light diagonal gradient. The two stops are within ~3% of each
     other so the wash is felt more than seen. */
  background:
    linear-gradient(155deg, var(--sl-bg) 0%, var(--sl-bg-gradient-tint) 100%) fixed;
  color: var(--sl-fg);
  font-family: var(--font-face-sans, 'Geist'), -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  -webkit-font-smoothing: antialiased;
  line-height: 1.5;
  /* Establish a stacking context so the ::before rain layer below can sit
     visually behind content (z-index: -1) without escaping the section. */
  position: relative;
  isolation: isolate;
}

/* (Rain effect removed.) */

/* (Illustrated-sections styles removed with the IllustratedSections
   component — see git history if the Create/Activate/Reach blocks return.) */

/* ---------- Scroll progress line ---------- */
/* A vertical dotted line absolutely positioned between the hero manifesto
   and the beta-signup section. JS in ScrollLine.tsx sets `top` + `height`
   based on those elements' positions and ties the fill to scrollY. */
.snapi-landing-v2 .sl-scroll-line {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  width: 2px;
  pointer-events: none;
  /* Sits between the rain (z-index: -2) and the page content (default flow).
     Visible through any semi-transparent section background, hidden behind
     opaque elements. */
  z-index: -1;
}
/* No default track — only the filled portion is drawn so the line literally
   appears as the user scrolls. */
.snapi-landing-v2 .sl-scroll-line__track {
  display: none;
}
.snapi-landing-v2 .sl-scroll-line__fill {
  position: absolute;
  top: 0;
  /* Centre the (wider) dot column on the 2px line. */
  left: 50%;
  transform: translateX(-50%);
  width: 4px;
  height: 100%;
  /* Actual circular dots via radial-gradient — 3px diameter, 8px pitch.
     Animating `height` (not scaleY) keeps the 8px period constant as
     the line draws. */
  background-image: radial-gradient(
    circle at center,
    var(--sl-primary) 1px,
    transparent 1.5px
  );
  background-size: 4px 8px;
  background-position: center top;
  background-repeat: repeat-y;
}
/* Markers sit on the same z-layer as the line itself — below all page
   content, above the background fill. Putting them above content
   caused spinners to overlap section cards as the user scrolled past;
   tucking them behind keeps the line as a pure backdrop element. */
.snapi-landing-v2 .sl-scroll-line-markers {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  width: 2px;
  pointer-events: none;
  z-index: -1;
}
/* Each section anchor on the line hosts a SnapiMark spinner. The
   marker box provides centring; colour + animation come from the mark
   itself via `currentColor` + the SnapiMark animate prop. Box is
   sized to the spinner (100 px) — the dotted line passes through its
   centre. */
.snapi-landing-v2 .sl-scroll-line__marker {
  position: absolute;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 100px;
  height: 100px;
  display: flex;
  align-items: center;
  justify-content: center;
  /* Snapi-blue spinner so it matches the dotted scroll-line dots. */
  color: var(--sl-primary);
}
/* (The scroll caret moved into the hero cue — see .sl-hero__scroll-caret above.
   It's a flow child of the tagline group now, not a JS-positioned overlay on
   the scroll line.) */

/* Only the landing-local vars need a manual dark flip now — the promoted
   --sl-* vars above inherit their dark values from the Chakra theme tokens. */
[data-theme="dark"] .snapi-landing-v2 {
  --sl-dark: #020617;
  --sl-darker: #010409;
  --sl-shadow-color: 0, 0, 0;
  /* Keep the dark slate canvas — the teal wash above is light-mode only. */
  --sl-bg: var(--chakra-colors-canvas-base);
  --sl-bg-gradient-tint: var(--chakra-colors-canvas-tint);
}

.snapi-landing-v2 * {
  box-sizing: border-box;
}

.snapi-landing-v2 h1,
.snapi-landing-v2 h2,
.snapi-landing-v2 h3 {
  margin: 0;
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.1;
}

.snapi-landing-v2 p {
  margin: 0;
}

.snapi-landing-v2 a {
  color: inherit;
  text-decoration: none;
}

.snapi-landing-v2 button {
  font-family: inherit;
  cursor: pointer;
  border: none;
  background: none;
}

/* ---------- Header ---------- */
.sl-header {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  /* Avatar inset comes from the shared single source
     (--snapi-topnav-avatar-* in app.css), matched to /agents + the public
     agent page. align-items:flex-start makes the top var map directly to the
     avatar's top edge (no centring offset). pl stays 24px for the brand. */
  padding: var(--snapi-topnav-avatar-top) var(--snapi-topnav-avatar-right) 20px 24px;
  width: 100%;
  background: transparent;
}
.sl-header__brand {
  display: flex;
  align-items: center;
  gap: 12px;
}
.sl-header__brand-text {
  /* Matches the hero "SNAPI" wordmark: Geist 900, uppercase, white, with a
     scaled-down drop shadow so the white stays legible on the transparent
     header over the pale page bg. (Geist is already loaded app-wide via
     next/font in _app, so the wordmark costs no extra font request — the landing
     now loads only Geist + Lustria.) */
  font-family: var(--font-face-sans, 'Geist'), -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  font-size: 20px;
  font-weight: 900;
  color: #fff;
  text-shadow: 0 4px 12px rgba(0, 0, 0, 0.45);
  text-transform: uppercase;
  letter-spacing: 1px;
}
/* Logo wears the same drop shadow as the wordmark beside it. The wordmark uses
   text-shadow; the logo is a PNG, so filter:drop-shadow (same offset/blur/color)
   follows the circular alpha instead of boxing the whole image. */
.sl-header__brand img {
  filter: drop-shadow(0 4px 12px rgba(0, 0, 0, 0.45));
}
.sl-header__nav {
  display: flex;
  /* flex-start (not center) so the avatar's top edge equals the shared inset
     var rather than being pushed down ~3px by centring against the taller
     "Join Beta" button — keeps it pixel-aligned with /agents + the agent page. */
  align-items: flex-start;
  gap: 8px;
}
.snapi-landing-v2 .sl-header__nav .sl-btn-primary {
  display: none;
}
@media (min-width: 900px) {
  .snapi-landing-v2 .sl-header__nav .sl-btn-primary {
    display: inline-flex;
  }
}
.snapi-landing-v2 .sl-btn-primary {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 40px;
  font-size: 15px;
  font-weight: 600;
  color: #fff;
  /* CTA — the Snapi brand purple→magenta gradient (matches the pre-login guest
     avatar mark, founder 2026-09-17). */
  background: linear-gradient(90deg, #1818d0 0%, #ff00cc 100%);
  padding: 0 22px;
  margin-right: 20px;
  border-radius: 999px;
  transition: filter 0.15s;
}
.sl-btn-primary:hover {
  filter: brightness(0.93);
}
/* ---------- Hero ---------- */
.sl-hero {
  /* Top buffer matches the 24px side padding (was 60px). The fold min-height
     calc below subtracts this same value, so keep them in sync. */
  padding: 24px 24px 40px;
  max-width: none;
  margin: 0 auto;
}
.sl-hero__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 8px;
  align-items: center;
  text-align: center;
}
/* "Above the fold" container — fills the viewport (minus the sticky header
   + the .sl-hero top padding) so the SNAPI wordmark anchors just above the
   scroll boundary. The manifesto h2 sits outside this wrapper and is the
   first thing the user discovers when they start scrolling.

   100dvh is the dynamic viewport unit; on iOS Safari/Android Chrome it
   shrinks/grows with the URL bar so the wordmark stays at the visible fold
   instead of slipping behind the chrome. The 84px subtracts the sticky
   header (≈84px = 44px logo + 20px x 2 padding); the 24px subtracts the
   .sl-hero top padding above. */
.snapi-landing-v2 .sl-hero__fold {
  /* The fold IS the first screen — its bottom edge should land on the viewport
     bottom so the bottom-anchored cue (tagline + caret) sits a fixed gap above
     it on EVERY viewport. Height = viewport − sticky header (84px) − the hero's
     own top padding (24px on mobile and desktop, overridden below). The
     old `- 120px` guess matched neither, so the cue drifted "too high". */
  min-height: calc(100dvh - 84px - 24px);
  display: flex;
  flex-direction: column;
  align-items: stretch;
  /* The fold is a GRID ITEM (child of .sl-hero__grid). Its default
     `min-width: auto` = its min-content, which the full-bleed WebGL gallery
     inside drives wide. The gallery's canvas doesn't shrink when the window is
     resized narrower, so its stale width would otherwise force the fold past
     its `1fr` column — overflowing the viewport and pushing the hero rotating
     text off-screen (right in LTR, fully off-screen-left in RTL/Arabic).
     `min-width: 0` lets the fold shrink to its column; the over-wide gallery
     is just clipped (it's already `overflow: hidden`), and the subtitle wraps
     to fit instead of overflowing. */
  min-width: 0;
}
@media (min-width: 900px) {
  .snapi-landing-v2 .sl-hero__fold {
    min-height: calc(100dvh - 84px - 24px);
  }
}
/* Scroll cue = tagline + caret as ONE flow group. `margin-top: auto` pushes the
   group to the fold's bottom; `margin-bottom` holds it a fixed 20px above the
   viewport bottom. Both children are centred in the same flex column, so the
   caret is always dead-centre under the tagline a fixed gap below — pure CSS, so
   they can't misalign on resize the way the old JS-positioned caret did. */
.snapi-landing-v2 .sl-hero__cue {
  margin-top: auto;
  margin-bottom: 20px;
  display: flex;
  flex-direction: column;
  align-items: center;
  /* 0 (was 10px): sits the tagline right on the caret's 40px hit-box, whose
     internal padding supplies the visual breathing room. The group is
     bottom-anchored, so removing the gap drops the TAGLINE 10px (toward the
     caret) — the caret itself doesn't move. */
  gap: 0;
}
.snapi-landing-v2 .sl-hero__scroll-caret {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  padding: 0;
  border: none;
  background: none;
  color: var(--sl-primary);
  cursor: pointer;
  transition: transform 0.2s ease;
}
.snapi-landing-v2 .sl-hero__scroll-caret:hover {
  transform: translateY(3px);
}
@media (max-width: 899px) {
  /* Touch users swipe to scroll; keep the caret as a visual cue but drop the
     click-to-scroll action (desktop-only). */
  .snapi-landing-v2 .sl-hero__scroll-caret {
    pointer-events: none;
    cursor: default;
  }
}
.snapi-landing-v2 .sl-hero__subtitle {
  /* Now the supporting subtitle in the cue (above the scroll caret) — the
     animated "[adjective] agents for [audience]" sequence. Smaller than the
     static headline at the top of the fold. */
  margin: 0 auto 8px;
  font-family: var(--font-face-serif, 'Lustria'), 'LustriaFallback', Georgia, 'Times New Roman', Times, serif;
  font-weight: 600;
  font-size: clamp(15px, 1.6vw, 24px);
  line-height: 1;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  /* Reserve two title lines' worth of height (line-height is 1, so 2em = two
     lines). The rotating words swap between different lengths, so at wrapping
     widths the phrase flips between 1 and 2 lines — without a reserved height
     the gallery/spinner below jumps each time. Desktop (≥1100px) is nowrap
     (always one line, never bounces), so the reserve is dropped there. */
  min-height: 2em;
  color: var(--sl-fg-muted);
  max-width: none;
  /* Three-column grid: left adjective | "agents for" | right audience.
     The middle (`auto`) column is bounded by two equal `1fr` columns, so
     "agents for" is ALWAYS pinned to the horizontal centre of the viewport
     regardless of how long either rotating word is. The flex layout we had
     before centred the whole line as a group, which drifted left/right as
     word lengths changed. */
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: baseline;
  column-gap: 0.4em;
}
/* Dual class (.sl-features__title.sl-hero__headline) so this beats the
   .sl-features__title section-heading rule defined later in the file —
   otherwise that rule's 40px size + opaque fill win. This is now the prominent
   hero HEADLINE (the static brand tagline "Shareable Multiexperience Agents")
   at the top of the fold: big serif, sentence case. */
.snapi-landing-v2 .sl-features__title.sl-hero__headline {
  margin: 0 auto -6px;
  padding: 0 24px;
  font-family: var(--font-face-serif, 'Lustria'), 'LustriaFallback', Georgia, 'Times New Roman', Times, serif;
  font-weight: 700;
  font-size: clamp(31px, 3.4vw, 56px);
  line-height: 1.05;
  text-transform: none;
  letter-spacing: normal;
  color: var(--sl-fg);
  text-align: center;
  /* No opaque heading fill (the .sl-features__title band would clip the hero). */
  background: none;
}
/* Full phrase on tablet/desktop; compact on mobile (the long "Shareable
   Multiexperience Agents" wraps to two lines on narrow screens). */
.snapi-landing-v2 .sl-hero__headline-compact {
  display: none;
}
@media (max-width: 767px) {
  .snapi-landing-v2 .sl-hero__headline-full {
    display: none;
  }
  .snapi-landing-v2 .sl-hero__headline-compact {
    display: inline;
  }
}
.snapi-landing-v2 .sl-hero__rotating {
  display: inline-block;
  position: relative;
  color: var(--sl-primary);
}
.snapi-landing-v2 .sl-hero__rotating--left {
  /* Logical so the word hugs the centre anchor in both LTR and RTL.
     `end` = right in LTR, left in RTL — always the side next to the anchor. */
  text-align: end;
}
/* Sentence case: capitalise the first letter of both rotating words
   (the data is stored lowercase in the i18n bundle). */
.snapi-landing-v2 .sl-hero__rotating--left .sl-hero__rotating-word::first-letter,
.snapi-landing-v2 .sl-hero__rotating--right .sl-hero__rotating-word::first-letter {
  text-transform: uppercase;
}
.snapi-landing-v2 .sl-hero__rotating--right {
  /* `start` = left in LTR, right in RTL — the side next to the anchor. */
  text-align: start;
}
.snapi-landing-v2 .sl-hero__rotating-anchor {
  white-space: nowrap;
}
.snapi-landing-v2 .sl-hero__rotating-word {
  display: inline-block;
  font-family: var(--font-face-serif, 'Lustria'), 'LustriaFallback', Georgia, 'Times New Roman', Times, serif;
  font-weight: 800;
  /* Both rotating words use the blur-morph + scale pop swap (WORD_PRESET). */
  will-change: transform, filter, opacity;
}
/* Sentence case: capitalise the first letter of the left-side adjective so
   each variant reads like a complete sentence ("Social agents for artists"). */
.snapi-landing-v2 .sl-hero__rotating--left .sl-hero__rotating-word::first-letter {
  text-transform: uppercase;
}
@media (max-width: 899px) {
  /* The desktop 3-column grid forces each flanking column to at least its
     longest word's width, so long-word languages (Filipino, Hungarian, …)
     pushed the phrase past the screen edge and shoved it right of centre. A
     centred flex-wrap can't overflow: the adjective / "agents for" / audience
     wrap onto centred lines as needed and always fit. The column-gap also
     restores the spacing the grid used to provide (no "Agenticagents for"). */
  .snapi-landing-v2 .sl-hero__subtitle {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    align-items: baseline;
    column-gap: 0.3em;
    row-gap: 0;
    text-align: center;
  }
  .snapi-landing-v2 .sl-hero__rotating--left,
  .snapi-landing-v2 .sl-hero__rotating--right {
    text-align: center;
    min-width: 0;
  }
  .snapi-landing-v2 .sl-hero__rotating-word {
    overflow-wrap: anywhere;
  }
}
/* Large viewports: keep the phrase on one line. Grid already enforces this
   via `auto` middle + `1fr` flanks; just ensure no wrapping inside slots. */
@media (min-width: 1100px) {
  .snapi-landing-v2 .sl-hero__subtitle {
    white-space: nowrap;
    /* nowrap → always one line here, so no bounce; drop the 2-line reserve. */
    min-height: 0;
  }
  .snapi-landing-v2 .sl-hero__rotating--left,
  .snapi-landing-v2 .sl-hero__rotating--right {
    min-width: 0;
  }
}
.sl-hero__visual {
  position: relative;
  /* Cap by viewport height so the SNAPI wordmark + tagline + caret stay above
     the fold on short screens (the gallery shrinks instead of pushing them down).
     Uses dvh — NOT vh — to match the .sl-hero__fold height math: vh is the
     static (URL-bar-hidden) viewport, so on mobile a vh-sized gallery rendered
     taller than the dvh-sized fold and pushed the wordmark below the screen. */
  /* Taller again (500px/50dvh → 540px/54dvh with the 1.32 cardScaleBoost,
     founder 2026-09-14): the mobile fit clamp caps the card at canvas −
     margins − dip, so the canvas must grow for a size boost to actually
     land on phones. 54dvh still fits the fold on an iPhone SE (667px). */
  height: min(540px, 54dvh);
  /* Full-bleed: break out of the hero's 24px side padding so the gallery spans
     the whole viewport width edge-to-edge (no side buffer). */
  width: calc(100% + 48px);
  margin-inline: -24px;
  overflow: hidden;
  /* Belt-and-suspenders with the fold's `min-width: 0`: keep the gallery's
     stale (un-resized) canvas from contributing a wide min-content to the fold.
     The explicit width above still drives the full-bleed size. */
  min-width: 0;
}

@media (min-width: 900px) {
  .sl-hero {
    /* +100px bottom padding (was 112px) on desktop: extra buffer between the
       hero scroll caret and the first (touchpoints) section title. Moves the
       whole touchpoints section + its scroll-line marker down together, so the
       marker stays aligned with the heading. */
    padding: 24px 24px 212px;
  }
  .sl-hero__grid {
    grid-template-columns: 1fr;
    gap: 0;
    text-align: center;
  }
  .sl-hero__subtitle {
    margin-left: auto;
    margin-right: auto;
  }
  .sl-hero__visual {
    /* Tall enough that the boosted cards keep an ARC (not a flat row) on
       wide desktops without clipping: a shorter box → wider aspect → the gallery
       has to auto-flatten hard to fit the taller cards (see orbitRadiusFor), which
       reads as a straight line. The fold has spare room (the cue is
       bottom-anchored), so a taller gallery still sits above the fold.
       620px/72dvh → 680px/76dvh with the 1.32 boost (founder 2026-09-14),
       for the same clamp-headroom reason as the mobile height above. */
    height: min(680px, 76dvh);
  }
}

/* ─── EXPERIMENT: hero-no-wordmark — reversible via HERO_EXPERIMENT in
   hero-experiment.ts (which adds `.sl-hero-exp` to <main>). Every rule below
   is scoped to `.sl-hero-exp`, so flipping the flag to false (class removed)
   restores the original hero exactly. Delete this block + the flag's three
   call sites to drop the experiment entirely. ─────────────────────────────── */
/* (2) + (3): the big hero SNAPI wordmark was deleted outright, and the
   tagline + caret are now bottom-anchored as one .sl-hero__cue group in the
   base hero CSS (no longer experiment-gated), so those two overrides are gone.
   The header brand always-on (1) lives in Header.tsx. */
/* (4) Top buffer pushes the rotating tagline + gallery spinner down — 20px on
   desktop, matching mobile (below). (Trimmed from 80px; the deeper buffer left
   too much dead space above the tagline.) */
.snapi-landing-v2.sl-hero-exp .sl-hero__fold {
  padding-top: 20px;
}
/* Mobile: much less top buffer (→ 20px) — the desktop buffer crowds small screens. */
@media (max-width: 899px) {
  .snapi-landing-v2.sl-hero-exp .sl-hero__fold {
    padding-top: 20px;
  }
}
/* (5) Drop the gallery below the rotating tagline so the spinner clears the
   animated text above it, and give it more height than the base canvas so the
   wide full-bleed arc's dipping edge cards clear the bottom (a wide-short
   canvas exaggerates the dip and cropped them). */
.snapi-landing-v2.sl-hero-exp .sl-hero__visual {
  /* Drop below the rotating tagline, and TALL enough that the ~20%-boosted cards
     keep an arc without clipping: a short/wide canvas forces the gallery to
     auto-flatten toward a straight row (see orbitRadiusFor). The fold has spare
     room (the cue is bottom-anchored), so a taller gallery still sits above it. */
  margin-top: 40px;
  height: min(600px, 64dvh);
}
/* Mobile: lift the spinner (smaller top margin). Height gives the arc enough
   vertical room that the edge/near cards don't dip past the canvas bottom
   (overflow:hidden cropped them at ~750px-wide widths where the old 440px cap
   dominated: a taller canvas shrinks the px→world margin conversion in
   orbitRadiusFor, leaving more world-room for the dip). Raised cap + dvh share;
   the fold keeps positive slack so the bottom-anchored manifesto + caret stay
   ~40px above the fold edge. */
@media (max-width: 899px) {
  .snapi-landing-v2.sl-hero-exp .sl-hero__visual {
    margin-top: 40px;
    height: min(560px, 50dvh);
  }
  /* Push the touchpoints section (and its scroll-line spinner) below the fold
     so the initial mobile view shows only the manifesto + caret — the spinner
     is revealed on scroll. (Shortening the gallery above pulled the first
     marker up into view.) */
  .snapi-landing-v2.sl-hero-exp .sl-hero {
    padding-bottom: 160px;
  }
}
/* Short desktop/laptop viewports (≈700–860px tall): the full-size gallery + its
   80px top buffer would overflow the fold and push the bottom-anchored cue off
   the screen. Trim both so the subtitle + gallery + cue all fit and the cue
   stays ~20px above the fold edge. (Mobile already uses a smaller gallery; this
   targets short landscape/laptop screens at desktop width.) */
@media (min-width: 900px) and (max-height: 860px) {
  .snapi-landing-v2.sl-hero-exp .sl-hero__visual {
    /* Short laptops: keep the arc + drop, sized to the shorter fold via dvh so
       the bottom-anchored cue still fits (the gallery auto-flattens only as much
       as the reduced height needs). */
    margin-top: 40px;
    height: min(600px, 64dvh);
  }
}
/* ─── /EXPERIMENT: hero-no-wordmark ─────────────────────────────────────── */

/* (Workflow-steps styles removed with the v2 WorkflowSteps component.
   The old `/` landing still ships its own copies in landing/landing.css.) */

/* ---------- Feature grid ---------- */
.sl-features {
  /* 40 px above, 100 px below (24 px side gutters). Applied on all
     breakpoints — the previous desktop override to 112px was removed. */
  padding: 40px 24px 100px;
  max-width: 1200px;
  margin: 0 auto;
}
/* Extra breathing room below the touchpoints section specifically. */
.snapi-landing-v2 .sl-features--touchpoints {
  margin-bottom: 20px;
}
.snapi-landing-v2 .sl-features__title {
  font-family: var(--font-face-serif, 'Lustria'), 'LustriaFallback', Georgia, 'Times New Roman', Times, serif;
  font-size: clamp(28px, 4vw, 40px);
  text-align: center;
  max-width: 760px;
  margin: 0 auto;
  /* Opaque fill so the dotted scroll line (z-index: -1) running down the
     page centre doesn't show through the gaps around the heading text.
     Reuses the page's own `fixed` background gradient — because a fixed
     background is painted relative to the viewport, this patch lines up
     pixel-for-pixel with the page behind it (invisible), while still
     occluding the line. Adapts to dark mode via the same CSS vars. */
  background: linear-gradient(155deg, var(--sl-bg) 0%, var(--sl-bg-gradient-tint) 100%) fixed;
}
/* (sl-features__mark removed — section-top Snapi marks were a duplicate
   of the line marker spinners at the same anchor positions. The line
   marker now serves both roles.) */
/* Adjacent .sl-features sections get a 40 px breathing buffer between
   them (was 0 — the sections were butting up directly against each
   other). The first .sl-features keeps its full 80/112 px padding-top
   so the hero/illustrated-sections rhythm above is unaffected. */
.snapi-landing-v2 .sl-features + .sl-features {
  padding-top: 40px;
}
/* Reach section is the last .sl-features block — its world map is tall
   enough that the full 80/112 px bottom padding feels excessive before
   the LearnCards section. Trim 60 px off so the page transitions more
   tightly into "Snapi is a complete ecosystem for Audience Success". */
.snapi-landing-v2 .sl-features--reach {
  padding-bottom: 20px;
}
@media (min-width: 900px) {
  .snapi-landing-v2 .sl-features--reach {
    padding-bottom: 52px;
  }
}
@media (min-width: 900px) {
  /* Desktop: 80px (was 40px) top padding between adjacent feature sections —
     adds +40px gap between touchpoints / widgets / AI / reach. */
  .snapi-landing-v2 .sl-features + .sl-features {
    padding-top: 80px;
  }
}
/* ---------- Widget marquee ---------- */
.snapi-landing-v2 .sl-widget-slider {
  margin-top: 48px;
  margin-bottom: 48px;
  overflow: hidden;
  position: relative;
  /* Page-matching opaque fill so the dotted scroll line behind the
     marquee doesn't show through the gaps between tiles. Centre of the
     row (where the line runs) is fully opaque; the horizontal mask below
     only fades the far left/right edges, away from the line. */
  background: linear-gradient(155deg, var(--sl-bg) 0%, var(--sl-bg-gradient-tint) 100%) fixed;
  -webkit-mask-image: linear-gradient(to right, transparent, black 6%, black 94%, transparent);
  mask-image: linear-gradient(to right, transparent, black 6%, black 94%, transparent);
}
.snapi-landing-v2 .sl-widget-slider__track {
  display: flex;
  gap: 20px;
  width: max-content;
  animation: sl-widget-slider-scroll 133s linear infinite reverse;
}
.snapi-landing-v2 .sl-widget-slider:hover .sl-widget-slider__track {
  animation-play-state: paused;
}
/* Pause the marquee whenever the slider is off-screen — `.is-paused` is
   toggled by Widget/TouchpointSlider via useInView. Saves CPU on long
   pages and idle background tabs. */
.snapi-landing-v2 .sl-widget-slider.is-paused .sl-widget-slider__track {
  animation-play-state: paused;
}
.snapi-landing-v2 .sl-widget-slider__item {
  flex: 0 0 auto;
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 18px 14px;
  min-width: 116px;
  border-radius: 16px;
  background: rgba(255, 255, 255, 0.8);
  transition: transform 0.2s, background 0.2s;
}
.snapi-landing-v2 .sl-widget-slider__item:hover {
  transform: translateY(-2px);
  background: rgba(255, 255, 255, 0.95);
}
.snapi-landing-v2 .sl-widget-slider__icon {
  width: 48px;
  height: 48px;
  object-fit: contain;
  display: block;
}
/* Hugeicon variant — strokes are crisper than brand SVGs so a touch smaller
   keeps the optical weight even with the brand-icon tiles in the row below.
   Rendered in Snapi blue (the brand accent used by the CTAs, scroll line and
   reach-map dots) — `currentColor` drives the icon strokes. */
.snapi-landing-v2 .sl-widget-slider__icon--hugeicon {
  width: 40px;
  height: 40px;
  color: var(--sl-primary);
}
.snapi-landing-v2 .sl-widget-slider__name {
  font-size: 13px;
  font-weight: 500;
  color: var(--sl-fg-muted);
  white-space: nowrap;
}
/* "Soon" badge for touchpoints not yet shipped. Sits in the top-right of
   the tile without affecting layout. Styled to match the premium chip in
   the Snapi builder widget grid (`builder/widget-grid/widget-grid.tsx`):
   a translucent-blue pill with #007AFF text. Same colours in both themes,
   like the builder chip. */
.snapi-landing-v2 .sl-widget-slider__badge {
  position: absolute;
  top: 6px;
  right: 8px;
  padding: 2px 6px;
  border-radius: 999px;
  background: rgba(0, 122, 255, 0.15);
  color: #007aff;
  font-size: 8px;
  font-weight: 700;
  letter-spacing: 0.03em;
  line-height: 1.4;
}
@keyframes sl-widget-slider-scroll {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}
/* Touchpoint marquee scrolls the opposite direction to the widget marquee
   so the two rows visually cross — reads as "many moving parts in motion"
   rather than a single conveyor belt. */
.snapi-landing-v2 .sl-widget-slider__track--touchpoints {
  animation-direction: normal;
  /* The keyframe translates each track by -50% of ITS OWN width over the
     shared 133s, so on-screen px/s is proportional to track width. The
     touchpoint track has far fewer tiles (8×2) than the widget track (~44×2),
     so at 133s it crawled ~5.6× slower. Scale the duration down by the same
     ratio (133s × touchpointWidth / widgetWidth ≈ 24s) so both marquees move
     at the same ~45 px/s. Per-tile width matches the widget row, so this
     tracks item-count changes roughly proportionally; retune if the tile set
     changes a lot. */
  animation-duration: 24s;
}

.sl-features__grid {
  margin-top: 56px;
  margin-bottom: 40px;
  max-width: none;
  margin-left: auto;
  margin-right: auto;
  display: grid;
  grid-template-columns: 1fr;
  gap: 24px;
}
@media (min-width: 680px) {
  .sl-features__grid {
    grid-template-columns: 1fr 1fr;
  }
}
@media (min-width: 1000px) {
  .sl-features__grid {
    grid-template-columns: repeat(3, 1fr);
  }
}
/* Feature cards reuse the LearnCards visual language — pastel gradient panel,
   circular icon chip, Geist title/body — minus the CTA link. */
.sl-feature {
  /* Gradient stops stay landing-local; accent + tag-bg bridge to the shared
     Chakra accent tokens (which flip for dark on their own). */
  --sl-feat-grad-from: #dbeafe;
  --sl-feat-grad-to: #ede9fe;
  --sl-feat-tag-bg: var(--chakra-colors-accent-blue-bg);
  --sl-feat-accent: var(--chakra-colors-accent-blue-fg);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  padding: 36px 36px 32px;
  border: none;
  border-radius: 24px;
  background: linear-gradient(135deg, var(--sl-feat-grad-from) 0%, var(--sl-feat-grad-to) 100%);
  transition: transform 0.25s ease, box-shadow 0.25s ease;
}
.sl-feature:hover {
  transform: translateY(-4px);
  box-shadow: 0 18px 40px rgba(15, 23, 42, 0.08);
}
/* Per-card gradients, harmonised with each card's icon tile. */
.sl-feature--c1 { --sl-feat-grad-from: #fce7f3; --sl-feat-grad-to: #ffe4e6; --sl-feat-tag-bg: var(--chakra-colors-accent-pink-bg); --sl-feat-accent: var(--chakra-colors-accent-pink-fg); }
.sl-feature--c2 { --sl-feat-grad-from: #dbeafe; --sl-feat-grad-to: #ede9fe; --sl-feat-tag-bg: var(--chakra-colors-accent-blue-bg); --sl-feat-accent: var(--chakra-colors-accent-blue-fg); }
.sl-feature--c3 { --sl-feat-grad-from: #dcfce7; --sl-feat-grad-to: #e0f2fe; --sl-feat-tag-bg: var(--chakra-colors-accent-green-bg); --sl-feat-accent: var(--chakra-colors-accent-green-fg); }
.sl-feature__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 52px;
  height: 52px;
  border-radius: 50%;
  background: var(--sl-feat-tag-bg);
  color: var(--sl-feat-accent);
}
.snapi-landing-v2 .sl-feature__title {
  margin: 22px 0 16px;
  font-family: var(--font-face-sans, 'Geist'), -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  font-size: clamp(22px, 2.2vw, 28px);
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: normal;
  color: var(--sl-fg);
}
.sl-feature__body {
  margin-top: 0;
  font-family: var(--font-face-sans, 'Geist'), -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  color: var(--sl-fg-muted);
  font-size: 15px;
  line-height: 1.5;
}

/* ---------- Beta signup ---------- */
.sl-beta {
  /* Centred 1200 px column. No top buffer — the Builder heading above
     leads straight into the form; bottom padding clears the footer.
     No panel fill — sits directly on the page background. */
  padding: 0 24px 80px;
  max-width: 1200px;
  margin: 0 auto;
  color: var(--sl-fg);
  text-align: center;
}
@media (min-width: 900px) {
  .sl-beta {
    padding: 0 24px 112px;
  }
}
.sl-beta__inner {
  max-width: 640px;
  margin: 0 auto;
}
/* Blue eyebrow label above the form. Plain text (no fill) in the Snapi-blue
   primary token so it reads as a quiet accent on the dark page. */
.sl-beta__eyebrow {
  display: inline-block;
  margin-bottom: 6px;
  color: var(--sl-primary);
  font-size: 14px;
  font-weight: 600;
  letter-spacing: 0.01em;
}
.sl-beta__form {
  margin-top: 28px;
  display: grid;
  grid-template-columns: 1fr;
  gap: 12px;
}
@media (min-width: 680px) {
  .sl-beta__form {
    /* name pill (first ┃ last) | email | Get Started — the pill gets the
       widest cell so both placeholder labels render uncropped. minmax(0,…)
       strips the inputs' intrinsic min-content floor (a bare <input> wants
       ~240px, which otherwise starves the pill of its fr share). */
    grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr) auto;
  }
}
/* One rounded pill holding First + Last name, split by a hairline. The pill
   carries the fill/focus ring; the inner inputs go transparent + square. */
.sl-beta__name-group {
  display: grid;
  grid-template-columns: 1fr 1px 1fr;
  align-items: center;
  height: 60px;
  border-radius: 999px;
  background: #fff;
  overflow: hidden;
}
.snapi-landing-v2 .sl-beta__name-group .sl-beta__input {
  height: 100%;
  min-width: 0;
  border-radius: 0;
  background: transparent;
  /* Halved cell = halved breathing room — trim the pill-inherited 22px side
     padding so "First name" / "Last name" placeholders never crop. */
  padding: 0 16px;
}
.sl-beta__name-group:focus-within {
  box-shadow: 0 0 0 4px rgba(37, 99, 235, 0.25);
}
.snapi-landing-v2 .sl-beta__name-group .sl-beta__input:focus {
  box-shadow: none;
}
.sl-beta__name-divider {
  width: 1px;
  height: 28px;
  background: #e2e8f0;
}
.sl-beta__input {
  border: none;
  border-radius: 999px;
  height: 60px;
  padding: 0 22px;
  font-size: 16px;
  color: var(--sl-fg);
  background: #fff;
  outline: none;
  font-family: inherit;
}
.sl-beta__input::placeholder {
  color: #94a3b8;
}
/* The global app.css rule forces 'Geist Mono' 12px !important on every
   placeholder — on the landing's large pill inputs that monospace reads as
   chunky/bold ghost text. Restore the page's regular Geist sans at the field's
   own size for the signup form (scoped + !important to beat the global). */
.snapi-landing-v2 .sl-beta__input::placeholder {
  font-family: var(--font-face-sans, 'Geist'), -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif !important;
  font-size: 16px !important;
  font-weight: 400 !important;
}
.sl-beta__input:focus {
  box-shadow: 0 0 0 4px rgba(37, 99, 235, 0.25);
}
.snapi-landing-v2 .sl-beta__submit {
  border-radius: 999px;
  height: 60px;
  padding: 0 30px;
  /* CTA — Snapi brand purple→magenta gradient (matches .sl-btn-primary + the
     pre-login guest avatar). */
  background: linear-gradient(90deg, #1818d0 0%, #ff00cc 100%);
  color: #fff;
  font-weight: 600;
  font-size: 16px;
  white-space: nowrap;
  transition: filter 0.15s, opacity 0.15s;
}
.snapi-landing-v2 .sl-beta__submit:hover:not(:disabled) {
  filter: brightness(0.93);
}
.snapi-landing-v2 .sl-beta__submit:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}
.sl-beta__success {
  margin-top: 60px;
  font-size: 18px;
  font-weight: 500;
  background: rgba(255, 255, 255, 0.12);
  border-radius: 14px;
  padding: 24px;
}
.sl-beta__error {
  margin-top: 20px;
  display: inline-block;
  font-size: 14px;
  color: #fee2e2;
  background: rgba(239, 68, 68, 0.3);
  padding: 10px 16px;
  border-radius: 10px;
}

/* ---------- Footer ---------- */
.sl-footer {
  padding: 56px 24px;
  color: #94a3b8;
}
/* The legacy `/` landing's landing.css defines UNSCOPED `.sl-beta` and
   `.sl-footer` background fills (var(--sl-primary) / var(--sl-darker))
   that leak onto this page through the global stylesheet import. The v2
   design has no panel fills on these, so override them with a v2-scoped
   transparent background (specificity 0,2,0 beats the leaked 0,1,0). */
.snapi-landing-v2 .sl-beta,
.snapi-landing-v2 .sl-footer {
  background: transparent;
}
.sl-footer__inner {
  max-width: none;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: 28px;
  justify-content: space-between;
}
@media (min-width: 680px) {
  .sl-footer__inner {
    flex-direction: column;
    align-items: flex-start;
  }
}
.sl-footer__brand {
  display: flex;
  align-items: center;
  gap: 12px;
}
.sl-footer__brand-name {
  color: #fff;
  font-weight: 600;
}
.sl-footer__brand-tagline {
  font-size: 14px;
}
.sl-footer__nav {
  display: flex;
  align-items: center;
  gap: 28px;
  font-size: 14px;
  margin-left: 52px;
}
.sl-footer__nav a:hover {
  color: #fff;
}
.snapi-landing-v2 .sl-footer__copy {
  max-width: none;
  margin: 60px auto 0;
  font-size: 12px;
  color: var(--sl-fg-soft);
  text-align: center;
}

/* ---------- Learn cards (pastel-gradient promo blocks) ----------
   Three cards in a row on desktop, stacked on mobile. Each card has a
   pill tag, a bold serif headline (with emoji), a muted body paragraph,
   and a coloured CTA link. Variants drive the accent + gradient via
   custom-property overrides scoped to the variant class. */
.snapi-landing-v2 .sl-learn {
  padding: 80px 24px;
  max-width: 1200px;
  margin: 0 auto;
}
.snapi-landing-v2 .sl-learn .sl-features__title {
  margin-top: 40px;
  margin-bottom: 40px;
}
/* (.sl-learn__mark removed — the scroll line now terminates above the
   "Audience Success" heading and its bottom-cap marker serves as the
   section mark, so the static SnapiMark above the heading is gone.) */
.snapi-landing-v2 .sl-learn__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 20px;
}
/* Midway step (matches .sl-features__grid's 680px convention) — without it
   the 12 cards jump straight from 3-across to a single column. */
@media (min-width: 680px) {
  .snapi-landing-v2 .sl-learn__grid {
    grid-template-columns: repeat(2, 1fr);
  }
}
@media (min-width: 900px) {
  .snapi-landing-v2 .sl-learn__grid {
    grid-template-columns: repeat(3, 1fr);
  }
}
.snapi-landing-v2 .sl-learn__card {
  /* Gradient stops stay landing-local; accent + tag-bg bridge to the shared
     Chakra accent tokens (which flip for dark on their own). */
  --sl-learn-accent: var(--chakra-colors-accent-green-fg);
  --sl-learn-tag-bg: var(--chakra-colors-accent-green-bg);
  --sl-learn-grad-from: #dcfce7;
  --sl-learn-grad-to: #e0f2fe;
  /* Containing block for the absolutely-positioned `.sl-learn__badge`.
     Without this the badge anchors to the page-level positioned ancestor
     (.snapi-landing-v2) and only snapped onto the card on hover, when the
     hover `transform` created a containing block. */
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  padding: 36px 36px 32px;
  border-radius: 24px;
  background: linear-gradient(135deg, var(--sl-learn-grad-from) 0%, var(--sl-learn-grad-to) 100%);
  text-decoration: none;
  color: inherit;
  transition: transform 0.25s ease, box-shadow 0.25s ease;
  min-height: 320px;
}
.snapi-landing-v2 .sl-learn__card:hover {
  transform: translateY(-4px);
  box-shadow: 0 18px 40px rgba(15, 23, 42, 0.08);
}
.snapi-landing-v2 .sl-learn__card--green {
  --sl-learn-accent: var(--chakra-colors-accent-green-fg);
  --sl-learn-tag-bg: var(--chakra-colors-accent-green-bg);
  --sl-learn-grad-from: #dcfce7;
  --sl-learn-grad-to: #e0f2fe;
}
.snapi-landing-v2 .sl-learn__card--blue {
  --sl-learn-accent: var(--chakra-colors-accent-blue-fg);
  --sl-learn-tag-bg: var(--chakra-colors-accent-blue-bg);
  --sl-learn-grad-from: #dbeafe;
  --sl-learn-grad-to: #ede9fe;
}
.snapi-landing-v2 .sl-learn__card--purple {
  --sl-learn-accent: var(--chakra-colors-accent-purple-fg);
  --sl-learn-tag-bg: var(--chakra-colors-accent-purple-bg);
  --sl-learn-grad-from: #ede9fe;
  --sl-learn-grad-to: #fce7f3;
}
.snapi-landing-v2 .sl-learn__card--pink {
  --sl-learn-accent: var(--chakra-colors-accent-pink-fg);
  --sl-learn-tag-bg: var(--chakra-colors-accent-pink-bg);
  --sl-learn-grad-from: #fce7f3;
  --sl-learn-grad-to: #ffe4e6;
}
.snapi-landing-v2 .sl-learn__card--amber {
  --sl-learn-accent: var(--chakra-colors-accent-amber-fg);
  --sl-learn-tag-bg: var(--chakra-colors-accent-amber-bg);
  --sl-learn-grad-from: #fef3c7;
  --sl-learn-grad-to: #ffedd5;
}
.snapi-landing-v2 .sl-learn__card--teal {
  --sl-learn-accent: var(--chakra-colors-accent-teal-fg);
  --sl-learn-tag-bg: var(--chakra-colors-accent-teal-bg);
  --sl-learn-grad-from: #ccfbf1;
  --sl-learn-grad-to: #cffafe;
}
.snapi-landing-v2 .sl-learn__card--indigo {
  --sl-learn-accent: var(--chakra-colors-accent-indigo-fg);
  --sl-learn-tag-bg: var(--chakra-colors-accent-indigo-bg);
  --sl-learn-grad-from: #e0e7ff;
  --sl-learn-grad-to: #ede9fe;
}
.snapi-landing-v2 .sl-learn__card--rose {
  --sl-learn-accent: var(--chakra-colors-accent-rose-fg);
  --sl-learn-tag-bg: var(--chakra-colors-accent-rose-bg);
  --sl-learn-grad-from: #ffe4e6;
  --sl-learn-grad-to: #fef2f2;
}
.snapi-landing-v2 .sl-learn__card--cyan {
  --sl-learn-accent: var(--chakra-colors-accent-cyan-fg);
  --sl-learn-tag-bg: var(--chakra-colors-accent-cyan-bg);
  --sl-learn-grad-from: #cffafe;
  --sl-learn-grad-to: #ecfeff;
}
.snapi-landing-v2 .sl-learn__card--lime {
  --sl-learn-accent: var(--chakra-colors-accent-lime-fg);
  --sl-learn-tag-bg: var(--chakra-colors-accent-lime-bg);
  --sl-learn-grad-from: #ecfccb;
  --sl-learn-grad-to: #f7fee7;
}
/* "Soon" badge for in-flight Learn cards. Same visual as the touchpoint
   badge but positioned at the top-right of the card with a bit more
   inset to clear the rounded gradient corner. */
.snapi-landing-v2 .sl-learn__badge {
  position: absolute;
  top: 18px;
  right: 20px;
  padding: 3px 9px;
  border-radius: 999px;
  background: rgba(15, 23, 42, 0.08);
  color: rgba(15, 23, 42, 0.6);
  font-family: var(--font-face-sans, 'Geist'), -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.snapi-landing-v2 .sl-learn__tag {
  display: inline-block;
  padding: 6px 14px;
  border-radius: 999px;
  background: var(--sl-learn-tag-bg);
  color: var(--sl-learn-accent);
  font-family: var(--font-face-sans, 'Geist'), -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.01em;
}
/* Icon variant — fully round pill that hosts a Hugeicons mark instead
   of text. Used for cards that reuse a Snapi-native icon in place of
   the text tag (Lists, Collections, Messaging, Workflows, Heroes). */
.snapi-landing-v2 .sl-learn__tag--icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 52px;
  height: 52px;
  padding: 0;
  border-radius: 50%;
}
.snapi-landing-v2 .sl-learn__title {
  margin: 22px 0 16px;
  font-family: var(--font-face-sans, 'Geist'), -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  font-size: clamp(22px, 2.2vw, 28px);
  font-weight: 700;
  line-height: 1.2;
  color: var(--sl-fg);
}
.snapi-landing-v2 .sl-learn__body {
  font-family: var(--font-face-sans, 'Geist'), -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  font-size: 15px;
  line-height: 1.5;
  color: var(--sl-fg-muted);
  flex: 1;
}
.snapi-landing-v2 .sl-learn__cta {
  margin-top: 28px;
  font-family: var(--font-face-sans, 'Geist'), -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  font-size: 15px;
  font-weight: 600;
  color: var(--sl-learn-accent);
  display: inline-flex;
  align-items: center;
  gap: 6px;
  transition: gap 0.2s ease;
}
.snapi-landing-v2 .sl-learn__card:hover .sl-learn__cta {
  gap: 10px;
}

/* ============================================================
   Dark-mode overrides for /v2
   ------------------------------------------------------------
   The base token block at line ~170 already flips --sl-bg /
   --sl-fg / --sl-primary etc. for [data-theme="dark"]. This
   block covers components whose colours are hardcoded (white
   tile backgrounds, pastel gradients, the Soon badge, the
   beta input) and would otherwise look washed-out or unreadable
   on the dark page gradient.
   ============================================================ */

/* Marquee tiles (touchpoints + widgets) — flip the white-on-cream
   surface to a translucent slate that lifts off the dark gradient. */
[data-theme="dark"] .snapi-landing-v2 .sl-widget-slider__item {
  background: rgba(30, 41, 59, 0.55);
}
[data-theme="dark"] .snapi-landing-v2 .sl-widget-slider__item:hover {
  background: rgba(30, 41, 59, 0.85);
}
[data-theme="dark"] .snapi-landing-v2 .sl-widget-slider__name {
  color: var(--sl-fg);
}
/* Touchpoint hugeicons render in --sl-primary, which already has its own
   dark-theme value, so no dark override is needed here. */

/* "Soon" badge — was dark-on-light; flip to light-on-translucent. */
/* No dark override for the badge — the premium-chip blue (#007AFF on a
   translucent-blue fill) reads on both the light and dark backgrounds,
   matching the builder chip which has no dark variant. */

/* Feature grid cards (Fast / Integrations / Collections / …) — same
   translucent-slate treatment as the marquee tiles. */
[data-theme="dark"] .snapi-landing-v2 .sl-feature {
  background: rgba(30, 41, 59, 0.55);
}
[data-theme="dark"] .snapi-landing-v2 .sl-feature:hover {
  background: rgba(30, 41, 59, 0.85);
}
/* Feature card title/body/accent dark overrides are gone — title → var(--sl-fg),
   body → var(--sl-fg-muted), and the per-variant accent/tag-bg vars now resolve
   to the shared Chakra accent tokens, which carry their own dark values. Only
   the translucent-slate panel fill above still needs a dark override. */

/* Beta form input — was white with dark text; invert to slate with
   light text so it reads against the dark page. Placeholder + focus
   ring inherit from existing rules where possible. */
[data-theme="dark"] .snapi-landing-v2 .sl-beta__input {
  /* color now comes from the base rule's var(--sl-fg), which flips on its own;
     only the translucent fill + border need a dark override. */
  background: rgba(15, 23, 42, 0.5);
  border: 1px solid rgba(241, 245, 249, 0.12);
}
[data-theme="dark"] .snapi-landing-v2 .sl-beta__input::placeholder {
  color: rgba(241, 245, 249, 0.45);
}
[data-theme="dark"] .snapi-landing-v2 .sl-beta__input:focus {
  box-shadow: 0 0 0 4px rgba(59, 130, 246, 0.35);
}
/* Name pill dark: the GROUP carries the slate fill/border; inner inputs stay
   transparent (must out-specify the dark .sl-beta__input rule above). */
[data-theme="dark"] .snapi-landing-v2 .sl-beta__name-group {
  background: rgba(15, 23, 42, 0.5);
  border: 1px solid rgba(241, 245, 249, 0.12);
}
[data-theme="dark"] .snapi-landing-v2 .sl-beta__name-group .sl-beta__input {
  background: transparent;
  border: none;
}
[data-theme="dark"] .snapi-landing-v2 .sl-beta__name-group .sl-beta__input:focus {
  box-shadow: none;
}
[data-theme="dark"] .snapi-landing-v2 .sl-beta__name-divider {
  background: rgba(241, 245, 249, 0.16);
}
[data-theme="dark"] .snapi-landing-v2 .sl-beta__name-group:focus-within {
  box-shadow: 0 0 0 4px rgba(59, 130, 246, 0.35);
}

/* Footer copyright line now uses var(--sl-fg-soft) in its base rule, which flips
   for dark on its own — no separate dark override needed. */

/* Scroll-line dots — light mode uses --sl-dark on the cream bg. In dark
   mode the same token is essentially invisible, so override to a
   translucent light tint. Same circular-dot geometry (3px ⌀ / 8px pitch). */
[data-theme="dark"] .snapi-landing-v2 .sl-scroll-line__fill {
  background-image: radial-gradient(
    circle at center,
    var(--sl-primary) 1px,
    transparent 1.5px
  );
}
/* Marker spinners — tint via `color` so SnapiMark's currentColor flows. */
[data-theme="dark"] .snapi-landing-v2 .sl-scroll-line__marker {
  color: var(--sl-primary);
}
/* LearnCards — the light-mode pastel gradients (e.g. #dcfce7 → #e0f2fe)
   are too pale to read on dark. Swap each variant for a deeper jewel-tone
   gradient that retains the accent's hue. Tag pills stay light-on-deep
   for contrast with the card body; title gets pulled up to the light fg;
   body stays muted; CTA accent stays the lighter accent so the colour
   reads. */
[data-theme="dark"] .snapi-landing-v2 .sl-learn__card {
  --sl-learn-grad-from: #0f2a1a;
  --sl-learn-grad-to: #0e2540;
}
/* Only the gradient stops are flipped here now — each card's accent + tag-bg
   resolve to the shared Chakra accent tokens, which carry their own dark values. */
[data-theme="dark"] .snapi-landing-v2 .sl-learn__card--green {
  --sl-learn-grad-from: #0f2a1a;
  --sl-learn-grad-to: #0e2540;
}
[data-theme="dark"] .snapi-landing-v2 .sl-learn__card--blue {
  --sl-learn-grad-from: #0e2540;
  --sl-learn-grad-to: #1c1e4a;
}
[data-theme="dark"] .snapi-landing-v2 .sl-learn__card--purple {
  --sl-learn-grad-from: #1c1e4a;
  --sl-learn-grad-to: #3a1e3f;
}
[data-theme="dark"] .snapi-landing-v2 .sl-learn__card--pink {
  --sl-learn-grad-from: #3a1e3f;
  --sl-learn-grad-to: #3a1726;
}
[data-theme="dark"] .snapi-landing-v2 .sl-learn__card--amber {
  --sl-learn-grad-from: #2a1f0e;
  --sl-learn-grad-to: #3a1b0a;
}
[data-theme="dark"] .snapi-landing-v2 .sl-learn__card--teal {
  --sl-learn-grad-from: #0c2a26;
  --sl-learn-grad-to: #0e2540;
}
[data-theme="dark"] .snapi-landing-v2 .sl-learn__card--indigo {
  --sl-learn-grad-from: #1c1e4a;
  --sl-learn-grad-to: #0e2540;
}
[data-theme="dark"] .snapi-landing-v2 .sl-learn__card--rose {
  --sl-learn-grad-from: #3a1726;
  --sl-learn-grad-to: #2a1014;
}
[data-theme="dark"] .snapi-landing-v2 .sl-learn__card--cyan {
  --sl-learn-grad-from: #082f3a;
  --sl-learn-grad-to: #0a2f49;
}
[data-theme="dark"] .snapi-landing-v2 .sl-learn__card--lime {
  --sl-learn-grad-from: #1a2410;
  --sl-learn-grad-to: #16200a;
}
[data-theme="dark"] .snapi-landing-v2 .sl-learn__badge {
  background: rgba(241, 245, 249, 0.14);
  color: rgba(241, 245, 249, 0.75);
}
/* Learn title/body dark overrides removed — base rules use var(--sl-fg) /
   var(--sl-fg-muted), which flip on their own. */
[data-theme="dark"] .snapi-landing-v2 .sl-learn__card:hover {
  box-shadow: 0 18px 40px rgba(0, 0, 0, 0.4);
}

/* Header wordmark stronger dark-mode lift (the big hero wordmark was removed). */
[data-theme="dark"] .snapi-landing-v2 .sl-header__brand-text {
  text-shadow: 0 4px 12px rgba(0, 0, 0, 0.6);
}

/* ---------- Reach section ---------- */
/* Dotted world map fetched from /landing/world-dotted.svg and injected
   inline so each `<circle>` can be individually targeted. ReachMap.tsx
   tags ~14% of the land dots with `.sl-reach__dot--lit` (stable, evenly
   spread "city lights"). The flicker animation below only runs while the
   section is in view (the `.is-active` gate); at rest the whole map sits
   at the muted grey baseline. Each lit dot pulses on its own clock via a
   per-dot randomised duration + delay so the cities don't blink in sync. */
.snapi-landing-v2 .sl-reach {
  max-width: 1200px;
  margin: 32px auto 0;
  padding: 0 24px;
  /* Establish a stacking context that sits above the dotted scroll line
     and its section markers (both at z-index: -1) so the map is never
     overdrawn by the line running down the page centre. */
  position: relative;
  z-index: 2;
  /* Page-matching opaque fill (the page's own `fixed` background gradient)
     so the dotted scroll line behind the map doesn't show through the gaps
     between the dots. Invisible against the page — just occludes the line. */
  background: linear-gradient(155deg, var(--sl-bg) 0%, var(--sl-bg-gradient-tint) 100%) fixed;
}
.snapi-landing-v2 .sl-reach__map {
  width: 100%;
  line-height: 0; /* drop the extra inline-baseline space below the SVG */
}
.snapi-landing-v2 .sl-reach__map svg {
  width: 100%;
  height: auto;
  display: block;
}
/* Base dot — muted grey foreground. Overrides the inline `fill="#FFFFFF"`
   from the source SVG so the map adapts to light + dark themes. */
.snapi-landing-v2 .sl-reach__map svg circle {
  fill: var(--sl-fg-muted);
  opacity: 0.22;
  transition: fill 0.3s ease, opacity 0.3s ease;
}
/* Lit dots — animate via the flicker keyframe, but ONLY once the section
   scrolls into view (`.is-active`). Out of view they stay at the grey
   baseline like every other dot. */
.snapi-landing-v2 .sl-reach.is-active .sl-reach__map svg circle.sl-reach__dot--lit {
  animation: sl-reach-flicker var(--sl-reach-flicker-dur, 3.5s)
    var(--sl-reach-flicker-delay, 0s) infinite ease-in-out;
}
@keyframes sl-reach-flicker {
  0%, 100% {
    fill: var(--sl-fg-muted);
    opacity: 0.22;
  }
  50% {
    fill: var(--sl-primary);
    opacity: 1;
  }
}
/* Dark mode — bump baseline opacity slightly so the un-lit dots remain
   visible against the deep navy background, and tint the lit accent
   to the cooler primary used elsewhere on the v2 page. */
[data-theme="dark"] .snapi-landing-v2 .sl-reach__map svg circle {
  opacity: 0.18;
}
[data-theme="dark"] .snapi-landing-v2 .sl-reach.is-active .sl-reach__map svg circle.sl-reach__dot--lit {
  animation-name: sl-reach-flicker-dark;
}
@keyframes sl-reach-flicker-dark {
  0%, 100% {
    fill: var(--sl-fg-muted);
    opacity: 0.18;
  }
  50% {
    fill: var(--sl-primary);
    opacity: 1;
  }
}

/* ---------- Floating language menu (bottom-left) ---------- */
/* A round globe button anchored to the bottom-left corner. Clicking it opens
   a popup of every locale Snapi ships. Sits above page content but the panel
   is keyboard- + outside-click-dismissable (logic in LanguageMenu.tsx). */
.snapi-landing-v2 .sl-lang {
  position: fixed;
  /* Logical so the button sits bottom-left in LTR, bottom-right in RTL. */
  inset-inline-start: 24px;
  /* 16px (not 24px) so the floating button's centre lines up with the
     footer's content row when scrolled to the bottom — the 56px button sat
     ~8px high of the footer-text centre at 24px. Matches the mobile value. */
  bottom: 16px;
  z-index: 40;
}
/* Bare icon button — no fill/border/box. The lift comes from a drop-shadow on
   the icon glyph itself (below), so it reads as a floating mark on the page. */
.snapi-landing-v2 .sl-lang__btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 56px;
  height: 56px;
  background: none;
  color: var(--sl-fg);
  border: none;
  padding: 0;
  cursor: pointer;
  transition: transform 0.15s ease, color 0.15s ease;
}
.snapi-landing-v2 .sl-lang__btn:hover {
  transform: translateY(-2px);
  color: var(--sl-primary);
}
.snapi-landing-v2 .sl-lang__btn--open {
  color: var(--sl-primary);
}
/* Shadow/blur lives on the glyph so it follows the icon shape, not a box. */
.snapi-landing-v2 .sl-lang__icon {
  display: block;
  filter: drop-shadow(0 4px 10px rgba(var(--sl-shadow-color), 0.45));
}

.snapi-landing-v2 .sl-lang__panel {
  position: absolute;
  inset-inline-start: 0;
  bottom: calc(100% + 12px);
  width: 280px;
  max-height: min(60vh, 440px);
  display: flex;
  flex-direction: column;
  background: var(--sl-card-bg);
  border: 1px solid var(--sl-border);
  border-radius: 16px;
  box-shadow: 0 24px 60px -16px rgba(var(--sl-shadow-color), 0.34);
  overflow: hidden;
  transform-origin: bottom left;
}
/* Machine-translation disclaimer pinned above the scrollable list. */
.snapi-landing-v2 .sl-lang__note {
  margin: 0;
  padding: 11px 14px 10px;
  font-size: 11.5px;
  line-height: 1.35;
  color: var(--sl-fg-soft);
  border-bottom: 1px solid var(--sl-border);
}
.snapi-landing-v2 .sl-lang__list {
  margin: 0;
  padding: 6px;
  list-style: none;
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
}
.snapi-landing-v2 .sl-lang__item {
  display: flex;
  align-items: baseline;
  gap: 8px;
  width: 100%;
  padding: 9px 12px;
  border-radius: 10px;
  background: transparent;
  border: none;
  cursor: pointer;
  text-align: left;
  font-family: var(--font-face-sans, 'Geist'), -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  color: var(--sl-fg);
  transition: background 0.12s ease;
}
.snapi-landing-v2 .sl-lang__item:hover {
  background: var(--sl-surface-alt);
}
.snapi-landing-v2 .sl-lang__item--active {
  background: var(--sl-surface-alt);
}
/* Locales whose v2 strings aren't translated yet — greyed out + inert. */
.snapi-landing-v2 .sl-lang__item--disabled {
  opacity: 0.4;
  cursor: not-allowed;
}
.snapi-landing-v2 .sl-lang__item--disabled:hover {
  background: transparent;
}
.snapi-landing-v2 .sl-lang__item-native {
  font-size: 15px;
  font-weight: 500;
}
.snapi-landing-v2 .sl-lang__item--active .sl-lang__item-native {
  color: var(--sl-primary);
  font-weight: 600;
}
.snapi-landing-v2 .sl-lang__item-name {
  font-size: 12px;
  color: var(--sl-fg-soft);
}
.snapi-landing-v2 .sl-lang__check {
  margin-left: auto;
  align-self: center;
  color: var(--sl-primary);
  flex: none;
}

@media (max-width: 520px) {
  .snapi-landing-v2 .sl-lang {
    inset-inline-start: 16px;
    bottom: 16px;
  }
  .snapi-landing-v2 .sl-lang__panel {
    width: min(280px, calc(100vw - 32px));
  }
}
