PageSourceSearch

https://vo.dev/problem/

html vo.dev collected 2026-10-04 13:33:25 UTC 47,467 bytes, 316 lines download raw bytes

1<!DOCTYPE html><html lang="en"> <head><meta name="sentry-route-name" content="%2Fproblem"/><meta charset="utf-8"><!-- Persona attribute BEFORE first paint (no-flicker rule, same pattern
2         as dark-mode gates): the header CTA's maker label is CSS keyed off
3         html[data-persona], so the right label renders on the very first
4         frame instead of swapping at DOMContentLoaded. Keys owned by
5         dev-entry.js (ritual_dev_entry / ritual_maker_entry). -->
5<script>
6      try {
7        var p =
8          localStorage.getItem("ritual_maker_entry") === "1"
9            ? "maker"
10            : localStorage.getItem("ritual_dev_entry") === "1"
11              ? "developer"
12              : "";
13        if (p) document.documentElement.setAttribute("data-persona", p);
14      } catch (e) {
15        /* storage blocked: default CTA renders */
16      }
17    </script>
17<!-- Same no-flicker rule, for the verified developer coming back from the
18         email link. The CLI is a client:only island, so the marketing page is
19         what paints while React loads, and they watched the page they had just
20         left reassemble itself before the console they came back for arrived.
21         Stamping html here covers that gap from the first frame; CliHeroPlugin
22         mounts straight into fullscreen underneath it and clears the flag.
23
24         The style is INLINE rather than in cli.css: that sheet ships with the
25         island's chunk, which by definition has not loaded yet at the moment
26         this needs to be painted.
27
28         Scoped to the developer pages, since ?return=1 is a common enough
29         param to belong to something else elsewhere. -->
29<script>
30      try {
31        if (
32          location.pathname.indexOf("/product/developer") === 0 &&
33          new URLSearchParams(location.search).get("return") === "1"
34        ) {
35          document.documentElement.setAttribute("data-cli-return", "");
36          /* Never strand them on a dark screen: if the island fails to mount
37             (JS blocked, chunk 404), the page comes back on its own. Longer
38             than a slow mount, shorter than a visitor's patience. */
39          setTimeout(function () {
40            document.documentElement.removeAttribute("data-cli-return");
41          }, 8000);
42        }
43      } catch (e) {
44        /* no URL API / blocked: the old flash is the fallback, not a failure */
45      }
46    </script>
46<style>
47      /* #1B1A2A is --cli-bg, hardcoded for the same reason the style is inline:
48         the sheet that defines the token has not arrived yet. */
49      html[data-cli-return] {
50        background: #1b1a2a;
51      }
52      html[data-cli-return]::before {
53        content: "";
54        position: fixed;
55        inset: 0;
56        background: #1b1a2a;
57        /* Under the takeover (100) so the console draws over it, above
58           everything else so the page underneath never shows. */
59        z-index: 99;
60        /* A full-screen overlay that ate clicks would be its own bug. */
61        pointer-events: none;
62      }
63      html[data-cli-return] body {
64        overflow: hidden;
65      }
66    </style><link rel="icon" type="image/png" href="/favicon.png"><link rel="apple-touch-icon" href="/favicon.png"><!-- interactive-widget=resizes-content: the on-screen keyboard SHRINKS the
67         layout viewport, so the prelogin CLI's fullscreen input + action button
68         sit above the keyboard instead of behind it on mobile. Harmless on
69         pages without the CLI (only changes keyboard-resize behavior). --><meta name="viewport" content="width=device-width, initial-scale=1, interactive-widget=resizes-content"><meta name="generator" content="Astro v6.4.8"><meta name="description" content="Why AI tools lose context, what it costs, and how Ritual fixes it."><link rel="canonical" href="https://ritual.work/problem/"><!-- Open Graph --><meta property="og:type" content="website"><meta property="og:title" content="The Problem — Ritual"><meta property="og:description" content="Why AI tools lose context, what it costs, and how Ritual fixes it."><meta property="og:url" content="https://ritual.work/problem/"><meta property="og:image" content="https://ritual.work/hero-graph.png"><meta property="og:site_name" content="Ritual"><!-- Twitter --><meta name="twitter:card" content="summary_large_image"><meta name="twitter:title" content="The Problem — Ritual"><meta name="twitter:description" content="Why AI tools lose context, what it costs, and how Ritual fixes it."><meta name="twitter:image" content="https://ritual.work/hero-graph.png"><link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap"><title>The Problem — Ritual</title>
69<script>(function(){const posthogKey = "phc_uDVTitoexBzZHYAc46FpaX2uRMhA8EWmZFNPfEDDykAM";
70const posthogHost = "https://us.i.posthog.com";
71const releaseSha = "0db980f";
72
73    !function(t,e){var o,n,p,r;e.__SV||(window.posthog=e,e._i=[],e.init=function(i,s,a){function g(t,e){var o=e.split(".");2==o.length&&(t=t[o[0]],e=o[1]),t[e]=function(){t.push([e].concat(Array.prototype.slice.call(arguments,0)))}}(p=t.createElement("script")).type="text/javascript",p.async=!0,p.src=s.api_host+"/static/array.js",(r=t.getElementsByTagName("script")[0]).parentNode.insertBefore(p,r);var u=e;for(void 0!==a?u=e[a]=[]:a="posthog",u.people=u.people||[],u.toString=function(t){var e="posthog";return"posthog"!==a&&(e+="."+a),t||(e+=" (stub)"),e},u.people.toString=function(){return u.toString(1)+".people (stub)"},o="capture identify alias people.set people.set_once set_config register register_once register_for_session unregister unregister_for_session opt_out_capturing has_opted_out_capturing opt_in_capturing reset isFeatureEnabled onFeatureFlags getFeatureFlag getFeatureFlagPayload reloadFeatureFlags group updateEarlyAccessFeatureEnrollment getEarlyAccessFeatures getActiveMatchingSurveys getSurveys getNextSurveyStep onSessionId".split(" "),n=0;n<o.length;n++)g(u,o[n]);e._i.push([i,s,a])},e.__SV=1)}(document,window.posthog||[]);
74
75    // Don't send analytics from local dev hosts — keeps localhost test
76    // events (and their localhost $current_url / fake UTMs) out of the
77    // production PostHog project. The stub still exists, so capture/register
78    // calls below are harmless no-ops and the CTA-routing logic still runs.
79    var phHost = location.hostname;
80    var phIsDevHost =
81      phHost === "localhost" ||
82      phHost === "127.0.0.1" ||
83      phHost === "0.0.0.0" ||
84      phHost === "::1" ||
85      phHost === "[::1]" ||
86      phHost.slice(-6) === ".local";
87    if (!phIsDevHost) {
88      // Scope replay to the developer funnel — watch where users stall on
89      // /product/developer + the quickstart, without recording the whole site.
90      var phPath = location.pathname;
91      var phFunnelPage =
92        phPath.indexOf('/product/developer') === 0 ||
93        phPath.indexOf('/product/makers') === 0 ||
94        phPath.indexOf('/docs/quickstart') === 0;
95
96      posthog.init(posthogKey, {
97        api_host: posthogHost,
98        person_profiles: 'identified_only',
99        // Session replay stays OFF by default; `loaded` below turns it on for
100        // the funnel pages only. Inputs are masked, and anything tagged
101        // .ph-no-capture (e.g. the minted token) is masked in the replay too.
102        // (Also needs Session Replay enabled in the PostHog project settings.)
103        disable_session_recording: true,
104        session_recording: { maskAllInputs: true, maskTextSelector: '.ph-no-capture' },
105        // MUST start replay from `loaded`, NOT synchronously after init().
106        //
107        // This call used to sit right below init() behind a
108        // `posthog.startSessionRecording && …` guard, and it never once ran.
109        // At that moment window.posthog is still the SNIPPET STUB, which only
110        // proxies a fixed method list — capture, identify, register,
111        // onFeatureFlags and friends. `startSessionRecording` is NOT on that
112        // list, so the guard evaluated falsy and skipped silently, forever.
113        // Verified in-browser 2026-08-06 against production: at snippet time
114        // `!!posthog.startSessionRecording` is false; after the SDK loads it is
115        // a function, and `sessionRecording.status` reads "disabled" because
116        // nothing ever started it. $recording_status was "disabled" on all
117        // 1,782 developer-page events in the preceding two days.
118        //
119        // `loaded` fires with the REAL SDK, so the method exists. Same class of
120        // bug as the arm-resolution race this PR fixes: code assuming PostHog
121        // is ready when only its stub is.
122        loaded: function (ph) {
123          if (!phFunnelPage) return;
124          try { ph.startSessionRecording(); } catch (_) {}
125        },
126      });
127      // Deploy provenance on every client event (see frontmatter comment).
128      // `register` IS on the stub's proxy list, so this one is safe here.
129      if (releaseSha) {
130        posthog.register({ release_sha: releaseSha });
131      }
132    }
133
134    // CTA click delegation: any element (or ancestor up to 6 levels)
135    // with data-ph-cta becomes a tracked CTA. We also pick up the
136    // resolved destination so "Get started" → /ritual-mcp/docs#install
137    // tells us where they went without needing a separate prop.
138    (function () {
139      function readCta(el) {
140        for (var i = 0; i < 6 && el && el !== document; i++) {
141          if (el.dataset && el.dataset.phCta) {
142            return {
143              cta: el.dataset.phCta,
144              location: el.dataset.phCtaLocation || null,
145              href: el.getAttribute && (el.getAttribute("href") || el.getAttribute("formaction")) || null,
146              text: (el.innerText || el.textContent || "").trim().slice(0, 80) || null,
147            };
148          }
149          el = el.parentElement;
150        }
151        return null;
152      }
153      document.addEventListener("click", function (ev) {
154        var info = readCta(ev.target);
155        if (!info) return;
156        try {
157          window.posthog && window.posthog.capture && window.posthog.capture("cta_clicked", info);
158        } catch (_) {}
159      }, { capture: true });
160      // Form submit tracking: tag the <form> with data-ph-cta to
161      // capture the actual submission (more meaningful than a click
162      // for the waitlist form).
163      document.addEventListener("submit", function (ev) {
164        var info = readCta(ev.target);
165        if (!info) return;
166        try {
167          window.posthog && window.posthog.capture && window.posthog.capture("cta_submitted", info);
168        } catch (_) {}
169      }, { capture: true });
170    })();
171    // Developer-entrant detection + CTA routing lives in the bundled
172    // module src/scripts/dev-entry.js (mounted via DevEntryRouting.astro),
173    // which can import the shared Keycloak/connect-flow constants. Kept
174    // out of this inline snippet so we don't duplicate auth config here.
175  })();</script>
175<script type="module" src="/_astro/DevEntryRouting.astro_astro_type_script_index_0_lang.BMf2VZsx.js"></script>
175<link rel="stylesheet" href="/_astro/PostHogScript.CAMvvd4h.css"><style>.reveal[data-astro-cid-foqmza75],.reveal-step[data-astro-cid-foqmza75]{opacity:0;transform:translateY(16px);transition:opacity .7s cubic-bezier(.22,1,.36,1),transform .7s cubic-bezier(.22,1,.36,1)}.reveal[data-astro-cid-foqmza75].is-visible,.reveal-step[data-astro-cid-foqmza75].is-visible{opacity:1;transform:translateY(0)}.reveal-step[data-astro-cid-foqmza75].is-visible{transition-delay:var(--step-delay, 0ms)}.chain-slice[data-astro-cid-foqmza75]{opacity:0;transform:translateY(10px) scale(.94);transition:opacity .7s cubic-bezier(.22,1,.36,1),transform .7s cubic-bezier(.22,1,.36,1);transform-origin:center center;pointer-events:none}.chain-row[data-astro-cid-foqmza75].is-visible .chain-slice[data-astro-cid-foqmza75]{opacity:1;transform:translateY(0) scale(1)}.chain-row[data-astro-cid-foqmza75].is-visible .chain-slice-1[data-astro-cid-foqmza75]{transition-delay:.1s}.chain-row[data-astro-cid-foqmza75].is-visible .chain-slice-2[data-astro-cid-foqmza75]{transition-delay:.24s}.chain-row[data-astro-cid-foqmza75].is-visible .chain-slice-3[data-astro-cid-foqmza75]{transition-delay:.38s}.chain-row[data-astro-cid-foqmza75].is-visible .chain-slice-4[data-astro-cid-foqmza75]{transition-delay:.52s}.chain-row[data-astro-cid-foqmza75].is-visible .chain-slice-5[data-astro-cid-foqmza75]{transition-delay:.66s}.problem-card[data-astro-cid-foqmza75]{border:2px solid transparent}.problem-card[data-astro-cid-foqmza75] .card-icon-wrap[data-astro-cid-foqmza75]{background-color:var(--color-accent-100);transition:background-color .3s ease,transform .3s ease}.problem-card[data-astro-cid-foqmza75] .card-icon-wrap[data-astro-cid-foqmza75] img[data-astro-cid-foqmza75]{transition:transform .3s ease,opacity .3s ease}.problem-card[data-astro-cid-foqmza75].is-focused{border-color:var(--color-accent-500)}.problem-card[data-astro-cid-foqmza75].is-focused .card-icon-wrap[data-astro-cid-foqmza75]{animation:icon-pulse 2.2s cubic-bezier(.4,0,.6,1) .22s infinite}.problem-card[data-astro-cid-foqmza75].is-focused .card-icon-wrap[data-astro-cid-foqmza75] img[data-astro-cid-foqmza75]{animation:icon-fade 2.2s ease-in-out .22s infinite}@keyframes icon-pulse{0%,to{transform:scale(1);background-color:var(--color-accent-100)}50%{transform:scale(1.06);background-color:var(--color-accent-50)}}@keyframes icon-fade{0%,to{opacity:1;transform:scale(1)}50%{opacity:.7;transform:scale(.96)}}@media(prefers-reduced-motion:reduce){.reveal[data-astro-cid-foqmza75],.reveal-step[data-astro-cid-foqmza75],.chain-slice[data-astro-cid-foqmza75],.problem-card[data-astro-cid-foqmza75],.problem-card[data-astro-cid-foqmza75].is-focused,.problem-card[data-astro-cid-foqmza75] .card-icon-wrap[data-astro-cid-foqmza75],.problem-card[data-astro-cid-foqmza75] .card-icon-wrap[data-astro-cid-foqmza75] img[data-astro-cid-foqmza75]{animation:none!important;transition:none!important;opacity:1!important;transform:none!important;stroke-dashoffset:0!important}}
176.cta-label-maker,html[data-persona=maker] .cta-label-default{display:none}html[data-persona=maker] .cta-label-maker{display:inline}
177</style>
177<script type="module" src="/_astro/page.Bm8nvw0p.js"></script>
177</head> <body class="min-h-screen flex flex-col"> <header class="sticky top-0 z-50 bg-canvas/85 backdrop-blur border-b border-ink-100"> <div class="mx-auto max-w-7xl px-6 h-20 flex items-center justify-between"> <a href="/" class="flex items-center gap-2" aria-label="Ritual home"> <img src="/ritual-logo.svg" alt="Ritual" class="h-9 w-auto"> </a> <!-- Desktop nav --> <nav class="hidden md:flex items-center gap-2 text-base text-ink-700"> <a href="/" class="px-4 py-2.5 rounded-md hover:text-ink-900 transition-colors"> Home </a><a href="/problem" class="px-4 py-2.5 rounded-md hover:text-ink-900 transition-colors"> Problem </a><div class="relative group"> <button type="button" class="inline-flex items-center gap-1 px-4 py-2.5 rounded-md hover:text-ink-900 transition-colors" aria-haspopup="true" aria-expanded="false"> Product <svg viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" class="h-4 w-4 transition-transform group-hover:rotate-180"> <path fill-rule="evenodd" d="M5.23 7.21a.75.75 0 011.06.02L10 11.06l3.71-3.83a.75.75 0 111.08 1.04l-4.25 4.39a.75.75 0 01-1.08 0L5.21 8.27a.75.75 0 01.02-1.06z" clip-rule="evenodd"></path> </svg> </button> <div class="invisible opacity-0 translate-y-1 group-hover:visible group-hover:opacity-100 group-hover:translate-y-0 group-focus-within:visible group-focus-within:opacity-100 group-focus-within:translate-y-0 transition-all absolute left-0 top-full pt-2 w-72"> <div class="rounded-xl bg-white shadow-lg ring-1 ring-ink-100 p-2"> <a href="/product/builder" class="block px-3 py-2.5 rounded-lg hover:bg-ink-50 transition-colors"> <div class="text-sm font-semibold text-ink-900">Product</div> <div class="text-xs text-ink-500 mt-0.5">Clear and compelling PRDs</div> </a><a href="/product/developer" class="block px-3 py-2.5 rounded-lg hover:bg-ink-50 transition-colors"> <div class="text-sm font-semibold text-ink-900">Developer</div> <div class="text-xs text-ink-500 mt-0.5">Agentic coding without the drift</div> </a><a href="/product/makers" class="block px-3 py-2.5 rounded-lg hover:bg-ink-50 transition-colors"> <div class="text-sm font-semibold text-ink-900">Prototyping</div> <div class="text-xs text-ink-500 mt-0.5">Turn ideas into better builds</div> </a> </div> </div> </div><div class="relative group"> <button type="button" class="inline-flex items-center gap-1 px-4 py-2.5 rounded-md hover:text-ink-900 transition-colors" aria-haspopup="true" aria-expanded="false"> Use Cases <svg viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" class="h-4 w-4 transition-transform group-hover:rotate-180"> <path fill-rule="evenodd" d="M5.23 7.21a.75.75 0 011.06.02L10 11.06l3.71-3.83a.75.75 0 111.08 1.04l-4.25 4.39a.75.75 0 01-1.08 0L5.21 8.27a.75.75 0 01.02-1.06z" clip-rule="evenodd"></path> </svg> </button> <div class="invisible opacity-0 translate-y-1 group-hover:visible group-hover:opacity-100 group-hover:translate-y-0 group-focus-within:visible group-focus-within:opacity-100 group-focus-within:translate-y-0 transition-all absolute left-0 top-full pt-2 w-72"> <div class="rounded-xl bg-white shadow-lg ring-1 ring-ink-100 p-2"> <a href="/use-cases/agentic-coding" class="block px-3 py-2.5 rounded-lg hover:bg-ink-50 transition-colors"> <div class="text-sm font-semibold text-ink-900">Agentic Coding</div> <div class="text-xs text-ink-500 mt-0.5">Context &amp; constraints for coding agents</div> </a><a href="/use-cases/requirements" class="block px-3 py-2.5 rounded-lg hover:bg-ink-50 transition-colors"> <div class="text-sm font-semibold text-ink-900">Product Requirements</div> <div class="text-xs text-ink-500 mt-0.5">Build-ready specs without the rework</div> </a><a href="/use-cases/prototyping" class="block px-3 py-2.5 rounded-lg hover:bg-ink-50 transition-colors"> <div class="text-sm font-semibold text-ink-900">Prototyping</div> <div class="text-xs text-ink-500 mt-0.5">Turn ideas into better builds</div> </a><a href="/use-cases/strategy" class="block px-3 py-2.5 rounded-lg hover:bg-ink-50 transition-colors"> <div class="text-sm font-semibold text-ink-900">Strategy &amp; Transformation</div> <div class="text-xs text-ink-500 mt-0.5">Turn initiatives into actionable explorations</div> </a> </div> </div> </div><a href="/about" class="px-4 py-2.5 rounded-md hover:text-ink-900 transition-colors"> About </a><a href="/technology" class="px-4 py-2.5 rounded-md hover:text-ink-900 transition-colors"> Technology </a> </nav> <div class="flex items-center gap-2"> <a href="https://app.ritual.work" target="_blank" rel="noopener noreferrer" data-ph-cta="get_started" data-ph-cta-location="header" class="hidden sm:inline-flex items-center rounded-full bg-ink-900 text-white text-base px-5 py-2.5 hover:bg-ink-700 transition-colors"> <span class="cta-label-default">Get started for free</span><span class="cta-label-maker">
177Build Now</span> </a> <!-- Mobile menu toggle --> <button type="button" class="md:hidden inline-flex items-center justify-center h-11 w-11 rounded-md text-ink-700 hover:bg-ink-50 transition-colors" aria-label="Toggle menu" aria-expanded="false" aria-controls="mobile-menu" data-mobile-toggle> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="h-5 w-5 [data-open=true]_&]:hidden" aria-hidden="true"> <line x1="3" y1="6" x2="21" y2="6"></line> <line x1="3" y1="12" x2="21" y2="12"></line> <line x1="3" y1="18" x2="21" y2="18"></line> </svg> </button> </div> </div> <!-- Mobile menu panel --> <div id="mobile-menu" class="md:hidden hidden border-t border-ink-100 bg-canvas" data-mobile-panel> <nav class="mx-auto max-w-7xl px-6 py-4 flex flex-col gap-1.5 text-sm"> <a href="/" class="flex items-center min-h-[44px] px-3 py-2.5 rounded-lg text-ink-900 hover:bg-ink-50 transition-colors"> Home </a><a href="/problem" class="flex items-center min-h-[44px] px-3 py-2.5 rounded-lg text-ink-900 hover:bg-ink-50 transition-colors"> Problem </a><div class="py-1"> <div class="px-3 py-2 text-xs font-semibold uppercase tracking-wider text-ink-400"> Product </div> <a href="/product/builder" class="flex flex-col justify-center min-h-[44px] px-3 py-2.5 rounded-lg hover:bg-ink-50 transition-colors"> <div class="text-sm font-semibold text-ink-900">Product</div> <div class="text-xs text-ink-500 mt-0.5">Clear and compelling PRDs</div> </a><a href="/product/developer" class="flex flex-col justify-center min-h-[44px] px-3 py-2.5 rounded-lg hover:bg-ink-50 transition-colors"> <div class="text-sm font-semibold text-ink-900">Developer</div> <div class="text-xs text-ink-500 mt-0.5">Agentic coding without the drift</div> </a><a href="/product/makers" class="flex flex-col justify-center min-h-[44px] px-3 py-2.5 rounded-lg hover:bg-ink-50 transition-colors"> <div class="text-sm font-semibold text-ink-900">Prototyping</div> <div class="text-xs text-ink-500 mt-0.5">Turn ideas into better builds</div> </a> </div><div class="py-1"> <div class="px-3 py-2 text-xs font-semibold uppercase tracking-wider text-ink-400"> Use Cases </div> <a href="/use-cases/agentic-coding" class="flex flex-col justify-center min-h-[44px] px-3 py-2.5 rounded-lg hover:bg-ink-50 transition-colors"> <div class="text-sm font-semibold text-ink-900">Agentic Coding</div> <div class="text-xs text-ink-500 mt-0.5">Context &amp; constraints for coding agents</div> </a><a href="/use-cases/requirements" class="flex flex-col justify-center min-h-[44px] px-3 py-2.5 rounded-lg hover:bg-ink-50 transition-colors"> <div class="text-sm font-semibold text-ink-900">Product Requirements</div> <div class="text-xs text-ink-500 mt-0.5">Build-ready specs without the rework</div> </a><a href="/use-cases/prototyping" class="flex flex-col justify-center min-h-[44px] px-3 py-2.5 rounded-lg hover:bg-ink-50 transition-colors"> <div class="text-sm font-semibold text-ink-900">Prototyping</div> <div class="text-xs text-ink-500 mt-0.5">Turn ideas into better builds</div> </a><a href="/use-cases/strategy" class="flex flex-col justify-center min-h-[44px] px-3 py-2.5 rounded-lg hover:bg-ink-50 transition-colors"> <div class="text-sm font-semibold text-ink-900">Strategy &amp; Transformation</div> <div class="text-xs text-ink-500 mt-0.5">Turn initiatives into actionable explorations</div> </a> </div><a href="/about" class="flex items-center min-h-[44px] px-3 py-2.5 rounded-lg text-ink-900 hover:bg-ink-50 transition-colors"> About </a><a href="/technology" class="flex items-center min-h-[44px] px-3 py-2.5 rounded-lg text-ink-900 hover:bg-ink-50 transition-colors"> Technology </a> <a href="https://app.ritual.work" target="_blank" rel="noopener noreferrer" data-ph-cta="get_started" data-ph-cta-location="header_mobile" class="mt-2 inline-flex items-center justify-center min-h-[44px] rounded-full bg-ink-900 text-white text-sm px-4 py-2.5 hover:bg-ink-700 transition-colors"> <span class="cta-label-default">Get started for free</span><span class="cta-label-maker">
177Build Now</span> </a> </nav> </div> </header>   
177<script>
178  (function () {
179    var p = document.documentElement.getAttribute("data-persona");
180    if (!p) return;
181    if (p === "developer" && location.pathname.indexOf("/product/developer") === 0) return;
182    document
183      .querySelectorAll('a[data-ph-cta-location="header"], a[data-ph-cta-location="header_mobile"]')
184      .forEach(function (a) {
185        if (p === "maker") {
186          a.setAttribute("href", "/product/makers#nc-idea");
187          a.setAttribute("data-ph-cta", "nav_build_now");
188        } else {
189          a.setAttribute("href", "/product/developer");
190          a.setAttribute("data-ph-cta", "nav_dev_hero");
191        }
192        a.removeAttribute("target");
193        a.removeAttribute("rel");
194      });
195  })();
196</script>
196 
196<script>
197  (function () {
198    function init() {
199      var btn = document.querySelector("[data-mobile-toggle]");
200      var panel = document.querySelector("[data-mobile-panel]");
201      if (!btn || !panel) return;
202      btn.addEventListener("click", function () {
203        var open = panel.classList.toggle("hidden") === false;
204        btn.setAttribute("aria-expanded", open ? "true" : "false");
205      });
206    }
207    if (document.readyState === "loading") {
208      document.addEventListener("DOMContentLoaded", init);
209    } else {
210      init();
211    }
212  })();
213</script>
213 <main class="flex-1">   <section class="relative overflow-hidden bg-gradient-to-b from-accent-50/40 via-canvas to-canvas" data-astro-cid-foqmza75> <div class="mx-auto max-w-6xl px-6 pt-12 md:pt-20 pb-10 md:pb-12" data-astro-cid-foqmza75> <div class="text-center reveal" data-reveal data-astro-cid-foqmza75> <p class="text-lg md:text-2xl font-semibold tracking-[0.2em] uppercase text-accent-600" data-astro-cid-foqmza75> The Problem </p> <h1 class="mt-4 text-4xl md:text-5xl lg:text-6xl font-bold leading-[1.05] tracking-tight text-ink-900 text-balance" data-astro-cid-foqmza75> AI Tools Lose Context at Every Step </h1> <p class="mt-6 text-base md:text-lg text-ink-500 max-w-2xl mx-auto" data-astro-cid-foqmza75> As AI agents work through multi-step tasks, critical information gets lost, forgotten, or pushed out of memory — breaking the chain of understanding. </p> </div> <!-- Chain illustration (no background) --> <div class="reveal mt-6 md:mt-8 max-w-5xl mx-auto" data-reveal data-astro-cid-foqmza75> <!-- Chain image sliced into 5 --> <div class="chain-row relative flex justify-center items-center" data-astro-cid-foqmza75> <div class="chain-stage relative w-full max-w-3xl mx-auto" style="aspect-ratio: 1135 / 346;" data-astro-cid-foqmza75> <img src="/chain-link.png" alt="" class="chain-slice chain-slice-1 absolute inset-0 w-full h-full object-contain select-none" style="clip-path: inset(0 80% 0 0);" aria-hidden="true" data-astro-cid-foqmza75> <img src="/chain-link.png" alt="" class="chain-slice chain-slice-2 absolute inset-0 w-full h-full object-contain select-none" style="clip-path: inset(0 60% 0 20%);" aria-hidden="true" data-astro-cid-foqmza75> <img src="/chain-link.png" alt="" class="chain-slice chain-slice-3 absolute inset-0 w-full h-full object-contain select-none" style="clip-path: inset(0 40% 0 40%);" aria-hidden="true" data-astro-cid-foqmza75> <img src="/chain-link.png" alt="" class="chain-slice chain-slice-4 absolute inset-0 w-full h-full object-contain select-none" style="clip-path: inset(0 20% 0 60%);" aria-hidden="true" data-astro-cid-foqmza75> <img src="/chain-link.png" alt="Five chain links progressively breaking apart" class="chain-slice chain-slice-5 absolute inset-0 w-full h-full object-contain select-none" style="clip-path: inset(0 0 0 80%);" data-astro-cid-foqmza75> </div> </div> </div> <!-- Problem cards (one in focus at a time, rotates automatically).
214           No data-reveal here — we want the sand-panel band to peek up
215           from below the fold on first load so the user has a visual
216           cue that there's more to scroll to. Without this, the chain
217           sat above an invisible block and the page felt like it ended
218           at the hero. --> <div class="mt-12 md:mt-16 max-w-6xl mx-auto" data-problem-cards data-astro-cid-foqmza75> <div class="rounded-3xl bg-gradient-to-br from-sand-100 to-accent-50 ring-1 ring-accent-100 p-5 sm:p-8 md:p-10" data-astro-cid-foqmza75> <div class="grid md:grid-cols-3 gap-4 md:gap-6" data-astro-cid-foqmza75> <div class="problem-card bg-white rounded-2xl p-6 md:p-7 flex items-start gap-5 shadow-sm transition-all duration-500 is-focused" data-astro-cid-foqmza75> <span class="card-icon-wrap w-16 h-16 rounded-xl flex items-center justify-center flex-shrink-0" data-astro-cid-foqmza75> <img src="/db-small.png" alt="" width="44" height="44" class="w-11 h-11" aria-hidden="true" data-astro-cid-foqmza75> </span> <div class="min-w-0 pt-0.5" data-astro-cid-foqmza75> <h3 class="text-lg md:text-xl font-bold text-ink-900 mb-1.5 leading-tight" data-astro-cid-foqmza75>No Persistence</h3> <p class="text-ink-500 text-sm md:text-[15px] leading-snug" data-astro-cid-foqmza75>Data vanishes between sessions</p> </div> </div><div class="problem-card bg-white rounded-2xl p-6 md:p-7 flex items-start gap-5 shadow-sm transition-all duration-500" data-astro-cid-foqmza75> <span class="card-icon-wrap w-16 h-16 rounded-xl flex items-center justify-center flex-shrink-0" data-astro-cid-foqmza75> <img src="/memory-small.png" alt="" width="44" height="44" class="w-11 h-11" aria-hidden="true" data-astro-cid-foqmza75> </span> <div class="min-w-0 pt-0.5" data-astro-cid-foqmza75> <h3 class="text-lg md:text-xl font-bold text-ink-900 mb-1.5 leading-tight" data-astro-cid-foqmza75>Memory Reset</h3> <p class="text-ink-500 text-sm md:text-[15px] leading-snug" data-astro-cid-foqmza75>Each conversation starts fresh</p> </div> </div><div class="problem-card bg-white rounded-2xl p-6 md:p-7 flex items-start gap-5 shadow-sm transition-all duration-500" data-astro-cid-foqmza75> <span class="card-icon-wrap w-16 h-16 rounded-xl flex items-center justify-center flex-shrink-0" data-astro-cid-foqmza75> <img src="/context-small.png" alt="" width="44" height="44" class="w-11 h-11" aria-hidden="true" data-astro-cid-foqmza75> </span> <div class="min-w-0 pt-0.5" data-astro-cid-foqmza75> <h3 class="text-lg md:text-xl font-bold text-ink-900 mb-1.5 leading-tight" data-astro-cid-foqmza75>Context Overflow</h3> <p class="text-ink-500 text-sm md:text-[15px] leading-snug" data-astro-cid-foqmza75>Old info pushed out of window</p> </div> </div> </div> </div> </div> <!-- Sound familiar? (below carousel) --> <div class="reveal mt-14 md:mt-20 max-w-6xl mx-auto text-center" data-reveal data-astro-cid-foqmza75> <p class="text-base md:text-xl font-semibold tracking-[0.2em] uppercase text-ink-400 mb-6 md:mb-7" data-astro-cid-foqmza75>
219Sound familiar? This happens with...
220</p> <div class="flex flex-wrap md:flex-nowrap justify-center items-center gap-2 md:gap-4" data-astro-cid-foqmza75> <span class="reveal-step inline-flex items-center justify-center rounded-full bg-white border border-accent-500 md:border-2 px-3 md:px-6 py-1.5 md:py-3.5 text-xs md:text-base font-medium text-ink-700 shadow-[0_2px_8px_-2px_rgba(238,113,0,0.18)] md:shadow-[0_4px_14px_-2px_rgba(238,113,0,0.18)] whitespace-nowrap" style="--step-delay: 0ms" data-reveal-step data-astro-cid-foqmza75> Vibe coding (Claude, Cursor) </span><span class="reveal-step inline-flex items-center justify-center rounded-full bg-white border border-accent-500 md:border-2 px-3 md:px-6 py-1.5 md:py-3.5 text-xs md:text-base font-medium text-ink-700 shadow-[0_2px_8px_-2px_rgba(238,113,0,0.18)] md:shadow-[0_4px_14px_-2px_rgba(238,113,0,0.18)] whitespace-nowrap" style="--step-delay: 80ms" data-reveal-step data-astro-cid-foqmza75> Cursor rules </span><span class="reveal-step inline-flex items-center justify-center rounded-full bg-white border border-accent-500 md:border-2 px-3 md:px-6 py-1.5 md:py-3.5 text-xs md:text-base font-medium text-ink-700 shadow-[0_2px_8px_-2px_rgba(238,113,0,0.18)] md:shadow-[0_4px_14px_-2px_rgba(238,113,0,0.18)] whitespace-nowrap" style="--step-delay: 160ms" data-reveal-step data-astro-cid-foqmza75> Custom GPTs </span><span class="reveal-step inline-flex items-center justify-center rounded-full bg-white border border-accent-500 md:border-2 px-3 md:px-6 py-1.5 md:py-3.5 text-xs md:text-base font-medium text-ink-700 shadow-[0_2px_8px_-2px_rgba(238,113,0,0.18)] md:shadow-[0_4px_14px_-2px_rgba(238,113,0,0.18)] whitespace-nowrap" style="--step-delay: 240ms" data-reveal-step data-astro-cid-foqmza75>
220 Your normal prompting approach </span> </div> </div> </div> </section>  <section class="bg-canvas" data-astro-cid-foqmza75> <div class="mx-auto max-w-5xl px-6 py-10 md:py-12" data-astro-cid-foqmza75> <div class="text-center reveal" data-reveal data-astro-cid-foqmza75> <p class="text-lg md:text-2xl font-semibold tracking-[0.2em] uppercase text-accent-600" data-astro-cid-foqmza75>The Symptoms</p> <h2 class="mt-4 text-3xl md:text-4xl lg:text-5xl font-bold text-ink-900 text-balance" data-astro-cid-foqmza75>
221What Context Loss Looks Like in Your Output
222</h2> <p class="mt-6 text-base md:text-lg text-ink-500 max-w-2xl mx-auto" data-astro-cid-foqmza75>
223These red flags show up in AI-generated code and responses when context has drifted or been lost entirely.
224</p> </div> <div class="mt-12 md:mt-14 grid sm:grid-cols-2 gap-5 md:gap-6 max-w-5xl mx-auto" data-astro-cid-foqmza75> <div class="reveal-step flex items-start gap-4 bg-white border border-accent-300 rounded-2xl p-6 md:p-7 transition-colors duration-300 hover:border-accent-500" style="--step-delay: 0ms" data-reveal-step data-astro-cid-foqmza75> <span class="w-10 h-10 rounded-lg bg-red-100 flex items-center justify-center flex-shrink-0" data-astro-cid-foqmza75> <svg width="18" height="18" viewBox="0 0 16 16" fill="none" aria-hidden="true" data-astro-cid-foqmza75> <path d="M4 4L12 12M12 4L4 12" stroke="#ef4444" stroke-width="2.5" stroke-linecap="round" data-astro-cid-foqmza75></path> </svg> </span> <div class="min-w-0" data-astro-cid-foqmza75> <h3 class="font-bold text-ink-900 text-lg mb-1.5" data-astro-cid-foqmza75>Hallucinations</h3> <p class="text-ink-500 text-sm md:text-[15px] leading-snug" data-astro-cid-foqmza75>Confident but fabricated information</p> </div> </div><div class="reveal-step flex items-start gap-4 bg-white border border-accent-300 rounded-2xl p-6 md:p-7 transition-colors duration-300 hover:border-accent-500" style="--step-delay: 80ms" data-reveal-step data-astro-cid-foqmza75> <span class="w-10 h-10 rounded-lg bg-red-100 flex items-center justify-center flex-shrink-0" data-astro-cid-foqmza75> <svg width="18" height="18" viewBox="0 0 16 16" fill="none" aria-hidden="true" data-astro-cid-foqmza75> <path d="M4 4L12 12M12 4L4 12" stroke="#ef4444" stroke-width="2.5" stroke-linecap="round" data-astro-cid-foqmza75></path> </svg> </span> <div class="min-w-0" data-astro-cid-foqmza75> <h3 class="font-bold text-ink-900 text-lg mb-1.5" data-astro-cid-foqmza75>Context Drift</h3> <p class="text-ink-500 text-sm md:text-[15px] leading-snug" data-astro-cid-foqmza75>Gradually loses track of requirements</p> </div> </div><div class="reveal-step flex items-start gap-4 bg-white border border-accent-300 rounded-2xl p-6 md:p-7 transition-colors duration-300 hover:border-accent-500" style="--step-delay: 160ms" data-reveal-step data-astro-cid-foqmza75> <span class="w-10 h-10 rounded-lg bg-red-100 flex items-center justify-center flex-shrink-0" data-astro-cid-foqmza75> <svg width="18" height="18" viewBox="0 0 16 16" fill="none" aria-hidden="true" data-astro-cid-foqmza75> <path d="M4 4L12 12M12 4L4 12" stroke="#ef4444" stroke-width="2.5" stroke-linecap="round" data-astro-cid-foqmza75></path> </svg> </span> <div class="min-w-0" data-astro-cid-foqmza75> <h3 class="font-bold text-ink-900 text-lg mb-1.5" data-astro-cid-foqmza75>Unresolved Trade-offs</h3> <p class="text-ink-500 text-sm md:text-[15px] leading-snug" data-astro-cid-foqmza75>Ignores competing constraints</p> </div> </div><div class="reveal-step flex items-start gap-4 bg-white border border-accent-300 rounded-2xl p-6 md:p-7 transition-colors duration-300 hover:border-accent-500" style="--step-delay: 240ms" data-reveal-step data-astro-cid-foqmza75> <span class="w-10 h-10 rounded-lg bg-red-100 flex items-center justify-center flex-shrink-0" data-astro-cid-foqmza75> <svg width="18" height="18" viewBox="0 0 16 16" fill="none" aria-hidden="true" data-astro-cid-foqmza75> <path d="M4 4L12 12M12 4L4 12" stroke="#ef4444" stroke-width="2.5" stroke-linecap="round" data-astro-cid-foqmza75></path> </svg> </span> <div class="min-w-0" data-astro-cid-foqmza75> <h3 class="font-bold text-ink-900 text-lg mb-1.5" data-astro-cid-foqmza75>Guesswork</h3> <p class="text-ink-500 text-sm md:text-[15px] leading-snug" data-astro-cid-foqmza75>Fills gaps with assumptions</p> </div> </div><div class="reveal-step flex items-start gap-4 bg-white border border-accent-300 rounded-2xl p-6 md:p-7 transition-colors duration-300 hover:border-accent-500" style="--step-delay: 320ms" data-reveal-step data-astro-cid-foqmza75> <span class="w-10 h-10 rounded-lg bg-red-100 flex items-center justify-center flex-shrink-0" data-astro-cid-foqmza75> <svg width="18" height="18" viewBox="0 0 16 16" fill="none" aria-hidden="true" data-astro-cid-foqmza75> <path d="M4 4L12 12M12 4L4 12" stroke="#ef4444" stroke-width="2.5" stroke-linecap="round" data-astro-cid-foqmza75></path> </svg> </span> <div class="min-w-0" data-astro-cid-foqmza75> <h3 class="font-bold text-ink-900 text-lg mb-1.5" data-astro-cid-foqmza75>Flawed Assumptions</h3> <p class="text-ink-500 text-sm md:text-[15px] leading-snug" data-astro-cid-foqmza75>Builds on incorrect premises</p> </div> </div><div class="reveal-step flex items-start gap-4 bg-white border border-accent-300 rounded-2xl p-6 md:p-7 transition-colors duration-300 hover:border-accent-500" style="--step-delay: 400ms" data-reveal-step data-astro-cid-foqmza75> <span class="w-10 h-10 rounded-lg bg-red-100 flex items-center justify-center flex-shrink-0" data-astro-cid-foqmza75> <svg width="18" height="18" viewBox="0 0 16 16" fill="none" aria-hidden="true" data-astro-cid-foqmza75> <path d="M4 4L12 12M12 4L4 12" stroke="#ef4444" stroke-width="2.5" stroke-linecap="round" data-astro-cid-foqmza75></path> </svg> </span> <div class="min-w-0" data-astro-cid-foqmza75> <h3 class="font-bold text-ink-900 text-lg mb-1.5" data-astro-cid-foqmza75>Weak Reasoning</h3> <p class="text-ink-500 text-sm md:text-[15px] leading-snug" data-astro-cid-foqmza75>Shallow logic without full picture</p> </div> </div> </div> </div> </section>  <section class="bg-canvas" data-astro-cid-foqmza75> <div class="mx-auto max-w-7xl px-6 pt-8 md:pt-10 pb-10 md:pb-12" data-astro-cid-foqmza75> <div class="text-center reveal" data-reveal data-astro-cid-foqmza75> <p class="text-lg md:text-2xl font-semibold tracking-[0.2em] uppercase text-accent-600" data-astro-cid-foqmza75>The Impact</p> <h2 class="mt-4 text-3xl md:text-4xl lg:text-5xl font-bold text-ink-900 text-balance" data-astro-cid-foqmza75>
225Lost Context Means Lost Productivity
226</h2> <p class="mt-6 text-base md:text-lg text-ink-500 max-w-2xl mx-auto" data-astro-cid-foqmza75>
227When AI tools forget what they knew, developers pay the price in rework, frustration, and wasted t
227ime.
228</p> </div> <div class="mt-12 md:mt-14 max-w-4xl mx-auto space-y-4 md:space-y-5" data-astro-cid-foqmza75> <div class="reveal-step bg-canvas-soft rounded-2xl px-6 md:px-8 py-7 md:py-8 ring-1 ring-ink-100 transition-all duration-300 hover:-translate-y-0.5 hover:shadow-md" style="--step-delay: 0ms" data-reveal-step data-astro-cid-foqmza75> <div class="text-4xl md:text-5xl font-bold bg-gradient-to-r from-accent-500 to-accent-700 bg-clip-text text-transparent mb-3" data-astro-cid-foqmza75> 47% </div> <h3 class="text-2xl md:text-3xl font-bold text-ink-900 mb-2" data-astro-cid-foqmza75>Time Re-explaining</h3> <p class="text-ink-500 leading-relaxed text-sm md:text-base" data-astro-cid-foqmza75>Developers spend nearly half their AI interaction time re-explaining context that was already provided in earlier sessions.</p> </div><div class="reveal-step bg-canvas-soft rounded-2xl px-6 md:px-8 py-7 md:py-8 ring-1 ring-ink-100 transition-all duration-300 hover:-translate-y-0.5 hover:shadow-md" style="--step-delay: 120ms" data-reveal-step data-astro-cid-foqmza75> <div class="text-4xl md:text-5xl font-bold bg-gradient-to-r from-accent-500 to-accent-700 bg-clip-text text-transparent mb-3" data-astro-cid-foqmza75> 3.2x </div> <h3 class="text-2xl md:text-3xl font-bold text-ink-900 mb-2" data-astro-cid-foqmza75>More Iterations</h3> <p class="text-ink-500 leading-relaxed text-sm md:text-base" data-astro-cid-foqmza75>Tasks requiring cross-session knowledge take 3.2x more back-and-forth cycles to complete correctly.</p> </div><div class="reveal-step bg-canvas-soft rounded-2xl px-6 md:px-8 py-7 md:py-8 ring-1 ring-ink-100 transition-all duration-300 hover:-translate-y-0.5 hover:shadow-md" style="--step-delay: 240ms" data-reveal-step data-astro-cid-foqmza75> <div class="text-4xl md:text-5xl font-bold bg-gradient-to-r from-accent-500 to-accent-700 bg-clip-text text-transparent mb-3" data-astro-cid-foqmza75> 68% </div> <h3 class="text-2xl md:text-3xl font-bold text-ink-900 mb-2" data-astro-cid-foqmza75>PRs Need Rework</h3> <p class="text-ink-500 leading-relaxed text-sm md:text-base" data-astro-cid-foqmza75>The majority of AI-generated pull requests require significant revision because agents lack awareness of project conventions.</p> </div> </div> </div> </section> <section class="bg-night-900 text-white"> <div class="mx-auto max-w-7xl px-6 py-20 text-center"> <h2 class="text-3xl md:text-4xl font-bold tracking-tight"> 
229Ready to own the <span class="bg-gradient-to-r from-accent-500 to-sand-300 bg-clip-text text-transparent">frontier</span>?
230 </h2> <p class="mt-4 text-ink-300 max-w-xl mx-auto text-sm md:text-base">Join thousands of users already using our platform to drive growth and innovation.</p> <div class="mt-8 flex items-center justify-center gap-3"> <a href="https://app.ritual.work" target="_blank" rel="noopener noreferrer" data-ph-cta="get_started" data-ph-cta-location="cta_section_primary" class="inline-flex items-center rounded-full bg-white text-ink-900 text-sm font-medium px-5 py-2.5 hover:bg-ink-100 transition-colors"> Get Started </a> <a href="https://calendly.com/mike-hkg/30min" target="_blank" rel="noopener noreferrer" data-ph-cta="book_demo" data-ph-cta-location="cta_section_secondary" class="inline-flex items-center rounded-full border border-white/30 text-white text-sm font-medium px-5 py-2.5 hover:bg-white/10 transition-colors"> Schedule a Demo </a> </div> </div> </section>  </main> <footer class="bg-canvas border-t border-ink-100"> <div class="mx-auto max-w-7xl px-6 py-10 md:py-14"> <div class="grid grid-cols-2 md:grid-cols-4 gap-8 md:gap-10"> <div class="col-span-2 md:col-span-1"> <a href="/" class="flex items-center gap-2" aria-label="Ritual home"> <img src="/ritual-logo.svg" alt="Ritual" class="h-7 w-auto"> </a> <p class="mt-4 text-sm text-ink-500 max-w-xs">
231Move from idea to action with AI‑powered collaboration.
232</p> <div class="mt-5 flex items-center gap-3"> <a href="https://www.linkedin.com/company/ritualai" target="_blank" rel="noopener noreferrer" aria-label="Ritual on LinkedIn" class="inline-flex h-9 w-9 items-center justify-center rounded-full ring-1 ring-ink-100 text-ink-500 hover:text-ink-900 hover:ring-ink-300 transition-colors"> <svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" class="h-4 w-4"> <path d="M20.452 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.356V9h3.414v1.561h.046c.477-.9 1.637-1.852 3.37-1.852 3.602 0 4.266 2.37 4.266 5.455v6.288zM5.337 7.433a2.062 2.062 0 01-2.063-2.064 2.063 2.063 0 112.063 2.064zM7.119 20.452H3.553V9h3.566v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"></path> </svg> </a> </div> </div> <div> <h4 class="text-sm font-semibold text-ink-900">Product</h4> <ul class="mt-4 space-y-3"> <li> <a href="/product/builder" class="text-sm text-ink-500 hover:text-ink-900 transition-colors"> Product </a> </li><li> <a href="/product/developer" class="text-sm text-ink-500 hover:text-ink-900 transition-colors"> Developer </a> </li><li> <a href="/product/makers" class="text-sm text-ink-500 hover:text-ink-900 transition-colors"> Prototyping </a> </li> </ul> </div><div> <h4 class="text-sm font-semibold text-ink-900">Resources</h4> <ul class="mt-4 space-y-3"> <li> <a href="/docs/quickstart" class="text-sm text-ink-500 hover:text-ink-900 transition-colors"> Quick start </a> </li><li> <a href="/faq" class="text-sm text-ink-500 hover:text-ink-900 transition-colors"> FAQ </a> </li><li> <a href="/support" class="text-sm text-ink-500 hover:text-ink-900 transition-colors"> Support </a> </li><li> <a href="/security" class="text-sm text-ink-500 hover:text-ink-900 transition-colors"> Security </a> </li> </ul> </div><div> <h4 class="text-sm font-semibold text-ink-900">Company</h4> <ul class="mt-4 space-y-3"> <li> <a href="/about" class="text-sm text-ink-500 hover:text-ink-900 transition-colors"> About </a> </li> </ul> </div> </div> <div class="mt-14 pt-6 border-t border-ink-100 text-center text-xs text-ink-400">
233© 2025 Ritual. All rights reserved.
234</div> </div> </footer> </body></html>  
234<script>
235  (function () {
236    function initReveal() {
237      var targets = document.querySelectorAll(
238        "[data-reveal], [data-reveal-step], .chain-row"
239      );
240      if (!("IntersectionObserver" in window)) {
241        targets.forEach(function (el) { el.classList.add("is-visible"); });
242        return;
243      }
244      var io = new IntersectionObserver(function (entries) {
245        entries.forEach(function (entry) {
246          if (entry.isIntersecting) {
247            entry.target.classList.add("is-visible");
248            io.unobserve(entry.target);
249          }
250        });
251      }, { threshold: 0.15, rootMargin: "0px 0px -40px 0px" });
252      targets.forEach(function (el) { io.observe(el); });
253    }
254
255    function initProblemCards() {
256      var root = document.querySelector("[data-problem-cards]");
257      if (!root) return;
258      var cards = root.querySelectorAll(".problem-card");
259      if (cards.length === 0) return;
260
261      var current = 0;
262      var rotateMs = 3000;
263      var timer = null;
264      var paused = false;
265
266      function setFocus(i) {
267        current = i;
268        cards.forEach(function (card, idx) {
269          card.classList.toggle("is-focused", idx === i);
270        });
271      }
272      function startRotate() {
273        stopRotate();
274        if (paused) return;
275        timer = window.setInterval(function () {
276          setFocus((current + 1) % cards.length);
277        }, rotateMs);
278      }
279      function stopRotate() {
280        if (timer) { window.clearInterval(timer); timer = null; }
281      }
282
283      // Pause auto-rotate when the user hovers the card row — gives them
284      // a chance to read without the focus moving out from under them.
285      // Resume on leave. NOT paused on click (cards are non-interactive).
286      root.addEventListener("mouseenter", function () { paused = true; stopRotate(); });
287      root.addEventListener("mouseleave", function () { paused = false; startRotate(); });
288
289      // Only start rotating once the section scrolls into view — no
290      // sense burning a setInterval while the user is reading the hero.
291      if ("IntersectionObserver" in window) {
292        var startIO = new IntersectionObserver(function (entries) {
293          entries.forEach(function (entry) {
294            if (entry.isIntersecting) {
295              startRotate();
296              startIO.unobserve(entry.target);
297            }
298          });
299        }, { threshold: 0.3 });
300        startIO.observe(root);
301      } else {
302        startRotate();
303      }
304    }
305
306    function init() {
307      initReveal();
308      initProblemCards();
309    }
310    if (document.readyState === "loading") {
311      document.addEventListener("DOMContentLoaded", init);
312    } else {
313      init();
314    }
315  })();
316</script>

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.