diff --git a/.impeccable.md b/.impeccable.md new file mode 100644 --- /dev/null +++ b/.impeccable.md @@ -0,0 +1,19 @@ +## Design Context + +### Users +Community members, developers, and newcomers exploring the AT Protocol / Atmosphere ecosystem. They arrive from the newsletter, Bluesky, Discourse, or search. They want to see what's happening in the community — new blog posts, upcoming events, how to get involved, and where their local community meetup is. Context: casual browsing, often on mobile, during breaks or after seeing a link shared on Bluesky. + +### Brand Personality +Warm, open, approachable. The Atmosphere community is grassroots, people-forward, decentralized. It should feel like a welcoming town square, not a corporate portal. + +### Aesthetic Direction +**"Horizon"** — light theme with sky-blue palette and CSS cloud motifs. People-forward: author avatars and names are prominent on every content card. Clean card-based layouts with generous whitespace. serif display headings (Crimson Pro) paired with a geometric sans body (Plus Jakarta Sans). The cloud/atmosphere motif ties back to the "Atmosphere" name without being heavy-handed. + +Anti-references: corporate SaaS dashboards, dark-mode-by-default dev tools, anything that feels like a generic startup landing page. + +### Design Principles +1. **People first** — Every piece of content highlights who created it. Avatars, names, and community context are always visible. +2. **Sky-light, not heavy** — The light blue palette and cloud motifs create an airy, optimistic feel. Don't overload pages. +3. **Structured simplicity** — Card-based layout with clear hierarchy. Information-dense but not cluttered. +4. **Real community, not marketing** — Copy should be direct and helpful. No buzzwords, no hard sells. +5. **Accessible by default** — WCAG AA contrast, semantic HTML, keyboard-navigable, `prefers-reduced-motion` respected. diff --git a/astro.config.mjs b/astro.config.mjs --- a/astro.config.mjs +++ b/astro.config.mjs @@ -2,4 +2,7 @@ import { defineConfig } from 'astro/config'; // https://astro.build/config -export default defineConfig({}); +export default defineConfig({ + site: 'https://atmosphere.community', + output: 'static', +}); diff --git a/package-lock.json b/package-lock.json --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "atproto-community", "version": "0.0.1", "dependencies": { + "@bryanguffey/astro-standard-site": "^1.0.3", "astro": "^6.1.7" }, "engines": { @@ -88,6 +89,155 @@ "node": "18.20.8 || ^20.3.0 || >=22.0.0" } }, + "node_modules/@atproto/api": { + "version": "0.15.27", + "resolved": "https://registry.npmjs.org/@atproto/api/-/api-0.15.27.tgz", + "integrity": "sha512-ok/WGafh1nz4t8pEQGtAF/32x2E2VDWU4af6BajkO5Gky2jp2q6cv6aB2A5yuvNNcc3XkYMYipsqVHVwLPMF9g==", + "license": "MIT", + "dependencies": { + "@atproto/common-web": "^0.4.2", + "@atproto/lexicon": "^0.4.12", + "@atproto/syntax": "^0.4.0", + "@atproto/xrpc": "^0.7.1", + "await-lock": "^2.2.2", + "multiformats": "^9.9.0", + "tlds": "^1.234.0", + "zod": "^3.23.8" + } + }, + "node_modules/@atproto/api/node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/@atproto/common-web": { + "version": "0.4.21", + "resolved": "https://registry.npmjs.org/@atproto/common-web/-/common-web-0.4.21.tgz", + "integrity": "sha512-Odq+wdk3YNasGCjjlpl3bCIPvqYHige5DLfMkIffNv/2PI/iIj5ZvAvMvJlJ59OhReKSxtpI0invx5UQPc3+fw==", + "license": "MIT", + "dependencies": { + "@atproto/lex-data": "^0.0.15", + "@atproto/lex-json": "^0.0.16", + "@atproto/syntax": "^0.5.4", + "zod": "^3.23.8" + } + }, + "node_modules/@atproto/common-web/node_modules/@atproto/syntax": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/@atproto/syntax/-/syntax-0.5.4.tgz", + "integrity": "sha512-9XJOpMAgsGFxMEIp8nJ8AIWv+krrY1xQMj+wULbbXhQztQV+9aZ0TbG9Jtn3Op2or8Kr6OqyWR4ga9Z189kKDw==", + "license": "MIT", + "dependencies": { + "tslib": "^2.8.1" + } + }, + "node_modules/@atproto/common-web/node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/@atproto/lex-data": { + "version": "0.0.15", + "resolved": "https://registry.npmjs.org/@atproto/lex-data/-/lex-data-0.0.15.tgz", + "integrity": "sha512-ZsbGiaM5S3CnGrcTMbDGON3bLZzCi/Mx9UvcMREKSRujnF68eHgMiXxJqvykP7+QpOX6tYCK93axZkuJVhtSEw==", + "license": "MIT", + "dependencies": { + "multiformats": "^9.9.0", + "tslib": "^2.8.1", + "uint8arrays": "3.0.0", + "unicode-segmenter": "^0.14.0" + } + }, + "node_modules/@atproto/lex-json": { + "version": "0.0.16", + "resolved": "https://registry.npmjs.org/@atproto/lex-json/-/lex-json-0.0.16.tgz", + "integrity": "sha512-IgLgQ0krshVlrIYZ+heTBDbCnM3LmAgWvsaYn5MxvKA3LcBot3PG3ptdO8VOweVZ+WgCLuo39cz9EbUmIbqdtg==", + "license": "MIT", + "dependencies": { + "@atproto/lex-data": "^0.0.15", + "tslib": "^2.8.1" + } + }, + "node_modules/@atproto/lexicon": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/@atproto/lexicon/-/lexicon-0.4.14.tgz", + "integrity": "sha512-jiKpmH1QER3Gvc7JVY5brwrfo+etFoe57tKPQX/SmPwjvUsFnJAow5xLIryuBaJgFAhnTZViXKs41t//pahGHQ==", + "license": "MIT", + "dependencies": { + "@atproto/common-web": "^0.4.2", + "@atproto/syntax": "^0.4.0", + "iso-datestring-validator": "^2.2.2", + "multiformats": "^9.9.0", + "zod": "^3.23.8" + } + }, + "node_modules/@atproto/lexicon/node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/@atproto/syntax": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@atproto/syntax/-/syntax-0.4.3.tgz", + "integrity": "sha512-YoZUz40YAJr5nPwvCDWgodEOlt5IftZqPJvA0JDWjuZKD8yXddTwSzXSaKQAzGOpuM+/A3uXRtPzJJqlScc+iA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.8.1" + } + }, + "node_modules/@atproto/xrpc": { + "version": "0.7.7", + "resolved": "https://registry.npmjs.org/@atproto/xrpc/-/xrpc-0.7.7.tgz", + "integrity": "sha512-K1ZyO/BU8JNtXX5dmPp7b5UrkLMMqpsIa/Lrj5D3Su+j1Xwq1m6QJ2XJ1AgjEjkI1v4Muzm7klianLE6XGxtmA==", + "license": "MIT", + "dependencies": { + "@atproto/lexicon": "^0.6.0", + "zod": "^3.23.8" + } + }, + "node_modules/@atproto/xrpc/node_modules/@atproto/lexicon": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/@atproto/lexicon/-/lexicon-0.6.2.tgz", + "integrity": "sha512-p3Ly6hinVZW0ETuAXZMeUGwuMm3g8HvQMQ41yyEE6AL0hAkfeKFaZKos6BdBrr6CjkpbrDZqE8M+5+QOceysMw==", + "license": "MIT", + "dependencies": { + "@atproto/common-web": "^0.4.18", + "@atproto/syntax": "^0.5.0", + "iso-datestring-validator": "^2.2.2", + "multiformats": "^9.9.0", + "zod": "^3.23.8" + } + }, + "node_modules/@atproto/xrpc/node_modules/@atproto/syntax": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/@atproto/syntax/-/syntax-0.5.4.tgz", + "integrity": "sha512-9XJOpMAgsGFxMEIp8nJ8AIWv+krrY1xQMj+wULbbXhQztQV+9aZ0TbG9Jtn3Op2or8Kr6OqyWR4ga9Z189kKDw==", + "license": "MIT", + "dependencies": { + "tslib": "^2.8.1" + } + }, + "node_modules/@atproto/xrpc/node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, "node_modules/@babel/helper-string-parser": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", @@ -132,6 +282,28 @@ }, "engines": { "node": ">=6.9.0" + } + }, + "node_modules/@bryanguffey/astro-standard-site": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@bryanguffey/astro-standard-site/-/astro-standard-site-1.0.3.tgz", + "integrity": "sha512-+4//yk8rRD3ZfC9uOKY7OHu7Shm5qMZSgFTIcDs079hcoV42yF8mK8O0AI6QMFb7iMCPqN9rO+leP+PMEEmR3A==", + "license": "MIT", + "dependencies": { + "@atproto/api": "^0.15.0", + "zod": "^3.24.0" + }, + "peerDependencies": { + "astro": "^5.0.0" + } + }, + "node_modules/@bryanguffey/astro-standard-site/node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" } }, "node_modules/@capsizecss/unpack": { @@ -1706,6 +1878,12 @@ "sharp": "^0.34.0" } }, + "node_modules/await-lock": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/await-lock/-/await-lock-2.2.2.tgz", + "integrity": "sha512-aDczADvlvTGajTDjcjpJMqRkOF6Qdz3YbPZm/PyW6tKPkx2hlYBzxMhEywM/tU72HrVZjgl5VCdRuMlA7pZ8Gw==", + "license": "MIT" + }, "node_modules/axobject-query": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", @@ -2575,6 +2753,12 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/iso-datestring-validator": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/iso-datestring-validator/-/iso-datestring-validator-2.2.2.tgz", + "integrity": "sha512-yLEMkBbLZTlVQqOnQ4FiMujR6T4DEcCb1xizmvXS+OxuhwcbtynoosRzdMA69zZCShCNAbi+gJ71FxZBBXx1SA==", + "license": "MIT" }, "node_modules/js-yaml": { "version": "4.1.1", @@ -3446,6 +3630,12 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, + "node_modules/multiformats": { + "version": "9.9.0", + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.9.0.tgz", + "integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==", + "license": "(Apache-2.0 AND MIT)" + }, "node_modules/nanoid": { "version": "3.3.11", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", @@ -4204,6 +4394,15 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, + "node_modules/tlds": { + "version": "1.261.0", + "resolved": "https://registry.npmjs.org/tlds/-/tlds-1.261.0.tgz", + "integrity": "sha512-QXqwfEl9ddlGBaRFXIvNKK6OhipSiLXuRuLJX5DErz0o0Q0rYxulWLdFryTkV5PkdZct5iMInwYEGe/eR++1AA==", + "license": "MIT", + "bin": { + "tlds": "bin.js" + } + }, "node_modules/trim-lines": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", @@ -4248,14 +4447,22 @@ "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD", - "optional": true + "license": "0BSD" }, "node_modules/ufo": { "version": "1.6.3", "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.3.tgz", "integrity": "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==", "license": "MIT" + }, + "node_modules/uint8arrays": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-3.0.0.tgz", + "integrity": "sha512-HRCx0q6O9Bfbp+HHSfQQKD7wU70+lydKVt4EghkdOvlK/NlrF90z+eXV34mUd48rNvVJXwkrMSPpCATkct8fJA==", + "license": "MIT", + "dependencies": { + "multiformats": "^9.4.2" + } }, "node_modules/ultrahtml": { "version": "1.6.0", @@ -4267,6 +4474,12 @@ "version": "0.1.3", "resolved": "https://registry.npmjs.org/uncrypto/-/uncrypto-0.1.3.tgz", "integrity": "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==", + "license": "MIT" + }, + "node_modules/unicode-segmenter": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/unicode-segmenter/-/unicode-segmenter-0.14.5.tgz", + "integrity": "sha512-jHGmj2LUuqDcX3hqY12Ql+uhUTn8huuxNZGq7GvtF6bSybzH3aFgedYu/KTzQStEgt1Ra2F3HxadNXsNjb3m3g==", "license": "MIT" }, "node_modules/unified": { diff --git a/package.json b/package.json --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "astro": "astro" }, "dependencies": { + "@bryanguffey/astro-standard-site": "^1.0.3", "astro": "^6.1.7" } -} \ No newline at end of file +} diff --git a/skills-lock.json b/skills-lock.json new file mode 100644 --- /dev/null +++ b/skills-lock.json @@ -0,0 +1,90 @@ +{ + "version": 1, + "skills": { + "adapt": { + "source": "pbakaus/impeccable", + "sourceType": "github", + "computedHash": "65085998d643c3b64ff323ca74d76496b47484046b030730c00c03a0208bf410" + }, + "animate": { + "source": "pbakaus/impeccable", + "sourceType": "github", + "computedHash": "354414a934957f9d54a71468abe81888304d35b47a4fe8e27fff08f60b457d53" + }, + "audit": { + "source": "pbakaus/impeccable", + "sourceType": "github", + "computedHash": "115a00d21d91d52123115af789948cb22bd604de0084837b5533f5e4af3c4055" + }, + "bolder": { + "source": "pbakaus/impeccable", + "sourceType": "github", + "computedHash": "1787478962577c9d5bde26e89e47c1654aa9c8f3c47c316a026731db0000a92e" + }, + "clarify": { + "source": "pbakaus/impeccable", + "sourceType": "github", + "computedHash": "42877142fcc51dcc6be696349aa7df8887eb29510e2a5868beac913f5f84de31" + }, + "colorize": { + "source": "pbakaus/impeccable", + "sourceType": "github", + "computedHash": "4793ac377b2bc1a5831d9634ce882373350cc5d097fd631d192155266204ceb8" + }, + "critique": { + "source": "pbakaus/impeccable", + "sourceType": "github", + "computedHash": "977f6fc3aa1002ec095f649e1b7c4fa52ee08a447f19229062810a9323c5c342" + }, + "delight": { + "source": "pbakaus/impeccable", + "sourceType": "github", + "computedHash": "1f6f4adee0b964e8344c0baef46b4e303ab3ba20932907bcbb1444ba7b3273b2" + }, + "distill": { + "source": "pbakaus/impeccable", + "sourceType": "github", + "computedHash": "669a671f855be8773e4c2936e54d4243fbd1d273f87633158544efe3dbc4d825" + }, + "impeccable": { + "source": "pbakaus/impeccable", + "sourceType": "github", + "computedHash": "a26b3dd377c4572b1c34c68f82ab9a1cb806f21c7157060327fe60e9b6d2e277" + }, + "layout": { + "source": "pbakaus/impeccable", + "sourceType": "github", + "computedHash": "6b5fd49587616ca1e594e9c6b11bc1cef5eb0b2d137c307de54a8a650770f4ce" + }, + "optimize": { + "source": "pbakaus/impeccable", + "sourceType": "github", + "computedHash": "979ffc76a4345c081fdf89078b7107c216d70696e027b23e8e24972dd4e457b2" + }, + "overdrive": { + "source": "pbakaus/impeccable", + "sourceType": "github", + "computedHash": "30e2909c14b9e860b580e63f9bbe10cc1dee8de0be9b03013218c3ef8d9ede78" + }, + "polish": { + "source": "pbakaus/impeccable", + "sourceType": "github", + "computedHash": "c294f2570dcc5b8865d17f0dc5ef339a700c868f1b20fa9994297f64ace2d4de" + }, + "quieter": { + "source": "pbakaus/impeccable", + "sourceType": "github", + "computedHash": "2c20b12bb4ece445d45fc63bda020aecf78b3cdf6d593beb59c273f658293130" + }, + "shape": { + "source": "pbakaus/impeccable", + "sourceType": "github", + "computedHash": "8edad33758f2461f51afdb51741bfcc4cc57d84ea42e2751a84be2c6a2d48f69" + }, + "typeset": { + "source": "pbakaus/impeccable", + "sourceType": "github", + "computedHash": "1cd76e560d1ba25b0bd5f7adfa2957a9f653a3ad0b031d467221154fcd1e0423" + } + } +} diff --git a/docs/atmosphere-community-design-spec.md b/docs/atmosphere-community-design-spec.md new file mode 100644 --- /dev/null +++ b/docs/atmosphere-community-design-spec.md @@ -0,0 +1,236 @@ +# atmosphere.community — Design Spec + +Addendum to the main project spec. This documents the chosen visual direction ("Horizon") for implementation in Astro. + +--- + +## Design direction: Horizon + +Warm, people-forward, approachable. The design puts authors and community members front and center on every content card, leans into cloud/sky imagery as the atmospheric motif, and uses a clean card-based layout that works well on mobile. + +### Reference mockup + +See the refined Horizon mockup with cloud shapes generated alongside this document. The mockup shows the full homepage layout: nav, hero with cloud accents, blog post list, events grid, community pills, get-involved cards, and footer. + +--- + +## Typography + +**Primary (body, UI, navigation):** Plus Jakarta Sans +- Weights used: 400 (body), 500 (nav links, secondary labels), 600 (card titles, buttons, stats), 700 (logo, hero stat numbers) +- Available on Google Fonts: `family=Plus+Jakarta+Sans:wght@400;500;600;700` + +**Display (page headings, section titles):** Crimson Pro +- A serif with character. Used for the hero h1 and section h2 headings. +- Weights used: 500, 600 +- Available on Google Fonts: `family=Crimson+Pro:opsz,wght@6..72,500;6..72,600` + +**Sizing scale:** +- Hero h1: 32–36px on desktop, 26–28px on mobile +- Section h2: 20–22px on desktop, 18px on mobile +- Post card title (h3): 15–16px on desktop, 13px on mobile +- Body text: 14–15px +- Meta/labels: 12px +- Tags, small labels: 10–11px + +--- + +## Color palette + +### Primary blues + +| Token | Hex | Usage | +|-------|-----|-------| +| `--blue-900` | `#0c2d4a` | Darkest text on light backgrounds | +| `--blue-800` | `#1a3d5c` | Primary headings | +| `--blue-700` | `#2563a8` | Primary brand color, links, CTA backgrounds, logo | +| `--blue-600` | `#378add` | Secondary links, active states | +| `--blue-500` | `#4a90d9` | Accent blue, author avatars | +| `--blue-400` | `#5ba3e0` | Light accent, `@` symbol in logo | +| `--blue-300` | `#7ab8e8` | Hero gradient mid-tone | +| `--blue-200` | `#b5d4f4` | Cloud fills, subtle backgrounds | +| `--blue-100` | `#d8e8f5` | Borders, dividers | +| `--blue-50` | `#eef3fb` | Tag backgrounds, very light fills | + +### Neutrals + +| Token | Hex | Usage | +|-------|-----|-------| +| `--neutral-900` | `#1a2a3a` | Primary text (headings in content area) | +| `--neutral-800` | `#2a3a4a` | Body text | +| `--neutral-600` | `#5a7a8a` | Secondary body text | +| `--neutral-500` | `#7a8a9a` | Muted text, descriptions | +| `--neutral-400` | `#9aaaba` | Meta text, timestamps | +| `--neutral-200` | `#e8edf5` | Card borders, dividers | +| `--neutral-100` | `#f0f4f8` | Page background alternate | +| `--neutral-50` | `#fafbfe` | Page background | + +### Accent colors (for community/category differentiation) + +| Name | Hex | Usage | +|------|-----|-------| +| Teal | `#1d9e75` / `#5dcaa5` | IndieSky content, EU community dot | +| Purple | `#7f77dd` / `#afa9ec` | Community Fund content | +| Coral | `#d85a30` | NYC community dot, warm accent | +| Green | `#3b6d11` | Location badge text on `#f0f5ee` background | + +### Semantic + +| Name | Background | Text | +|------|-----------|------| +| Location badge | `#f0f5ee` | `#3b6d11` | +| Online badge | `#eef3fb` | `#2563a8` | +| Content tag | `#eef3fb` | `#2563a8` | + +--- + +## Layout + +### Page background +`#fafbfe` — a very slight blue-tinted off-white. Cards sit on `#ffffff` with `1px solid #e8edf5` borders. + +### Content width +Max content width: 720px on the blog/about pages, 960px on the homepage. Centered with auto margins. 24px padding on mobile. + +### Card system +All cards share: +- Background: `#ffffff` +- Border: `1px solid #e8edf5` +- Border radius: 12px +- Padding: 14–16px + +### Grid breakpoints +- Mobile (< 640px): single column, full-width cards +- Tablet (640–960px): 2-column grid for events and highlights +- Desktop (> 960px): full layout, wider hero stats row + +--- + +## Component specifications + +### Navigation bar +- Background: `#ffffff`, bottom border `1px solid #e8edf5` +- Logo: small cloud icon (CSS-drawn, `#b5d4f4`) + `@atmosphere` in Plus Jakarta Sans 700, `@` in `#5ba3e0`, `atmosphere` in `#2563a8` +- Nav links: Plus Jakarta Sans 500, 12–13px, `#7a8a9a`, no underlines +- Sticky on scroll (optional for v1) + +### Hero section +- Background: solid `#2563a8` +- Cloud shapes: CSS-only, built from overlapping elements with `border-radius: 50%` and pill shapes (`border-radius: [height]px`), filled with `rgba(255,255,255,0.10)`. 3–4 clouds at different sizes and positions, layered behind content. They create an organic sky feeling without requiring image assets. +- Headline: Crimson Pro 600, 28–36px, white +- Subhead: Plus Jakarta Sans 400, 13–14px, `rgba(255,255,255,0.75)` +- CTA button: white background, `#2563a8` text, 8px border-radius, 600 weight +- Secondary link: `rgba(255,255,255,0.85)`, no decoration +- Stats row: 3 stat blocks (number in 700 weight white, label in 9px uppercase `rgba(255,255,255,0.6)`) +- Stats are real numbers: subscriber count, regional groups count, ATProto network user count + +### Blog post cards (list layout) +- Horizontal layout: author avatar (36x36, 10px border-radius, solid color or profile image) on the left, content on the right +- Title: Plus Jakarta Sans 600, 14–15px, `#1a2a3a` +- Excerpt: 12px, `#7a8a9a`, 2 lines max (line-clamp) +- Meta row: category tag pill (`#eef3fb` background, `#2563a8` text, 6px radius) + author name + date in `#9aaaba` +- Each card links to the full post on Offprint (`blog.atmosphere.community`) +- Author avatars: for v1, generate colored squares from author handle. Later, pull profile avatar from ATProto identity. + +### Event cards (2-column grid) +- Date label: Plus Jakarta Sans 600, 11px, `#2563a8` +- Event name: 13px, 600 weight, `#1a2a3a` +- Description: 11px, `#7a8a9a` +- Location badge: pill shape, 9px, either green (`#f0f5ee` / `#3b6d11`) for in-person or blue (`#eef3fb` / `#2563a8`) for online + +### Community pills +- Pill shape: `border-radius: 20px`, white background, `1px solid #e8edf5` +- Left element: 24px colored circle with 2–3 letter abbreviation in white, 700 weight, 9px +- Text: community name in 600 weight 12px + location in 9px `#9aaaba` +- Laid out in a horizontal row, wrapping on mobile + +### Avatar stack (social proof) +- Row of 5–6 overlapping circular avatars (28px, 50% radius, 2px white border, -6px margin-left overlap) +- Followed by text: "Join 1,000+ people in the Atmosphere" in 12px `#7a8a9a` +- Placed below the events section + +### Get involved / highlights (2-column grid) +- Standard card with h4 title (13px, 600), description (11px, `#7a8a9a`), and a link in `#2563a8` 500 weight +- 4 cards: Discourse forum, Community Fund, ATmosphereConf, GitHub + +### Footer +- Background: `#ffffff`, top border `1px solid #e8edf5` +- Left: `atmosphere.community · Built on AT Protocol` in 11px `#9aaaba` +- Right: Subscribe button (small, `#2563a8` background, white text, 6px radius) + +--- + +## Cloud motif details + +Clouds are the recurring visual motif. They appear in three places: + +1. **Hero background:** 3–4 decorative clouds at varying sizes and positions, built with CSS pseudo-elements. Each cloud is a horizontal pill (wide `border-radius`) with 1–2 circles (`border-radius: 50%`) overlapping on top to create the bumpy cumulus silhouette. Fill: `rgba(255,255,255,0.10)` — very subtle, layered. + +2. **Logo mark:** A tiny cloud shape (18x10px) next to the text logo, using the same CSS construction at small scale. Fill: `#b5d4f4`. + +3. **Optional: section dividers or page backgrounds.** Very faint cloud shapes could be placed as decorative elements between sections or on the About page, but keep them subtle — the hero is the primary canvas for this motif. + +### CSS cloud construction pattern + +Each cloud is built from a base pill shape + 1–2 `::before`/`::after` pseudo-element circles: + +```css +.cloud { + position: absolute; + width: 140px; + height: 48px; + border-radius: 48px; /* pill shape = base of cloud */ + background: rgba(255,255,255,0.10); +} +.cloud::before { + content: ''; + position: absolute; + width: 60px; + height: 60px; + border-radius: 50%; /* big bump */ + background: rgba(255,255,255,0.10); + top: -30px; /* rises above the pill */ + left: 30px; +} +.cloud::after { + content: ''; + position: absolute; + width: 44px; + height: 44px; + border-radius: 50%; /* smaller bump */ + background: rgba(255,255,255,0.10); + top: -22px; + left: 70px; +} +``` + +Vary the sizes, positions, and number of bumps to create 3–4 distinct cloud shapes. Keep them positioned with `position: absolute` inside the hero's `overflow: hidden` container. + +For an SVG approach (if preferred over CSS), the same shapes can be drawn as compound paths with arc commands, which gives more control over the silhouette and allows for easier reuse as decorative elements elsewhere. + +--- + +## Accessibility + +- All text meets WCAG AA contrast ratios against its background (the blue-on-white and white-on-blue combinations in this palette pass) +- Interactive elements (buttons, links, cards) have visible focus states +- Card links use semantic `` wrapping the entire card, with `aria-label` including the post title +- Hero stats use semantic markup (not just visual formatting) +- Cloud decorations are `aria-hidden="true"` +- Images (author avatars) include `alt` text with the author's name +- Nav uses `