···121121- Horizontal scroll: smooth scroll-snap with momentum
122122- Responsive collapse: `Presence` crossfade when switching between multicolumn and single-column modes
123123- Skeleton screens per column while content loads
124124+125125+## Responsive Behavior
126126+127127+- On narrow windows (< 768px), collapse to single-column view with horizontal swipe navigation
128128+- On smaller widths, multiple columns should collapse into vertical, labeled panes within the single-column layout
129129+- Columns containing sensitive content (e.g., DMs) should support an autoblur option — allow marking any column as blurrable so content is obscured until hovered or clicked
+94
docs/specs/profile.md
···11+# Profile Screens
22+33+## Profile View
44+55+The profile view is the primary way to inspect any user on the network. It renders a hero section (banner, avatar, identity, stats) followed by tabbed content (posts, replies, media, likes). The hero section uses scroll-driven animation to condense into a compact header as the user scrolls down.
66+77+### Profile Data (XRPC via jacquard)
88+99+| Action | Lexicon |
1010+| ------------------- | ------------------------------------ |
1111+| Get profile | `app.bsky.actor.getProfile` |
1212+| Author feed | `app.bsky.feed.getAuthorFeed` |
1313+| Actor likes | `app.bsky.feed.getActorLikes` |
1414+| Follow | `app.bsky.graph.follow` (create) |
1515+| Unfollow | `app.bsky.graph.follow` (delete) |
1616+| Get followers | `app.bsky.graph.getFollowers` |
1717+| Get following | `app.bsky.graph.getFollows` |
1818+1919+### Hero Section
2020+2121+The hero contains the banner image, avatar, display name, handle, bio, metadata (website, join date, DID), and social stats.
2222+2323+**Scroll-driven condensation:** As the user scrolls, the avatar shrinks and slides right while the display name and handle slide up to sit beside it, forming a compact sticky header. The banner parallax-scrolls behind.
2424+2525+- Avatar starts at 128px, scales down to ~84px (`1 - progress * 0.34`)
2626+- Display name and handle translate upward and leftward to sit beside the shrunk avatar
2727+- The avatar + name + handle group sticks to the top of the scroll container
2828+- Banner offset: `scrollTop * 0.28` (capped at 88px), scale: `1 + scrollTop / 1600` (capped at 1.08)
2929+- All transforms use `translate3d` for GPU-accelerated compositing, `duration-100 ease-out`
3030+3131+### Tabs
3232+3333+Four content tabs below the hero: **Posts**, **Replies**, **Media**, **Likes**.
3434+3535+- Posts: author feed filtered to exclude replies
3636+- Replies: author feed filtered to replies only
3737+- Media: author feed filtered to posts with embeds
3838+- Likes: separate endpoint (`getActorLikes`)
3939+- Sticky tab bar with backdrop blur, sits below the condensed hero on scroll
4040+- Cursor-based pagination with "Load more" button
4141+4242+### Follow / Unfollow Actions
4343+4444+- Follow button on other users' profiles (not on self)
4545+- Visual state: "Follow" (outline) / "Following" (filled) / "Unfollow" (on hover of Following)
4646+- Creates/deletes `app.bsky.graph.follow` record
4747+- Optimistic UI update with rollback on error
4848+4949+### Following & Follower Lists
5050+5151+- Accessible from the follower/following stat counts on the profile hero
5252+- Paginated list using `app.bsky.graph.getFollowers` / `app.bsky.graph.getFollows`
5353+- Each entry is a compact actor card (avatar, name, handle, bio preview, follow button)
5454+- `Presence` slide-up overlay or route-based panel
5555+5656+### DMs
5757+5858+- DM button on other users' profiles
5959+- Opens `chat.bsky.convo.*` conversation view
6060+- **Deferred** to post-MVP unless trivial alongside feed DMs
6161+6262+### Profile Edit Screen
6363+6464+- Accessible only on self-profile
6565+- Controls for: display name, bio/description, avatar, banner, website, pronouns
6666+- Uses `com.atproto.repo.putRecord` on `app.bsky.actor.profile`
6767+- Image upload via `com.atproto.repo.uploadBlob`
6868+- Confirmation before discarding unsaved changes
6969+7070+## Keyboard Shortcuts
7171+7272+| Key | Action |
7373+| --------- | ------------------------ |
7474+| `Escape` | Close overlay / go back |
7575+| `1`–`4` | Switch profile tabs |
7676+7777+## UX Polish
7878+7979+- Avatar + name condensation: smooth scroll-driven transform (not IntersectionObserver snap)
8080+- Banner parallax: subtle depth via `translate3d` + `scale`
8181+- Tab switch: `Presence` crossfade between feed content
8282+- Skeleton screens for profile hero and feed content during load
8383+- Error state with retry button for network failures
8484+- Badge row for relationship indicators (Following, Follows you, Muted, etc.)
8585+8686+## Responsive Behavior
8787+8888+- On narrow widths (< 520px), reduce horizontal padding, compress hero spacing
8989+- On medium widths (< 760px), reduce banner height from 256px to 224px
9090+9191+## Parking Lot
9292+9393+- Profile edit screen (full settings exposure)
9494+- DM conversation view
···11-# Task 10: Spacedust
11+# Task 11: Spacedust
2233Spec: TBD (see [Spacedust API docs](../../.sandbox/spacedust.md))
44···6677[Spacedust](https://spacedust.microcosm.blue/) is a configurable ATProto notifications firehose by microcosm.blue. It streams real-time backlink events (likes, reposts, follows, replies, etc.) for specific subjects, with a built-in 21-second debounce buffer to filter out quickly-undone interactions.
8899-Where Jetstream (Task 09) streams raw firehose records, Spacedust streams *resolved backlinks* - making it ideal for live notification feeds and real-time engagement counters.
99+Where Jetstream (Task 10) streams raw firehose records, Spacedust streams *resolved backlinks* - making it ideal for live notification feeds and real-time engagement counters.
10101111## Tasks
1212