# SurveyStream — Open Graph card

1200 × 630, dark slate, dual-audience. Self-contained: **the three webfonts are embedded as
base64**, so the file renders identically on any machine with no network and no font installs.
That matters — an OG card rendered with a fallback face is a different design.

## Files

| File | Size | Notes |
| --- | --- | --- |
| `og-card.html` | 291 KB | The card. Open it and screenshot, or use the commands below. |
| `og-card.png` | 425 KB | 1200 × 630, exported. |
| `og-card@2x.png` | 1232 KB | 2400 × 1260, for retina previews. |

## Exporting

Chrome headless gives a pixel-exact export with no cropping:

```bash
CHROME="/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"

# 1× — 1200 × 630, the canonical OG size
"$CHROME" --headless --disable-gpu --hide-scrollbars \
  --window-size=1200,630 \
  --screenshot=og-card.png \
  "file://$PWD/og-card.html"

# 2× — 2400 × 1260
"$CHROME" --headless --disable-gpu --hide-scrollbars \
  --window-size=1200,630 --force-device-scale-factor=2 \
  --screenshot=og-card@2x.png \
  "file://$PWD/og-card.html"
```

`--hide-scrollbars` is not optional: without it Chrome reserves gutter width and the card is
cropped a few pixels on the right.

## Markup

```html
<meta property="og:image" content="https://surveystream.com/og-card.png">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:title" content="Turn Real-Time Feedback Into Instant Value">
<meta property="og:description" content="Survey takers cash out in minutes. Research teams get a verified, live data stream they can build on.">
<meta name="twitter:card" content="summary_large_image">
```

Serve the **1× PNG** as `og:image`. Most platforms re-encode anyway, and the 2× file mainly costs
bandwidth. Keep it under 1 MB — several scrapers refuse larger images outright.

## Composition notes

- **The scrim is doing the real work.** The stream visualisation lives on the right and is masked
  out of the left third; on top of that a `linear-gradient(96deg, …)` scrim holds a clean field
  under the headline. Without it the waves run straight through the type — I built that version
  first and the headline was unreadable.
- **Tested at feed size.** Rendered down to 504 px wide, which is roughly what a timeline shows.
  The headline, `12,480` and `$1,284.50` all still read; the mono footer row is at the edge of
  legibility, which is why nothing load-bearing lives there.
- **Numerals follow the type system:** `tabular-nums` throughout, and the payout amount carries
  `"tnum" 1, "lnum" 1, "zero" 0` — slashed zero explicitly off, because inside money it reads as
  a correction mark.
- Colours use the brand accents (Stream / Signal / Pulse) on the specified `#0F172A` ground.

## Two honest caveats

**1. The logo mark is below its own small-size threshold.** The lockup renders at 44 px, which puts
the mark at roughly 33 px — under the 40 px floor documented in `../logo/interlock/README.md`, and
far under it once a feed scales the card to half size. It degrades gracefully: the solid base still
reads as an S and only the thin accent softens. That is an acceptable trade for a card that is
mostly viewed large, but if you would rather be strict, swap the lockup for
`../logo/interlock/lockup-horizontal-mono.svg` (base only) and tint it Mist.

**2. `backdrop-filter` does not survive server-side OG rendering.** The glass panel depends on it.
Satori and `@vercel/og` do not implement `backdrop-filter`, so generating this card at request time
in that stack would render the panel as a flat translucent rectangle — losing the effect but not
breaking the layout. Options, in order of preference: ship the exported PNG (what this folder does);
or if you need per-page dynamic cards, replace the glass with an explicit gradient fill that
approximates the blur.

## Tailwind mapping

Written as plain CSS with custom properties so it works with or without a framework. If you port it:

| Here | Tailwind |
| --- | --- |
| `.og` | `relative w-[1200px] h-[630px] overflow-hidden bg-[#0F172A]` |
| `.panel` | `w-[356px] rounded-[22px] border border-white/[.16] backdrop-blur-[22px] backdrop-saturate-150` |
| `.scrim` | `absolute inset-0 z-[2] bg-[linear-gradient(96deg,…)]` |
| `h1 .lit` | `bg-gradient-to-r from-[#5FE3EC] to-[#2FE3A2] bg-clip-text text-transparent` |

The `inset` box-shadows on `.panel` have no clean utility equivalent — keep them as an arbitrary
`shadow-[…]` value or a small component class.
