Everything else you need
-{item.title}
-{item.text}
-Error: {error.message}
; return
+
{tokens.map((line, i) => (
{line.map((token, key) => (
@@ -62,7 +109,7 @@ function UserProfile({ id }) {
const codeAwait = `
{(user) => (
- // user is User — never undefined,
+ // user is User. Never undefined,
// never null, never loading.
{user.name}
@@ -71,24 +118,6 @@ const codeAwait = `
)}
`;
-const codeInstall = `
-import { useRemoteData, Await } from "use-remote-data";
-
-function UserProfile({ id }) {
- const store = useRemoteData(
- () => fetch(\`/api/users/\${id}\`).then(r => r.json()),
- { dependencies: [id] }
- );
-
- return (
- }
- >
- {(user) => {user.name}
}
-
- );
-}`;
-
const codeError = `
(
@@ -102,16 +131,13 @@ const codeError = `
`;
const codeRetry = `
-// When you combine three stores and one fails:
+// Combine three stores. One fails.
const allStore = RemoteDataStore.all(
userStore, postsStore, statsStore
);
-// The combined store moves to "failed".
-// But retry() only re-fetches the broken one.
+// retry() only re-fetches the broken one.
// The two successful stores keep their data.
-//
-// One button. One click. Surgical retry.
(
@@ -123,13 +149,12 @@ const allStore = RemoteDataStore.all(
const codeRefresh = `
const store = useRemoteData(
() => fetchPrices(), {
- // Re-fetch every 30 seconds
refresh: RefreshStrategy.afterMillis(30_000),
}
);
-// isStale is true while background
-// refresh is in progress — old data stays visible
+// isStale: true while background
+// refresh is in progress, old data stays visible
{(prices, isStale) => (
@@ -143,19 +168,17 @@ const todosStore = useRemoteData(() => fetchTodos());
const addTodo = useRemoteUpdate(
(text) => api.addTodo(text), {
- // After a successful mutation,
- // automatically re-fetch the todo list
refreshes: [todosStore],
}
);
// addTodo.run("Buy milk")
-// → mutation fires
-// → on success, todosStore re-fetches
-// → Await re-renders with fresh data`;
+// → mutation fires
+// → on success, todosStore re-fetches
+// → Await re-renders with fresh data`;
const codeCombine = `
-const userStore = useRemoteData(() => fetchUser(id), { dependencies: [id] });
+const userStore = useRemoteData(() => fetchUser(id), { dependencies: [id] });
const postsStore = useRemoteData(() => fetchPosts(id), { dependencies: [id] });
const statsStore = useRemoteData(() => fetchStats(id), { dependencies: [id] });
@@ -174,7 +197,7 @@ return (
const codeTesting = `
import { RemoteData, RemoteDataStore, Failure } from "use-remote-data";
-// A store that's already loaded — no fetch, no mock
+// A store that's already loaded. No fetch, no mock.
const store = RemoteDataStore.always(
RemoteData.success({ name: "Alice", email: "alice@ex.com" })
);
@@ -193,14 +216,14 @@ const failed = RemoteDataStore.always(
const codeLifetime = `
function UserPage({ id }) {
- // Store is created when UserPage mounts.
+ // Store created when UserPage mounts.
// Fetches on first render. Caches while mounted.
- // Unmount UserPage → store is gone. No stale cache.
+ // Unmount UserPage: store is gone. No stale cache.
const userStore = useRemoteData(
() => fetchUser(id), { dependencies: [id] }
);
- // Pass the store down — child components
+ // Pass the store down. Child components
// share the same fetch, same cache.
return (
@@ -212,17 +235,20 @@ function UserPage({ id }) {
const quickHits = [
{
- title: 'Zero dependencies, ~3.5kB gzipped',
- text: 'Just React. No runtime dependencies, no context providers, no bloat.',
+ title: 'Zero dependencies',
+ text: 'Just React. ~3.5kB gzipped, no runtime deps, no context providers, no bloat.',
+ },
+ {
+ title: 'SSR ready',
+ text: 'Pass server data as initial. The store starts in Success. No hydration boundaries to wire up.',
},
- { title: 'SSR ready', text: 'Pass server data as initial. No hydration boundaries.' },
{
title: 'Automatic cancellation',
text: 'When deps change or a component unmounts, in-flight requests are aborted. Stale responses are always discarded.',
},
{
title: 'Lazy by default',
- text: 'Stores only fetch when rendered. Define data dependencies upfront — only what mounts hits the network.',
+ text: 'Stores only fetch when rendered. Define data dependencies upfront; only what mounts hits the network.',
},
{
title: 'Mutations that refresh',
@@ -230,24 +256,20 @@ const quickHits = [
},
{
title: 'Typed errors',
- text: 'Separate domain errors from crashes. Validate with Zod, handle GraphQL unions — TypeScript knows which error you have.',
+ text: 'Separate domain errors from crashes. Validate with Zod, handle GraphQL unions; TypeScript knows which error you have.',
},
];
-function Section({ title, text, code, alt, reverse }) {
- const textBlock = (
-
- {title}
- {text}
-
- );
- const codeBlock = ;
-
+function Section({ label, title, text, code, alt, reverse }) {
return (
- {textBlock}
- {codeBlock}
+
+ {label}
+ {title}
+ {text}
+
+
);
@@ -255,142 +277,131 @@ function Section({ title, text, code, alt, reverse }) {
export default function Home() {
return (
-
- {/* Hero */}
-
-
- Fetch data in React without the boilerplate.
-
- One hook. One component. Your data is T, not T | undefined.
-
- Loading, error, success — always one state, always type-safe.
-
-
-
- Get Started
-
-
- View on GitHub →
-
+
+
+ {/* ── Hero ─────────────────────────────────── */}
+
+
+
+ Async data.
+
+ Zero guesswork.
+
+
+
+
+ A React hook with one promise: inside {''} your data is T,
+ never T | undefined. Loading, error, success — always one state, always
+ type-safe.
+
+
+
+
+ Read the docs →
+
+ npm install use-remote-data
+
-
+
+
+ {/* ── Before / After ───────────────────────── */}
+
+
The old way
-
+
use-remote-data
-
-
-
-
- {/* Section 2 */}
-
-
- {/* Section 3 */}
-
-
- {/* Section 4: Error handling */}
-
-
- {/* Combine */}
-
-
- {/* Section 5: Surgical retry */}
-
-
- {/* Invalidation */}
-
-
- {/* Mutation invalidation */}
-
-
- {/* Testing */}
-
-
- {/* Lifetime */}
-
-
- {/* Quick hits */}
-
-
- Everything else you need
-
- {quickHits.map((item) => (
-
- {item.title}
- {item.text}
-
- ))}
-
-
- {/* Bottom CTA */}
-
- Stop guessing.
-
-
- Get Started
-
- npm install use-remote-data
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* ── Everything else ─────────────────── */}
+
+
+ 09 / further notes
+ Six things you also get.
+
+
+ {quickHits.map((item, i) => (
+
+ {String(i + 1).padStart(2, '0')}
+ {item.title}
+ {item.text}
+
+ ))}
+
+
+
+
+
);
}
diff --git a/site/src/pages/index.module.css b/site/src/pages/index.module.css
index fd101c2..d90b63e 100644
--- a/site/src/pages/index.module.css
+++ b/site/src/pages/index.module.css
@@ -1,17 +1,19 @@
-/* Hero — light mode: clean white with teal accents */
+/* ─────────────────────────────────────────────────────────────
+ Landing — sharp monochrome with bold orange
+ ───────────────────────────────────────────────────────────── */
-.hero {
- background: linear-gradient(170deg, #ffffff 0%, #f0fdfa 50%, #ccfbf1 100%);
- color: #111827;
- padding: 6rem 2rem 5rem;
- min-height: 80vh;
- display: flex;
- align-items: center;
+.page {
+ background: var(--paper);
+ color: var(--ink);
+ font-family: var(--font-display);
}
-:global(html[data-theme='dark']) .hero {
- background: #09090b;
- color: #f9fafb;
+/* ── Hero ────────────────────────────────────────────────── */
+
+.hero {
+ padding: 8rem 2rem 4rem;
+ border-bottom: 1px solid var(--rule);
+ background: var(--paper);
}
.heroInner {
@@ -21,86 +23,189 @@
}
.heroHeadline {
- font-size: 3.2rem;
- font-weight: 800;
- letter-spacing: -0.02em;
- margin: 0 0 1rem;
- line-height: 1.1;
+ font-family: var(--font-display);
+ font-size: clamp(3rem, 9vw, 7rem);
+ font-weight: 700;
+ line-height: 1.02;
+ letter-spacing: -0.052em;
+ margin: 0 0 2rem;
+ color: var(--ink);
+ max-width: 16ch;
+ text-wrap: balance;
+ font-feature-settings:
+ 'ss01' on,
+ 'ss03' on,
+ 'cv01' on,
+ 'cv11' on;
}
-.heroHeadline code {
- color: #0d9488;
- background: none;
- font-size: inherit;
- padding: 0;
+.heroLine {
+ display: block;
}
-:global(html[data-theme='dark']) .heroHeadline code {
- color: #2dd4bf;
+.heroHeadline mark {
+ background: var(--accent);
+ color: var(--paper);
+ padding: 0.02em 0.18em 0.04em;
+ line-height: 0.95;
+ display: inline-block;
+ vertical-align: baseline;
+ border-radius: 0;
+ font-weight: 800;
+ letter-spacing: -0.055em;
+}
+
+html[data-theme='dark'] .heroHeadline mark {
+ color: var(--ink);
+ background: var(--accent);
}
.heroSubtitle {
- font-size: 1.25rem;
- color: #4b5563;
- max-width: 600px;
- margin: 0 0 2.5rem;
- line-height: 1.6;
+ font-family: var(--font-display);
+ font-size: clamp(1.1rem, 1.6vw, 1.3rem);
+ line-height: 1.42;
+ color: var(--ink-soft);
+ max-width: 56ch;
+ margin: 0 0 3rem;
+ font-weight: 400;
+ letter-spacing: -0.005em;
+ text-wrap: pretty;
}
-:global(html[data-theme='dark']) .heroSubtitle {
- color: #9ca3af;
+.heroSubtitle code {
+ font-family: var(--ifm-font-family-monospace);
+ background: transparent;
+ color: var(--ink);
+ font-weight: 500;
+ padding: 0 0.05em;
+ border: 0;
+ border-radius: 0;
+ font-size: 0.86em;
+ letter-spacing: -0.01em;
+ font-feature-settings:
+ 'liga' on,
+ 'calt' on,
+ 'zero' on;
+}
+
+html[data-theme='dark'] .heroSubtitle code {
+ color: var(--ink);
}
.heroCta {
display: flex;
align-items: center;
- gap: 1.5rem;
- margin-bottom: 3.5rem;
+ gap: 1.25rem;
+ flex-wrap: wrap;
}
+/* CTAs */
+
.ctaButton {
- display: inline-block;
- background: #0d9488;
- color: #fff;
- padding: 0.75rem 2rem;
- border-radius: 8px;
+ display: inline-flex;
+ align-items: center;
+ gap: 0.5rem;
+ background: var(--accent);
+ color: var(--paper);
+ padding: 0.95rem 1.6rem 1rem;
+ border: 1px solid var(--accent);
+ border-radius: 0;
+ font-family: var(--font-display);
font-weight: 600;
- font-size: 1rem;
+ font-size: 0.96rem;
+ letter-spacing: -0.012em;
text-decoration: none;
- transition: background 0.15s;
+ transition:
+ background 120ms ease,
+ color 120ms ease,
+ border-color 120ms ease;
+ font-feature-settings:
+ 'ss01' on,
+ 'cv11' on;
+}
+
+html[data-theme='dark'] .ctaButton {
+ color: var(--ink);
}
.ctaButton:hover {
- background: #0f766e;
- color: #fff;
+ background: var(--ink);
+ border-color: var(--ink);
+ color: var(--paper);
text-decoration: none;
}
-.githubLink {
- color: #6b7280;
- text-decoration: none;
- font-size: 0.95rem;
+html[data-theme='dark'] .ctaButton:hover {
+ background: var(--paper);
+ color: var(--ink);
+ border-color: var(--paper);
+}
+
+.ctaButtonGhost {
+ composes: ctaButton;
+ background: transparent;
+ color: var(--ink);
+ border-color: var(--ink);
+}
+
+.ctaButtonGhost:hover {
+ background: var(--ink);
+ color: var(--paper);
+ border-color: var(--ink);
}
-.githubLink:hover {
- color: #0d9488;
- text-decoration: underline;
+html[data-theme='dark'] .ctaButtonGhost {
+ color: var(--ink);
+ border-color: var(--ink);
}
-:global(html[data-theme='dark']) .githubLink {
- color: #9ca3af;
+html[data-theme='dark'] .ctaButtonGhost:hover {
+ background: var(--ink);
+ color: var(--paper);
+ border-color: var(--ink);
}
-:global(html[data-theme='dark']) .githubLink:hover {
- color: #2dd4bf;
+.installCmd {
+ font-family: var(--ifm-font-family-monospace);
+ font-size: 0.92rem;
+ color: var(--ink);
+ background: var(--paper-cool);
+ border: 1px solid var(--rule-soft);
+ padding: 0.85rem 1.25rem;
+ user-select: all;
+ cursor: copy;
+ display: inline-flex;
+ align-items: center;
+ gap: 0.6rem;
+ letter-spacing: -0.01em;
+ font-variant-numeric: tabular-nums;
+ font-feature-settings:
+ 'liga' on,
+ 'calt' on,
+ 'zero' on;
}
-/* Hero comparison */
+.installCmd::before {
+ content: '$';
+ color: var(--accent);
+ font-weight: 600;
+ user-select: none;
+}
+
+/* ── Comparison ──────────────────────────────────────────── */
.comparison {
+ padding: 4rem 2rem;
+ background: var(--paper-soft);
+ border-bottom: 1px solid var(--rule);
+}
+
+.comparisonInner {
+ max-width: 1200px;
+ margin: 0 auto;
display: grid;
grid-template-columns: 1fr 1fr;
- gap: 1.5rem;
+ gap: 1.25rem;
}
.comparisonPane {
@@ -108,46 +213,59 @@
flex-direction: column;
}
+.comparisonPane.after {
+ /* nothing extra; the dark code block is the frame */
+}
+
.comparisonLabel {
- font-size: 0.8rem;
+ display: flex;
+ align-items: center;
+ gap: 0.6rem;
+ font-family: var(--ifm-font-family-monospace);
+ font-size: 0.72rem;
font-weight: 600;
text-transform: uppercase;
- letter-spacing: 0.08em;
- margin-bottom: 0.5rem;
+ letter-spacing: 0.16em;
+ margin-bottom: 1.25rem;
+ color: var(--ink-soft);
+ font-variant-numeric: tabular-nums;
+ font-feature-settings:
+ 'zero' on,
+ 'ss05' on;
}
-.labelBefore {
- color: #ef4444;
+.labelBefore::before {
+ content: '✕';
+ color: var(--ink-soft);
}
.labelAfter {
- color: var(--landing-after-color);
+ color: var(--accent);
+}
+
+.labelAfter::before {
+ content: '✓';
+ color: var(--accent);
}
-/* Sections */
+/* ── Sections ────────────────────────────────────────────── */
.section {
- padding: 5rem 2rem;
+ padding: 6rem 2rem;
+ border-bottom: 1px solid var(--rule-soft);
+ background: var(--paper);
}
.sectionAlt {
- background: var(--landing-alt-bg);
-}
-
-.sectionInner {
- max-width: 1100px;
- margin: 0 auto;
- display: grid;
- grid-template-columns: 1fr 1fr;
- gap: 4rem;
- align-items: center;
+ background: var(--paper-soft);
}
+.sectionInner,
.sectionInnerReverse {
- max-width: 1100px;
+ max-width: 1200px;
margin: 0 auto;
display: grid;
- grid-template-columns: 1fr 1fr;
+ grid-template-columns: 1fr 1.4fr;
gap: 4rem;
align-items: center;
}
@@ -160,159 +278,258 @@
order: 1;
}
+.sectionLabel {
+ font-family: var(--ifm-font-family-monospace);
+ font-size: 0.72rem;
+ font-weight: 600;
+ text-transform: uppercase;
+ letter-spacing: 0.16em;
+ color: var(--accent);
+ margin: 0 0 1.1rem;
+ display: block;
+ font-variant-numeric: tabular-nums;
+ font-feature-settings:
+ 'zero' on,
+ 'ss05' on;
+}
+
.sectionTitle {
- font-size: 2rem;
+ font-family: var(--font-display);
+ font-size: clamp(1.8rem, 3.4vw, 2.6rem);
font-weight: 700;
- letter-spacing: -0.01em;
- margin: 0 0 1rem;
- color: var(--landing-text-primary);
+ line-height: 1.05;
+ letter-spacing: -0.032em;
+ margin: 0 0 1.25rem;
+ color: var(--ink);
+ text-wrap: balance;
+ font-feature-settings:
+ 'ss01' on,
+ 'ss03' on,
+ 'cv01' on,
+ 'cv11' on;
}
.sectionText {
- font-size: 1.1rem;
- color: var(--landing-text-secondary);
- line-height: 1.7;
+ font-family: var(--font-display);
+ font-size: 1.06rem;
+ color: var(--ink-soft);
+ line-height: 1.55;
margin: 0;
+ max-width: 44ch;
+ letter-spacing: -0.005em;
+ text-wrap: pretty;
}
-/* Code blocks */
+.sectionText code {
+ background: var(--paper-cool);
+ color: var(--ink);
+ border: 1px solid var(--rule-soft);
+ padding: 0.05em 0.35em;
+ font-size: 0.86em;
+ letter-spacing: -0.01em;
+}
+/* Code blocks — bright in light mode, dark in dark mode */
.codeBlock {
- border-radius: 10px;
- overflow: hidden;
+ background: #fafafa;
+ border: 1px solid var(--rule-soft);
+ color: var(--ink);
+}
+
+html[data-theme='dark'] .codeBlock {
+ background: #0a0a0a;
+ border: 1px solid var(--rule-mid);
+ color: #e5e5e5;
}
.codeBlock pre {
margin: 0;
- padding: 1.25rem 1.5rem;
- font-size: 0.875rem;
- line-height: 1.6;
+ padding: 1.5rem 1.6rem 1.6rem;
+ font-size: 0.84rem;
+ line-height: 1.65;
overflow-x: auto;
- border-radius: 10px;
+ background: transparent !important;
+ border-radius: 0 !important;
+ font-family: var(--ifm-font-family-monospace);
+ font-feature-settings:
+ 'liga' on,
+ 'calt' on;
+ color: inherit;
}
-/* Quick hits grid */
+/* ── Quick hits — clean grid ─────────────────────────────── */
.gridSection {
- padding: 5rem 2rem;
+ padding: 6rem 2rem;
+ background: var(--paper);
+ border-bottom: 1px solid var(--rule);
}
.gridInner {
- max-width: 1100px;
+ max-width: 1200px;
margin: 0 auto;
}
+.gridLabel {
+ font-family: var(--ifm-font-family-monospace);
+ font-size: 0.72rem;
+ font-weight: 600;
+ text-transform: uppercase;
+ letter-spacing: 0.16em;
+ color: var(--accent);
+ margin: 0 0 1.1rem;
+ display: block;
+ font-variant-numeric: tabular-nums;
+ font-feature-settings:
+ 'zero' on,
+ 'ss05' on;
+}
+
.gridTitle {
- font-size: 2rem;
+ font-family: var(--font-display);
+ font-size: clamp(1.8rem, 3.4vw, 2.6rem);
font-weight: 700;
- text-align: center;
+ letter-spacing: -0.032em;
margin: 0 0 3rem;
- color: var(--landing-text-primary);
+ color: var(--ink);
+ max-width: 22ch;
+ line-height: 1.05;
+ text-wrap: balance;
+ font-feature-settings:
+ 'ss01' on,
+ 'ss03' on,
+ 'cv01' on,
+ 'cv11' on;
}
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
- gap: 2rem;
+ border: 1px solid var(--rule);
}
-.gridItem h3 {
- font-size: 1.1rem;
- font-weight: 700;
- margin: 0 0 0.4rem;
- color: var(--landing-text-primary);
+.gridItem {
+ padding: 2rem 1.75rem;
+ border-right: 1px solid var(--rule-soft);
+ border-bottom: 1px solid var(--rule-soft);
+ display: flex;
+ flex-direction: column;
+ gap: 0.6rem;
}
-.gridItem p {
- font-size: 0.95rem;
- color: var(--landing-text-secondary);
- line-height: 1.6;
- margin: 0;
+.gridItem:nth-child(3n) {
+ border-right: 0;
}
-/* Bottom CTA */
-
-.bottomCta {
- background: linear-gradient(170deg, #0f766e 0%, #134e4a 100%);
- color: #f9fafb;
- padding: 5rem 2rem;
- text-align: center;
+.gridItem:nth-last-child(-n + 3) {
+ border-bottom: 0;
}
-:global(html[data-theme='dark']) .bottomCta {
- background: #09090b;
+.gridItemNumber {
+ font-family: var(--ifm-font-family-monospace);
+ font-size: 0.7rem;
+ color: var(--accent);
+ letter-spacing: 0.12em;
+ margin-bottom: 0.2rem;
+ font-weight: 600;
+ font-variant-numeric: tabular-nums;
+ font-feature-settings:
+ 'zero' on,
+ 'ss05' on;
}
-.bottomCtaHeadline {
- font-size: 2.5rem;
- font-weight: 800;
- margin: 0 0 2rem;
+.gridItem h3 {
+ font-family: var(--font-display);
+ font-size: 1.15rem;
+ font-weight: 700;
+ letter-spacing: -0.022em;
+ margin: 0;
+ color: var(--ink);
+ line-height: 1.2;
+ text-wrap: balance;
}
-.bottomCtaActions {
- display: flex;
- align-items: center;
- justify-content: center;
- gap: 2rem;
- flex-wrap: wrap;
+.gridItem p {
+ font-size: 0.95rem;
+ color: var(--ink-soft);
+ line-height: 1.5;
+ margin: 0;
+ letter-spacing: -0.005em;
+ text-wrap: pretty;
}
-.bottomCta .ctaButton {
- background: #fff;
- color: #134e4a;
-}
+/* ── Reveal ──────────────────────────────────────────────── */
-.bottomCta .ctaButton:hover {
- background: #f0fdfa;
- color: #134e4a;
+.reveal {
+ opacity: 0;
+ transform: translateY(8px);
+ animation: rev 600ms cubic-bezier(0.2, 0.65, 0.2, 1) forwards;
}
-:global(html[data-theme='dark']) .bottomCta .ctaButton {
- background: #2dd4bf;
- color: #09090b;
+.r1 {
+ animation-delay: 0ms;
}
-
-:global(html[data-theme='dark']) .bottomCta .ctaButton:hover {
- background: #14b8a6;
- color: #09090b;
+.r2 {
+ animation-delay: 100ms;
+}
+.r3 {
+ animation-delay: 220ms;
+}
+.r4 {
+ animation-delay: 360ms;
}
-.installCmd {
- font-family: var(--ifm-font-family-monospace);
- font-size: 0.95rem;
- color: #ccfbf1;
- background: rgba(255, 255, 255, 0.15);
- padding: 0.6rem 1.25rem;
- border-radius: 8px;
+@keyframes rev {
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
}
-:global(html[data-theme='dark']) .installCmd {
- color: #9ca3af;
- background: #1a1a1f;
+@media (prefers-reduced-motion: reduce) {
+ .reveal {
+ opacity: 1;
+ transform: none;
+ animation: none;
+ }
}
-/* Responsive */
+/* ── Responsive ──────────────────────────────────────────── */
-@media screen and (max-width: 768px) {
+@media screen and (max-width: 968px) {
.hero {
- padding: 4rem 1.5rem 3rem;
- min-height: auto;
+ padding: 5rem 1.5rem 3rem;
}
.heroHeadline {
- font-size: 2rem;
+ font-size: clamp(2.5rem, 11vw, 4rem);
}
.heroSubtitle {
font-size: 1.05rem;
+ max-width: none;
+ }
+
+ .heroCta {
+ flex-direction: column;
+ align-items: stretch;
+ }
+
+ .heroCta > * {
+ width: 100%;
+ justify-content: center;
}
.comparison {
+ padding: 2.5rem 1rem;
+ }
+
+ .comparisonInner {
grid-template-columns: 1fr;
}
.section {
- padding: 3rem 1.5rem;
+ padding: 4rem 1.5rem;
}
.sectionInner,
@@ -329,33 +546,26 @@
order: 2;
}
- .sectionTitle {
- font-size: 1.5rem;
+ .gridSection {
+ padding: 4rem 1.5rem;
}
.grid {
grid-template-columns: 1fr;
}
- .gridTitle {
- font-size: 1.5rem;
+ .gridItem,
+ .gridItem:nth-child(3n) {
+ border-right: 0;
+ border-bottom: 1px solid var(--rule-soft);
}
- .bottomCtaHeadline {
- font-size: 1.75rem;
+ .gridItem:last-child {
+ border-bottom: 0;
}
.codeBlock pre {
- font-size: 0.8rem;
- }
-}
-
-@media screen and (min-width: 769px) and (max-width: 968px) {
- .heroHeadline {
- font-size: 2.5rem;
- }
-
- .grid {
- grid-template-columns: repeat(2, 1fr);
+ font-size: 0.78rem;
+ padding: 1.1rem 1.1rem;
}
}
diff --git a/site/static/img/favicon.svg b/site/static/img/favicon.svg
new file mode 100644
index 0000000..e3de6ca
--- /dev/null
+++ b/site/static/img/favicon.svg
@@ -0,0 +1,15 @@
+
diff --git a/site/static/img/logo-dark.svg b/site/static/img/logo-dark.svg
new file mode 100644
index 0000000..4b52ebf
--- /dev/null
+++ b/site/static/img/logo-dark.svg
@@ -0,0 +1,9 @@
+
diff --git a/site/static/img/logo.svg b/site/static/img/logo.svg
index c809830..69a4f0e 100644
--- a/site/static/img/logo.svg
+++ b/site/static/img/logo.svg
@@ -1,37 +1,9 @@
-