---
applyTo: "src/sites/yusi/**"
applyTo: "astro.config.yusi.mjs"
applyTo: "wrangler.yusi.toml"
applyTo: ".github/workflows/deploy-yusi.yml"
---

# YUSI Site Instructions

## What is YUSI

YUSI is a cinema-integrated education platform — a curated VOD app for schools that maps world cinema (primarily short films) to learning objectives and provides teacher guides and student reflection tools. It is a standalone product, not part of the CULTSCALE brand. Never mention CULTSCALE on the YUSI website.

**Founder:** Aya Al Blouchi — Founder and Chief Education Officer

**Live site:** https://yusiapp.com

**Cloudflare Pages project:** `yusi-web`

**Primary domain:** `yusiapp.com` (custom domain on `yusi-web`)

**Redirect domains:** `yusi.app` and `www.yusiapp.com` 302-redirect to `yusiapp.com` via Cloudflare Bulk Redirects (`dns/bulk-redirects.json`)

---

## Commands

```bash
npm run dev:yusi          # Dev server at localhost:4323
npm run build:yusi        # Build to dist/yusi/
npm run deploy:yusi       # wrangler pages deploy dist/yusi
```

---

## Site Structure

```
src/sites/yusi/
├── pages/
│   └── index.astro       # Single-page site — all content and scoped CSS
├── public/
│   ├── robots.txt
│   ├── _redirects        # Cloudflare path shortlinks
│   └── _headers          # Cloudflare cache/security headers
├── layouts/
│   └── BaseLayout.astro  # YUSI layout (OG tags, Turnstile script, fonts)
└── components/
    ├── Header.astro       # YUSI header with logo
    ├── Footer.astro       # YUSI footer (© 2026 YUSI)
    └── Logo.astro         # YUSI logotype
```

**Key design rules:**
- No em dashes anywhere in copy — rephrase instead
- No CULTSCALE mentions on any public-facing page
- No investor/business-model language — this is an institution-facing pitch site
- Alternate cream (`section-cream`) and dark (`section-dark`) background sections for visual rhythm

---

## Cloudflare Pages Deployment

**Config file:** `wrangler.yusi.toml`
```toml
name = "yusi-web"
compatibility_date = "2025-12-12"
pages_build_output_dir = "dist/yusi"
```

**Astro config:** `astro.config.yusi.mjs`
- `site: 'https://yusiapp.com'`
- `outDir: './dist/yusi'`
- `srcDir: './src/sites/yusi'`

**GitHub Actions workflow:** `.github/workflows/deploy-yusi.yml`
- Triggers on push to `main` when `src/sites/yusi/**`, `src/shared/**`, `src/assets/**`, `astro.config.yusi.mjs`, or `wrangler.yusi.toml` change
- Also supports `workflow_dispatch` for manual triggers
- Uses `cloudflare/wrangler-action@v3` with `CLOUDFLARE_API_TOKEN` and `CLOUDFLARE_ACCOUNT_ID` secrets
- Includes a `continue-on-error` step to add `yusiapp.com` as custom domain post-deploy

**Note:** Workflow path filter does NOT include `.github/workflows/` — changes to the workflow itself don't auto-trigger. Use `gh workflow run deploy-yusi.yml` to trigger manually after workflow changes.

**Local deployment:**
```bash
npm run build:yusi
wrangler pages deploy dist/yusi --project-name yusi-web --branch main
```

---

## Git Push Pattern

The `yusi` branch is developed in the `/home/mnm/workspaces/yusi` worktree. `main` is checked out in the `/home/mnm/workspaces/cultscale` worktree, so `git checkout main` will fail here.

**Correct push pattern from the yusi worktree:**
```bash
git fetch origin main
git rebase origin/main
git push origin yusi:main
```

---

## Portal Integration (Form → Newsletter)

The beta signup form POSTs to `https://cultscale.org/api/newsletter/subscribe`.

**CORS:** The portal (`portal/src/index.ts`) has `yusiapp.com` and `yusi-web.pages.dev` in `CORS_ORIGINS`. When adding new YUSI deployment URLs, update that list.

**Payload shape:**
```json
{
  "email": "...",
  "list": "yusi-beta",
  "source": "yusiapp.com",
  "cfTurnstileResponse": "...",
  "consent": {
    "givenAt": "ISO timestamp",
    "version": "2025",
    "name": "...",
    "role": "teacher|administrator|curriculum|ministry|other",
    "school": "...",
    "country": "ISO 3166-1 alpha-2",
    "comment": "..."
  }
}
```

Extra fields (name, role, school, country, comment) are packed into the `consent` object — no schema migration needed. The `ensureList()` call in the portal auto-creates the `yusi-beta` list on first signup.

---

## Turnstile (Spam Protection)

- **Client-side widget key:** `PUBLIC_TURNSTILE_SITE_KEY` — Astro bakes this at build time. Set it in the Cloudflare Pages project's environment variables, then redeploy.
- **Server-side secret:** `TURNSTILE_SECRET_KEY` — set as a Workers secret on `cultscale-os`:
  ```bash
  cd /home/mnm/workspaces/cultscale
  npx wrangler secret put TURNSTILE_SECRET_KEY --name cultscale-os
  ```
- Turnstile is **optional** on the server: verification only runs when `TURNSTILE_SECRET_KEY` is set. Form works without it (Turnstile is cosmetic until the secret is configured).

---

## Assets

**YUSI-specific assets** are prefixed `yusi-`:

| File | Purpose |
|------|---------|
| `src/assets/src/yusi-aya-al-blouchi.jpg` | Founder photo (363×363 JPEG, EXIF stripped) |
| `src/assets/src/yusi-logo.svg` | YUSI logotype SVG |
| `src/assets/src/yusi-social-share.svg` | OG image source (SVG) |
| `src/assets/out/yusi-social-share.png` | OG image PNG (built at 2x zoom) |
| `src/assets/out/yusi-social-share.jpg` | OG image JPEG (quality 92) |
| `src/assets/out/yusi-favicon.ico` | Favicon |

**Social share image build:** The Makefile renders `yusi-social-share.svg` at `--zoom=2` (2400×1260) then resizes to 1200×630. This gives sharp anti-aliasing on text. Quality is 92 (not 80) to avoid JPEG blockiness on flat-colour/text graphics. Requires `rsvg-convert` installed and Space Grotesk fonts registered in fontconfig.

```bash
# Prerequisites (one-time setup)
sudo apt-get install librsvg2-bin
cp src/assets/lib/fonts/*.ttf ~/.local/share/fonts/
fc-cache -f

# Rebuild OG image
cd src/assets && make yusi-social-share
```

---

## Founder Section

The founder section appears between the CTA mid-section and the beta signup form. It shows Aya Al Blouchi's photo, name, LinkedIn link, title, and bio.

**Key details (do not get wrong):**
- **Name:** Aya Al Blouchi (not Bloushi)
- **Title:** Founder and Chief Education Officer
- **Previous role:** Senior Film Programmer and Youth Programmes Specialist at the Doha Film Institute
- **LinkedIn:** https://www.linkedin.com/in/aya-al-blouchi-013a8526/
- **Photo:** `src/assets/src/yusi-aya-al-blouchi.jpg`

---

## Page Section Order

```
HERO (dark)
  "See further." — tagline
HOW IT WORKS (cream)
  Three-step workflow: Choose → Teach → Reflect
FOR EVERY ROLE (dark)
  Students / Teachers / Schools — 3 columns
EVIDENCE (cream)
  Research stats + proven programme references
THE INSIGHT (saffron accent)
  Blockquote
CTA MID (dark)
  "Make cinema the heart of your curriculum." + pilot CTA
FOUNDER (cream)
  Aya Al Blouchi photo, bio, LinkedIn
BETA SIGNUP (dark)
  Full form: Name, Email, Role, School, Country, Comment + Turnstile
FOOTER
```

---

## Content Tone Rules

1. No em dashes — rephrase: use commas, colons, or restructure the sentence
2. No investor framing — no "market size", "unit economics", "the ask"
3. No negative framings ("not X, but Y") — state the positive directly
4. No explicit framework namedropping (Peter Thiel's Zero to One, etc.)
5. No mention of CULTSCALE, Maroun Najm, or internal infrastructure
6. Arabic tagline **شاهد أبعد** appears in the footer alongside "See further."

---

## DNS

`yusiapp.com` is the canonical domain. DNS is managed via OctoDNS in `dns/zones/yusiapp.com.yaml` — the root uses `type: ALIAS` pointing to `yusi-web.pages.dev.` with `proxied: true`.

`yusi.app` is in `dns/bulk-redirects.json` as a 302 redirect to `https://yusiapp.com/`.

See `.github/instructions/dns.instructions.md` for full DNS management instructions.
