/* ══════════════════════════════════════════════════════════════════════════════
   Garden landing surface — /home-next
   ══════════════════════════════════════════════════════════════════════════════
   Ported from the 2026-08-08 design handoff (design_handoff_delist_landing).
   Values here are authoritative and were transcribed from the prototype rather
   than re-derived: colors, type, the 28px vertical rhythm, radii, shadows, and
   every easing curve and duration.

   PAGE-LOCAL BY DECISION. This file does not touch paper-tokens.css, so the
   rest of the marketing site, the SPA and admin keep their current palette
   while this page is measured. Promoting these tokens sitewide is a separate
   wave.

   The inlined Organic layer is scoped with :where(.garden), which scopes at
   zero added specificity. That is deliberate — see the note above that block.
   Do not rewrite it as `.garden h2` / `.garden .btn`; the extra specificity
   silently outranks the page's own single-class overrides.

   Load order on the page: fonts.css → paper-tokens.css → chat-funnel.css →
   this file. It comes last so the wizard retoken at the bottom wins.
   ══════════════════════════════════════════════════════════════════════════════ */

/* ── Organic base ──────────────────────────────────────────────────────────────
   The design consumes a handful of primitives from the Organic design system
   via its ds-base.js loader. We don't load that (it injects a stylesheet and a
   component bundle we have no use for), so the seven classes the markup
   actually touches are inlined here verbatim from its styles.css, along with
   the spacing/radius/shadow tokens they read.

   Audited rather than guessed: of the classes used in the handoff markup, only
   .btn-primary comes through unmodified — .btn, .btn-ghost, .btn-icon, .input,
   .nav and .nav-brand are all restyled by the page's own CSS below.

   Shadows are the Organic values, tuned to a cream ground. Do not substitute
   generic black shadows; they go muddy on #efeee3.                            */
.garden {
  --space-1: 4.4px;
  --space-2: 8.8px;
  --space-3: 13.2px;
  --space-4: 17.6px;
  --space-6: 26.4px;
  --space-8: 35.2px;
  --radius-sm: 8px;
  --radius-md: 16px;
  --radius-lg: 28px;
  --shadow-sm: 0 1px 2px color-mix(in srgb, #2e2b25 14%, transparent);
  --shadow-md: 0 3px 10px color-mix(in srgb, #2e2b25 16%, transparent);
  --shadow-lg: 0 12px 32px color-mix(in srgb, #2e2b25 22%, transparent);
}
/* Organic's element layer. The page CSS below is written assuming these are in
   force — it overrides sizes but inherits the families, margins and resets. The
   nav in particular is unstyled without them: no gap between links, and every
   link underlined in accent blue.

   :where(.garden) is doing real work here, not decoration. These rules must
   land at EXACTLY Organic's specificity — bare `h2` is (0,0,1), `.btn` is
   (0,1,0) — because the page's own styles are single-class overrides that beat
   them only by a hair. A plain `.garden h2` descendant selector is (0,1,1) and
   silently outranks `.sec-title`, which is how the problem headline lost its
   40px/42px for h2's 32px. :where() contributes zero specificity, so the
   scoping is free and the cascade below behaves exactly as the prototype's. */
:where(.garden) h1, :where(.garden) h2, :where(.garden) h3,
:where(.garden) h4, :where(.garden) h5, :where(.garden) h6 {
  font-family: var(--font-heading); font-weight: var(--font-heading-weight);
  line-height: 1.12; letter-spacing: -0.015em; margin: 0 0 var(--space-2);
}
:where(.garden) h1 { font-size: 42px; }
:where(.garden) h2 { font-size: 32px; }
:where(.garden) h3 { font-size: 25px; }
:where(.garden) h4 { font-size: 20px; }
:where(.garden) h5 { font-size: 16px; }
:where(.garden) h6 { font-size: 13px; letter-spacing: 0.08em; text-transform: uppercase; }
:where(.garden) { font-size: 15px; line-height: 1.55; font-weight: 400; }
:where(.garden) p { margin: 0 0 var(--space-3); }
:where(.garden) a { color: var(--color-accent); text-underline-offset: 3px; }
:where(.garden) img { display: block; max-width: 100%; }
:where(.garden) .nav { display: flex; align-items: center; gap: var(--space-4);
  padding: var(--space-3) var(--space-4); border-bottom: none; }
:where(.garden) .nav-brand { font-family: var(--font-heading);
  font-weight: var(--font-heading-weight); font-size: 18px; margin-right: auto; }
:where(.garden) .nav a { color: inherit; text-decoration: none; font-size: 14px; }
:where(.garden) .nav a:hover,
:where(.garden) .nav a[aria-current='page'] { color: var(--color-accent); }

/* Organic's component layer — the five primitives the handoff markup uses.
   Scoped the same way and for the same reason. */
:where(.garden) .btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  cursor: pointer; text-decoration: none;
  font-family: var(--font-heading); font-weight: var(--font-heading-weight);
  font-size: 14px; line-height: 1.2; color: var(--color-text);
  background: transparent; border: 1px solid transparent;
  padding: var(--space-2) calc(var(--space-3) * 1.2);
  border-radius: 999px;
}
:where(.garden) .btn svg { display: block; }
:where(.garden) .btn:disabled { opacity: 0.45; cursor: not-allowed; }
:where(.garden) .btn-primary { background: var(--color-accent); color: var(--color-bg); }
:where(.garden) .btn-primary:hover { background: var(--color-accent-600); }
:where(.garden) .btn-primary:active { background: var(--color-accent-700); }
:where(.garden) .btn-ghost { color: var(--color-accent); padding-inline: var(--space-1); }
:where(.garden) .btn-ghost:hover { background: color-mix(in srgb, var(--color-accent) 10%, transparent); }
:where(.garden) .btn-ghost:active { background: color-mix(in srgb, var(--color-accent) 18%, transparent); }
:where(.garden) .btn-icon { width: 36px; height: 36px; padding: 0; }
:where(.garden) .input {
  width: 100%; min-height: 36px; padding: 6px 14px; font: inherit;
  font-size: 14px; color: var(--color-text); caret-color: var(--color-accent);
  background: var(--color-surface);
  border: 1px solid var(--color-divider); border-radius: 999px;
}
:where(.garden) .input:hover { border-color: color-mix(in srgb, var(--color-text) 45%, transparent); }
:where(.garden) .input:focus-visible { border-color: var(--color-accent); outline-offset: 0; }
/* Never the browser default — spec'd explicitly for every interactive element. */
.garden :focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; }
.garden ::selection { background: color-mix(in srgb, var(--color-accent) 30%, transparent); }

/* Venice re-theme: the Organic tokens are overwritten at :root — ivory ground,
   deep navy ink, lagoon-blue accent, sea-glass second accent, Playfair serif
   display over DM Sans. Every component below reads these vars. */
.garden {
  --color-bg: #efeee3;
  --color-text: #1d3b57;
  --font-heading: "Playfair Display", Georgia, serif;
  --font-body: "DM Sans", system-ui, sans-serif;
  --font-heading-weight: 500;
  --color-accent: #1f6bb5;
  --color-accent-100: #e3edf6;
  --color-accent-200: #c8dcee;
  --color-accent-300: #a2c4e1;
  --color-accent-400: #6fa3cf;
  --color-accent-500: #1f6bb5;
  --color-accent-600: #1a5d9f;
  --color-accent-700: #174f88;
  --color-accent-800: #123e6b;
  --color-accent-900: #0d2e50;
  --color-accent-2: #71875a;
  --color-accent-2-100: #ecefe4;
  --color-accent-2-200: #dde3cd;
  --color-accent-2-300: #c3cda9;
  --color-accent-2-400: #9cad7f;
  --color-accent-2-500: #71875a;
  --color-accent-2-600: #5f744b;
  --color-accent-2-700: #4d5e3d;
  --color-accent-2-800: #3e4c31;
  --color-accent-2-900: #2f3a26;
  --color-neutral-100: #fbfaf3;
  --color-neutral-200: #f2f1e7;
  --color-neutral-300: #e2e1d4;
  --color-neutral-400: #c3c5bc;
  --color-neutral-500: #9aa0a0;
  --color-neutral-600: #6f7b83;
  --color-neutral-700: #4d5f6e;
  --color-neutral-800: #33475a;
  --color-neutral-900: #1d3145;
  --color-surface: #fbfaf3;
  --color-divider: color-mix(in srgb, #1d3b57 18%, transparent);
}
.garden .btn { font-family: var(--font-body); font-weight: 600; }
.garden .nav-brand { font-weight: 600; }
body.garden { font-family: var(--font-body); color: var(--color-text); }
.garden {
  --leading: 28px;
  --half: 14px;
  --edge: clamp(20px, 5vw, 72px);
  --measure: 58ch;
}
/* overflow-x on html, not just body. The backdrop drifts wider than a phone
   viewport and body is not the scroll container, so body-only clipping left the
   landing scrolling sideways 59px at 390. Measured on prod before this landed. */
html:has(body.garden) { scroll-behavior: smooth; overflow-x: clip; }
@media (prefers-reduced-motion: reduce) { html:has(body.garden) { scroll-behavior: auto; } }
body.garden { margin: 0; position: relative; text-wrap: pretty; overflow-x: clip; }

/* ── The wizard, retokened ─────────────────────────────────────────────────────
   chat-funnel.css is the scan wizard the hero capture hands off to. It carries
   its own light-grey/indigo/Figtree theme, so left alone the handoff at email
   submit would look like two different products.

   It is cleanly token-driven (187 var() reads against the --cf-* block below),
   and its custom-property namespace does not overlap the garden's at a single
   name — verified, not assumed. So rather than overriding its rules we change
   its inputs, page-locally, and the whole wizard renders in the garden palette.

   --cf-bg is transparent on purpose: .page-sheet is a floating cream sheet over
   the fixed backdrop, and the garden is meant to show in the margins. An opaque
   body would paint over it.                                                     */
body.garden {
  --cf-bg: transparent;
  --cf-surface: var(--color-surface);
  --cf-surface-2: var(--color-neutral-200);
  --cf-text: var(--color-text);
  --cf-muted: color-mix(in srgb, var(--color-text) 62%, transparent);
  --cf-line: var(--color-divider);
  --cf-line-soft: color-mix(in srgb, var(--color-text) 10%, transparent);
  --cf-accent: var(--color-accent);
  --cf-positive: var(--color-accent-2-700);
  --cf-warning: #8a5617;
  --cf-danger: #a33b2b;
  --cf-font: var(--font-body);
}
/* Literal, not var(--color-bg): the token is defined on body.garden and custom
   properties inherit DOWN, so reading it on <html> resolved to nothing and this
   rule was a no-op. Invisible while the backdrop loads; a white flash if it
   ever fails to. */
html:has(body.garden) { background: #efeee3; }

/* — the backdrop: one photograph fixed behind the whole page, graded warm and
   slowly breathing (Ken Burns) with drifting mist — zen — */
.backdrop { position: fixed; inset: 0; z-index: -2; overflow: clip; }
/* image-slot was the prototype's drag-and-drop placeholder element; the handoff
   says explicitly not to port it, so this is a real <img> inside a <picture>. */
.backdrop img { width: 100%; height: 100%; object-fit: cover; display: block;
  animation: kenburns 64s ease-in-out infinite alternate; transform-origin: 50% 40%; }
@keyframes kenburns {
  from { transform: scale(1) translateY(0); }
  to { transform: scale(1.09) translateY(-1.5%); }
}
@media (prefers-reduced-motion: reduce) {
  .backdrop img { animation: none; }
}
body.garden::before { content: none; }
/* hero type in warm near-black — the navy clashed with the photograph */
.hero .display, .hero .defn { color: #24231f; }
.hero .pos { color: color-mix(in srgb, #24231f 68%, transparent); }
.hero .fineprint { color: color-mix(in srgb, #24231f 68%, transparent); }
/* A full-bleed vertical scrim, not a glow. The radial gradient this replaces
   had a visible edge on the photograph -- you could see where it began and
   ended, so it read as a shape laid over the garden rather than as light in it.
   inset: 0 means there is no edge anywhere; the weighting does the work
   instead, strongest at the very top and bottom where type sits and lightest
   through the middle where the photograph should stay photographic.
   The contrast reasoning the old comment carried is not lost, it moved: the
   17px sub that measured 2.94:1 and forced the wash up to 80/55 is gone from
   the markup entirely, so the worst case in the hero is now the 60px h1. No
   brightness/contrast filter on the image -- the glow was the defect, not the
   photograph.
   The 44% stop is 38%, not the handoff's 22%. Measured over the actual
   photograph, 22% puts the 60px h1 at 2.63:1 against the darkest foliage it
   crosses -- under the 3.0 large-text floor, before the Ken Burns drift moves
   the foliage. The sweep: 22 -> 2.63, 30 -> 3.26, 38 -> 3.97, 46 -> 4.78.
   38 clears the bar with room for the animation and is still less than half
   the 80% the old radial wash needed. The 70% and 100% stops are the handoff's
   values untouched, so the middle still lightens toward the foot of the hero. */
.hero::before { content: ""; position: absolute; z-index: -1; inset: 0;
  background: linear-gradient(to bottom,
    color-mix(in srgb, var(--color-bg) 40%, transparent) 0%,
    color-mix(in srgb, var(--color-bg) 38%, transparent) 44%,
    color-mix(in srgb, var(--color-bg) 26%, transparent) 70%,
    color-mix(in srgb, var(--color-bg) 44%, transparent) 100%); }

/* The scrim above ends exactly where the sheet begins, AT ITS BRIGHTEST STOP
   (44%) -- the gradient ramps up into the cut -- while the fixed backdrop keeps
   running behind the sheet's 14px gutters and its 40px corner arcs. Measured a
   0.15 luminance step across a hard horizontal line.
   This picks up at that same 44% and decays to nothing over the first screenful
   of the sheet. The ::before stops are deliberately NOT touched: its 44% bottom
   stop is what gives .learn its 4.40:1 on mobile (see the note at .learn), so
   softening the ramp there to shrink the step would silently break contrast on
   a link that has no backing of its own. */
.hero::after { content: ""; position: absolute; left: 0; right: 0; top: 100%;
  height: 260px; z-index: -1; pointer-events: none;
  background: linear-gradient(to bottom,
    color-mix(in srgb, var(--color-bg) 44%, transparent) 0%,
    color-mix(in srgb, var(--color-bg) 30%, transparent) 38%,
    color-mix(in srgb, var(--color-bg) 12%, transparent) 70%,
    transparent 100%); }

/* .nav-links: the canonical nav wraps its four links so the mobile drawer can
   collapse ONE element. This sheet never had the rule — unstyled it is a
   display:block div inside a flex row, so the links lose the 22px rhythm and
   run together. Values mirror content-base.css so the two navs measure the same.
   The 44px minimums are the documented touch floor; index's .btn-ghost rendered
   39px at desktop because this sheet only applied the floor below 900px. */
.nav-links { display: flex; align-items: center; gap: 22px; min-width: 0; }
.nav .nav-brand { min-height: 44px; padding: 9px 4px; }
.nav .btn-ghost { min-height: 44px; padding-inline: 14px; }

/* — pill nav: hidden over the hero, slides in once you scroll past it — */
.nav { position: fixed; top: 14px; left: 50%; transform: translate(-50%, -10px); z-index: 50;
  display: flex; align-items: center;
  width: min(1060px, calc(100% - 2 * var(--edge))); box-sizing: border-box;
  border-radius: 999px; background: var(--color-bg);
  box-shadow: var(--shadow-md); padding: 10px 14px 10px 26px;
  /* visibility, not just opacity. The handoff hides the nav with opacity alone,
     which leaves its email field and four links in the tab order while the hero
     is on screen — a keyboard visitor tabs off the hero into an invisible nav.
     visibility: hidden takes it out of the tab order and the a11y tree, and it
     still transitions because it is animatable (it snaps at the end of the
     0.3s window rather than interpolating, which is the behaviour we want). */
  opacity: 0; pointer-events: none; visibility: hidden;
  transition: opacity 0.3s ease, transform 0.3s ease, visibility 0.3s; }
.nav.show { opacity: 1; transform: translate(-50%, 0); pointer-events: auto;
  visibility: visible; }
.nav .nav-brand { margin-right: 10px; display: flex; align-items: center; }
.nav .nav-scan { margin-right: auto; align-self: center; }
.nav a { white-space: nowrap; font-size: 16px; }
/* mini scan input beside the logomark — expands to fill the nav on focus,
   the other items folding away */
.nav-scan { display: flex; align-items: center; gap: 6px; min-width: 0; box-sizing: border-box;
  background: var(--color-surface); border-radius: 999px; padding: 4px 4px 4px 16px;
  border: 1px solid color-mix(in srgb, var(--color-text) 12%, transparent);
  flex: 0.0001 1 210px; transition: flex-grow 0.45s cubic-bezier(0.22, 0.8, 0.24, 1), background 0.3s ease, box-shadow 0.3s ease, border-color 0.3s ease; }
.nav-scan input { border: 0; background: transparent; outline: none; flex: 1; min-width: 0;
  padding: 6px 0; font: 15px var(--font-body); color: var(--color-text); }
.nav-scan input::placeholder { color: color-mix(in srgb, var(--color-text) 45%, transparent); }
.nav-scan .btn-icon { width: 30px; height: 30px; padding: 0; flex: none; }
.nav .btn-ghost { font-size: 16px; font-weight: 500; white-space: nowrap; }
.nav a, .nav .btn-ghost { max-width: 170px; overflow: hidden;
  transition: opacity 0.25s ease, max-width 0.45s cubic-bezier(0.22, 0.8, 0.24, 1), padding 0.45s ease; }
.nav:has(.nav-scan input:focus) .nav-scan { flex-grow: 1;
  background: var(--color-surface); box-shadow: var(--shadow-sm);
  border-color: color-mix(in srgb, var(--color-text) 22%, transparent); }
.nav:has(.nav-scan input:focus) a,
.nav:has(.nav-scan input:focus) .btn-ghost { opacity: 0; max-width: 0; padding-inline: 0; pointer-events: none; }
@media (max-width: 640px) { .nav-scan { display: none; } }

/* — zen entrances: section content breathes in once, on first view — */
[data-rise] { opacity: 0; transform: translateY(12px);
  transition: opacity 0.9s ease, transform 0.9s ease; }
[data-rise].risen { opacity: 1; transform: none; }
@media (max-width: 880px), (prefers-reduced-motion: reduce) {
  [data-rise] { opacity: 1; transform: none; }
}
/* calm hovers */
:where(.garden) .btn { transition: background 0.35s ease, color 0.35s ease, box-shadow 0.35s ease, border-color 0.35s ease; }
.nav a, .qcol a, .learn { transition: color 0.3s ease, text-decoration-color 0.3s ease; }
/* the scroll cue rests once you begin */
body.scrolled .learn svg { animation-play-state: paused; }

.kicker {
  display: block; font-size: 12px; line-height: var(--half);
  letter-spacing: 0.08em; text-transform: uppercase; font-weight: 700;
  color: var(--color-accent-700);
  font-feature-settings: "tnum" 1;
  margin: 0 0 calc(var(--leading) - var(--half));
}

/* — hero: immersive full viewport over the photograph; just the brand and a
   log-in pill at the top — */
.hero { position: relative; min-height: 100svh; box-sizing: border-box;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  text-align: center; padding: calc(3.5 * var(--leading)) var(--edge) calc(2 * var(--leading)); }
.hero-bar { position: absolute; top: 0; left: 0; right: 0;
  display: flex; align-items: center; justify-content: space-between;
  padding: 22px clamp(20px, 3vw, 44px); }
.hero-brand { display: inline-flex; line-height: 0; position: relative; }
/* Pricing in the hero bar. `.hero-bar` is space-between with the brand and the
   sign-in button; margin-left:auto absorbs the free space so the brand stays
   left and Pricing groups with Log in on the right rather than floating in the
   middle. Link weight, not button weight -- the email capture below is the only
   action in the hero that should look like one. */
/* No ::before here. The lockup had its own scaled copy of the radial glow --
   the same visible-edge defect, smaller. The scrim's 40% top stop covers the
   hero bar, so the blob has nothing left to do. */
.hero-brand img { height: 30px; width: auto; display: block; }
.nav-brand img { height: 22px; width: auto; display: block; }
.btn-soft { background: var(--color-surface); box-shadow: var(--shadow-sm);
  padding: 13px 24px; font-size: 15px; font-weight: 500; }
.btn-soft:hover { background: var(--color-neutral-200); }
.display {
  font-family: var(--font-heading); font-weight: var(--font-heading-weight);
  font-size: clamp(40px, 4.8vw, 72px);
  line-height: 1.14; max-width: 18ch; margin: 0 auto;
  letter-spacing: 0; text-wrap: balance;
  text-box: trim-both cap alphabetic;
}
.pos { font-style: italic; font-size: 21px; line-height: var(--leading);
  margin: calc(var(--leading) - 1cap) 0 0;
  color: color-mix(in srgb, var(--color-text) 70%, transparent); }
/* — the dictionary entry: one horizontal beat — word | definition | garden — */
/* The definition block is the first thing under the hero, and it inherited
   `.page-sheet > section`'s 3.25-leading top padding while its own bottom was
   zeroed -- 119px above the word against 42px below the quote, nearly 3:1, so
   it read as floating high in the sheet with the next section crowding it.
   2 leading above and 2.25 below: near-even, and the slightly larger gap below
   is the one that separates two different sections rather than the one that
   separates a block from the sheet edge it already has padding from. */
.defn-sec { padding-bottom: 0 !important;
  display: grid; grid-template-columns: auto minmax(0, 1fr) clamp(180px, 20vw, 280px);
  gap: var(--half) clamp(20px, 3vw, 44px); align-items: center; }
/* `.page-sheet > section` is 0-1-1 and sets the top padding via a shorthand, so
   a bare `.defn-sec` rule (0-1-0) loses to it -- the reason the first attempt at
   this changed nothing. Scoped to match. */
.page-sheet > .defn-sec { padding-top: calc(2 * var(--leading)); }
.defn-sec + #problem { padding-top: calc(2.25 * var(--leading)); }
.defn-sec .word { font-family: var(--font-heading); font-weight: var(--font-heading-weight);
  font-size: clamp(40px, 4.5vw, 60px); line-height: 1.1; margin: 0;
  text-box: trim-both cap alphabetic; }
.defn-sec .pos { margin: 6px 0 0; font-size: 18px; }
.defn-sec .lhs { align-self: center; }
.defn-sec .defn-left { margin: 0 !important; max-width: none; font-size: clamp(19px, 1.75vw, 26px); line-height: var(--leading); }
@media (min-width: 880px) { .defn-sec .defn-left { white-space: nowrap; text-wrap: nowrap; } }
.defn-sec .ex { font-style: italic; font-size: 16px; line-height: var(--leading);
  color: color-mix(in srgb, var(--color-text) 72%, transparent);
  margin: var(--half) 0 0; }
.defn-sec .art { margin: 0; pointer-events: none; }
.defn-sec .art img { width: 100%; height: auto; display: block; }
@media (max-width: 880px) {
  .defn-sec { grid-template-columns: 1fr; }
  .defn-sec .art { display: none; }
}
.defn { font-family: var(--font-heading); font-weight: var(--font-heading-weight);
  font-size: clamp(26px, 2.8vw, 36px); line-height: calc(1.5 * var(--leading));
  margin: calc(var(--leading) - 1cap) auto 0; max-width: 22ch;
  text-wrap: balance; text-box: trim-both cap alphabetic; }
.capture { display: flex; align-items: center; gap: var(--space-2);
  /* 760, matching the closing CTA. The two .capture instances were 560 and 760
     -- one component, two widths, which is the mismatch the design agent found
     on their own page and we had live on ours. 560 was never chosen: it was
     inherited from the pre-photograph layout when this field sat on cream, and
     under a 60px display heading over a photograph it reads as a leftover
     rather than a target. */
  width: min(760px, 100%); margin: calc(1.5 * var(--leading)) auto 0;
  box-sizing: border-box; padding: 6px 6px 6px 22px;
  background: var(--color-neutral-100); border-radius: 999px;
  box-shadow: var(--shadow-lg); }
.capture > svg { flex: none; color: color-mix(in srgb, var(--color-text) 50%, transparent); }
/* 16px, not the 14px Organic's .input defaults to. Contrast here is fine —
   11:1 navy on the pill — but 14px in a hero-scale pill reads as faint and
   undersized, and the ≤900px block already sets 16px for touch, so desktop
   was the only place left at 14. */
.capture .input { flex: 1; min-width: 0; border: 0; background: transparent;
  box-shadow: none; font-size: 16px; }
.fineprint { display: block; text-align: center;
  font-size: 12px; line-height: var(--half); margin: 10px 0 0;
  color: color-mix(in srgb, var(--color-text) 70%, transparent); }
.fineprint a { color: inherit; text-decoration: underline; text-underline-offset: 2px;
  text-decoration-color: color-mix(in srgb, currentColor 45%, transparent); }
.fineprint a:hover { text-decoration-color: currentColor; }
.learn { position: absolute; left: 50%; bottom: 14px; transform: translateX(-50%);
  display: inline-flex; align-items: center; gap: 8px;
  font-size: 15px; font-weight: 500; white-space: nowrap;
  color: #24231f; text-decoration: none; }
/* No wash here either. This was the third copy of the cream-glow device, and
   the scrim replaced the reason for it: the old radial hero glow was 76% tall
   centred at 46% and stopped short of this link at bottom: 14px, which is why
   the link needed its own. The scrim is inset: 0 and strongest at the bottom
   stop, so it covers the link by construction.
   Measured before removing, across the Ken Burns cycle: 4.73:1 desktop and
   4.40:1 mobile with the blob, and the identical values without it. It was
   contributing nothing -- painting under the scrim rather than over the
   photograph -- so it was decoration that also happened to be inert. */
.learn:hover { color: color-mix(in srgb, #24231f 70%, transparent); }
.learn svg { animation: nudge 3.2s ease-in-out infinite; }
@keyframes nudge {
  0%, 100% { transform: translateY(0); opacity: 1; }
  50% { transform: translateY(5px); opacity: 0.55; }
}
@media (prefers-reduced-motion: reduce) { .learn svg { animation: none; } }

/* — the panel: one continuous rounded ivory sheet below the hero — */
.page-sheet { background: var(--color-bg); border-radius: 40px;
  width: min(1400px, calc(100% - 28px)); margin: 0 auto 18px;
  padding: var(--leading) clamp(24px, 6vw, 96px); box-shadow: var(--shadow-sm); }
.page-sheet > section { padding: calc(3.25 * var(--leading)) 0; }
#outcome { padding-top: calc(1.5 * var(--leading)); }

/* — the woven exposure story —
   The problem lays out six dashed sockets; exposure cards land in them as the
   section enters. Each How-it-works step then pulls its cards across the page
   into its own socket, redacting them on arrival; by The outcome every card
   has dissolved. The cards live on a document-level layer and animate between
   in-layout sockets, so they are part of each section's UI, never an overlay
   floating over copy. */
.problem-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(300px, 540px);
  gap: calc(1.5 * var(--leading)) clamp(28px, 4vw, 72px); align-items: center;
  min-height: 55svh; }
.problem-head { max-width: 620px; }
.cluster { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px;
  align-content: center; }
.slot, .fslot { height: 94px; border-radius: calc(1.25 * var(--radius-lg)); box-sizing: border-box;
  background: color-mix(in srgb, var(--color-text) 4%, transparent);
  border: 1.5px dotted color-mix(in srgb, var(--color-text) 18%, transparent); }
.fslot { height: 202px; } /* holds a pair of cards, stacked with air */
.xcount { grid-column: 1 / -1; display: flex; align-items: baseline; justify-content: center;
  gap: 10px; background: var(--color-accent-100); border-radius: var(--radius-lg);
  padding: 13px 18px;
  opacity: 0; scale: 0.96;
  transition: opacity 0.45s ease, scale 0.45s ease, background 0.6s ease; }
/* resolved: zero exposure flips the counter to moss — peace restored */
.xcount.zero { background: var(--color-accent-2-100); }
.xcount.zero .num { color: var(--color-accent-2-800); }
.xcount.is-in { opacity: 1; scale: 1; }
.xcount .num { font-family: var(--font-heading); font-weight: 600; font-size: 32px;
  line-height: 1; color: var(--color-accent-800); font-feature-settings: "tnum" 1;
  min-width: 2ch; text-align: right; transition: color 0.6s ease; }
.xcount .lbl { font-size: 12px; letter-spacing: 0.07em; text-transform: uppercase;
  font-weight: 700; color: color-mix(in srgb, var(--color-text) 60%, transparent); }

/* the traveling cards */
.jlayer { position: absolute; left: 0; top: 0; width: 100%; height: 0;
  overflow: visible; z-index: 5; pointer-events: none; }
.xcard { background: var(--color-surface); border-radius: calc(1.25 * var(--radius-lg));
  box-shadow: var(--shadow-md); padding: 13px 18px; display: grid; gap: 4px;
  box-sizing: border-box; }
.jlayer .xcard { position: absolute; left: 0; top: 0; width: 250px; opacity: 0;
  height: 96px; overflow: hidden; align-content: center;
  will-change: transform; rotate: 0deg; transform-origin: top left;
  transition: transform 0.9s cubic-bezier(0.22, 0.8, 0.24, 1),
    width 0.9s cubic-bezier(0.22, 0.8, 0.24, 1), rotate 0.9s cubic-bezier(0.22, 0.8, 0.24, 1),
    opacity 0.6s ease; }
.jlayer .xcard.depart { z-index: 6; box-shadow: var(--shadow-lg); rotate: 2.2deg; }
.jlayer .xcard.snap { transition: opacity 0.4s ease; } /* reverse scroll: no flight, just reappear + unredact */
.jlayer .xcard.is-in { opacity: 1; }
.jlayer .xcard.is-redacted { opacity: 1; }
.jlayer .xcard.is-redacted .xlabel { color: color-mix(in srgb, var(--color-text) 38%, transparent); }
.jlayer .xcard.is-redacted .xval { color: color-mix(in srgb, var(--color-text) 45%, transparent); }
.jlayer .xcard.is-gone { opacity: 0; }
.xlabel { font-size: 11px; letter-spacing: 0.07em; text-transform: uppercase;
  font-weight: 700; color: color-mix(in srgb, var(--color-text) 55%, transparent); }
.xval { position: relative; font-size: 15px; font-weight: 600; width: fit-content;
  white-space: nowrap; }
.xval .bar { position: absolute; inset: 0 -4px; border-radius: 4px;
  background: var(--color-text); transform: scaleX(0); transform-origin: left center;
  transition: transform 0.5s ease 0.35s; }
.is-redacted .xval .bar { transform: scaleX(1); }
.xtag { font-size: 12px; font-weight: 700; white-space: nowrap; }
.xtag .t-found { display: inline-flex; align-items: center; gap: 5px; color: var(--color-accent-2-700); }
.xtag .t-gone { display: none; align-items: center; gap: 5px; color: var(--color-accent-700); }
.is-redacted .xtag .t-found { display: none; }
.is-redacted .xtag .t-gone { display: inline-flex; }
/* — step-aware card tags: each card's fate matches the step it landed on.
   Scan's cards stay readable (found, not yet redacted); Remove's get the
   sweep; Monitor's watch; Protect's encrypt. — */
.jlayer .xtag span { display: none; align-items: center; gap: 5px; }
.jlayer .xcard .t-found { display: inline-flex; color: var(--color-accent-2-700); }
.jlayer .xcard.m-scan .t-found, .jlayer .xcard.m-remove .t-found,
.jlayer .xcard.m-monitor .t-found, .jlayer .xcard.m-protect .t-found { display: none; }
.jlayer .xcard.m-scan .t-scan { display: inline-flex; color: var(--color-accent-700); }
.jlayer .xcard.m-remove .t-remove { display: inline-flex; color: var(--color-accent-700); }
.jlayer .xcard.m-monitor .t-monitor { display: inline-flex; color: var(--color-accent-2-700); }
.jlayer .xcard.m-protect .t-protect { display: inline-flex; color: var(--color-accent-2-800); }
/* protect: cards settle into quiet encrypted shells */
.jlayer .xcard.m-protect { background: color-mix(in srgb, var(--color-surface) 72%, transparent);
  box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--color-accent-2) 45%, transparent); }
/* the visceral beat: the redaction bar sweeps only once the card has docked
   in its socket (.settled), so the data visibly disappears on screen */
.jlayer .xcard .xval .bar { transition: transform 0.75s cubic-bezier(0.3, 0.7, 0.2, 1) 0.7s; }
.jlayer .xcard.is-redacted:not(.settled) .xval .bar { transform: scaleX(0); }
.jlayer .xcard.is-redacted.settled .xval .bar { transform: scaleX(1); }
.jlayer .xcard.is-redacted:not(.settled) .xlabel { color: color-mix(in srgb, var(--color-text) 55%, transparent); }
.jlayer .xcard.is-redacted:not(.settled) .xval { color: var(--color-text); }
/* — monitor socket: the same beat as scan and remove, on a loop. Two cards
   arrive, are found, get swept, and leave — because monitoring is that cycle
   running forever. Timings and easings mirror the flight cards exactly. — */
.fslot-mon { position: relative; height: 202px; }
.mon-card { position: absolute; left: 0; right: 0; width: auto;
  opacity: 0; translate: 0 14px; height: 96px; overflow: hidden; align-content: center;
  transition: opacity 0.6s ease, translate 0.9s cubic-bezier(0.22, 0.8, 0.24, 1); }
.mon-card:nth-of-type(2) { top: 106px; }
.mon-card.arrive { opacity: 1; translate: 0 0; }
.mon-card.leave { opacity: 0; translate: 0 -14px; }
.mon-card .xval .bar { transition: transform 0.75s cubic-bezier(0.3, 0.7, 0.2, 1); }
.mon-card.swept .xval .bar { transform: scaleX(1); }
.mon-card.swept .xlabel { color: color-mix(in srgb, var(--color-text) 38%, transparent); }
.mon-card.swept .xval { color: color-mix(in srgb, var(--color-text) 45%, transparent); }
.mon-card .t-gone { display: none; }
.mon-card.swept .t-found { display: none; }
.mon-card.swept .t-gone { display: inline-flex; }
/* static fallback cards (mobile + reduced motion) */
.cluster .xcard.static { display: none; }

/* — the woven treatment: vacated sockets flip to a "Cleared" state, each
   step's number fills in as its cards are redacted, and the cards dissolve
   into the sand at The outcome. — */
.slot { position: relative; transition: background 0.8s ease, border-color 0.8s ease; }
.slot::after { content: "Cleared"; position: absolute; inset: 0; display: grid;
  place-content: center; font: 700 10px var(--font-body); letter-spacing: 0.09em;
  text-transform: uppercase; color: var(--color-accent-2-700);
  opacity: 0; transition: opacity 0.8s ease 0.55s; }
.slot.cleared {
  background: var(--color-accent-2-100); border-style: solid;
  border-color: color-mix(in srgb, var(--color-accent-2) 40%, transparent); }
.slot.cleared::after { opacity: 1; }
.feature.done .f-title::before {
  content: "✓"; font-size: 14px; background: var(--color-accent-2);
  border-color: var(--color-accent-2); color: #fff; }
/* card exit: staggered dissolve-in-place, settling into the sand */
.jlayer .xcard.is-gone { transition-duration: 1.3s; }
.features { position: relative; }


.sec-title { font-family: var(--font-heading); font-weight: var(--font-heading-weight);
  font-size: clamp(28px, 3.2vw, 40px); line-height: calc(1.5 * var(--leading));
  margin: 0; text-box: trim-both cap alphabetic; }
.sec-title em { font-style: italic; color: var(--color-accent-2-800); }
.note { font-size: 16px; line-height: var(--leading);
  color: color-mix(in srgb, var(--color-text) 78%, transparent);
  margin: calc(var(--leading) - 1cap) 0 0; max-width: 48ch; text-box: trim-both cap alphabetic; }

/* — feature rows: title, copy, and the step's socket the cards land in — */
.features { padding: 0; }
.features .sec-title { margin-bottom: calc(1.5 * var(--leading)); }
.feature { display: grid;
  grid-template-columns: minmax(0, 150px) minmax(0, 1fr) clamp(220px, 19vw, 260px);
  gap: var(--leading) clamp(20px, 2.5vw, 40px); align-items: center;
  padding: var(--half) 0; }
.fslot { align-self: center; }
.f-title { position: relative; font-family: var(--font-heading); font-weight: var(--font-heading-weight);
  font-size: 26px; line-height: var(--leading);
  margin: 0; text-box: trim-both cap alphabetic; }
.f-title::before { content: attr(data-step); position: absolute;
  border: 2.5px solid var(--color-accent); box-sizing: border-box;
  width: 30px; height: 30px; border-radius: 50%;
  left: -48px; top: calc(0.5cap - 15px);
  display: grid; place-content: center;
  font: 600 12px/1 var(--font-body); color: var(--color-accent-700);
  font-feature-settings: "tnum" 1; }
/* Below 1280 there is no gutter left to hang the badge in, so it comes back
   inline immediately rather than at 880. The handoff moved this rule inside its
   ≤880 block, which left 881–1279px — iPad landscape, iPad Pro landscape, and
   any laptop window under 1280 — with no step marker at all. Same rules, just
   promoted to the breakpoint where the gutter badge actually drops out. */
@media (max-width: 1280px) {
  .f-title::before { position: static; width: 26px; height: 26px;
    flex: none; border-width: 2px; }
  .f-title { display: flex; align-items: center; gap: 12px; }
}
.f-copy { font-size: 16px; line-height: var(--leading); margin: 0;
  color: color-mix(in srgb, var(--color-text) 78%, transparent);
  max-width: 52ch; text-box: trim-both cap alphabetic; }

/* — outcome split — */
.split { display: grid; grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
  gap: var(--leading) clamp(24px, 5vw, 96px); align-items: center;
  padding: 0 0 var(--leading); }
.split-title { font-family: var(--font-heading); font-weight: var(--font-heading-weight);
  font-size: clamp(28px, 3.2vw, 40px); line-height: calc(1.5 * var(--leading));
  margin: 0; text-box: trim-both cap alphabetic; }
/* "delisted" un-redacts: starts as an ink bar, the word fades in as the bar
   sweeps away once the section lands */
.split-title em { position: relative; }
.split-title em::after { content: ""; position: absolute; inset: 0.05em -0.08em -0.02em;
  border-radius: 4px; background: var(--color-text);
  transform-origin: right center; transition: transform 0.7s cubic-bezier(0.3, 0.7, 0.2, 1) 0.5s; }
.split-title em .w { opacity: 0; transition: opacity 0.4s ease 0.75s; }
#outcome.landed .split-title em::after { transform: scaleX(0); }
#outcome.landed .split-title em .w { opacity: 1; }
/* checklist cascade */
.checklist li { opacity: 0; transform: translateY(10px);
  transition: opacity 0.5s ease, transform 0.5s ease; }
#outcome.landed .checklist li { opacity: 1; transform: none; }
#outcome.landed .checklist li:nth-child(2) { transition-delay: 0.08s; }
#outcome.landed .checklist li:nth-child(3) { transition-delay: 0.16s; }
#outcome.landed .checklist li:nth-child(4) { transition-delay: 0.24s; }
@media (max-width: 880px), (prefers-reduced-motion: reduce) {
  .checklist li { opacity: 1; transform: none; }
  .split-title em::after { display: none; }
  .split-title em .w { opacity: 1; }
}
.split-figure { margin: 0; width: min(400px, 100%); justify-self: end;
  border-radius: calc(2 * var(--radius-lg)); overflow: hidden; }
.split-figure img { width: 100%; aspect-ratio: 493 / 668; object-fit: cover; display: block; }
/* — borrowed scenery: arched windows where the garden shows through the sheet.
   background-attachment: fixed aligns with the fixed backdrop, so the garden
   slides behind the openings as you scroll. — */
.window { position: relative; aspect-ratio: 493 / 668;
  border-radius: 999px 999px calc(2 * var(--radius-lg)) calc(2 * var(--radius-lg));
  /* image-set so the arch gets the AVIF too; the JPEG is the fallback leg. */
  background: image-set(
      url("/img/garden/hero-backdrop-1536.avif") type("image/avif"),
      url("/img/garden/hero-backdrop-1536.jpg") type("image/jpeg"))
    center / cover no-repeat fixed;
  opacity: 0; transition: opacity 1.2s ease; } /* no transform — it would break the fixed bg */
#outcome.landed .window, #outcome.landed ~ * .window { opacity: 1; }
@media (max-width: 880px), (prefers-reduced-motion: reduce) { .window { opacity: 1; } }
.window::after { content: ""; position: absolute; inset: 0; pointer-events: none;
  background: color-mix(in srgb, var(--color-bg) 12%, transparent); }

.checklist { list-style: none; margin: calc(1.5 * var(--leading)) 0 0; padding: 0;
  display: grid; gap: var(--half); }
.checklist li { display: flex; gap: var(--space-3); align-items: center;
  font-size: 16px; line-height: var(--leading); }
.checklist svg { flex: none; color: var(--color-accent-2-700); }

/* — garden art: painted elements embedded in the page flow — */
.garden-art { pointer-events: none; }
.art-stream { width: min(1000px, 94%); margin: 0 auto calc(-1.5 * var(--leading)); }
.art-stream img, .art-wave img { width: 100%; height: auto; display: block; }
.art-wave { width: min(760px, 88%); margin: calc(-2.5 * var(--leading)) auto calc(-1.5 * var(--leading)); }
.art-lantern { position: absolute; bottom: 0; right: clamp(10px, 4vw, 72px);
  width: clamp(110px, 11vw, 158px); }
.art-lantern img { width: 100%; height: auto; display: block; }
@media (max-width: 900px) { .art-lantern { display: none; } }

/* Touch sizing runs to 900px, NOT 560px. Tablets are touch devices too, and the
   narrower scope left the hero field at 14px/36px at 768 — under iOS's 16px
   zoom threshold, so focusing it zoomed the whole page, and under the 44px
   touch minimum. Do not narrow this breakpoint back. */
@media (max-width: 900px) {
  .capture { padding: 7px 7px 7px 18px; }
  .capture .input { font-size: 16px; min-height: 44px; }
  .capture .btn-icon { width: 44px; height: 44px; }
  /* The two pill buttons -- the hero bar's Log in / Sign up (.btn-ghost) and
     the closing CTA's secondary (.btn-soft) -- rendered 39px tall here. The
     package's .btn carries the 44px floor; this page runs on paper-tokens'
     .btn, which does not, so the floor was never inherited. Set on .btn rather
     than on the two variants: the next variant added to this page inherits the
     floor instead of missing it the same way. */
  .btn { min-height: 44px; }
  .nav-scan input { font-size: 16px; min-height: 40px; }
  .nav-scan .btn-icon { width: 40px; height: 40px; }
}



/* — quote — */
.quote { padding: calc(3 * var(--leading)) 0 0; }
.quote blockquote {
  font-family: var(--font-heading); font-weight: var(--font-heading-weight);
  font-size: clamp(24px, 2.6vw, 32px); line-height: calc(1.5 * var(--leading));
  max-width: 32ch; margin: 0;
  text-indent: -0.559em;
  text-box: trim-both cap alphabetic;
}
.quote figcaption { font-size: 16px; line-height: var(--leading);
  color: color-mix(in srgb, var(--color-text) 70%, transparent);
  margin: calc(2 * var(--leading) - 1cap) 0 0;
  text-indent: -1.347em;
  text-box: trim-both cap alphabetic; }
@media (max-width: 720px) {
  .quote blockquote, .quote figcaption { text-indent: 0; }
}

/* — the close patch — */
.patch { background: var(--color-accent-2-100);
  border-radius: calc(2 * var(--radius-lg));
  margin: var(--leading) 0 calc(1.5 * var(--leading));
  padding: calc(3.5 * var(--leading)) clamp(32px, 6vw, 96px); }
.patch-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(300px, 380px);
  gap: calc(1.5 * var(--leading)) clamp(28px, 5vw, 80px); align-items: center; }
.patch-list { margin-top: var(--leading); }
.patch-list li { align-items: flex-start; }
.patch-list svg { margin-top: 4px; }
.patch-card { background: var(--color-surface); border-radius: calc(1.5 * var(--radius-lg));
  padding: calc(1.25 * var(--leading)) var(--leading); box-shadow: var(--shadow-md);
  display: grid; gap: 12px; }
.patch-card-kicker { font-size: 12px; letter-spacing: 0.08em; text-transform: uppercase;
  font-weight: 700; color: var(--color-accent-700); }
.patch-card .btn-block { width: 100%; padding-block: 12px; }
.patch-card .assure { flex-direction: column; align-items: flex-start; gap: 8px;
  justify-content: flex-start; margin-top: 4px; }
@media (max-width: 880px) { .patch-grid { grid-template-columns: 1fr; } }

/* — the close, Venice-style: big serif line on the open sheet, pill capture,
   two actions — */
.close-cta { text-align: center; padding: calc(3 * var(--leading)) 0 calc(3 * var(--leading)); position: relative; }
.close-cta h3 { font-family: var(--font-heading); font-weight: var(--font-heading-weight);
  font-size: clamp(38px, 4.6vw, 64px); line-height: 1.22; margin: 0 auto;
  max-width: 18ch; text-wrap: balance;
  text-box: trim-both cap alphabetic; }
.close-cta h3 .priv { color: var(--color-accent-2-600); }
.close-cta .sub { font-size: 17px; line-height: var(--leading);
  color: color-mix(in srgb, var(--color-text) 78%, transparent);
  max-width: 64ch; margin: calc(1.25 * var(--leading)) auto 0; }
.close-cta .sub-note { font-size: 14.5px; margin-top: var(--half);
  color: color-mix(in srgb, var(--color-text) 62%, transparent); }
.close-cta .capture { width: min(760px, 100%); margin-top: calc(1.75 * var(--leading));
  padding: 9px 9px 9px 26px; box-shadow: var(--shadow-md); }
.close-cta .capture .input { min-height: 44px; font-size: 15px; }
/* 15px is a desktop-only value. The <=900px touch block sets 16px on
   `.capture .input`, but that is 0-2-0 against this rule's 0-3-0 AND sits 60
   lines earlier, so the override lost on specificity and on source order —
   belt and braces, both in the wrong direction. The closing field stayed at
   15px on every phone, under the iOS zoom threshold the touch block exists to
   clear, so focusing it zoomed the page. Scoped here, next to the rule it
   corrects, rather than back in the touch block where it would lose again. */
@media (max-width: 900px) { .close-cta .capture .input { font-size: 16px; } }
.cta-btns { display: flex; justify-content: center; align-items: center; gap: 12px;
  flex-wrap: wrap; margin-top: calc(1.5 * var(--leading)); }
.cta-btns .btn { padding: 13px 26px; font-size: 15px; }
.cta-btns .btn-soft { font-weight: 500; }
.finelegal { font-size: 12px; line-height: 18px; margin: 10px auto 0;
  color: color-mix(in srgb, var(--color-text) 58%, transparent); }
.finelegal a { color: inherit; text-decoration: underline;
  text-underline-offset: 2px; text-decoration-color: color-mix(in srgb, currentColor 45%, transparent); }
.finelegal a:hover { text-decoration-color: currentColor; }
.patch h3 { font-family: var(--font-heading); font-weight: var(--font-heading-weight);
  font-size: clamp(26px, 3vw, 36px); line-height: calc(1.5 * var(--leading));
  margin: 0; text-box: trim-both cap alphabetic; }
.patch .sub { font-size: 16px; line-height: var(--leading);
  color: color-mix(in srgb, var(--color-text) 78%, transparent);
  margin: calc(var(--leading) - 1cap) 0 0; max-width: 46ch; text-box: trim-both cap alphabetic; }
.signup { display: flex; gap: var(--space-3); align-items: stretch; max-width: 480px;
  margin: var(--leading) auto 0; }
.signup .input { flex: 1; }
.signup .input, .signup .btn { min-height: 36px; }
.assure { list-style: none; display: flex; flex-wrap: wrap; justify-content: center;
  gap: var(--half) calc(1.5 * var(--leading)); margin: var(--leading) 0 0; padding: 0; }
.assure li { display: inline-flex; align-items: center; gap: 7px;
  font-size: 13px; font-weight: 400;
  color: color-mix(in srgb, var(--color-text) 72%, transparent); }
.assure svg { color: var(--color-accent-2-700); }
/* — the quiet footer: its own ivory sheet so it reads over the backdrop — */
.qfooter { background: var(--color-bg); border-radius: 40px; box-shadow: var(--shadow-sm);
  width: min(1400px, calc(100% - 28px)); margin: 18px auto;
  padding: calc(1.5 * var(--leading)) clamp(24px, 6vw, 96px) 0; box-sizing: border-box; }
.qcols { display: grid; grid-template-columns: minmax(0, 1.3fr) minmax(0, 0.9fr) minmax(0, 1fr) minmax(0, 1.25fr) minmax(0, 0.9fr);
  gap: var(--leading) clamp(20px, 3vw, 44px); padding-bottom: calc(1.5 * var(--leading));
  border-bottom: 1px solid color-mix(in srgb, var(--color-text) 14%, transparent); }
.qbrand img { height: 20px; width: auto; display: block; }
.qbrand p { font-size: 13.5px; line-height: 1.55; margin: var(--half) 0 0; max-width: 24ch;
  color: color-mix(in srgb, var(--color-text) 70%, transparent); }
.qcol h4 { font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase; font-weight: 700;
  margin: 4px 0 var(--half); }
.qcol h4 a { display: inline-flex; align-items: center; gap: 5px; text-decoration: none;
  color: color-mix(in srgb, var(--color-text) 50%, transparent); transition: color 0.2s ease; }
.qcol h4 a::after { content: "\2192"; font-size: 11px; opacity: 0;
  translate: -4px 0; transition: opacity 0.2s ease, translate 0.2s ease; }
.qcol h4 a:hover { color: var(--color-accent-700); }
.qcol h4 a:hover::after { opacity: 1; translate: 0 0; }
.qcol ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
.qcol a { font-size: 14px; color: var(--color-text); text-decoration: none; }
.qcol li a { display: block; line-height: 1.45; text-wrap: pretty; }
.qcol a:hover { color: var(--color-accent-700); }
.qbar { display: flex; align-items: center; justify-content: space-between; gap: var(--half);
  padding: var(--half) 0 var(--leading); font-size: 13px; color: #24231f; }
.qbar .legal { display: flex; gap: 18px; }
.qbar a { color: inherit; text-decoration: underline; text-underline-offset: 2px;
  text-decoration-color: color-mix(in srgb, currentColor 35%, transparent); }
.qbar a:hover { text-decoration-color: currentColor; }
@media (max-width: 860px) { .qcols { grid-template-columns: 1fr 1fr; } .qbrand { grid-column: 1 / -1; } }

/* — mobile / reduced-motion end-state cards: with the flight disabled, each
   step shows its own outcome as a static card so no socket is ever empty — */
.mcard { display: none; }
.mcard .xtag span { display: inline-flex; align-items: center; gap: 5px; }
.mcard .t-scan { color: var(--color-accent-700); }
.mcard .t-remove { color: var(--color-accent-700); }
.mcard .t-monitor { color: var(--color-accent-2-700); }
.mcard.redacted .xlabel { color: color-mix(in srgb, var(--color-text) 38%, transparent); }
.mcard.redacted .xval { color: color-mix(in srgb, var(--color-text) 45%, transparent); }
.mcard.redacted .bar { transform: scaleX(1); transition: none; }
/* — responsive / reduced-motion: the journey collapses to static cards in the
   problem cluster — */
@media (max-width: 880px) {
  .problem-grid { grid-template-columns: 1fr; min-height: 0; }
  .cluster .slot { display: none; }
  .cluster .xcard.static { display: grid; }
  .xval { white-space: normal; }
  .xcount { opacity: 1; scale: 1; }
  .jlayer, .thread, .variants { display: none !important; }
  .feed .fr { opacity: 1; transform: none; }
  .doss { position: static; margin-top: var(--leading); }
  .doss-wrap { grid-template-columns: 1fr; }
  .hv-4 .tall { height: auto; }
  .mover { display: none; }
  .ccol { min-height: 0; }
  .feature { grid-template-columns: 1fr; gap: var(--half); padding: var(--leading) 0; }
  /* height:auto, not just display:block. The 202px socket is sized for the
     flying PAIR; in static mode each step carries ONE .mcard, so the spare
     ~105px rendered as an empty dashed placeholder under steps 01 and 02 and
     read as a skeleton loader that never resolved. .fslot-mon already had this
     treatment -- .fslot was simply never given it. */
  .fslot { display: block; height: auto; }
  .fslot-mon { height: auto; }
  .mon-card { display: none; }
  .mcard { display: grid; }
  .f-copy { max-width: var(--measure); }
  /* (the inline step badge is handled at ≤1280 above, where the gutter runs out) */
  /* the arch becomes a static crop — iOS ignores background-attachment: fixed */
  .window { background-attachment: scroll; }
  .split-figure { width: 100%; }
}
@media (max-width: 560px) {
  .cluster { grid-template-columns: 1fr; }
  .hero-bar .btn-soft { padding: 10px 16px; font-size: 14px; }
  .hero-brand img { height: 26px; }
  .qcols { grid-template-columns: 1fr; gap: calc(1.5 * var(--leading)); }
  /* stacked footer links need their tap rows to clear each other */
  .qcols a { padding-block: 5px; }
}
@media (min-width: 561px) and (max-width: 880px) {
  .qcols { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (prefers-reduced-motion: reduce) {
  .cluster .slot { display: none; }
  .cluster .xcard.static { display: grid; }
  .xcount { opacity: 1; scale: 1; }
  .jlayer, .thread, .variants { display: none !important; }
  .feed .fr { opacity: 1; transform: none; }
  .doss { position: static; margin-top: var(--leading); }
  .doss-wrap { grid-template-columns: 1fr; }
  .hv-4 .tall { height: auto; }
  .mover { display: none; }
  .ccol { min-height: 0; }
  /* Same void as the =880px block above, and unreported: a reduced-motion
     visitor at desktop width kept the three-column layout AND the 202px
     sockets, one card each. */
  .fslot { height: auto; }
  .fslot-mon { height: auto; }
  .mon-card { display: none; }
  .mcard { display: grid; }
}
@media (max-width: 720px) {
  .split { grid-template-columns: 1fr; }
  .split-figure { justify-self: start; }
}

/* Review aid: the 28px rhythm drawn as hairlines — debug chrome, toggled by
   ?baselines or the B key, never part of the look. */
body[data-baselines] { position: relative; }
body[data-baselines]::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background:
    repeating-linear-gradient(to bottom,
      color-mix(in srgb, var(--color-accent) 35%, transparent) 0 1px,
      transparent 1px var(--leading)),
    repeating-linear-gradient(to bottom,
      transparent 0 var(--half),
      color-mix(in srgb, var(--color-accent) 16%, transparent) var(--half) calc(var(--half) + 1px),
      transparent calc(var(--half) + 1px) var(--leading));
}

/* ── Landing ⇄ wizard ──────────────────────────────────────────────────────────
   The handoff describes a marketing page; chat-funnel.js drives a scan wizard.
   They share this document and swap places on email submit, which is exactly
   what the live homepage does today: syncIntroState() flips body[data-cf-mode]
   from "landing" to "wizard", same URL, no navigation.

   Defaults matter here. data-cf-mode is not set until chat-funnel.js has run,
   so the wizard is hidden unless a mode explicitly asks for it — otherwise it
   flashes under the hero on first paint.

   The swap toggles .garden-wizard — a bare wrapper with no styles of its own —
   and never .cf-layout. That distinction is the whole fix: chat-funnel.css owns
   .cf-layout's display and it is RESPONSIVE (grid at >=940px, where the setup
   rail is a sidebar beside the conversation). Restating it as block here, which
   is what the first version did, stacked the rail on top and pushed the
   composer to y=1025 on a 900px-tall window — the wizard looked like a static
   summary with no way to continue. Toggle a wrapper; let the stylesheet that
   owns a property keep owning it.                                              */
body.garden .garden-wizard { display: none; }
body.garden[data-cf-mode="wizard"] .garden-wizard,
body.garden[data-cf-mode="results"] .garden-wizard { display: block; }
body.garden[data-cf-mode="wizard"] .garden-landing,
body.garden[data-cf-mode="results"] .garden-landing { display: none; }

/* The funnel's own landing furniture is superseded by the garden hero. */
body.garden .cf-landing-visual { display: none; }

/* The wizard inherits the sheet: a cream page floating on the fixed garden,
   so the backdrop still shows at the margins once the marketing page is gone.
   Visual treatment ONLY — no display, no width. chat-funnel.css owns the
   wizard's geometry and it is responsive in both properties. */
body.garden[data-cf-mode="wizard"] .cf-layout,
body.garden[data-cf-mode="results"] .cf-layout {
  background: var(--color-bg);
  border-radius: 40px;
  padding: var(--leading) clamp(20px, 3vw, 44px);
  /* 76px is the pinned nav's footprint (top: 14px + its 62px height); the
     leading on top of it is the clearance. Without it the sheet's top edge
     and the nav's bottom edge both sit at y=76 and the funnel reads as
     welded to the chrome. Every other gap on this page is a multiple of
     --leading; this one should be too. */
  margin-block: calc(76px + var(--leading)) 18px;
  box-shadow: var(--shadow-sm);
}

/* The two in-page anchors are dead once the funnel opens: .garden-landing is
   display:none. The nav now carries the canonical link set (all real page
   loads), so the old `a[href^="#"]` selector would match NOTHING and every link
   would stay visible mid-funnel — a silent break, since nothing in CI watches
   this. Hiding .nav-links is the same intent expressed on the wrapper: the pill
   nav's job here is wayfinding on the landing, not navigation mid-task. Sign in
   stays — it is outside .nav-links. The email pill goes too, since the visitor
   is already in the funnel it would start. */
body.garden[data-cf-mode="wizard"] .nav .nav-links,
body.garden[data-cf-mode="results"] .nav .nav-links,
body.garden[data-cf-mode="wizard"] .nav .nav-scan,
body.garden[data-cf-mode="results"] .nav .nav-scan { display: none; }
/* nav-scan carried margin-right:auto, which pushed the rest of the pill right.
   With it gone the brand needs to take that job or the links bunch up. */
body.garden[data-cf-mode="wizard"] .nav .nav-brand,
body.garden[data-cf-mode="results"] .nav .nav-brand { margin-right: auto; }

/* Mobile gets a half-step, not a full leading. The nav is 73px there rather than
   76, and vertical room is scarce: the review step's composer has to stay on
   screen at 390x844 — pinned by chat-funnel.spec.js — and a full leading of
   clearance pushes it 12px past the fold. Chrome clearance loses to being able
   to reach the submit without scrolling. */
@media (max-width: 880px) {
  body.garden[data-cf-mode="wizard"] .cf-layout,
  body.garden[data-cf-mode="results"] .cf-layout {
    margin-block: calc(73px + var(--half)) 18px;
  }
}

/* Off the landing view the nav has no hero to clear, so it simply stays put. */
body.garden[data-cf-mode="wizard"] .nav,
body.garden[data-cf-mode="results"] .nav { opacity: 1; pointer-events: auto;
  transform: translate(-50%, 0); }

/* ── Mobile nav drawer (index) ─────────────────────────────────────────────
   Ported from content-base.css so index gets the SAME drawer the other 352
   pages already have. index does not load that sheet (the two designs collide
   on seven class names, CONTRACT.md §7), so the rules are duplicated here on
   purpose — keep the two in sync; nav-menu.js itself is shared verbatim.

   This also fixes a live defect independent of the redesign: home-next.css hid
   `.nav a:not(.btn)` below 480px, so Pricing and About were unreachable from
   the homepage nav on ANY phone. That rule is deleted; the drawer replaces it.

   Breakpoint is 860px, matching content-base — below that the four links and
   the scan pill cannot both fit on one bar. */
.navmenu-btn { display: none; }
.nav .navmenu-btn { width: 44px; height: 44px; padding: 0; flex: none;
  align-items: center; justify-content: center; margin-left: 4px;
  background: none; border: 0; border-radius: 999px; cursor: pointer;
  color: var(--color-text); }
.nav .navmenu-btn:hover { background: color-mix(in srgb, var(--color-accent) 12%, transparent); }
.nav .navmenu-btn svg { display: block; flex: none; }
.navmenu-btn .bar { transform-origin: 12px 12px;
  transition: transform 0.28s cubic-bezier(0.22, 0.8, 0.24, 1), opacity 0.18s ease; }
.navmenu-btn[aria-expanded="true"] .bar-a { transform: translateY(3.5px) rotate(45deg); }
.navmenu-btn[aria-expanded="true"] .bar-b { transform: translateY(-3.5px) rotate(-45deg); }

@media (max-width: 860px) {
  .nav { flex-wrap: wrap; row-gap: 0; }
  .nav .navmenu-btn { display: inline-flex; order: 3; margin-left: auto; }
  .nav .nav-brand { margin-right: auto; }
  /* display:none, not height/opacity — a hidden-but-focusable panel is a
     tab-order trap. */
  .nav[data-menu="closed"] .nav-links { display: none; }
  .nav[data-menu="open"], .nav:not([data-menu]) { border-radius: 28px; padding-bottom: 8px; }
  .nav[data-menu="open"] .nav-links, .nav:not([data-menu]) .nav-links {
    display: grid; gap: 0; width: 100%; order: 9; margin-top: 8px; padding-top: 4px;
    border-top: 1px solid color-mix(in srgb, var(--color-text) 12%, transparent); }
  .nav[data-menu="open"] .nav-links > a, .nav:not([data-menu]) .nav-links > a {
    display: flex; align-items: center; min-height: 48px; max-width: none;
    padding: 0 8px; font-size: 17px; }
  /* Sign in sits in the drawer (owner decision 2026-08-28), matching the
     sitewide change in content-base.css. */
  .nav .btn-ghost { order: 10; width: 100%; max-width: none; min-height: 48px; margin-top: 6px;
    justify-content: flex-start; padding-inline: 8px; font-size: 17px;
    border-top: 1px solid color-mix(in srgb, var(--color-text) 12%, transparent);
    border-radius: 0; background: none; }
  .nav[data-menu="closed"] .btn-ghost { display: none; }
}
/* The .nav:not([data-menu]) half of the pairs above is the JS-off case: no
   button was injected, so the links render stacked and stay reachable. */
