Website for the Lede browser extension.
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Landing: plainer copy, optional install detail, bolder editorial styling

+215 -127
+7 -7
public/extension-demo/popup-demo.js
··· 12 12 13 13 const SAMPLE_SUMMARY = `## The lede 14 14 15 - This is the **same chrome** as the Lede extension: summarize the active tab, then chat with answers grounded in that text. 15 + This is what the **Lede** popup looks like: one tap for a short summary, then chat about the page. 16 16 17 - - **Quick Summary** is real in the build you install—here it’s sample copy. 18 - - **Chat** uses placeholder replies so you can try the layout without an API key. 19 - - Use **Regenerate** after a summary to replay the flow.`; 17 + - **Quick Summary** uses sample text here; after you install it reads the tab you’re on. 18 + - **Chat** shows placeholder answers on this site so you can try the layout at your own pace. 19 + - Tap **Regenerate** to replay the sample summary.`; 20 20 21 21 const ASSISTANT_REPLIES = [ 22 - "In the installed extension I read the tab’s extracted text and answer from that. Here you’re seeing canned replies so the marketing site stays fast and private.", 23 - "After you install, open **Settings** (this demo’s gear only shows a hint) to point at **Ollama** or your own API and model.", 24 - "Try **Regenerate** on the summary card to replay the streamed summary—useful when a page updates underneath you.", 22 + "Once Lede is installed, answers come from the article open in your browser. Here the replies are samples so this page stays quick and private.", 23 + "When you’re ready, open **Settings** in the real extension to choose a model on your computer or one you already use.", 24 + "**Regenerate** on the summary is handy if the page changed and you want a fresh take.", 25 25 ]; 26 26 27 27 let currentTheme = "system";
+1 -1
src/components/SiteFooter.astro
··· 10 10 <div class="wrap footer-inner"> 11 11 <span class="font-display" style="font-weight: 700; color: var(--color-ink)">Lede</span> 12 12 <div class="footer-links"> 13 - <a href={tangled} target="_blank" rel="noopener noreferrer">Repo on Tangled</a> 13 + <a href={tangled} target="_blank" rel="noopener noreferrer">Project page</a> 14 14 <a href="#install">Install</a> 15 15 <a href="#privacy">Privacy</a> 16 16 <a href="#product">Product</a>
+2 -2
src/components/SiteHeader.astro
··· 10 10 { href: "#product", label: "Product" }, 11 11 { href: "#usage", label: "Usage" }, 12 12 { href: "#faq", label: "FAQ" }, 13 - { href: tangled, label: "Repo", external: true }, 13 + { href: tangled, label: "Project", external: true }, 14 14 ] as const; 15 15 --- 16 16 ··· 48 48 <a class="btn btn--primary btn--sm nav-install" href="#install">Install beta</a> 49 49 </div> 50 50 </div> 51 - <p class="site-header__tagline" aria-hidden="true">Beta · source install · Chrome and Firefox</p> 51 + <p class="site-header__tagline" aria-hidden="true">Beta · Chrome and Firefox</p> 52 52 </div> 53 53 </header>
+3 -3
src/components/sections/EditorialValue.astro
··· 14 14 </article> 15 15 <article class="editorial-block"> 16 16 <h3 class="heading-md">Questions stay grounded</h3> 17 - <p>Follow-ups reference the page and the summary you already generated—no free-floating chat pretending it read for you.</p> 17 + <p>Follow-ups stick to the page and the summary you already made—no vague answers from something that never read the article.</p> 18 18 </article> 19 19 <article class="editorial-block"> 20 - <h3 class="heading-md">Your stack</h3> 21 - <p>Ollama native, OpenAI-compatible hosts, Groq, LM Studio—pick the model and base URL in settings instead of a locked vendor.</p> 20 + <h3 class="heading-md">Your choice of AI</h3> 21 + <p>Use a model on your machine or one you already pay for—set it once in settings instead of being locked to a single vendor.</p> 22 22 </article> 23 23 </div> 24 24 </section>
+25 -8
src/components/sections/FAQCompact.astro
··· 1 + --- 2 + interface Props { 3 + tangled: string; 4 + } 5 + 6 + const { tangled } = Astro.props; 7 + --- 8 + 1 9 <section id="faq" class="section wrap" aria-labelledby="faq-heading"> 2 10 <header class="section__head"> 3 11 <p class="eyebrow">FAQ</p> 4 - <h2 id="faq-heading" class="heading-xl">When something blocks install</h2> 12 + <h2 id="faq-heading" class="heading-xl">Quick answers</h2> 5 13 </header> 6 14 <div class="faq-stack"> 7 15 <details class="faq-disclosure"> 8 - <summary>Cannot connect to localhost:11434</summary> 16 + <summary>Why isn&apos;t Lede in the store yet?</summary> 17 + <div class="faq-disclosure__body"> 18 + <p> 19 + We&apos;re still in beta and iterating quickly. Installing from the project page keeps early testers close to 20 + the latest fixes while we work toward a store listing. 21 + </p> 22 + </div> 23 + </details> 24 + <details class="faq-disclosure"> 25 + <summary>Does Lede watch everything I read?</summary> 9 26 <div class="faq-disclosure__body"> 10 27 <p> 11 - Run <span class="kbd">ollama serve</span>, confirm models with <span class="kbd">ollama list</span>, and keep 12 - Native mode on <span class="kbd">http://localhost:11434</span> without <span class="kbd">/v1</span>. 28 + No. Lede only looks at the active tab when you open it and run a summary or a question. There isn&apos;t a 29 + background feed of your browsing. 13 30 </p> 14 31 </div> 15 32 </details> 16 33 <details class="faq-disclosure"> 17 - <summary>HTTP 403 or 405</summary> 34 + <summary>Setup or connection errors</summary> 18 35 <div class="faq-disclosure__body"> 19 36 <p> 20 - Wrong API mode for the URL: Native → no <span class="kbd">/v1</span>. OpenAI-compatible → include 21 - <span class="kbd">/v1</span> (for example <span class="kbd">http://localhost:11434/v1</span> for Ollama 22 - compatibility mode). 37 + If something won&apos;t connect or the README mentions a setting you don&apos;t recognize, the 38 + <a href={tangled} target="_blank" rel="noopener noreferrer">project page</a> has the latest step-by-step 39 + notes—we keep them with the extension itself. 23 40 </p> 24 41 </div> 25 42 </details>
+7 -7
src/components/sections/HeroWithProof.astro
··· 9 9 <section class="hero-mast" aria-labelledby="hero-heading"> 10 10 <div class="wrap hero-mast__grid reveal-group"> 11 11 <div class="hero-mast__copy"> 12 - <p class="eyebrow reveal-item" style="--i: 0">Page summarizer and chat · Chrome and Firefox</p> 12 + <p class="eyebrow reveal-item" style="--i: 0">Summarize any page · Chrome and Firefox</p> 13 13 <h1 id="hero-heading" class="display-hero reveal-item" style="--i: 1">Don&apos;t bury the lede</h1> 14 14 <p class="deck reveal-item" style="--i: 2"> 15 - Summarize and ask about <strong>this tab</strong> before you spend twenty minutes on noise. 15 + Get the gist of <strong>this tab</strong> in a few seconds—then ask follow-ups if you want more. 16 16 </p> 17 17 <p class="lede lede--tight reveal-item" style="--i: 3"> 18 - Answers trace the page you have open—not a blank assistant waiting for a prompt. 18 + Lede reads what you&apos;re looking at, not a blank chat box that guesses what you meant. 19 19 </p> 20 20 <div class="actions reveal-item" style="--i: 4"> 21 21 <a class="btn btn--primary" href="#install">Install (beta)</a> 22 22 <a class="btn btn--secondary" href={tangled} target="_blank" rel="noopener noreferrer"> 23 - Extension repo on Tangled 23 + Get Lede 24 24 </a> 25 25 </div> 26 - <p class="eyebrow reveal-item" style="--i: 5; margin-top: var(--space-md)">Keyboard</p> 26 + <p class="eyebrow reveal-item" style="--i: 5; margin-top: var(--space-md)">Shortcut</p> 27 27 <p 28 28 class="reveal-item" 29 29 style="--i: 6; margin: 0; font-size: var(--text-sm); color: var(--color-ink-secondary)" ··· 40 40 id="extension-demo" 41 41 class="extension-demo" 42 42 src="/extension-demo/index.html" 43 - title="Interactive Lede popup demo: summarize and chat (mocked responses)" 43 + title="Try the Lede popup: sample summary and replies" 44 44 width="400" 45 45 height="560" 46 46 loading="eager"></iframe> ··· 48 48 <figcaption class="hero-proof__caption"> 49 49 <span class="beta-tag">Beta</span> 50 50 <span class="hero-proof__capline"> 51 - Interactive demo uses the same popup layout as the extension—mocked summary and chat only. 51 + Play with the real layout here; after you install, summaries use your page and your settings. 52 52 </span> 53 53 <button type="button" class="demo-reset" id="extension-demo-reset">Reset demo</button> 54 54 </figcaption>
+38 -45
src/components/sections/InstallJourney.astro
··· 10 10 <div class="wrap"> 11 11 <header class="section__head section__head--install"> 12 12 <p class="eyebrow reveal-item" style="--i: 0">Install</p> 13 - <h2 id="install-heading" class="heading-xl reveal-item" style="--i: 1">From repo to toolbar</h2> 13 + <h2 id="install-heading" class="heading-xl reveal-item" style="--i: 1">Try the beta</h2> 14 14 </header> 15 15 16 16 <div class="journey-band journey-band--callout reveal-item" style="--i: 2"> 17 17 <p class="journey-band__text"> 18 - <strong>Clone webai-summarizer on Tangled</strong>—not this marketing repo. You need a folder that contains 19 - <code class="kbd">manifest.json</code>. <code class="kbd">lede-website</code> is only this page. 18 + Lede isn&apos;t in the Chrome or Firefox stores yet. Download the extension folder from the project page, then 19 + add it to your browser—full click-by-click steps are there too. 20 20 </p> 21 21 </div> 22 22 23 23 <div class="journey-strip reveal-item" style="--i: 3" aria-label="Three-step overview"> 24 24 <div class="journey-strip__cell"> 25 25 <span class="journey-strip__num" aria-hidden="true">1</span> 26 - <h3 class="journey-strip__title">Get the code</h3> 27 - <p class="journey-strip__body">Download or clone the extension repo so the project lives on disk.</p> 28 - <a href={tangled} target="_blank" rel="noopener noreferrer">Open Tangled repo</a> 26 + <h3 class="journey-strip__title">Grab the build</h3> 27 + <p class="journey-strip__body">Open the project page and download the extension files to your computer.</p> 28 + <a href={tangled} target="_blank" rel="noopener noreferrer">Open project page</a> 29 29 </div> 30 30 <div class="journey-strip__cell"> 31 31 <span class="journey-strip__num" aria-hidden="true">2</span> 32 - <h3 class="journey-strip__title">Choose a browser</h3> 33 - <p class="journey-strip__body">Chrome uses unpacked load; Firefox uses a temporary add-on.</p> 32 + <h3 class="journey-strip__title">Add it in the browser</h3> 33 + <p class="journey-strip__body">Chrome and Firefox each have a simple “load from folder” flow for betas.</p> 34 34 </div> 35 35 <div class="journey-strip__cell"> 36 36 <span class="journey-strip__num" aria-hidden="true">3</span> 37 - <h3 class="journey-strip__title">Load and configure</h3> 38 - <p class="journey-strip__body">Point settings at Ollama native or an OpenAI-compatible endpoint, then try a tab.</p> 37 + <h3 class="journey-strip__title">Pick how Lede thinks</h3> 38 + <p class="journey-strip__body">In settings, choose a local model or another provider you already use.</p> 39 39 </div> 40 40 </div> 41 41 42 - <div class="install-wrap reveal-item" style="--i: 4"> 43 - <div class="install-panel"> 44 - <div> 45 - <h3 class="heading-lg">Chrome</h3> 46 - <ol> 47 - <li>Open <span class="kbd">chrome://extensions/</span></li> 48 - <li>Enable <strong>Developer mode</strong></li> 49 - <li>Click <strong>Load unpacked</strong></li> 50 - <li>Select the <strong>webai-summarizer</strong> folder that contains <code class="kbd">manifest.json</code></li> 51 - <li>Optional: shortcuts at <span class="kbd">chrome://extensions/shortcuts</span></li> 52 - </ol> 42 + <details class="disclosure reveal-item" style="--i: 4"> 43 + <summary>Step-by-step for Chrome or Firefox</summary> 44 + <div class="disclosure__body install-wrap"> 45 + <div class="install-panel"> 46 + <div> 47 + <h3 class="heading-lg">Chrome</h3> 48 + <ol> 49 + <li>Open <span class="kbd">chrome://extensions/</span></li> 50 + <li>Enable <strong>Developer mode</strong></li> 51 + <li>Click <strong>Load unpacked</strong></li> 52 + <li>Select the extension folder that contains <code class="kbd">manifest.json</code></li> 53 + <li>Optional: shortcuts at <span class="kbd">chrome://extensions/shortcuts</span></li> 54 + </ol> 55 + </div> 56 + <div> 57 + <h3 class="heading-lg">Firefox</h3> 58 + <ol> 59 + <li>Open <span class="kbd">about:debugging#/runtime/this-firefox</span></li> 60 + <li>Click <strong>Load Temporary Add-on</strong></li> 61 + <li>Select <strong>manifest.json</strong> inside the extension folder</li> 62 + <li>Add-ons → gear → <strong>Manage Extension Shortcuts</strong> for the hotkey</li> 63 + </ol> 64 + <p class="firefox-note"> 65 + Temporary add-ons clear when you fully quit Firefox—reload during active dev sessions. 66 + </p> 67 + </div> 53 68 </div> 54 - <div> 55 - <h3 class="heading-lg">Firefox</h3> 56 - <ol> 57 - <li>Open <span class="kbd">about:debugging#/runtime/this-firefox</span></li> 58 - <li>Click <strong>Load Temporary Add-on</strong></li> 59 - <li>Select <strong>manifest.json</strong> inside <strong>webai-summarizer</strong></li> 60 - <li>Add-ons → gear → <strong>Manage Extension Shortcuts</strong> for the hotkey</li> 61 - </ol> 62 - <p class="firefox-note"> 63 - Temporary add-ons clear when you fully quit Firefox—reload during active dev sessions. 64 - </p> 65 - </div> 66 - </div> 67 - </div> 68 - 69 - <details class="disclosure reveal-item" style="--i: 5"> 70 - <summary>Advanced: build scripts per browser</summary> 71 - <div class="disclosure__body"> 72 - <p> 73 - If you already use split manifests, <span class="kbd">./build.sh chrome</span> or 74 - <span class="kbd">./build.sh firefox</span> from the extension repo targets a specific build. 75 - </p> 76 69 </div> 77 70 </details> 78 71 79 - <p class="repo-note reveal-item" style="--i: 6"> 80 - Source: 72 + <p class="repo-note reveal-item" style="--i: 5"> 73 + Project: 81 74 <a href={tangled} target="_blank" rel="noopener noreferrer">{tangled}</a> 82 75 </p> 83 76 </div>
+9 -8
src/components/sections/PrivacyBand.astro
··· 1 1 <section id="privacy" class="section section--dark" aria-labelledby="privacy-heading"> 2 2 <div class="wrap"> 3 3 <header class="section__head"> 4 - <p class="eyebrow">Privacy and APIs</p> 5 - <h2 id="privacy-heading" class="heading-xl">Where text goes</h2> 4 + <p class="eyebrow">Privacy</p> 5 + <h2 id="privacy-heading" class="heading-xl">Your reading stays yours</h2> 6 6 </header> 7 7 <div class="split split--privacy"> 8 8 <div class="prose prose--dark"> 9 - <h3 class="heading-md">Ollama native</h3> 9 + <h3 class="heading-md">On your computer</h3> 10 10 <p> 11 - <code class="kbd">/api/generate</code> on your machine. Base URL omits <span class="kbd">/v1</span>. 11 + Point Lede at a local model and page text stays on your machine. Nothing is uploaded in the background while 12 + you browse. 12 13 </p> 13 14 </div> 14 15 <div class="prose prose--dark"> 15 - <h3 class="heading-md">OpenAI-compatible</h3> 16 + <h3 class="heading-md">When you use a cloud model</h3> 16 17 <p> 17 - <code class="kbd">/v1/chat/completions</code> to the endpoint you configure. Content leaves the browser only when 18 - you summarize or chat—not via a script on every site. 18 + If you connect to a hosted service you trust, text is sent only when you summarize or chat—not on every site 19 + you visit. 19 20 </p> 20 21 </div> 21 22 </div> 22 - <p class="privacy-kicker prose prose--dark">Extraction is on-demand when you ask.</p> 23 + <p class="privacy-kicker prose prose--dark">Lede only reads a tab when you ask it to.</p> 23 24 </div> 24 25 </section>
+2 -2
src/components/sections/UsageMicro.astro
··· 28 28 </ol> 29 29 30 30 <p class="usage-afterword"> 31 - The hero above is a live shell of the extension popup—try theme, <strong>Quick Summary</strong>, and chat there; 32 - install from source for the real pipeline (page extraction, your model, settings). 31 + The preview above matches the real popup—try the theme, <strong>Quick Summary</strong>, and chat. After you install, 32 + those same controls work on whatever page you have open. 33 33 </p> 34 34 </section>
+1 -1
src/pages/index.astro
··· 35 35 <EditorialValue /> 36 36 <UsageMicro /> 37 37 <PrivacyBand /> 38 - <FAQCompact /> 38 + <FAQCompact tangled={TANGLED_REPO_URL} /> 39 39 </main> 40 40 <SiteFooter tangled={TANGLED_REPO_URL} /> 41 41 </div>
+120 -43
src/styles/global.css
··· 17 17 --color-ink-muted: oklch(72% 0.02 var(--hue-ink)); 18 18 --color-surface: oklch(99.4% 0.004 var(--hue-brand)); 19 19 20 - --color-brand: oklch(63.5% 0.196 38); 21 - --color-brand-hover: oklch(57% 0.18 38); 22 - --color-brand-active: oklch(50% 0.165 38); 20 + --color-brand: oklch(64.5% 0.205 38); 21 + --color-brand-hover: oklch(58% 0.19 38); 22 + --color-brand-active: oklch(51% 0.175 38); 23 + --color-brand-soft: color-mix(in oklch, var(--color-brand) 14%, var(--color-canvas)); 23 24 --color-on-brand: oklch(99% 0.01 95); 24 25 25 26 --color-link: oklch(38% 0.02 var(--hue-ink)); ··· 38 39 --font-mono: ui-monospace, "SF Mono", "Cascadia Code", monospace; 39 40 40 41 /* Fluid display scale (≥1.25 ratio between steps) */ 41 - --text-hero: clamp(2.25rem, 4vw + 1.5rem, 3.75rem); 42 - --text-xl: clamp(1.75rem, 2.2vw + 1.1rem, 2.4rem); 42 + --text-hero: clamp(2.85rem, 5.5vw + 1.15rem, 4.85rem); 43 + --text-xl: clamp(1.9rem, 2.6vw + 1.05rem, 2.75rem); 43 44 --text-lg: clamp(1.35rem, 1.2vw + 1rem, 1.75rem); 44 45 --text-md: clamp(1.0625rem, 0.5vw + 0.95rem, 1.25rem); 45 46 --text-sm: 0.875rem; ··· 80 81 --shadow-card-edge: oklch(0% 0 0 / 0.07); 81 82 --shadow-card-soft: oklch(0% 0 0 / 0.11); 82 83 --shadow-popup: 83 - 0 0 0 1px oklch(0% 0 0 / 0.07), 0 10px 24px oklch(0% 0 0 / 0.07), 0 28px 70px oklch(0% 0 0 / 0.11); 84 + 0 0 0 1px color-mix(in oklch, var(--color-brand) 18%, oklch(0% 0 0 / 0.06)), 85 + 0 12px 28px oklch(0% 0 0 / 0.08), 86 + 0 32px 80px oklch(0% 0 0 / 0.12); 84 87 } 85 88 86 89 @media (prefers-color-scheme: dark) { ··· 94 97 --color-ink-muted: oklch(56% 0.022 70); 95 98 --color-surface: oklch(21.2% 0.014 var(--hue-brand)); 96 99 97 - --color-brand: oklch(69% 0.19 38); 98 - --color-brand-hover: oklch(75% 0.195 40); 99 - --color-brand-active: oklch(61% 0.17 38); 100 + --color-brand: oklch(70% 0.2 38); 101 + --color-brand-hover: oklch(76% 0.2 40); 102 + --color-brand-active: oklch(62% 0.175 38); 103 + --color-brand-soft: color-mix(in oklch, var(--color-brand) 18%, var(--color-canvas)); 100 104 --color-on-brand: oklch(14% 0.02 42); 101 105 102 106 --color-link: oklch(78% 0.04 72); ··· 112 116 --shadow-card-edge: oklch(100% 0 0 / 0.08); 113 117 --shadow-card-soft: oklch(0% 0 0 / 0.42); 114 118 --shadow-popup: 115 - 0 0 0 1px oklch(100% 0 0 / 0.1), 0 12px 28px oklch(0% 0 0 / 0.42), 116 - 0 28px 72px oklch(0% 0 0 / 0.52); 119 + 0 0 0 1px color-mix(in oklch, var(--color-brand) 28%, oklch(100% 0 0 / 0.12)), 120 + 0 14px 32px oklch(0% 0 0 / 0.45), 121 + 0 36px 88px oklch(0% 0 0 / 0.55); 117 122 } 118 123 119 124 .section--dark .eyebrow { 120 125 color: oklch(76% 0.055 55); 121 126 } 127 + 128 + .hero-mast { 129 + background: 130 + radial-gradient(ellipse 78% 58% at 0% 0%, color-mix(in oklch, var(--color-brand) 24%, transparent), transparent 55%), 131 + linear-gradient( 132 + 172deg, 133 + color-mix(in oklch, var(--color-subtle) 92%, #000) 0%, 134 + var(--color-canvas) 48%, 135 + oklch(14.5% 0.016 var(--hue-brand)) 100% 136 + ); 137 + } 138 + 139 + .hero-mast .eyebrow { 140 + color: color-mix(in oklch, var(--color-brand) 48%, var(--color-ink-muted)); 141 + } 122 142 } 123 143 124 144 *, ··· 236 256 font-family: var(--font-display); 237 257 font-size: var(--text-hero); 238 258 font-weight: 700; 239 - line-height: var(--leading-tight); 240 - letter-spacing: var(--tracking-display); 259 + line-height: 1.02; 260 + letter-spacing: -0.028em; 241 261 color: var(--color-ink); 242 262 margin: 0 0 var(--space-sm); 263 + text-wrap: balance; 243 264 } 244 265 245 266 .heading-xl { ··· 293 314 position: sticky; 294 315 top: 0; 295 316 z-index: 50; 296 - background: color-mix(in oklch, var(--color-canvas) 92%, transparent); 297 - backdrop-filter: blur(10px); 317 + isolation: isolate; 318 + background: color-mix(in oklch, var(--color-canvas) 96%, transparent); 319 + backdrop-filter: blur(6px); 298 320 border-bottom: 1px solid var(--color-border); 321 + box-shadow: 0 1px 0 color-mix(in oklch, var(--color-brand) 8%, transparent); 322 + } 323 + 324 + .site-header::before { 325 + content: ""; 326 + position: absolute; 327 + inset: 0 0 auto 0; 328 + height: 3px; 329 + background: linear-gradient( 330 + 90deg, 331 + color-mix(in oklch, var(--color-brand) 88%, transparent), 332 + color-mix(in oklch, var(--color-brand) 35%, var(--color-canvas)) 333 + ); 334 + pointer-events: none; 299 335 } 300 336 301 337 .site-header__inner { ··· 481 517 } 482 518 483 519 .btn--primary { 484 - color: var(--color-brand); 485 - background: transparent; 486 - border-color: var(--color-brand); 520 + color: var(--color-on-brand); 521 + background: var(--color-brand); 522 + border-color: color-mix(in oklch, var(--color-brand) 78%, var(--color-ink)); 523 + box-shadow: 524 + 0 1px 0 color-mix(in oklch, var(--color-on-brand) 22%, transparent), 525 + 0 3px 0 color-mix(in oklch, var(--color-brand-active) 55%, var(--color-ink)); 487 526 } 488 527 489 528 .btn--primary:hover { 490 - background: var(--color-brand); 529 + background: var(--color-brand-hover); 530 + border-color: var(--color-brand-hover); 491 531 color: var(--color-on-brand); 492 - border-color: var(--color-brand); 493 - transform: translateY(-1px); 532 + transform: translateY(-2px); 533 + box-shadow: 534 + 0 1px 0 color-mix(in oklch, var(--color-on-brand) 28%, transparent), 535 + 0 5px 0 color-mix(in oklch, var(--color-brand-active) 45%, var(--color-ink)), 536 + 0 14px 28px color-mix(in oklch, var(--color-brand) 22%, transparent); 494 537 } 495 538 496 539 .btn--primary:active { 497 540 background: var(--color-brand-active); 498 541 border-color: var(--color-brand-active); 499 542 color: var(--color-on-brand); 500 - transform: translateY(0); 543 + transform: translateY(1px); 544 + box-shadow: 0 1px 0 color-mix(in oklch, var(--color-on-brand) 15%, transparent); 501 545 } 502 546 503 547 .btn--secondary { ··· 527 571 528 572 /* Privacy dark band */ 529 573 .section--dark { 530 - background: var(--color-dark-canvas); 574 + background-color: var(--color-dark-canvas); 575 + background-image: 576 + radial-gradient(ellipse 120% 70% at 100% 0%, oklch(38% 0.06 48 / 0.4), transparent 52%), 577 + radial-gradient(ellipse 90% 55% at 0% 100%, oklch(32% 0.07 38 / 0.35), transparent 48%); 531 578 color: var(--color-dark-ink); 532 - padding-block: var(--space-3xl); 579 + padding-block: calc(var(--space-3xl) + var(--space-md)); 533 580 border-block: 1px solid var(--color-dark-border); 534 581 } 535 582 ··· 643 690 644 691 .reveal-item { 645 692 opacity: 0; 646 - transform: translateY(12px); 693 + transform: translateY(18px); 647 694 animation: reveal-in var(--duration-enter) var(--ease-out) forwards; 648 695 animation-delay: calc(var(--i, 0) * var(--stagger)); 649 696 } ··· 687 734 688 735 .deck { 689 736 font-family: var(--font-display); 690 - font-size: clamp(1.125rem, 1.5vw + 0.75rem, 1.45rem); 737 + font-size: clamp(1.2rem, 1.85vw + 0.7rem, 1.6rem); 691 738 font-weight: 600; 692 739 line-height: var(--leading-ui); 693 - letter-spacing: -0.015em; 740 + letter-spacing: -0.018em; 694 741 color: var(--color-ink); 695 742 max-width: 28em; 696 743 margin: 0 0 var(--space-sm); ··· 702 749 } 703 750 704 751 .hero-mast { 705 - padding-block: var(--space-2xl) var(--space-3xl); 752 + position: relative; 753 + isolation: isolate; 754 + padding-block: calc(var(--space-2xl) + var(--space-sm)) calc(var(--space-3xl) + var(--space-md)); 706 755 border-bottom: 1px solid var(--color-border); 756 + background: 757 + radial-gradient(ellipse 85% 65% at 0% 0%, var(--color-brand-soft), transparent 58%), 758 + linear-gradient( 759 + 168deg, 760 + color-mix(in oklch, var(--color-surface) 55%, var(--color-canvas)) 0%, 761 + var(--color-canvas) 42%, 762 + color-mix(in oklch, var(--color-subtle) 88%, var(--color-canvas)) 100% 763 + ); 764 + } 765 + 766 + .hero-mast .eyebrow { 767 + color: color-mix(in oklch, var(--color-brand) 42%, var(--color-ink-muted)); 707 768 } 708 769 709 770 .hero-mast__grid { ··· 714 775 715 776 @media (min-width: 960px) { 716 777 .hero-mast__grid { 717 - grid-template-columns: minmax(0, 1fr) minmax(320px, 1.05fr); 718 - gap: var(--space-2xl); 778 + grid-template-columns: minmax(0, 1.02fr) minmax(320px, 1.12fr); 779 + gap: clamp(var(--space-2xl), 4vw, var(--space-3xl)); 719 780 align-items: center; 720 781 } 721 782 } ··· 850 911 } 851 912 852 913 .journey-band--callout { 853 - background: color-mix(in oklch, var(--color-subtle) 65%, var(--color-canvas)); 914 + background: linear-gradient( 915 + 135deg, 916 + color-mix(in oklch, var(--color-brand-soft) 80%, var(--color-subtle)) 0%, 917 + color-mix(in oklch, var(--color-subtle) 72%, var(--color-canvas)) 100% 918 + ); 919 + border-color: color-mix(in oklch, var(--color-brand) 22%, var(--color-border)); 854 920 } 855 921 856 922 .journey-band__text { ··· 891 957 .journey-strip__num { 892 958 font-family: var(--font-display); 893 959 font-weight: 700; 894 - font-size: var(--text-xl); 960 + font-size: clamp(2.25rem, 4.5vw + 1rem, 3.35rem); 895 961 color: var(--color-brand); 896 - line-height: 1; 962 + line-height: 0.95; 963 + letter-spacing: -0.03em; 897 964 } 898 965 899 966 .journey-strip__title { ··· 930 997 931 998 @media (min-width: 800px) { 932 999 .editorial-grid { 933 - grid-template-columns: repeat(3, 1fr); 934 - gap: var(--space-lg); 1000 + grid-template-columns: 1.18fr 0.92fr 0.92fr; 1001 + gap: clamp(var(--space-lg), 3vw, var(--space-xl)); 1002 + align-items: start; 935 1003 } 936 1004 } 937 1005 938 1006 .editorial-block { 939 - padding-top: var(--space-md); 940 - border-top: 2px solid color-mix(in oklch, var(--color-brand) 35%, var(--color-border)); 1007 + padding-top: var(--space-lg); 1008 + border-top: 3px solid color-mix(in oklch, var(--color-brand) 52%, var(--color-border)); 941 1009 } 942 1010 943 1011 .editorial-block p { 944 - margin: var(--space-xs) 0 0; 945 - font-size: var(--text-sm); 1012 + margin: var(--space-sm) 0 0; 1013 + font-size: clamp(0.9375rem, 0.35vw + 0.88rem, 1.0625rem); 946 1014 line-height: var(--leading-prose); 947 1015 color: var(--color-ink-secondary); 1016 + } 1017 + 1018 + @media (min-width: 800px) { 1019 + .editorial-block:first-child .heading-md { 1020 + font-size: clamp(1.2rem, 0.9vw + 1rem, 1.45rem); 1021 + } 948 1022 } 949 1023 950 1024 .usage-flow { ··· 1000 1074 } 1001 1075 1002 1076 .privacy-kicker { 1003 - margin: var(--space-lg) 0 0; 1004 - font-weight: 600; 1005 - font-size: var(--text-sm); 1006 - max-width: 42ch; 1077 + margin: var(--space-xl) 0 0; 1078 + font-family: var(--font-display); 1079 + font-weight: 700; 1080 + font-size: var(--text-md); 1081 + letter-spacing: -0.02em; 1082 + max-width: 40ch; 1083 + color: var(--color-dark-ink); 1007 1084 } 1008 1085 1009 1086 .faq-stack {