# Sidebar Slide-Out Menu — Staggered Cards Sliding In From The Right + Background Blur

## Goal
Build a fullscreen hero page with a small **"Get the Overlay" toggle** pinned in the bottom-right corner. Clicking it slides a fixed **column of three white cards in from the right edge** of the screen with a fast GSAP **0.075s stagger** on a `power4.out` ease, while the whole page content **blurs to 15px** and the toggle button itself **slides off-screen to the right**. Clicking **any card** reverses everything — the cards slide back out past the right edge, the toggle slides back into its corner, and the page un-blurs. On top of that, each card has pure-CSS hover behavior: hovering a card swaps it to a deep-blue fill and reveals its body copy, and the first card additionally pops in a large close (×) icon. It is entirely **click- and hover-driven** — no scroll, no autoplay.

## Tech
Vanilla HTML/CSS/JS with ES module imports. Use `gsap` (npm) only — **no GSAP plugins**, no ScrollTrigger, no smooth-scroll library. Import as:
```js
import gsap from "gsap";
```
Icons come from the **Phosphor Icons** web font, loaded via a `<script>` tag in `<head>`:
```html
<script src="https://unpkg.com/@phosphor-icons/web"></script>
```
Used icon classes: `ph ph-arrow-right` (the arrow in the toggle) and `ph-thin ph-x` (the close × on card 1).

## Layout / HTML
```
.container                             (fullscreen, position:relative — holds the site + toggle; this is what blurs)
  .website-content
    nav                                (fixed top bar, flex, 3 equal columns)
      .logo            "Motionprompts"
      .cta             "Subscribe"      (center column)
      .links                            (right column, flex-end)
        a "About"  a "Infos"  a "Contact"
    .hero                               (left-aligned headline block, vertically centered)
      h1  "Elite web designs"
      p   (a paragraph of body copy)
  .overlay-toggle                       (bottom-right white pill — the OPEN click target)
    p  "Get the Overlay"
    p  > i.ph.ph-arrow-right

.sidebar                               (fixed full-height column on the right; clips the cards)
  .card                                 (card 1)
    .card-title
      div  "Showreel"
      .close-btn > i.ph-thin.ph-x       (large × — only on card 1)
    .card-copy > p                       (body copy, hidden until hover)
  .card                                 (card 2)
    .card-title  "Community"
    .card-copy > p
  .card                                 (card 3)
    .card-title  "Catalog"
    .card-copy > p
```
Note the `.sidebar` is a **sibling of `.container`, not inside it** — so when `.container` blurs, the sidebar cards stay sharp. Use neutral, fictional labels (Motionprompts / Subscribe / About / Infos / Contact / Showreel / Community / Catalog) — no real brand names. Card body copies are short lorem-ipsum sentences.

## Styling
Font: **"Neue Montreal"** (a clean neutral grotesque sans-serif). If unavailable, fall back to a similar sans (`system-ui`, Helvetica). `html, body { width:100%; height:100%; background:#000; color:#fff; font-family:"Neue Montreal"; }`.

Global reset: `* { margin:0; padding:0; box-sizing:border-box; }`.

Color tokens:
- Page background: `#000` (black)
- Text on hero: `#fff`; hero paragraph muted grey `#a0a0a0`
- Toggle pill + cards default fill: `#fff` with `#000` text
- **Card hover fill: `#020B44`** (deep navy blue) with `#fff` text

Structural / load-bearing CSS (these dimensions and the `right` offsets are what the GSAP tweens animate to/from — keep them exact):
- `.container`: `position: relative; width: 100vw; height: 100vh;` fullscreen hero background image `no-repeat 50% 50%`, `background-size: cover`.
- `nav`: `position: fixed; width: 100%; display: flex; padding: 1.5em;` with `nav > div { flex: 1; }`. `.cta { text-align: center; }`. `.links { display: flex; justify-content: flex-end; gap: 2em; }`. `a { text-decoration: none; color: #fff; }`.
- `.hero`: `position: absolute; top: 50%; transform: translateY(-50%); padding: 0 1.5em; width: 35%;`. `.hero h1 { font-size: 40px; font-weight: 400; margin-bottom: 10px; }`. `.hero p { color: #a0a0a0; line-height: 1.5; }`.
- `.overlay-toggle`: `position: absolute; right: 0; bottom: 0; width: 250px; height: 150px; margin: 0.75em; padding: 1em; border-radius: 0.5em; background: #fff; color: #000; display: flex; justify-content: space-between; cursor: pointer;` (label top-left, arrow icon top-right). Its `right` is the animated property (starts at the CSS `0`, effectively `right: 0.75em` visually via the margin).
- `.sidebar`: `position: fixed; top: 0; right: 0; width: 30vw; height: 100vh; padding: 0.75em; display: flex; flex-direction: column; gap: 0.75em; overflow: hidden; pointer-events: none;`. **`overflow: hidden` clips the cards while they sit off-screen at `right: -110%`; `pointer-events: none` is the closed state (JS toggles it to `all` when open so the cards become clickable).**
- `.card`: **`position: relative; right: -110%;`** (this off-screen offset is the closed state the GSAP tween animates from) `padding: 1em; flex: 1; background: #fff; color: #000; border-radius: 0.5em; overflow: hidden; display: flex; flex-direction: column; justify-content: space-between; cursor: pointer;`. Three equal-height cards stacked vertically.
- `.card-title`: `font-size: 50px; letter-spacing: -0.035em;`.
- `.card:nth-child(1) .card-title { display: flex; justify-content: space-between; }` (title text on the left, close-btn on the right — only card 1).
- `.close-btn`: `position: relative; font-size: 60px; transform: scale(0); transition: transform 0.3s; transform-origin: center;` — hidden by default, scaled up on card-1 hover.
- `.card-copy`: `position: relative; opacity: 0; transform: translateY(20px); font-size: 15px; transition: transform 0.3s, opacity 0.3s;` — hidden by default, revealed on hover.

**Pure-CSS hover behavior (NOT GSAP):**
```css
.card:hover                 { background: #020B44; color: #fff; }
.card:hover .card-copy      { opacity: 1; transform: translateY(0px); }   /* copy slides up + fades in over 0.3s */
.card:nth-child(1):hover .close-btn { transform: scale(1); }              /* × pops from scale 0→1 over 0.3s */
```

## GSAP effect (exhaustive)

No plugins, no timeline object — the effect is built from **standalone `gsap.to()` tweens** fired inside two functions (`animateCardsIn` on open, `animateCardsOut` on close). Grab refs once on `DOMContentLoaded`:
```js
const container     = document.querySelector(".container");
const sidebar       = document.querySelector(".sidebar");
const cards         = gsap.utils.toArray(".card");        // the 3 cards, in DOM order
const overlayToggle = document.querySelector(".overlay-toggle");
```

### Open — `animateCardsIn()`
Fires **three parallel standalone tweens**, all starting on the same tick (see note on `"<"` below):

1. **Toggle slides off-screen right:**
   ```js
   gsap.to(overlayToggle, { right: "-500px", duration: 1, ease: "power4.out" });
   ```
   Animates the pill's `right` from its resting `0` to `-500px`, sliding it out past the right edge. `duration: 1`, `ease: "power4.out"`.

2. **Cards slide in, staggered:**
   ```js
   gsap.to(cards, { right: "0%", stagger: 0.075, duration: 1, ease: "power4.out" }, "<");
   ```
   Animates each card's `right` from the CSS `-110%` (fully off-screen to the right, clipped by the sidebar's `overflow: hidden`) to `0%` (flush in place). **`stagger: 0.075`** fires them 0.075s apart in DOM order — card 1 first (Showreel), then card 2 (Community), then card 3 (Catalog). `duration: 1` each, `ease: "power4.out"` (fast launch, long smooth settle).

3. **Page content blurs:**
   ```js
   gsap.to(container, { filter: "blur(15px)", duration: 1, immediateRender: false }, "<");
   ```
   Animates the `.container`'s CSS `filter` from `blur(0px)` to `blur(15px)` over `duration: 1`. **No `ease` specified → GSAP default `power1.out`.** `immediateRender: false` prevents GSAP from snapping the blur to its end value before the tween runs. Because the sidebar is a sibling (outside `.container`), the incoming cards remain crisp while the site behind them goes soft.

### Close — `animateCardsOut()`
The mirror image, again three parallel standalone tweens:

1. **Toggle slides back into its corner:**
   ```js
   gsap.to(overlayToggle, { right: "0px", duration: 1, ease: "power4.out" });
   ```
   `right: -500px → 0px`, `duration: 1`, `ease: "power4.out"`.

2. **Cards slide back out, staggered:**
   ```js
   gsap.to(cards, { right: "-110%", stagger: 0.075, duration: 1, ease: "power4.out" });
   ```
   `right: 0% → -110%` (back off-screen), same `stagger: 0.075` in DOM order, `duration: 1`, `ease: "power4.out"`.

3. **Page un-blurs:**
   ```js
   gsap.to(container, { filter: "blur(0px)", duration: 1, immediateRender: false }, "<");
   ```
   `blur(15px) → blur(0px)`, `duration: 1`, default `power1.out` ease, `immediateRender: false`.

**Note on the `"<"` third argument:** in the source it is passed to some of these standalone `gsap.to()` calls, but the position parameter (`"<"`) is **only meaningful on timeline methods** — on the global `gsap.to()` it is simply ignored. The practical result is that all three tweens in each function start together on the same tick. (You may include it verbatim for fidelity, or omit it — behavior is identical.)

### Wiring
```js
overlayToggle.addEventListener("click", () => {
  sidebar.style.pointerEvents = "all";   // enable card clicks while open
  animateCardsIn();
});

cards.forEach((card) => {
  card.addEventListener("click", () => {
    sidebar.style.pointerEvents = "none"; // disable card clicks while closed
    animateCardsOut();
  });
});
```
- **Open:** clicking the `.overlay-toggle` sets the sidebar to `pointer-events: all` (so the cards become clickable) and runs `animateCardsIn()`.
- **Close:** clicking **any** card sets the sidebar back to `pointer-events: none` and runs `animateCardsOut()`. (Every card closes the menu, including card 1 — the × icon is decorative CSS, not a separate handler.)
- There is **no re-entrancy guard**; GSAP overwrites in-flight tweens naturally if the user clicks rapidly.

Wrap everything in `document.addEventListener("DOMContentLoaded", () => { ... })`.

## Assets / images
- **1 hero background image** — role: *fullscreen background behind the whole site, sits inside `.container` and is what blurs*. A moody, dark, photographic image (low-key, cinematic). Displayed `background-size: cover` at `50% 50%`. Landscape ~16:9 (e.g. 1920×1080 or larger). Because the UI text is white and the card hover fill is a deep navy, a darker image reads best.

## Behavior notes
- Entirely **click + hover driven** — no scroll, no ScrollTrigger, no loops, no autoplay.
- The card enter/exit + toggle slide + page blur are **GSAP**; the card color swap, body-copy reveal, and card-1 × pop are **pure CSS `:hover` transitions** (all `0.3s`).
- Closed state is expressed in CSS (`.card { right: -110% }`, `.sidebar { pointer-events: none }`); JS only ever tweens toward/away from it and toggles `pointer-events`.
- Responsive (`max-width: 900px`): `.hero { top: 25%; width: 100%; }` and `.sidebar { width: 100vw; }` (the sidebar becomes a full-width overlay; cards still slide in from the right with the same stagger).
