# Vibn — Marketing Site
Production Vite + React 18 + Tailwind CSS implementation of the Vibn marketing
homepage and beta-invite signup page.
## Stack
- **Vite 6** — dev server, HMR, multi-page build
- **React 18** — function components + hooks, no router (two static entries)
- **Tailwind CSS 3** — utility classes + a small `@layer components` block for
things that don't compress cleanly to utilities (gradients, pseudo-elements,
custom shadows)
- **No CSS-in-JS, no UI library** — design tokens live as CSS custom properties
so a tweak panel or theme switcher can runtime-swap the accent palette
- **Geist + Geist Mono** — loaded from Google Fonts in each entry HTML
## Getting started
```bash
npm install
npm run dev # http://localhost:5173 (homepage)
# http://localhost:5173/beta.html (signup)
npm run build # production build → dist/
npm run preview # serve the built bundle
```
## Project layout
```
vibn-app/
├── index.html ← homepage entry
├── beta.html ← beta-signup entry
├── vite.config.js ← multi-page input config
├── tailwind.config.js ← design tokens + named animations
├── postcss.config.js
├── public/
│ └── logo-black.png ← favicon (V_ mark on black)
└── src/
├── main.jsx ← mounts
├── beta-main.jsx ← mounts
├── styles.css ← Tailwind + tokens + keyframes + .btn / .card / .logo-mark
├── App.jsx ← homepage composition
├── BetaApp.jsx ← signup-page composition
├── lib/
│ └── primitives.jsx ← Logo, LogoMark, Arrow, Eyebrow, Glow, TrustStrip
└── components/
├── Nav.jsx
├── Hero.jsx ← Reddit-quote / promise variants + prompt input
├── Wall.jsx ← faux chat-window "homework wall" scene
├── CrossedOut.jsx ← animated strike-through term wall
├── Journey.jsx ← 4-step path + "where others stop" marker
├── Audience.jsx ← 3 audience cards w/ Reddit-style quotes
├── Closing.jsx
├── Footer.jsx
├── LaunchModal.jsx ← hero prompt-submit modal
└── beta/
├── BetaForm.jsx ← 5-step form
├── Confirmed.jsx ← submitted state w/ queue card + referral
└── Benefits.jsx ← "what you get inside" trio
```
## Design tokens
All colors are exposed as CSS custom properties (see `src/styles.css`,
`:root` block) and aliased in `tailwind.config.js → theme.extend.colors`:
| Tailwind class | CSS var | Default |
|---|---|---|
| `bg-bg` | `--c-bg` | `oklch(0.155 0.008 60)` |
| `bg-bg-1` | `--c-bg-1` | `oklch(0.185 0.009 60)` |
| `text-fg` | `--c-fg` | `oklch(0.97 0.005 80)` |
| `text-fg-dim` | `--c-fg-dim` | `oklch(0.78 0.006 80)` |
| `text-fg-mute` | `--c-fg-mute` | `oklch(0.58 0.006 80)` |
| `text-fg-faint` | `--c-fg-faint` | `oklch(0.42 0.006 80)` |
| `text-accent` | `--c-accent` | `oklch(0.74 0.175 35)` (coral) |
| `bg-accent` | `--c-accent` | (same) |
| `border-hairline` | `--c-hairline` | `oklch(0.32 0.010 60 / 0.55)` |
| `text-ok` | `--c-ok` | `oklch(0.78 0.16 155)` |
To re-theme at runtime, set the variables on `:root` from JS:
```js
document.documentElement.style.setProperty("--c-accent", "#9ee649");
document.documentElement.style.setProperty("--c-accent-glow", "#9ee64959");
document.documentElement.style.setProperty("--c-accent-fg", "#0f1408");
```
## Type scale
Fluid `clamp()` sizes are used inline:
- Hero headline: `clamp(44px, 7.4vw, 104px)`
- Section H2: `clamp(36px, 4.8vw, 64px)`
- Body / sub: `clamp(16–17px, 1.6–2.2vw, 19–28px)`
Geist is the body face; Geist Mono is reserved for tags, eyebrows, code, and
"trust strip" details.
## Animations
Keyframes are defined once in `styles.css`; some are also registered as named
Tailwind utilities (`animate-caret-blink`, `animate-pulse-ok`, etc.) for
ergonomics. Anything not in the config uses an inline `style={{ animation: ... }}`
with the keyframe name.
## Notes & next steps
- **No router.** Homepage links to `/beta.html` directly. Drop in
`react-router-dom` if you need client-side navigation between more pages.
- **Form submission is a stub.** `BetaForm` just waits 700 ms and toggles to
the confirmed state. Wire to your real endpoint (e.g. `fetch("/api/invite", …)`).
- **Queue position is deterministic on email.** Replace with the real one from
your backend.
- **The hero "Live from minute one" pill is currently not rendered** in this
port (the marketing prototype defaults it off). Re-add by uncommenting the
pill in `Hero.jsx` if you want it back.
- **The Tweaks panel from the prototype is not ported.** Tweaks are a design-time
tool; runtime theming is enough via the CSS-var token system.
## Browser support
Uses `oklch()`, `text-wrap: balance`, and `backdrop-filter`. Safari 15.4+,
Chrome 111+, Firefox 113+.