# Login Page

**Status:** ✅ Implemented | Real floating book covers with professional animations

Stylized entry point with Plex/Audiobookshelf authentication, animated floating popular audiobook covers, and dynamic description based on backend configuration.

## Design

- Full-screen immersive experience with gradient background
- Centered hero with login button
- Animated floating real audiobook covers (popular releases)
- **100 randomly positioned covers** with varied sizes, animations, and depth
- Multi-layer depth effect with z-index layering (0-20)
- Dark theme optimized with glassmorphism card
- Professional streaming service aesthetic
- **Dynamic description** based on backend mode (Plex/Audiobookshelf) and automation status

## Authentication Flow

1. User visits protected route → redirected to `/login`
2. Clicks "Login with Plex"
3. `POST /api/auth/plex/login` → requests PIN
4. Opens Plex OAuth in popup
5. Polls `/api/auth/plex/callback` for authorization
6. User authorizes in Plex popup
7. Callback receives auth token
8. Creates/updates user in DB
9. Returns JWT tokens
10. Client stores tokens in localStorage
11. Redirects to originally requested page or homepage

## Book Covers

**Data Source:** `GET /api/audiobooks/covers`
- Returns up to 200 popular audiobook covers
- Uses cached thumbnails from `audible_cache` table
- Shuffled on each request for variety
- Fallback to placeholder elements if API fails

**Display:**
- **100 covers** shown simultaneously for immersive experience
- Varied sizes: 80-160px wide (1.5 aspect ratio)
- Opacity range: 0.15-0.35 for subtle layering and depth
- Staggered animation delays (0-10s) for natural movement
- Z-index layering (0-20) for depth perception
- Programmatic positioning using seeded random for consistency
- Lazy loading (first 10 eager, rest lazy) for performance
- Hover pauses animation and scales for interaction

**Positioning Algorithm:**
- Seeded random function ensures consistent positions per cover index
- Random distribution across full viewport (0-100% both axes)
- Each cover gets unique: size, position, opacity, delay, z-index, animation type
- Seed multipliers (7, 13, 17, 23, 29, 31) prevent pattern repetition
- Math.sin() based pseudo-random for deterministic results

## Dynamic Description

Description text adapts to backend configuration:

**Plex + Automation Enabled:** "Request audiobooks and they'll automatically download and appear in your Plex library"
**Plex + No Automation:** "Request audiobooks for your Plex library"
**Audiobookshelf + Automation:** "Request audiobooks and they'll automatically download and appear in your Audiobookshelf library"
**Audiobookshelf + No Automation:** "Request audiobooks for your Audiobookshelf library"
**Loading State:** "Your Personal Audiobook Library Manager"

Automation is detected by checking for configured indexer (Prowlarr) via `/api/auth/providers` endpoint.

## State

```typescript
interface LoginPageState {
  isLoggingIn: boolean;
  error: string | null;
  pinId: number | null;
  authWindow: Window | null;
  bookCovers: BookCover[];
  showAdminLogin: boolean;
  adminUsername: string;
  adminPassword: string;
  authProviders: {
    backendMode: string;
    providers: string[];
    registrationEnabled: boolean;
    hasLocalUsers: boolean;
    oidcProviderName: string | null;
    localLoginDisabled: boolean;
    automationEnabled: boolean;
  } | null;
}

interface BookCover {
  asin: string;
  title: string;
  author: string;
  coverUrl: string;
}
```

## Error Handling

**Popup Blocked:** "Popup was blocked. Please allow popups."
**Login Timeout:** 2 min polling timeout
**Plex Unavailable:** "Plex services currently unavailable."
**Covers Fail:** Silent fallback to placeholder gradient elements

## Animations

Three animation speeds with realistic floating motion:

```css
@keyframes float-slow {
  /* 22s cycle with 4 keyframes */
  0%, 100% { transform: translateY(0) translateX(0) rotate(0deg) scale(1); }
  25% { transform: translateY(-25px) translateX(15px) rotate(2deg) scale(1.03); }
  50% { transform: translateY(-35px) translateX(25px) rotate(4deg) scale(1.05); }
  75% { transform: translateY(-20px) translateX(-10px) rotate(-2deg) scale(1.02); }
}

@keyframes float-medium {
  /* 16s cycle with 3 keyframes */
  0%, 100% { transform: translateY(0) translateX(0) rotate(0deg) scale(1); }
  33% { transform: translateY(-30px) translateX(-20px) rotate(-3deg) scale(1.04); }
  66% { transform: translateY(-15px) translateX(10px) rotate(3deg) scale(1.02); }
}

@keyframes float-fast {
  /* 12s cycle with 2 keyframes */
  0%, 100% { transform: translateY(0) translateX(0) rotate(0deg) scale(1); }
  50% { transform: translateY(-28px) translateX(18px) rotate(5deg) scale(1.06); }
}
```

**Features:**
- Scale transformations (1.02-1.06) for depth
- Rotation (-5° to +5°) for natural movement
- X/Y translation for floating effect
- Hover pauses animation
- Shadow-2xl for 3D depth

## Security

- Tokens in localStorage (access 1hr, refresh 7d)
- Tokens cleared on logout
- OAuth state parameter validation
- SameSite cookie attributes

## Tech Stack

- Next.js 14+ Client Component
- Tailwind CSS with custom animations
- Plex OAuth via AuthContext
