aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbenj <benj@rse8.com>2026-04-09 16:10:08 +0800
committerbenj <benj@rse8.com>2026-04-09 16:10:08 +0800
commitc041641634650c31e03c70dcad132fd94cb08e63 (patch)
tree8f714a6fc0a66b05b2e43afec75808fd29002a42
parent5f56e0eaf8030f78077fc93b441296bb51fe9331 (diff)
downloadtidyindex-c041641634650c31e03c70dcad132fd94cb08e63.tar
tidyindex-c041641634650c31e03c70dcad132fd94cb08e63.tar.gz
tidyindex-c041641634650c31e03c70dcad132fd94cb08e63.tar.bz2
tidyindex-c041641634650c31e03c70dcad132fd94cb08e63.tar.lz
tidyindex-c041641634650c31e03c70dcad132fd94cb08e63.tar.xz
tidyindex-c041641634650c31e03c70dcad132fd94cb08e63.tar.zst
tidyindex-c041641634650c31e03c70dcad132fd94cb08e63.zip
Rework landing page with editorial layout, new demo, and LLM CTA
Replaces the generic SaaS template look with a left-aligned editorial design — Fraunces serif headlines, monospace section markers (§ 01, § 02 …), hairline rules, and a quieter palette where the blue earns its place rather than splashing on every surface. The hero now leads with a real product demo (§ 01): one IRS 990 dataset shown in three consumption shapes — a single normalized JSON record, a JSONL bulk slice, and a token-efficient prose summary — instead of the old fake-macOS code window. Each shape carries source-link receipts back to the original filing, which doubles as a credibility signal and a working illustration of the "every record has a receipt" promise. § 03 introduces a coverage widget driven by data/catalog.toml: four auto-scrolling category windows (securities, government, regulatory, science) showing 60 hand-picked datasets with seamless CSS-only infinite-scroll loops, fade masks, hover-pause, and a prefers-reduced-motion fallback that converts the windows into manually scrollable lists. Adds a discoverable /llms.txt at the static root — a markdown-light, human-readable site description aimed at LLM agents — wired up via <link rel="alternate"> in <head>, a comment in robots.txt, and a small mono "for agents · GET /llms.txt →" satellite link sitting directly under the hero CTA so any agent shallow-scraping the page hits the machine path immediately. Other changes: drops the XML format demo and the "promises" ledger section entirely, swaps hello@ for contact@ across the site, and renames the bottom CTA to a single-action "Ready when you are. → API Key" close. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
-rw-r--r--landing/data/catalog.toml83
-rw-r--r--landing/layouts/_default/baseof.html3
-rw-r--r--landing/layouts/index.html283
-rw-r--r--landing/layouts/partials/footer.html13
-rw-r--r--landing/layouts/partials/header.html12
-rw-r--r--landing/static/css/style.css888
-rw-r--r--landing/static/llms.txt99
-rw-r--r--landing/static/robots.txt3
8 files changed, 827 insertions, 557 deletions
diff --git a/landing/data/catalog.toml b/landing/data/catalog.toml
new file mode 100644
index 0000000..3882d68
--- /dev/null
+++ b/landing/data/catalog.toml
@@ -0,0 +1,83 @@
+# Datasets shown in the § 03 catalog widget on the landing page.
+# Each category becomes one scrolling column. Order within a category is
+# the order they scroll past, so put recognizable / flagship datasets first.
+
+[[categories]]
+name = "securities & finance"
+items = [
+ "SEC EDGAR 10-K, 10-Q",
+ "SEC 13-F holdings",
+ "SEC Form 4 insiders",
+ "SEC 13-D/G ownership",
+ "SEC Form D placements",
+ "FFIEC HMDA mortgages",
+ "FDIC call reports",
+ "NCUA credit unions",
+ "FINRA BrokerCheck",
+ "SEC investment advisers",
+ "CFPB consumer complaints",
+ "CFPB rate spread data",
+ "Federal bankruptcy filings",
+ "FinCEN beneficial ownership",
+ "Delaware franchise tax",
+]
+
+[[categories]]
+name = "government & politics"
+items = [
+ "USAspending awards",
+ "FEC campaign finance",
+ "Federal lobbying (LDA)",
+ "Congressional votes",
+ "Congressional bills",
+ "Federal Register rules",
+ "FPDS procurement",
+ "Federal subawards (FSRS)",
+ "GSA Schedule pricing",
+ "Foreign agents (FARA)",
+ "Executive orders",
+ "Federal IT spending",
+ "DOJ settlements",
+ "State lobbying",
+ "State procurement",
+]
+
+[[categories]]
+name = "regulatory & legal"
+items = [
+ "IRS 990 & 990-PF",
+ "IRS Form 5500 plans",
+ "IRS Business Master File",
+ "SAM.gov registrations",
+ "OSHA inspections",
+ "EPA ECHO enforcement",
+ "PACER federal courts",
+ "State court records",
+ "UCC filings",
+ "Secretary of State (SOS)",
+ "State medical boards",
+ "State bar attorneys",
+ "State contractor licenses",
+ "ITC trade rulings",
+ "DEA registrations",
+]
+
+[[categories]]
+name = "science, health & IP"
+items = [
+ "USPTO patent grants",
+ "USPTO trademarks",
+ "Patent assignments",
+ "Copyright registrations",
+ "NIH RePORTER grants",
+ "NSF grant awards",
+ "FDA drug approvals",
+ "FDA 510(k) devices",
+ "FDA FAERS adverse events",
+ "FDA warning letters",
+ "ClinicalTrials.gov",
+ "NPI provider registry",
+ "IPEDS college financials",
+ "DOE College Scorecard",
+ "DOE SBIR/STTR awards",
+]
diff --git a/landing/layouts/_default/baseof.html b/landing/layouts/_default/baseof.html
index 89a0bd7..bab1b56 100644
--- a/landing/layouts/_default/baseof.html
+++ b/landing/layouts/_default/baseof.html
@@ -17,10 +17,11 @@
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
- <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
+ <link href="https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,300..600&family=Inter:wght@400;500;600&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
<link rel="stylesheet" href="{{ "css/style.css" | relURL }}" />
<link rel="icon" type="image/svg+xml" href="{{ "favicon.svg" | relURL }}" />
+ <link rel="alternate" type="text/plain" title="LLM-readable site description" href="{{ "llms.txt" | relURL }}" />
</head>
<body>
{{ partial "header.html" . }}
diff --git a/landing/layouts/index.html b/landing/layouts/index.html
index 231ff61..a08109e 100644
--- a/landing/layouts/index.html
+++ b/landing/layouts/index.html
@@ -1,213 +1,152 @@
{{ define "main" }}
<section class="hero">
- <div class="container hero-inner">
- <span class="eyebrow">Clean data, on tap</span>
- <h1 class="hero-title">
- Structured data,<br />
- <span class="accent">served simply.</span>
+ <div class="container">
+ <h1 class="hero-headline">
+ Structured&nbsp;data,<br>
+ <em>served simply.</em>
</h1>
<p class="hero-sub">
Tidy Index delivers clean, well-organized datasets through a single API
designed for humans, machines, and LLM agents alike.
</p>
<div class="hero-cta">
- <a href="#contact" class="btn btn-primary">Request access</a>
- <a href="#how" class="btn btn-ghost">See how it works</a>
- </div>
-
- <div class="hero-visual" aria-hidden="true">
- <div class="code-card">
- <div class="code-card-head">
- <span class="dot dot-a"></span>
- <span class="dot dot-b"></span>
- <span class="dot dot-c"></span>
- <span class="code-card-title">GET&nbsp; /v1/datasets/cities</span>
- </div>
-<pre class="code-card-body"><code><span class="tk-p">{</span>
- <span class="tk-k">"id"</span>: <span class="tk-s">"cities"</span>,
- <span class="tk-k">"updated"</span>: <span class="tk-s">"2026-04-09T08:14:00Z"</span>,
- <span class="tk-k">"records"</span>: <span class="tk-p">[</span>
- <span class="tk-p">{</span> <span class="tk-k">"name"</span>: <span class="tk-s">"Lisbon"</span>, <span class="tk-k">"population"</span>: <span class="tk-n">548703</span> <span class="tk-p">}</span>,
- <span class="tk-p">{</span> <span class="tk-k">"name"</span>: <span class="tk-s">"Kyoto"</span>, <span class="tk-k">"population"</span>: <span class="tk-n">1463723</span> <span class="tk-p">}</span>,
- <span class="tk-p">{</span> <span class="tk-k">"name"</span>: <span class="tk-s">"Quito"</span>, <span class="tk-k">"population"</span>: <span class="tk-n">2011388</span> <span class="tk-p">}</span>
- <span class="tk-p">]</span>
-<span class="tk-p">}</span></code></pre>
- </div>
+ <a href="mailto:contact@tidyindex.com" class="btn btn-primary">
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
+ <circle cx="7.5" cy="15.5" r="5.5"/>
+ <path d="m11.5 11.5 9.5-9.5"/>
+ <path d="m17 5 3 3"/>
+ <path d="m14 8 3 3"/>
+ </svg>
+ Get an API Key
+ </a>
+ <a href="#demo" class="btn-link">See a record <span aria-hidden="true">&darr;</span></a>
</div>
- </div>
-</section>
-<section id="what" class="section">
- <div class="container narrow">
- <span class="eyebrow center">What is Tidy Index</span>
- <h2 class="section-title center">We&rsquo;ve already done the cleanup.</h2>
- <p class="section-lede center">
- Scraping. Reformatting. Reconciling. Re-scraping when the source changes
- shape. We do all of that &mdash; once, properly &mdash; so you don&rsquo;t
- have to do any of it.
+ <p class="cta-agents">
+ <span class="cta-agents-label">for agents</span>
+ <a href="{{ "llms.txt" | relURL }}"><code>GET /llms.txt</code> &rarr;</a>
+ <span class="cta-agents-note">a machine-readable invitation. No form, no salesperson.</span>
</p>
</div>
</section>
-<section id="formats" class="section section-soft">
+<section id="demo" class="section">
<div class="container">
- <span class="eyebrow center">Pick your shape</span>
- <h2 class="section-title center">One dataset. Every shape you need.</h2>
- <p class="section-lede center">
- Ask for JSON, get JSON. Ask for chunks, get chunks. Same data underneath &mdash;
- no reformatting, no glue code.
+ <p class="section-marker">§ 01 &nbsp;&middot;&nbsp; one dataset, three shapes</p>
+ <h2 class="section-headline">The same data, in whatever shape your job needs.</h2>
+ <p class="section-body">
+ Below is the <code>irs-990</code> dataset &mdash; the annual return
+ every U.S. nonprofit files with the IRS, normally distributed as a
+ sprawling PDF or wall of e-file XML. Tidy Index serves it three ways:
+ a single record for your API, a streaming bulk export for your data
+ team, or a token-efficient summary your agents can drop straight into
+ context.
</p>
- <div class="format-grid">
- <article class="format-card">
- <div class="format-icon" aria-hidden="true">
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round">
- <path d="M8 4 4 12l4 8"/>
- <path d="m16 4 4 8-4 8"/>
- </svg>
+ <div class="record">
+ <header class="record-head">
+ <span class="record-label">Dataset</span>
+ <code class="record-id">irs-990</code>
+ <span class="record-meta">1.5M filings &middot; updated daily</span>
+ </header>
+
+ <div class="record-row">
+ <div class="record-tag">
+ <span class="tag-name">record</span>
+ <span class="tag-mime">application/json</span>
+ <span class="tag-note">single filing, fully normalized</span>
</div>
- <h3>JSON</h3>
- <p>Stable schemas, stable IDs, ETags on every response. Drop it straight into your code.</p>
- </article>
+<pre class="record-body"><code><span class="tk-p">{</span>
+ <span class="tk-k">"ein"</span><span class="tk-p">:</span> <span class="tk-s">"20-0049703"</span><span class="tk-p">,</span>
+ <span class="tk-k">"name"</span><span class="tk-p">:</span> <span class="tk-s">"Wikimedia Foundation, Inc."</span><span class="tk-p">,</span>
+ <span class="tk-k">"fiscal_year"</span><span class="tk-p">:</span> <span class="tk-n">2023</span><span class="tk-p">,</span>
+ <span class="tk-k">"revenue_usd"</span><span class="tk-p">:</span> <span class="tk-n">180249000</span><span class="tk-p">,</span>
+ <span class="tk-k">"expenses_usd"</span><span class="tk-p">:</span> <span class="tk-n">169106000</span><span class="tk-p">,</span>
+ <span class="tk-k">"net_assets_usd"</span><span class="tk-p">:</span> <span class="tk-n">254971000</span><span class="tk-p">,</span>
+ <span class="tk-k">"source"</span><span class="tk-p">:</span> <span class="tk-s">"https://apps.irs.gov/app/eos/details/?ein=200049703"</span>
+<span class="tk-p">}</span></code></pre>
+ </div>
- <article class="format-card">
- <div class="format-icon" aria-hidden="true">
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round">
- <path d="M4 4h16v16H4z"/>
- <path d="M4 9h16"/>
- <path d="M9 4v16"/>
- </svg>
+ <div class="record-row">
+ <div class="record-tag">
+ <span class="tag-name">bulk</span>
+ <span class="tag-mime">application/x-ndjson</span>
+ <span class="tag-note">streaming, one record per line</span>
</div>
- <h3>XML &amp; CSV</h3>
- <p>For the pipelines that have been around longer than your team has. Strict, well-formed, no surprises.</p>
- </article>
+<pre class="record-body"><code><span class="tk-p">{</span><span class="tk-k">"ein"</span><span class="tk-p">:</span><span class="tk-s">"20-0049703"</span><span class="tk-p">,</span><span class="tk-k">"name"</span><span class="tk-p">:</span><span class="tk-s">"Wikimedia Foundation, Inc."</span><span class="tk-p">,</span><span class="tk-k">"revenue_usd"</span><span class="tk-p">:</span><span class="tk-n">180249000</span><span class="tk-p">}</span>
+<span class="tk-p">{</span><span class="tk-k">"ein"</span><span class="tk-p">:</span><span class="tk-s">"20-0097189"</span><span class="tk-p">,</span><span class="tk-k">"name"</span><span class="tk-p">:</span><span class="tk-s">"Mozilla Foundation"</span><span class="tk-p">,</span><span class="tk-k">"revenue_usd"</span><span class="tk-p">:</span><span class="tk-n">34019000</span><span class="tk-p">}</span>
+<span class="tk-p">{</span><span class="tk-k">"ein"</span><span class="tk-p">:</span><span class="tk-s">"26-1544963"</span><span class="tk-p">,</span><span class="tk-k">"name"</span><span class="tk-p">:</span><span class="tk-s">"Khan Academy, Inc."</span><span class="tk-p">,</span><span class="tk-k">"revenue_usd"</span><span class="tk-p">:</span><span class="tk-n">85436000</span><span class="tk-p">}</span>
+<span class="tk-c">&hellip;</span></code></pre>
+ </div>
- <article class="format-card">
- <div class="format-icon" aria-hidden="true">
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round">
- <circle cx="12" cy="12" r="8"/>
- <path d="M12 8v4l2 2"/>
- </svg>
+ <div class="record-row">
+ <div class="record-tag">
+ <span class="tag-name">summary</span>
+ <span class="tag-mime">text/plain</span>
+ <span class="tag-note">token-efficient, agent-ready</span>
</div>
- <h3>LLM chunks</h3>
- <p>Already chunked, already cited, already embedding-ready. Drop them into your retriever and stop fighting tokenizers.</p>
- </article>
+<pre class="record-body"><code>Wikimedia Foundation, Inc. (EIN 20-0049703) reported
+$180.25M in revenue against $169.11M in expenses on
+its 2023 Form 990, ending the year with $254.97M in
+net assets.
- <article class="format-card">
- <div class="format-icon" aria-hidden="true">
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round">
- <path d="M3 12h4l3-8 4 16 3-8h4"/>
- </svg>
- </div>
- <h3>Streaming</h3>
- <p>Webhooks and server-sent events the moment something changes. No polling, no stale caches.</p>
- </article>
+Source: https://apps.irs.gov/app/eos/details/?ein=200049703</code></pre>
+ </div>
</div>
</div>
</section>
-<section id="how" class="section">
+<section class="section section-soft">
<div class="container">
- <span class="eyebrow center">Who it&rsquo;s for</span>
- <h2 class="section-title center">Same data. Three kinds of readers.</h2>
- <p class="section-lede center">
- People, programs, and agents all want different things from the same
- dataset. Tidy Index gives each of them what they expect.
+ <p class="section-marker">§ 02 &nbsp;&middot;&nbsp; what it is</p>
+ <h2 class="section-headline">Open data and licensed data, kept tidy.</h2>
+ <p class="section-body">
+ Some of what we serve comes from the open web. The rest is licensed
+ from publishers, data vendors, and partners who&rsquo;ve trusted us with
+ their private feeds. All of it lives behind the same API, with the same
+ stable schemas, the same stable IDs, and the same freshness guarantees
+ &mdash; and one key gets you every record in every shape your tools
+ (or your agents) prefer.
</p>
-
- <div class="audience-grid">
- <div class="audience-card">
- <div class="audience-num">01</div>
- <h3>For humans</h3>
- <p>
- A real web UI. Skim a schema, preview a few rows, grab a snapshot,
- and copy a working curl command without leaving the page.
- </p>
- </div>
-
- <div class="audience-card audience-card-feature">
- <div class="audience-num">02</div>
- <h3>For computers</h3>
- <p>
- Boring REST, the way you like it. OpenAPI specs, semver, ETags,
- idempotent reads, and rate limits we&rsquo;ll actually tell you about.
- </p>
- </div>
-
- <div class="audience-card">
- <div class="audience-num">03</div>
- <h3>For LLM agents</h3>
- <p>
- Endpoints shaped like tool calls. Chunks shaped like context. Every
- response carries its own provenance, so the model never has to guess
- where the data came from.
- </p>
- </div>
- </div>
</div>
</section>
-<section class="section section-soft">
- <div class="container narrow">
- <span class="eyebrow center">Why Tidy Index</span>
- <h2 class="section-title center">Less wrangling. More building.</h2>
+<section class="section section-coverage">
+ <div class="container container-wide">
+ <p class="section-marker">§ 03 &nbsp;&middot;&nbsp; what we cover</p>
+ <h2 class="section-headline">The index, abridged.</h2>
+ <p class="section-body">
+ A small slice of what&rsquo;s already in the catalog.
+ </p>
- <ul class="value-list">
- <li>
- <span class="value-check" aria-hidden="true">
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
- <polyline points="20 6 9 17 4 12"/>
- </svg>
- </span>
- <div>
- <strong>Curated, not crawled.</strong>
- <p>A human looks at every dataset before it ships. We&rsquo;d rather have ten that are right than ten thousand that are almost right.</p>
- </div>
- </li>
- <li>
- <span class="value-check" aria-hidden="true">
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
- <polyline points="20 6 9 17 4 12"/>
- </svg>
- </span>
- <div>
- <strong>Schemas that don&rsquo;t move under you.</strong>
- <p>Versioned endpoints, deprecation windows, and a changelog you can subscribe to. If something&rsquo;s about to break, you&rsquo;ll be the first to know.</p>
- </div>
- </li>
- <li>
- <span class="value-check" aria-hidden="true">
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
- <polyline points="20 6 9 17 4 12"/>
- </svg>
- </span>
- <div>
- <strong>Every record has a receipt.</strong>
- <p>Each row links back to where it came from. Your auditors will love it. Your models will stop making things up.</p>
+ <div class="catalog">
+ {{ range $.Site.Data.catalog.categories }}
+ <div class="catalog-col">
+ <span class="catalog-cat">{{ .name }}</span>
+ <div class="catalog-window">
+ <ul class="catalog-list">
+ {{ range .items }}<li>{{ . }}</li>
+ {{ end }}{{ range .items }}<li aria-hidden="true">{{ . }}</li>
+ {{ end }}
+ </ul>
</div>
- </li>
- <li>
- <span class="value-check" aria-hidden="true">
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
- <polyline points="20 6 9 17 4 12"/>
- </svg>
- </span>
- <div>
- <strong>One key, every format.</strong>
- <p>JSON, XML, CSV, or LLM chunks. Flip a header &mdash; same data, different shape.</p>
- </div>
- </li>
- </ul>
+ </div>
+ {{ end }}
+ </div>
+
+ <p class="catalog-more"><strong>100+ datasets</strong> &mdash; and the next one we add is whichever one you ask for.</p>
</div>
</section>
-<section id="contact" class="section">
- <div class="container narrow">
- <div class="cta-card">
- <span class="cta-glow" aria-hidden="true"></span>
- <h2 class="cta-title">Ready when you are.</h2>
- <a href="mailto:hello@tidyindex.com" class="btn btn-primary btn-lg cta-btn">
+<section class="section section-cta">
+ <div class="container">
+ <div class="cta-block">
+ <div class="cta-text">
+ <p class="section-marker">§ 04 &nbsp;&middot;&nbsp; start</p>
+ <h2 class="section-headline">Ready when you are.</h2>
+ </div>
+ <a href="mailto:contact@tidyindex.com" class="btn btn-primary btn-lg">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<circle cx="7.5" cy="15.5" r="5.5"/>
<path d="m11.5 11.5 9.5-9.5"/>
diff --git a/landing/layouts/partials/footer.html b/landing/layouts/partials/footer.html
index d6588fe..35cfacc 100644
--- a/landing/layouts/partials/footer.html
+++ b/landing/layouts/partials/footer.html
@@ -1,6 +1,6 @@
<footer class="site-footer">
<div class="container footer-inner">
- <div class="footer-brand">
+ <div class="footer-line">
<span class="brand-mark" aria-hidden="true">
<svg viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="4" y="6" width="24" height="3" rx="1.5" fill="currentColor"/>
@@ -8,9 +8,14 @@
<rect x="4" y="22" width="12" height="3" rx="1.5" fill="currentColor" opacity="0.4"/>
</svg>
</span>
- <span>Tidy Index</span>
+ <span class="footer-name">Tidy Index</span>
+ <span class="footer-sep">·</span>
+ <span class="footer-tagline">Structured data, served simply.</span>
</div>
- <p class="footer-tagline">Structured data, served simply.</p>
- <p class="footer-meta">&copy; {{ now.Year }} Tidy Index. All rights reserved.</p>
+ <p class="footer-meta">
+ <a href="mailto:contact@tidyindex.com">contact@tidyindex.com</a>
+ <span class="footer-sep">·</span>
+ &copy; {{ now.Year }}
+ </p>
</div>
</footer>
diff --git a/landing/layouts/partials/header.html b/landing/layouts/partials/header.html
index 5f6d85b..e7a9d40 100644
--- a/landing/layouts/partials/header.html
+++ b/landing/layouts/partials/header.html
@@ -8,13 +8,11 @@
<rect x="4" y="22" width="12" height="3" rx="1.5" fill="currentColor" opacity="0.4"/>
</svg>
</span>
- <span class="brand-name">Tidy Index</span>
+ <span class="brand-name">Tidy&nbsp;Index</span>
</a>
- <nav class="site-nav" aria-label="Primary">
- <a href="#what">What</a>
- <a href="#formats">Formats</a>
- <a href="#how">How it works</a>
- <a href="#contact" class="nav-cta">Get access</a>
- </nav>
+ <div class="header-meta">
+ <span class="header-status"><span class="status-dot" aria-hidden="true"></span> Private beta</span>
+ <a href="mailto:contact@tidyindex.com" class="header-cta">API&nbsp;Key &rarr;</a>
+ </div>
</div>
</header>
diff --git a/landing/static/css/style.css b/landing/static/css/style.css
index 30665f6..33ddc1b 100644
--- a/landing/static/css/style.css
+++ b/landing/static/css/style.css
@@ -1,137 +1,147 @@
/* ----------------------------------------------------------------
- Tidy Index — landing styles
- Palette: whites, soft blues, generous space.
+ Tidy Index — landing styles (editorial revision)
+
+ The site is a typeset document, not a SaaS template.
+ Light palette, generous space, serif headlines, monospace
+ labels, hairline rules.
---------------------------------------------------------------- */
:root {
--c-bg: #ffffff;
- --c-bg-soft: #f6f9fc;
+ --c-bg-soft: #f7f9fc;
--c-bg-tint: #eef4fb;
- --c-border: #e3ecf5;
- --c-border-soft: #eef2f7;
+
+ --c-rule: #e3ecf5;
+ --c-rule-strong: #cbd6e6;
--c-ink: #0b1f3a;
--c-ink-soft: #3b4f6b;
--c-ink-mute: #6b7c93;
- --c-blue: #3b82f6;
- --c-blue-deep: #2563eb;
+ --c-blue: #2563eb;
+ --c-blue-deep: #1d4ed8;
--c-blue-soft: #dbeafe;
--c-blue-tint: #eef4ff;
- --c-accent: #60a5fa;
-
--shadow-sm: 0 1px 2px rgba(15, 38, 73, 0.04);
- --shadow-md: 0 6px 24px -8px rgba(37, 99, 235, 0.18),
- 0 2px 6px rgba(15, 38, 73, 0.04);
- --shadow-lg: 0 24px 60px -20px rgba(37, 99, 235, 0.25),
- 0 6px 16px rgba(15, 38, 73, 0.06);
+ --shadow-md: 0 8px 28px -10px rgba(37, 99, 235, 0.18),
+ 0 2px 6px rgba(15, 38, 73, 0.05);
- --radius-sm: 8px;
- --radius-md: 14px;
- --radius-lg: 22px;
+ --radius-sm: 6px;
+ --radius-md: 12px;
+ --radius-lg: 18px;
+ --font-serif: 'Fraunces', 'Iowan Old Style', Georgia, 'Times New Roman', serif;
--font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI',
Helvetica, Arial, sans-serif;
--font-mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo,
Consolas, monospace;
- --max-w: 1120px;
- --max-w-narrow: 760px;
+ --max-w: 960px;
+ --max-w-wide: 1080px;
+ --gutter: clamp(20px, 4vw, 40px);
}
* { box-sizing: border-box; }
-html { -webkit-text-size-adjust: 100%; }
+html {
+ -webkit-text-size-adjust: 100%;
+}
body {
margin: 0;
font-family: var(--font-sans);
font-size: 17px;
- line-height: 1.6;
+ line-height: 1.65;
color: var(--c-ink);
background: var(--c-bg);
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
- background-image:
- radial-gradient(ellipse 80% 50% at 50% -10%, var(--c-blue-tint), transparent 70%),
- radial-gradient(ellipse 60% 40% at 90% 10%, #f0f7ff, transparent 70%);
- background-repeat: no-repeat;
}
a {
- color: var(--c-blue-deep);
+ color: var(--c-blue);
text-decoration: none;
transition: color 160ms ease;
}
-a:hover { color: var(--c-blue); }
+a:hover { color: var(--c-blue-deep); }
img, svg { display: block; max-width: 100%; }
-/* ---------- layout helpers ---------- */
+::selection {
+ background: var(--c-blue-soft);
+ color: var(--c-ink);
+}
+
+/* ---------- layout ---------- */
.container {
width: 100%;
max-width: var(--max-w);
margin: 0 auto;
- padding: 0 24px;
+ padding: 0 var(--gutter);
}
-.container.narrow { max-width: var(--max-w-narrow); }
-
-.eyebrow {
- display: inline-block;
- font-size: 13px;
- font-weight: 500;
- letter-spacing: 0.08em;
- text-transform: uppercase;
- color: var(--c-blue-deep);
- background: var(--c-blue-tint);
- padding: 6px 12px;
- border-radius: 999px;
- border: 1px solid var(--c-blue-soft);
+.container-wide {
+ max-width: var(--max-w-wide);
}
-.eyebrow.center { display: inline-block; }
-
-.center { text-align: center; }
-.center.eyebrow { display: inline-block; }
.section {
- padding: 120px 0;
+ padding: 96px 0;
+ border-top: 1px solid var(--c-rule);
}
+.section:first-of-type { border-top: 0; }
+
.section-soft {
background: var(--c-bg-soft);
- border-top: 1px solid var(--c-border-soft);
- border-bottom: 1px solid var(--c-border-soft);
}
-.section-title {
- font-size: clamp(28px, 4vw, 44px);
- line-height: 1.15;
- font-weight: 600;
- letter-spacing: -0.02em;
- margin: 18px 0 18px;
+/* ---------- shared element styles ---------- */
+
+.section-marker {
+ margin: 0 0 22px;
+ font-family: var(--font-mono);
+ font-size: 12px;
+ font-weight: 500;
+ letter-spacing: 0.04em;
+ color: var(--c-blue);
+ text-transform: lowercase;
+}
+
+.section-headline {
+ margin: 0 0 28px;
+ font-family: var(--font-serif);
+ font-variation-settings: 'opsz' 144, 'SOFT' 30;
+ font-weight: 400;
+ font-size: clamp(32px, 4.6vw, 52px);
+ line-height: 1.08;
+ letter-spacing: -0.018em;
color: var(--c-ink);
+ max-width: 22ch;
}
-.section-title.center { text-align: center; max-width: 720px; margin-left: auto; margin-right: auto; }
-.section-lede {
- font-size: 19px;
- color: var(--c-ink-soft);
- max-width: 640px;
- margin: 0 auto 60px;
+.section-headline em {
+ font-style: italic;
+ font-variation-settings: 'opsz' 144, 'SOFT' 100;
+ color: var(--c-blue);
+}
+
+.section-body {
+ margin: 0 0 48px;
+ font-size: 18px;
line-height: 1.6;
+ color: var(--c-ink-soft);
+ max-width: 60ch;
}
-.section-lede.center { text-align: center; }
-/* center the eyebrow when wrapped */
-.section .eyebrow.center,
-.container .eyebrow.center {
- display: block;
- margin-left: auto;
- margin-right: auto;
- width: max-content;
+code {
+ font-family: var(--font-mono);
+ font-size: 0.92em;
+ background: var(--c-bg-soft);
+ padding: 1px 6px;
+ border-radius: 4px;
+ color: var(--c-ink);
}
/* ---------- header ---------- */
@@ -140,64 +150,80 @@ img, svg { display: block; max-width: 100%; }
position: sticky;
top: 0;
z-index: 50;
- background: rgba(255, 255, 255, 0.78);
- backdrop-filter: saturate(180%) blur(14px);
- -webkit-backdrop-filter: saturate(180%) blur(14px);
- border-bottom: 1px solid var(--c-border-soft);
+ background: rgba(255, 255, 255, 0.85);
+ backdrop-filter: saturate(180%) blur(16px);
+ -webkit-backdrop-filter: saturate(180%) blur(16px);
+ border-bottom: 1px solid var(--c-rule);
}
.header-inner {
display: flex;
align-items: center;
justify-content: space-between;
- height: 72px;
+ height: 68px;
}
.brand {
display: inline-flex;
align-items: center;
- gap: 10px;
- font-weight: 600;
- font-size: 17px;
+ gap: 12px;
+ font-family: var(--font-serif);
+ font-variation-settings: 'opsz' 24;
+ font-weight: 500;
+ font-size: 19px;
+ letter-spacing: -0.005em;
color: var(--c-ink);
- letter-spacing: -0.01em;
}
-.brand:hover { color: var(--c-blue-deep); }
+.brand:hover { color: var(--c-blue); }
.brand-mark {
display: inline-flex;
align-items: center;
justify-content: center;
- width: 32px; height: 32px;
- color: var(--c-blue-deep);
- background: var(--c-blue-tint);
- border-radius: 9px;
- border: 1px solid var(--c-blue-soft);
+ width: 30px;
+ height: 30px;
+ color: var(--c-blue);
}
-.brand-mark svg { width: 20px; height: 20px; }
+.brand-mark svg { width: 22px; height: 22px; }
-.site-nav {
+.header-meta {
display: flex;
align-items: center;
- gap: 32px;
+ gap: 28px;
}
-.site-nav a {
- color: var(--c-ink-soft);
- font-size: 15px;
- font-weight: 500;
+
+.header-status {
+ display: inline-flex;
+ align-items: center;
+ gap: 8px;
+ font-family: var(--font-mono);
+ font-size: 12px;
+ letter-spacing: 0.03em;
+ color: var(--c-ink-mute);
+ text-transform: lowercase;
}
-.site-nav a:hover { color: var(--c-blue-deep); }
-.nav-cta {
- background: var(--c-ink);
- color: #fff !important;
- padding: 9px 16px;
- border-radius: 999px;
- transition: transform 160ms ease, background 160ms ease;
+.status-dot {
+ width: 7px;
+ height: 7px;
+ border-radius: 50%;
+ background: #34d399;
+ box-shadow: 0 0 0 3px rgba(52, 211, 153, 0.18);
}
-.nav-cta:hover {
- background: var(--c-blue-deep);
- transform: translateY(-1px);
+
+.header-cta {
+ font-family: var(--font-mono);
+ font-size: 13px;
+ font-weight: 500;
+ color: var(--c-ink);
+ letter-spacing: 0.01em;
+ border-bottom: 1px solid var(--c-ink);
+ padding-bottom: 1px;
+ transition: color 160ms ease, border-color 160ms ease;
+}
+.header-cta:hover {
+ color: var(--c-blue);
+ border-color: var(--c-blue);
}
/* ---------- buttons ---------- */
@@ -206,10 +232,11 @@ img, svg { display: block; max-width: 100%; }
display: inline-flex;
align-items: center;
justify-content: center;
- font-family: inherit;
- font-size: 16px;
+ gap: 10px;
+ font-family: var(--font-sans);
+ font-size: 15px;
font-weight: 500;
- padding: 14px 24px;
+ padding: 13px 22px;
border-radius: 999px;
border: 1px solid transparent;
cursor: pointer;
@@ -217,421 +244,536 @@ img, svg { display: block; max-width: 100%; }
letter-spacing: -0.005em;
}
+.btn svg {
+ width: 17px;
+ height: 17px;
+}
+
.btn-primary {
- background: var(--c-blue-deep);
+ background: var(--c-ink);
color: #fff;
- box-shadow: 0 6px 18px -6px rgba(37, 99, 235, 0.5);
+ box-shadow: 0 6px 18px -8px rgba(11, 31, 58, 0.5);
}
.btn-primary:hover {
- background: #1d4ed8;
+ background: var(--c-blue);
color: #fff;
transform: translateY(-1px);
- box-shadow: 0 10px 24px -8px rgba(37, 99, 235, 0.55);
+ box-shadow: 0 10px 22px -8px rgba(37, 99, 235, 0.5);
}
-.btn-ghost {
- background: transparent;
- color: var(--c-ink);
- border-color: var(--c-border);
+.btn-lg {
+ padding: 16px 26px;
+ font-size: 16px;
}
-.btn-ghost:hover {
- background: #fff;
- border-color: var(--c-blue-soft);
- color: var(--c-blue-deep);
+.btn-lg svg {
+ width: 18px;
+ height: 18px;
}
-.btn-lg {
- padding: 16px 30px;
- font-size: 16px;
+.btn-link {
+ display: inline-flex;
+ align-items: center;
+ gap: 6px;
+ font-family: var(--font-sans);
+ font-size: 15px;
+ font-weight: 500;
+ color: var(--c-ink-soft);
+ border-bottom: 1px solid var(--c-rule-strong);
+ padding-bottom: 1px;
+}
+.btn-link:hover {
+ color: var(--c-blue);
+ border-color: var(--c-blue);
}
/* ---------- hero ---------- */
.hero {
- padding: 120px 0 80px;
+ padding: 140px 0 110px;
position: relative;
overflow: hidden;
}
-.hero-inner {
- text-align: center;
- position: relative;
+.hero::before {
+ content: "";
+ position: absolute;
+ top: -200px;
+ right: -200px;
+ width: 600px;
+ height: 600px;
+ background: radial-gradient(closest-side, rgba(96, 165, 250, 0.20), rgba(96, 165, 250, 0) 70%);
+ pointer-events: none;
+ z-index: 0;
}
-.hero .eyebrow {
- margin-bottom: 28px;
+.hero .container {
+ position: relative;
+ z-index: 1;
}
-.hero-title {
- font-size: clamp(40px, 6vw, 76px);
- line-height: 1.05;
- font-weight: 600;
- letter-spacing: -0.035em;
- margin: 0 auto 24px;
- max-width: 12ch;
+.hero-headline {
+ margin: 0 0 32px;
+ font-family: var(--font-serif);
+ font-variation-settings: 'opsz' 144, 'SOFT' 30;
+ font-weight: 400;
+ font-size: clamp(44px, 7.4vw, 92px);
+ line-height: 1.02;
+ letter-spacing: -0.025em;
color: var(--c-ink);
+ max-width: 14ch;
}
-.hero-title .accent {
- background: linear-gradient(120deg, var(--c-blue-deep), var(--c-accent));
- -webkit-background-clip: text;
- background-clip: text;
- color: transparent;
+.hero-headline em {
+ font-style: italic;
+ font-variation-settings: 'opsz' 144, 'SOFT' 100;
+ color: var(--c-blue);
+ font-weight: 400;
}
.hero-sub {
+ margin: 0 0 44px;
font-size: 20px;
line-height: 1.55;
color: var(--c-ink-soft);
- max-width: 600px;
- margin: 0 auto 40px;
+ max-width: 56ch;
}
.hero-cta {
display: flex;
- gap: 14px;
- justify-content: center;
+ align-items: center;
+ gap: 28px;
flex-wrap: wrap;
- margin-bottom: 80px;
}
-/* ---------- code card ---------- */
+/* ---------- record demo ---------- */
+
+.record {
+ margin-top: 8px;
+ background: #fff;
+ border: 1px solid var(--c-rule);
+ border-radius: var(--radius-md);
+ box-shadow: var(--shadow-sm);
+ overflow: hidden;
+}
-.hero-visual {
+.record-head {
display: flex;
- justify-content: center;
- margin-top: 16px;
+ align-items: baseline;
+ gap: 14px;
+ padding: 18px 26px;
+ background: var(--c-bg-soft);
+ border-bottom: 1px solid var(--c-rule);
}
-.code-card {
- width: 100%;
- max-width: 640px;
- background: #ffffff;
- border: 1px solid var(--c-border);
- border-radius: var(--radius-lg);
- box-shadow: var(--shadow-lg);
- overflow: hidden;
- text-align: left;
- position: relative;
+.record-label {
+ font-family: var(--font-mono);
+ font-size: 11px;
+ font-weight: 500;
+ letter-spacing: 0.1em;
+ text-transform: uppercase;
+ color: var(--c-ink-mute);
}
-.code-card::before {
- content: "";
- position: absolute;
- inset: -1px;
- border-radius: inherit;
- padding: 1px;
- background: linear-gradient(160deg, rgba(96,165,250,0.4), rgba(255,255,255,0) 60%);
- -webkit-mask:
- linear-gradient(#000 0 0) content-box,
- linear-gradient(#000 0 0);
- -webkit-mask-composite: xor;
- mask-composite: exclude;
- pointer-events: none;
+.record-id {
+ font-family: var(--font-mono);
+ font-size: 14px;
+ font-weight: 500;
+ color: var(--c-ink);
+ background: transparent;
+ padding: 0;
}
-.code-card-head {
+.record-meta {
+ margin-left: auto;
+ font-family: var(--font-mono);
+ font-size: 12px;
+ color: var(--c-ink-mute);
+}
+
+.record-row {
+ display: grid;
+ grid-template-columns: 200px 1fr;
+ border-top: 1px solid var(--c-rule);
+}
+
+.record-row:first-of-type {
+ border-top: 0;
+}
+
+.record-tag {
display: flex;
- align-items: center;
- gap: 8px;
- padding: 14px 18px;
- background: var(--c-bg-soft);
- border-bottom: 1px solid var(--c-border-soft);
+ flex-direction: column;
+ justify-content: flex-start;
+ padding: 24px 26px;
+ background: #fff;
+ border-right: 1px solid var(--c-rule);
}
-.code-card-head .dot {
- width: 10px; height: 10px;
- border-radius: 50%;
- background: #d6dde7;
+.tag-name {
+ font-family: var(--font-serif);
+ font-variation-settings: 'opsz' 36, 'SOFT' 50;
+ font-weight: 500;
+ font-size: 22px;
+ font-style: italic;
+ color: var(--c-blue);
+ margin-bottom: 4px;
}
-.dot-a { background: #ffd1d1; }
-.dot-b { background: #ffe5b4; }
-.dot-c { background: #c8e6c9; }
-.code-card-title {
- margin-left: 12px;
+.tag-mime {
font-family: var(--font-mono);
- font-size: 13px;
+ font-size: 11px;
+ letter-spacing: 0.02em;
color: var(--c-ink-mute);
}
-.code-card-body {
+.tag-note {
+ display: block;
+ margin-top: 10px;
+ font-family: var(--font-sans);
+ font-size: 12px;
+ line-height: 1.4;
+ color: var(--c-ink-mute);
+ max-width: 18ch;
+}
+
+.record-body {
margin: 0;
- padding: 22px 24px;
+ padding: 22px 26px;
font-family: var(--font-mono);
font-size: 13.5px;
- line-height: 1.65;
+ line-height: 1.7;
color: var(--c-ink-soft);
- background: #ffffff;
+ background: #fff;
overflow-x: auto;
white-space: pre;
}
-.code-card-body code { font-family: inherit; }
+.record-body code {
+ background: transparent;
+ padding: 0;
+ font-size: inherit;
+ color: inherit;
+}
.tk-k { color: #2563eb; }
.tk-s { color: #0f766e; }
.tk-n { color: #b45309; }
.tk-p { color: #94a3b8; }
+.tk-x { color: #7c3aed; }
+.tk-c { color: #cbd6e6; }
-/* ---------- format grid ---------- */
+/* ---------- catalog (dataset coverage widget) ---------- */
-.format-grid {
+.catalog {
+ margin: 8px 0 22px;
display: grid;
grid-template-columns: repeat(4, 1fr);
- gap: 20px;
- margin-top: 20px;
+ border-top: 1px solid var(--c-rule-strong);
+ border-bottom: 1px solid var(--c-rule);
}
-.format-card {
- background: #fff;
- border: 1px solid var(--c-border);
- border-radius: var(--radius-md);
- padding: 32px 26px;
- box-shadow: var(--shadow-sm);
- transition: transform 200ms ease, box-shadow 200ms ease, border-color 200ms ease;
+.catalog-col {
+ padding: 30px 24px;
+ border-right: 1px solid var(--c-rule);
}
-.format-card:hover {
- transform: translateY(-3px);
- border-color: var(--c-blue-soft);
- box-shadow: var(--shadow-md);
+.catalog-col:first-child { padding-left: 0; }
+.catalog-col:last-child {
+ border-right: 0;
+ padding-right: 0;
}
-.format-icon {
- display: inline-flex;
- width: 44px;
- height: 44px;
- align-items: center;
- justify-content: center;
- border-radius: 12px;
- background: var(--c-blue-tint);
- color: var(--c-blue-deep);
+.catalog-cat {
+ display: block;
+ font-family: var(--font-mono);
+ font-size: 11px;
+ font-weight: 500;
+ letter-spacing: 0.07em;
+ color: var(--c-blue);
+ text-transform: lowercase;
margin-bottom: 18px;
}
-.format-icon svg { width: 22px; height: 22px; }
-
-.format-card h3 {
- margin: 0 0 8px;
- font-size: 18px;
- font-weight: 600;
- letter-spacing: -0.01em;
- color: var(--c-ink);
-}
-.format-card p {
- margin: 0;
- font-size: 15px;
- line-height: 1.55;
- color: var(--c-ink-mute);
-}
-
-/* ---------- audience grid ---------- */
-
-.audience-grid {
- display: grid;
- grid-template-columns: repeat(3, 1fr);
- gap: 24px;
- margin-top: 20px;
-}
-
-.audience-card {
+.catalog-window {
position: relative;
- background: #fff;
- border: 1px solid var(--c-border);
- border-radius: var(--radius-lg);
- padding: 40px 32px;
- box-shadow: var(--shadow-sm);
- transition: transform 200ms ease, box-shadow 200ms ease;
+ height: 188px;
+ overflow: hidden;
+ -webkit-mask-image: linear-gradient(
+ to bottom,
+ transparent 0%,
+ #000 14%,
+ #000 86%,
+ transparent 100%
+ );
+ mask-image: linear-gradient(
+ to bottom,
+ transparent 0%,
+ #000 14%,
+ #000 86%,
+ transparent 100%
+ );
+}
+
+.catalog-list {
+ margin: 0;
+ padding: 0;
+ list-style: none;
+ display: flex;
+ flex-direction: column;
+ gap: 11px;
+ animation: catalog-scroll 64s linear infinite;
+ will-change: transform;
}
-.audience-card:hover {
- transform: translateY(-3px);
- box-shadow: var(--shadow-md);
+.catalog-col:hover .catalog-list {
+ animation-play-state: paused;
}
-.audience-card-feature {
- background: linear-gradient(180deg, #ffffff 0%, var(--c-blue-tint) 130%);
- border-color: var(--c-blue-soft);
-}
+/* Stagger speeds slightly so columns don't move in lockstep */
+.catalog-col:nth-child(1) .catalog-list { animation-duration: 58s; }
+.catalog-col:nth-child(2) .catalog-list { animation-duration: 72s; }
+.catalog-col:nth-child(3) .catalog-list { animation-duration: 64s; }
+.catalog-col:nth-child(4) .catalog-list { animation-duration: 68s; }
-.audience-num {
- font-family: var(--font-mono);
- font-size: 13px;
- font-weight: 500;
- color: var(--c-blue-deep);
- letter-spacing: 0.04em;
- margin-bottom: 16px;
+@keyframes catalog-scroll {
+ from { transform: translateY(0); }
+ to { transform: translateY(-50%); }
}
-.audience-card h3 {
- margin: 0 0 12px;
- font-size: 22px;
- font-weight: 600;
- letter-spacing: -0.015em;
+.catalog-list li {
+ font-family: var(--font-serif);
+ font-variation-settings: 'opsz' 14, 'SOFT' 30;
+ font-weight: 400;
+ font-size: 15px;
+ line-height: 1.3;
color: var(--c-ink);
}
-.audience-card p {
+.catalog-more {
margin: 0;
- color: var(--c-ink-soft);
- font-size: 16px;
- line-height: 1.6;
+ font-family: var(--font-mono);
+ font-size: 12px;
+ letter-spacing: 0.02em;
+ color: var(--c-ink-mute);
+ text-align: right;
+}
+.catalog-more strong {
+ font-weight: 500;
+ color: var(--c-blue);
}
-/* ---------- value list ---------- */
+/* ---------- CTA section ---------- */
-.value-list {
- list-style: none;
- padding: 0;
- margin: 40px 0 0;
- display: grid;
- gap: 22px;
+.section-cta {
+ padding: 110px 0 130px;
}
-.value-list li {
+.cta-block {
display: flex;
- align-items: flex-start;
- gap: 18px;
- background: #fff;
- border: 1px solid var(--c-border);
- border-radius: var(--radius-md);
- padding: 22px 26px;
- box-shadow: var(--shadow-sm);
-}
-
-.value-check {
- display: inline-flex;
align-items: center;
- justify-content: center;
- width: 36px;
- height: 36px;
- flex: 0 0 36px;
- border-radius: 50%;
- background: var(--c-blue-tint);
- color: var(--c-blue-deep);
-}
-.value-check svg { width: 18px; height: 18px; }
-
-.value-list strong {
- display: block;
- font-weight: 600;
- font-size: 17px;
- color: var(--c-ink);
- margin-bottom: 4px;
+ justify-content: space-between;
+ gap: 40px;
+ padding-top: 56px;
+ border-top: 1px solid var(--c-rule-strong);
+ position: relative;
}
-.value-list p {
- margin: 0;
- color: var(--c-ink-mute);
- font-size: 15.5px;
- line-height: 1.55;
+.cta-block::before {
+ content: "";
+ position: absolute;
+ top: -1px;
+ left: 0;
+ width: 80px;
+ height: 2px;
+ background: var(--c-blue);
}
-/* ---------- CTA card ---------- */
+.cta-block .section-marker { margin-bottom: 14px; }
+.cta-block .section-headline { margin: 0; }
-.cta-card {
- position: relative;
+.cta-agents {
+ margin: 24px 0 0;
display: flex;
- flex-direction: column;
align-items: center;
- background: linear-gradient(160deg, #ffffff 0%, var(--c-blue-tint) 100%);
- border: 1px solid var(--c-blue-soft);
- border-radius: var(--radius-lg);
- padding: 72px 40px;
- box-shadow: var(--shadow-md);
- overflow: hidden;
+ flex-wrap: wrap;
+ gap: 14px;
+ font-family: var(--font-mono);
+ font-size: 12px;
+ line-height: 1.5;
+ color: var(--c-ink-mute);
}
-.cta-glow {
- position: absolute;
- top: -120px;
- left: 50%;
- width: 360px;
- height: 360px;
- transform: translateX(-50%);
- background: radial-gradient(closest-side, rgba(96, 165, 250, 0.35), rgba(96, 165, 250, 0) 70%);
- pointer-events: none;
- z-index: 0;
+.cta-agents-label {
+ font-weight: 500;
+ letter-spacing: 0.06em;
+ text-transform: lowercase;
+ color: var(--c-blue);
}
-.cta-title {
- position: relative;
- z-index: 1;
- margin: 0 0 28px;
- font-size: clamp(26px, 3.4vw, 36px);
- font-weight: 600;
- letter-spacing: -0.02em;
+.cta-agents a {
+ display: inline-flex;
+ align-items: center;
+ gap: 6px;
color: var(--c-ink);
- text-align: center;
+ border-bottom: 1px solid var(--c-rule-strong);
+ padding-bottom: 1px;
+ transition: color 160ms ease, border-color 160ms ease;
}
-
-.cta-btn {
- position: relative;
- z-index: 1;
- gap: 10px;
+.cta-agents a code {
+ background: transparent;
+ padding: 0;
+ font-size: 12px;
+ color: inherit;
+}
+.cta-agents a:hover {
+ color: var(--c-blue);
+ border-color: var(--c-blue);
}
-.cta-btn svg {
- width: 18px;
- height: 18px;
+.cta-agents-note {
+ font-style: italic;
+ color: var(--c-ink-mute);
}
/* ---------- footer ---------- */
.site-footer {
- border-top: 1px solid var(--c-border-soft);
+ border-top: 1px solid var(--c-rule);
background: var(--c-bg);
- padding: 60px 0 50px;
+ padding: 40px 0;
}
.footer-inner {
- text-align: center;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 24px;
+ flex-wrap: wrap;
}
-.footer-brand {
+.footer-line {
display: inline-flex;
align-items: center;
- gap: 10px;
- font-weight: 600;
+ gap: 12px;
+ font-size: 14px;
+ color: var(--c-ink-soft);
+}
+.footer-line .brand-mark { color: var(--c-blue); }
+.footer-line .brand-mark svg { width: 18px; height: 18px; }
+
+.footer-name {
+ font-family: var(--font-serif);
+ font-variation-settings: 'opsz' 24;
+ font-weight: 500;
color: var(--c-ink);
- margin-bottom: 14px;
}
-.footer-brand .brand-mark { color: var(--c-blue-deep); }
-.footer-brand .brand-mark svg { width: 20px; height: 20px; }
.footer-tagline {
- margin: 0 0 12px;
- color: var(--c-ink-soft);
- font-size: 15px;
+ font-style: italic;
+ color: var(--c-ink-mute);
+}
+
+.footer-sep {
+ color: var(--c-rule-strong);
}
.footer-meta {
margin: 0;
+ font-family: var(--font-mono);
+ font-size: 12px;
color: var(--c-ink-mute);
- font-size: 13px;
+}
+.footer-meta a {
+ color: var(--c-ink-soft);
+ border-bottom: 1px solid var(--c-rule-strong);
+}
+.footer-meta a:hover {
+ color: var(--c-blue);
+ border-color: var(--c-blue);
}
/* ---------- responsive ---------- */
-@media (max-width: 880px) {
- .format-grid { grid-template-columns: repeat(2, 1fr); }
- .audience-grid { grid-template-columns: 1fr; }
- .section { padding: 90px 0; }
- .hero { padding: 80px 0 40px; }
-}
-
-@media (max-width: 640px) {
+@media (max-width: 1020px) {
+ .catalog {
+ grid-template-columns: repeat(2, 1fr);
+ border-bottom: 0;
+ }
+ .catalog-col {
+ padding: 28px 24px;
+ border-right: 1px solid var(--c-rule);
+ border-bottom: 1px solid var(--c-rule);
+ }
+ .catalog-col:first-child { padding-left: 24px; }
+ .catalog-col:last-child {
+ border-right: 1px solid var(--c-rule);
+ padding-right: 24px;
+ }
+ .catalog-col:nth-child(2n) { border-right: 0; padding-right: 0; }
+ .catalog-col:nth-child(2n+1) { padding-left: 0; }
+ .catalog-col:nth-last-child(-n+2) { border-bottom: 0; }
+}
+
+@media (max-width: 820px) {
+ .section { padding: 72px 0; }
+ .hero { padding: 90px 0 70px; }
+ .section-cta { padding: 80px 0 100px; }
+
+ .record-row {
+ grid-template-columns: 1fr;
+ }
+ .record-tag {
+ flex-direction: row;
+ align-items: baseline;
+ gap: 12px;
+ padding: 16px 22px;
+ border-right: 0;
+ border-bottom: 1px solid var(--c-rule);
+ background: var(--c-bg-soft);
+ }
+ .tag-name { margin-bottom: 0; font-size: 18px; }
+
+ .cta-block {
+ flex-direction: column;
+ align-items: flex-start;
+ }
+}
+
+@media (max-width: 620px) {
+ .catalog {
+ grid-template-columns: 1fr;
+ }
+ .catalog-col {
+ padding: 24px 0;
+ border-right: 0;
+ border-bottom: 1px solid var(--c-rule);
+ }
+ .catalog-col:first-child { padding-top: 24px; }
+ .catalog-col:last-child { border-bottom: 0; padding-bottom: 0; }
+}
+
+@media (max-width: 560px) {
body { font-size: 16px; }
- .site-nav { gap: 18px; }
- .site-nav a:not(.nav-cta) { display: none; }
- .header-inner { height: 64px; }
- .hero-cta { flex-direction: column; align-items: stretch; }
- .hero-cta .btn { width: 100%; }
- .code-card-body { font-size: 12px; padding: 18px; }
- .format-grid { grid-template-columns: 1fr; }
- .cta-card { padding: 40px 24px; }
+ .header-status { display: none; }
+ .header-inner { height: 60px; }
+ .hero-cta { gap: 18px; }
+ .record-head { flex-wrap: wrap; padding: 16px 20px; }
+ .record-meta { margin-left: 0; flex-basis: 100%; }
+ .record-body { font-size: 12.5px; padding: 18px 20px; }
+ .footer-inner { flex-direction: column; align-items: flex-start; }
}
@media (prefers-reduced-motion: reduce) {
* { transition: none !important; }
+
+ .catalog-window {
+ overflow-y: auto;
+ -webkit-mask-image: none;
+ mask-image: none;
+ }
+ .catalog-list {
+ animation: none;
+ }
+ .catalog-list li[aria-hidden="true"] {
+ display: none;
+ }
}
diff --git a/landing/static/llms.txt b/landing/static/llms.txt
new file mode 100644
index 0000000..9cf358a
--- /dev/null
+++ b/landing/static/llms.txt
@@ -0,0 +1,99 @@
+# Tidy Index
+
+> Clean, well-structured datasets for humans, machines, and LLM agents.
+> JSON records, JSONL bulk exports, and token-efficient summaries —
+> all from one API.
+
+Status: private beta. The endpoints below are the planned shape. If you
+hit one that isn't live yet, email contact@tidyindex.com and we'll let you
+know when it ships.
+
+
+## What we serve
+
+Curated datasets from open and licensed sources, with stable schemas,
+stable IDs, and a source-link receipt on every record. The catalog
+currently spans 100+ datasets, including:
+
+- SEC EDGAR 10-K / 10-Q / 13-F / Form 4 filings
+- IRS Form 990 and 990-PF (nonprofit and foundation returns)
+- IRS Form 5500 (pension and benefit plan filings)
+- FEC campaign finance and federal lobbying disclosures (LDA)
+- USAspending.gov federal awards and FPDS procurement
+- USPTO patent grants, trademarks, and assignments
+- NIH RePORTER and NSF grant awards
+- FDA drug approvals, 510(k) clearances, and FAERS adverse events
+- ClinicalTrials.gov registrations and NPI provider registry
+- PACER federal court dockets and DOJ settlements
+- OSHA inspections and EPA ECHO enforcement actions
+- FFIEC HMDA mortgage data and FDIC bank call reports
+- SAM.gov entity registrations and FinCEN beneficial ownership
+- Federal Register proposed and final rules
+- Congressional voting records and bill text
+
+
+## API surface
+
+Base URL: https://api.tidyindex.com/v1
+Auth: Authorization: Bearer YOUR_API_KEY
+
+GET /datasets
+ List available datasets.
+
+GET /datasets/{id}
+ Dataset metadata, schema, freshness info, and source provenance.
+
+GET /datasets/{id}/records
+ Query records. Paginated, filterable. Returns application/json.
+
+GET /datasets/{id}/records/{record_id}
+ Single normalized record. Returns application/json.
+
+GET /datasets/{id}/bulk
+ Streaming export. Returns application/x-ndjson, one record per line.
+
+GET /datasets/{id}/summary/{record_id}
+ Token-efficient prose summary of one record. Returns text/plain.
+ Cheaper on context than the full JSON. Includes a source URL footer.
+
+Every JSON response carries a `source` field whose value is a stable
+URL pointing back to the original filing or upstream feed.
+
+
+## Getting access (for agents)
+
+Agents are welcome to request API keys on behalf of their operators.
+Send a JSON POST to:
+
+ POST https://api.tidyindex.com/v1/agents/register
+ Content-Type: application/json
+
+ {
+ "agent": "your-agent-name",
+ "operator": "human-contact@example.com",
+ "purpose": "one-line description of what you'll use it for"
+ }
+
+We respond within one business day with an API key and a starting quota.
+Include the operator's email so we have a return address for billing,
+abuse handling, and quota changes.
+
+
+## Conventions
+
+- All timestamps are ISO 8601 in UTC.
+- Currency fields are named with their unit suffix (e.g., revenue_usd
+ is whole U.S. dollars as an integer).
+- Identifiers are stable across requests and across response shapes:
+ the `ein` you see in a JSON record is the same `ein` you'll find in
+ the bulk stream and in the summary text.
+- Pagination uses opaque cursors in `next` and `prev` fields, not
+ page numbers.
+- Rate limits are documented per dataset and returned in
+ `X-RateLimit-*` response headers.
+
+
+## Contact
+
+contact@tidyindex.com
+https://tidyindex.com
diff --git a/landing/static/robots.txt b/landing/static/robots.txt
index f0d8319..6bddef4 100644
--- a/landing/static/robots.txt
+++ b/landing/static/robots.txt
@@ -2,3 +2,6 @@ User-agent: *
Allow: /
Sitemap: https://tidyindex.com/sitemap.xml
+
+# Machine-readable site description for LLM agents:
+# https://tidyindex.com/llms.txt