# Landing Page Reveal — Portrait-Strip Preloader Wipe-Up

## Goal
Build a full-screen editorial landing hero with a cinematic **preloader-to-hero reveal** that plays automatically once on page load (~6.5 seconds total). A black full-screen loader holds a horizontal strip of **seven tall portrait images** (six photos plus a centered white monogram logo). On load the seven images **rise up from below** and stagger in, then the whole strip **slides sideways**; the six photos (but not the center logo) **wipe away upward** one after another via an animated `clip-path`; the entire black loader panel then **wipes upward** the same way, uncovering the page beneath; finally the nav links, the three-line hero headline, and the four footer thumbnails all **slide up and fade in**. Everything is driven by one single GSAP timeline using `power3.inOut` easing.

## Tech
Vanilla HTML/CSS/JS with ES module imports. Use `gsap` (npm) only — **no** GSAP plugins and **no** smooth-scroll library (the page never scrolls; `body` is `overflow:hidden`). Import the default export (`import gsap from "gsap"`) and fire the whole sequence inside a `DOMContentLoaded` listener.

## Layout / HTML
Semantic structure (class names / the `#loader-logo` id are load-bearing — the JS/CSS query them):

```
<div class="container">

  <!-- fixed black preloader on top of everything -->
  <div class="loader">
    <div class="loader-imgs">
      <div class="img"><img src="..." alt="" /></div>          <!-- photo 1 -->
      <div class="img"><img src="..." alt="" /></div>          <!-- photo 2 -->
      <div class="img"><img src="..." alt="" /></div>          <!-- photo 3 -->
      <div class="img" id="loader-logo"><img src="logo.png" alt="" /></div>  <!-- CENTER logo, survives the wipe -->
      <div class="img"><img src="..." alt="" /></div>          <!-- photo 4 -->
      <div class="img"><img src="..." alt="" /></div>          <!-- photo 5 -->
      <div class="img"><img src="..." alt="" /></div>          <!-- photo 6 -->
    </div>
  </div>

  <!-- the page underneath, revealed when the loader wipes away -->
  <div class="website-content">
    <nav>
      <div class="nav-item"><a href="#">( menu )</a></div>
      <div class="nav-item" id="logo"><a href="#">EliteWebsites</a></div>
      <div class="nav-item"><a href="#">( work* )</a></div>
    </nav>

    <div class="hero">
      <div class="h1"><h1>we believe</h1></div>
      <div class="h1"><h1>websites shape the</h1></div>
      <div class="h1"><h1><span>future</span></h1></div>
    </div>

    <footer>
      <div class="item"><img src="..." alt="" /></div>
      <div class="item"><img src="..." alt="" /></div>
      <div class="item"><img src="..." alt="" /></div>
      <div class="item"><img src="..." alt="" /></div>
    </footer>
  </div>

</div>
```

Notes:
- `.loader-imgs` holds exactly **7** `.img` wrappers. The **4th one (the center)** carries `id="loader-logo"` and holds the monogram logo — it is the one image that is **excluded** from the photo wipe and stays visible until the whole loader panel wipes away.
- `.website-content` holds the nav, the hero, and the footer, and sits underneath the loader.
- Use **"EliteWebsites"** as the neutral placeholder brand name in the center nav slot. The three headline lines are the tagline "we believe / websites shape the / future" — the word **"future"** is wrapped in a `<span>` so it can be styled bolder.

## Styling
Fonts: the CSS declares custom display faces — `"Sharp Grotesk"` (body + the `future` span), `"Neue Montreal"` (nav), `"PP Editorial Old"` (center nav brand), `"PP Migra"` (hero headline). **None of these are bundled or loaded** (there is no `@font-face` and no font `<link>`), so in practice everything falls back to the browser default sans-serif. Keep the declared `font-family` names for fidelity but do not attempt to fetch the missing fonts.

Palette:
- Page background: `#e7e4e5` (warm light grey).
- Loader background: `#000` (black).
- All text: `#000`.

Global:
- `* { margin:0; padding:0; box-sizing:border-box }`.
- `html, body { font-family:"Sharp Grotesk"; background:#e7e4e5; overflow:hidden }` (no scrolling).
- `img { width:100%; height:100%; object-fit:cover }`.
- `a { text-decoration:none; text-transform:uppercase; color:#000 }`.

Key elements (positioning + the **clip-paths and initial states the animation depends on**):

- `.loader`: `position:fixed; width:100vw; height:100vh; background:#000; pointer-events:none`. **Initial** `clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%)` (full rectangle — covers the whole viewport). This exact 4-point full-rect clip-path is required so GSAP can later animate it to a collapsed polygon.
- `.loader-imgs`: `width:150%; position:absolute; top:50%; left:50%; transform:translate(-50%,-50%); display:flex; gap:50px`; same full-rect `clip-path`. It is **150% wide**, centered, so the strip overflows the viewport on both sides.
- `.img`: `position:relative; flex:1` (seven equal columns filling the 150% strip); same full-rect `clip-path` on each.
- `nav`: `width:100%; padding:30px; display:flex; align-items:center; font-family:"Neue Montreal"`.
  - `.nav-item`: `position:relative; flex:1` (three equal thirds). `.nav-item:nth-child(2)` (the brand): `text-align:center; font-family:"PP Editorial Old"; font-size:24px; font-weight:500`. `.nav-item:nth-child(3)`: `text-align:right`. `#logo a { text-transform:none }` (brand name not uppercased).
- `.hero`: `width:100%; position:absolute; top:45%; transform:translateY(-50%); text-transform:uppercase; font-family:"PP Migra"`.
  - `.h1`: `width:100%; text-align:center; font-size:4vw`; same full-rect `clip-path` on each line.
  - `h1`: `position:relative; font-weight:400; line-height:85%`.
  - `h1 span`: `font-family:"Sharp Grotesk"; font-weight:700` (the word "future" renders heavier).
- `footer`: `width:100%; position:absolute; bottom:30px; right:30px; display:flex; justify-content:flex-end; gap:10px`; same full-rect `clip-path`.
  - `.item`: `position:relative; width:100px; height:100px` (four square thumbnails, bottom-right, `object-fit:cover`).

## GSAP effect (be exact)

### Initial states — set BEFORE building the timeline
```js
gsap.set(".img",        { y: 500 });            // all 7 strip images pushed 500px DOWN
gsap.set(".loader-imgs",{ x: 500 });            // whole strip shifted 500px to the RIGHT
gsap.set(".nav-item",   { y: 25, opacity: 0 }); // nav items 25px down, invisible
gsap.set("h1, .item, footer", { y: 200 });      // hero headlines, footer thumbs AND the footer container 200px down
```
(The full-rect `clip-path` initial states come from the CSS above, not from `gsap.set`.)

### One single timeline, delayed 1s
```js
const tl = gsap.timeline({ delay: 1 });
```
The whole sequence waits **1s** after `DOMContentLoaded`, then plays as a chain of five tweens. Position parameters are **relative offsets** (`"-=X"` = start X seconds before the current end of the timeline) — reproduce them exactly.

**Tween 1 — images rise (starts at timeline t=0):**
```js
tl.to(".img", {
  y: 0,
  duration: 1.5,
  stagger: 0.05,
  ease: "power3.inOut",
});
```
All 7 `.img` wrappers rise from `y:500` to `y:0`, left-to-right stagger `0.05s`, each `1.5s`, `power3.inOut`. (Strip fills from `t≈0` to `t≈1.8`.)

**Tween 2 — strip slides sideways (position `"-=2.5"`):**
```js
tl.to(".loader-imgs", {
  x: 0,
  duration: 3,
  ease: "power3.inOut",
}, "-=2.5");
```
The whole strip slides from `x:500` to `x:0` (moves left ~500px) over `3s`. Position `"-=2.5"` computes to a negative insertion point (GSAP clamps it to `0`), so this runs **in parallel with the rising images**, starting at `t≈0` and ending at `t≈3`.

**Tween 3 — the six photos wipe away upward (position `"-=1"`):**
```js
tl.to(".img:not(#loader-logo)", {
  clipPath: "polygon(0% 0%, 100% 0%, 100% 0%, 0% 0%)",
  duration: 1,
  stagger: 0.1,
  ease: "power3.inOut",
}, "-=1");
```
Every `.img` **except the center `#loader-logo`** (i.e. the 6 photos) animates its clip-path from the full rectangle to `polygon(0% 0%, 100% 0%, 100% 0%, 0% 0%)` — the bottom edge collapses up to the top edge, so each photo **wipes away upward**, staggered `0.1s`, `1s` each. Starts at `t≈2`. The center logo stays visible on the black panel.

**Tween 4 — the whole black loader wipes upward (position `"-=0.5"`):**
```js
tl.to(".loader", {
  clipPath: "polygon(0% 0%, 100% 0%, 100% 0%, 0% 0%)",
  duration: 1,
  ease: "power3.inOut",
}, "-=0.5");
```
The entire black `.loader` panel (still carrying the center logo) collapses its bottom edge up to the top the same way — wiping the whole preloader **upward off the screen** over `1s`, uncovering `.website-content` beneath. Starts at `t≈3`.

**Tween 5 — page content slides up + fades in (position `"-=0.5"`):**
```js
tl.to(".nav-item, h1, footer, .item", {
  y: 0,
  opacity: 1,
  stagger: 0.1,
  duration: 1,
  ease: "power3.inOut",
}, "-=0.5");
```
All nav items (3), all hero headline `h1`s (3), the footer container, and the footer thumbnails (4) — 11 targets total — slide from their offset (`y:200`, or `y:25` for nav) to `y:0` and fade `opacity 0→1` (only the nav items were transparent), staggered `0.1s`, `1s` each. Starts at `t≈3.5`, ends at `t≈5.5`.

### Timeline summary (timeline-relative seconds; add the 1s delay for wall-clock)
| t (s) | what |
|-------|------|
| 0.0–1.8 | 7 strip images rise `y:500→0` (stagger 0.05, dur 1.5) |
| 0.0–3.0 | strip slides `x:500→0` (dur 3) — parallel |
| 2.0–3.5 | 6 photos wipe upward via clip-path (stagger 0.1, dur 1) |
| 3.0–4.0 | whole black loader wipes upward via clip-path (dur 1) |
| 3.5–5.5 | nav + hero h1s + footer + thumbs slide up & fade in (stagger 0.1, dur 1) |

Total runtime ≈ **6.5s** (including the 1s start delay). Every tween uses `ease: "power3.inOut"`.

### Ease reference
- **Everything** uses `power3.inOut`. There is no CustomEase, SplitText, ScrollTrigger, lerp loop, or Three.js in this component — it is a pure load-triggered timeline of `y`, `x`, `clip-path` and `opacity` tweens.

## Assets / images
Thirteen image slots total: **6 tall portrait photos** + **1 portrait logo** in the loader strip, and **4 square thumbnails** in the footer.

- **Loader strip photos (6)** — tall **portrait ~2:3** editorial/cinematic frames, `object-fit:cover`, each a single subject with a moody, atmospheric palette (mixed teals, golds, greens). Roughly, in strip order: (1) a lone figure walking a wet reflective floor toward a shaft of light between dark angular walls; (2) extreme close-up of a glossy helmet with a swirled gold visor on lime-green; (3) a spacesuited figure before a huge pale sphere in hazy golden light; then the center logo; (4) a dark slit-view of a lower face holding a lit cigarette; (5) an orange-lit silhouette pressing a hand on frosted glass; (6) a side-lit portrait of a woman in dark clothing on a dark teal backdrop. They are only briefly seen before wiping away, so the palettes need not match.
- **Center logo (`#loader-logo`)** — an ornate **white cursive monogram letter on a solid black background**, **portrait ~3:4**. This is the one image that stays visible while the six photos wipe, then leaves with the black panel. Keep it on a black field so it blends into the loader.
- **Footer thumbnails (4)** — small **square** images (cropped to 100×100 via `object-fit:cover`), bottom-right. Any editorial/3D-render/portrait subjects work (e.g. a surreal metallic-faced 3D figure, a golden lucky-cat figurine in a red niche, a veiled portrait, a warm hazy city skyline). Do not use real brand marks.

If you have fewer fixtures than slots, repeat images to fill; if more, use the first ones.

## Behavior notes
- **Autoplay once** on `DOMContentLoaded`; no scroll, hover, or click triggers. The page never scrolls (`overflow:hidden`).
- The clip-path target `polygon(0% 0%, 100% 0%, 100% 0%, 0% 0%)` is the "wipe upward" shape (bottom edge collapsed to the top). The full-rectangle initial clip-paths on `.loader`, `.loader-imgs`, `.img`, `.h1` and `footer` must be present in CSS so GSAP can tween between matching 4-point polygons.
- No `will-change` hints, no reduced-motion handling, and no responsive breakpoints in the original — it renders the same at all widths (the loader strip is `150%` wide and centered, so it always overflows). Layout is light and mobile-safe.
