# Cima Progetti - Sito Aziendale

Sito web moderno, performante e accessibile sviluppato con **Svelte 5 + Vite** per presentare servizi, metodologia e contatti aziendali. Completamente responsivo con supporto completo per telefoni e tablet.

## ✨ Funzionalità principali

- 🌓 **Tema light/dark** con persistenza dual-storage (localStorage + cookie backup)
- 📱 **Design completamente responsivo** con breakpoint intelligenti
- ⬆️ **Header smart** — trasparente all'inizio, sfondo blur opaco dopo scroll
- 🍔 **Menu hamburger** con animazione fluida di apertura/chiusura
- 🎨 **Sistema di componenti riusabili** e theme-aware
- 🚀 **Routing client-side** con History API e fallback 404 per pagine non create
- 🔐 **Cookie consent** con personalizzazione categorie
- ♿ **Accessibilità** — focus-visible preservato, tap highlight rimosso su touch
- ⚡ **Svelte 5 Runes** — reattività state-driven con $state(), $derived()
- 🐛 **Global error handling** — trap di SyntaxError visibile su dev server

## 🛠️ Requisiti

- **Node.js** 18+ (consigliato LTS)
- **npm** 9+

## 🚀 Avvio rapido

```bash
npm install
npm run dev
```

Applicazione disponibile su `http://localhost:5173` (accesso locale) e `http://192.168.XX.XXX:5173` (rete locale).

## 📝 Script disponibili

| Script | Descrizione |
|--------|-------------|
| `npm run dev` | Avvia il server di sviluppo con hot reload (esposto su 0.0.0.0:5173) |
| `npm run build` | Genera la build di produzione ottimizzata in `dist/` |
| `npm run preview` | Avvia preview della build (simula produzione in locale) |

## 📁 Struttura del progetto

```
cimaprogetti/
├── index.html                    # Template HTML entry point
├── package.json                  # Dependencies e scripts
├── vite.config.js               # Configurazione Vite (SPA + host 0.0.0.0)
├── svelte.config.js             # Configurazione Svelte
│
├── src/
│   ├── main.js                  # Entry point con error trap globale
│   ├── App.svelte               # Root component con routing e layout
│   │
│   ├── components/
│   │   ├── Header/
│   │   │   ├── Header.svelte    # Navbar sticky con tema + scroll detection
│   │   │   └── Header.css       # Stili header (blur backdrop, absolute menu)
│   │   │
│   │   ├── Button/
│   │   │   ├── Button.svelte    # Button/link riusabile (16 prop)
│   │   │   └── Button.css       # Stili + focus-visible + no tap highlight
│   │   │
│   │   ├── CookiePopUp/
│   │   │   ├── CookiePopUp.svelte    # Cookie consent con toggle personalizzato
│   │   │   ├── CookiePopUp.css       # Dialog mobile + desktop
│   │   │   └── assets/               # SVG cookie icon
│   │   │
│   │   ├── Toggle/
│   │   │   ├── Toggle.svelte    # Switch accessibile
│   │   │   └── Toggle.css       # Stili toggle (animated knob)
│   │   │
│   │   ├── ThemeToggle/
│   │   │   ├── ThemeToggle.svelte
│   │   │   └── ThemeToggle.css
│   │   │
│   │   ├── Footer/
│   │   │   ├── Footer.svelte
│   │   │   └── Footer.css
│   │   │
│   │   └── Hero/, Services/     # Componenti home
│   │
│   ├── pages/
│   │   ├── index.svelte         # Home page
│   │   ├── Contacts.svelte      # Pagina contatti con team profiles
│   │   ├── 403.svelte, 404.svelte, 500.svelte, errore.svelte  # Error pages
│   │
│   ├── lib/
│   │   ├── theme.js             # Theme persistence (localStorage + cookie)
│   │   ├── navigation.js        # Client-side routing utilities
│   │   ├── cookieConsent.js     # Cookie storage & consent management
│   │   └── errorRouting.js      # Path normalization & aliases
│   │
│   └── styles/
│       ├── global.css           # CSS variables, typography, resets
│       ├── App.css              # Layout principale
│       ├── contacts.css         # Pagina contatti (flex + absolute positioning)
│       └── error-pages.css      # Pagine errore (clamp typography)
│
└── public/
    └── images/
        ├── background/          # Background patterns
        ├── icons/               # Logo, UI icons
        └── contacts/            # Hero images (light/dark theme)
```

## 🌐 Configurazione Network

Il server Vite è configurato per essere **accessibile dalla rete locale**:

```js
// vite.config.js
server: {
    host: '0.0.0.0',  // Ascolta su tutte le interfacce
    port: 5173,
}
```

### Accesso dal telefono sulla stessa Wi-Fi

1. Avvia il dev server: `npm run dev`
2. Nel terminale vedrai l'indirizzo IP locale (es. `192.168.68.119`)
3. Dal telefono apri: `http://192.168.68.119:5173`

**Nota:** Per produzione, usa `npm run build && npm run preview` per servire la versione compilata su `http://192.168.68.119:4173` (compatibile con browser vecchi).

## 🗺️ Routing

Il routing è **client-side only** — nessuna pagina server. Gestito in `App.svelte` leggendo `window.location.pathname` e reagendo ai cambi di History API.

### Tabella rotte

| Route | Pagina | Comportamento |
|-------|--------|---------------|
| `/` | `index.svelte` | Home page (Hero + Services) |
| `/contatti` o `/contacts` | `Contacts.svelte` | Info contatti + team profiles |
| `/servizi`, `/metodo`, `/progetti`, `/chi-siamo` | `404.svelte` | Non create — mostra 404 ma mantiene URL |
| `/403`, `/404`, `/500`, `/errore` | Error pages | Pagine errore dedicate |
| Qualsiasi altra rotta | `404.svelte` | Fallback automatico |

### Meccanismo di routing

```js
// src/App.svelte
const getRoute = (path) => {
    const normalized = resolvePathname(path)  // Normalizza trailing slash
    if (normalized === '/') return 'home'
    if (normalized === '/contatti' || normalized === '/contacts') return 'contacts'
    // ...
    return '404'  // Fallback
}

let currentRoute = $derived(getRoute(pathname))
```

### Come aggiungere una nuova pagina

1. **Crea il componente** in `src/pages/MyPage.svelte`
2. **Importa in App.svelte**:
   ```svelte
   import MyPage from "./pages/MyPage.svelte"
   ```
3. **Aggiungi la route** in `getRoute()`:
   ```js
   if (normalized === '/my-page') return 'mypage'
   ```
4. **Renderizza nel template**:
   ```svelte
   {:else if currentRoute === 'mypage'}
       <MyPage />
   ```

## 🎨 Sistema di Tema

### Tema Persistente Dual-Storage

Il tema viene salvato su **localStorage** (primario) e **cookie** (backup) simultaneamente. Questo assicura che il tema sopravviva anche se l'utente cancella parte dello storage del browser.

```js
// src/lib/theme.js

export const getSavedTheme = () => {
    // Prova localStorage prima, poi cookie come fallback
    return localStorage.getItem('theme') || getCookie('theme')
}

export const saveTheme = (theme) => {
    localStorage.setItem('theme', theme)
    setCookie('theme', theme)  // Backup redundante
}

export const applyTheme = (theme) => {
    document.documentElement.setAttribute('data-theme', theme)
}
```

### Variabili CSS Globali

Tutte le variabili tema sono in `src/styles/global.css`:

```css
:root {
    --navbar-height: 140px;
    --primary-color: #1343F0;      /* Blu Cima */
    --text-color: #111827;          /* Grigio scuro */
    --surface: #ffffff;             /* Background carta */
    --background: rgba(246, 249, 255, 0.5);
    --background-opaque: #00000033;
    --muted-color: #6b7280;
    --lateral-margin: 12rem;
}

:root[data-theme='dark'] {
    --primary-color: #4983F2;       /* Blu chiaro */
    --text-color: #e6eef8;           /* Grigio molto chiaro */
    --surface: #000;
    --background: rgba(0, 0, 0, 0.8);
    --background-opaque: rgba(255, 255, 255, 0.2);
}

/* Mobile breakpoint */
@media (max-width: 900px) {
    :root {
        --navbar-height: 110px;
        --lateral-margin: 1.5rem;
    }
}
```

### Come usare i colori tema

```svelte
<div style="color: var(--text-color); background: var(--surface);">
    Contenuto automaticamente theme-aware
</div>
```

## 🧩 Componenti Principali

### Header (Navbar Intelligente)

La navbar è **sticky** e reagisce allo scroll con una transizione elegante:

- **Trasparente all'inizio** (`background-color: transparent`)
- **Sfondo blur dopo 100px di scroll** (`backdrop-filter: blur(8px)`)
- **Scompare al scroll verso il basso** (nascosto con `translateY(-100%)`)
- **Riappare al scroll verso l'alto** (velocità rilevata)

```svelte
<Header />
```

**Modifiche in Header.svelte:**
- Stato `hasBackground` che attiva a `scrollY > 100`
- Classe `with-bg` per applicare blur e shadow
- Mobile menu hamburger con animazione da basso

**CSS Features:**
- `backdrop-filter: blur(8px)` per effetto frosted glass
- `position: fixed` con `transition: transform 0.28s`
- Menu mobile `transform: translateY(100%)` → `translateY(0)` con cubic-bezier smoothing

### Button (Componente Riusabile)

Componente ultra-flessibile che renderizza come `<a>` se ha `href`, altrimenti `<button>`.

```svelte
<Button 
    text="PRENOTA UNA CALL"
    href="/contatti"
    borderWidth="1.5px"
    borderColor="var(--text-color)"
    color="transparent"
    textColor="var(--text-color)"
    padding="12px 32px"
    round="5px"
    margin="1rem 0 0"
    bold
/>
```

**Tutte le prop:**

| Prop | Default | Descrizione |
|------|---------|-------------|
| `text` | `'Button'` | Testo del pulsante |
| `color` | `var(--primary-color)` | Background |
| `textColor` | `var(--surface)` | Colore testo |
| `padding` | `'10px 20px'` | Padding interno |
| `round` | `'5px'` | border-radius |
| `href` | — | Se presente, renderizza come `<a>` con navigazione client-side |
| `borderWidth` | `'0px'` | Spessore border interno (inset) |
| `borderColor` | `var(--primary-color)` | Colore border |
| `bold` | `true` | Font-weight bold |
| `margin` | `'0'` | **NEW** — margini esterni |

**Accessibilità:**
- Outline su `:focus-visible` (tastiera)
- Tap highlight rimosso su touch (`:focus:not(:focus-visible)`)

### CookiePopUp (Cookie Consent Dialog)

Dialog modale con due view:

1. **Main** — Descrizione generica + bottoni accetta/rifiuta/personalizza
2. **Prefs** — Toggle per tre categorie: Tecnici (always on), Analitici, Profilazione

```svelte
<CookiePopUp />
```

**Varianti layout:**
- **Desktop** (> 900px): Fixed al bottom, full-width
- **Tablet** (768–900px): Drawer da destra (clip-path animation)
- **Mobile** (< 768px): Full-page dal basso (translateY animation)

**Accessibilità:**
- `role="dialog"` + `aria-modal="true"`
- Focus trap — primo elemento focusabile automaticamente
- Escape key per chiudere (con reject)
- Tap highlight disabilitato

### Contacts Page (Pagina Contatti)

Layout two-column con immagine decorativa e team profiles.

```svelte
<div class="contact-us">
    <div class="contact-us-container">
        <!-- Titolo, testo, email/WhatsApp, button -->
    </div>
    <div class="contact-image">
        <!-- SVG tema-aware (light/dark) -->
    </div>
</div>

<div class="behind-cima">
    <h2>PEOPLE BEHIND CIMA</h2>
    <div class="profiles-container">
        <!-- Due profile cards con flex: 1 1 0 -->
    </div>
</div>
```

**Responsive:**
- **Desktop** (> 900px): Due colonne con gap 40px
- **Mobile** (< 900px): 
  - `contact-image` diventa `position: absolute` centrata 
  - `contact-us-container` full width
  - Profili stacked verticalmente

### Toggle (Accessibile Switch)

Switch accessibile con label opzionale e stato animato.

```svelte
<Toggle 
    bind:checked={analitici}
    label="Analitici"
    disabled={false}
/>
```

**CSS Variables** (customizzabile):
- `--toggle-on-bg` — colore quando ON
- `--toggle-off-bg` — colore quando OFF
- `--toggle-knob` — colore pallina
- `--toggle-width` / `--toggle-height` — dimensioni

## 📱 Responsive Design

### Breakpoint Principale

L'unico breakpoint è **900px** (tablet). Sotto questo valore attivano:

- Margini orizzontali ridotti: `12rem` → `1.5rem`
- Navbar height ridotta: `140px` → `110px`
- Menu hamburger (al posto di nav desktop)
- Header flexibile trasparente con blur
- Contatti layout single-column
- Profiles stacked
- Error pages con tipografia clamp()

### Clamp() per Tipografia Fluida

Errori, heading e font-size critici usano `clamp()` per scalare fluidamente:

```css
/* Error code number */
.error-code {
    font-size: clamp(2rem, 5vw, 4rem);
}

/* Error page title background */
.error-text {
    font-size: clamp(10rem, 20vw, 15rem) !important;
}

/* Links in contacts */
.contact-info-item a {
    font-size: clamp(1.25rem, 2.5vw, 2rem);
}
```

## 🔐 Cookie Consent & Privacy

### Gestione Categoria Cookie

```js
// src/lib/cookieConsent.js

const consent = {
    value: 'custom',  // 'accepted_all', 'rejected_all', 'custom'
    preferences: {
        tecnici: true,           // Obbligatorio
        analitici: false,        // Personalizzabile
        profilazione: false      // Personalizzabile
    }
}
```

### Persistenza

- Cookie di consenso salvato in `cookie-consent` (via `js-cookie`)
- Configurazione letta al mount di `App.svelte`
- Toggle popup non riappare se esiste consenso valido

## 🐛 Error Handling & Debugging

### Global Error Trap (main.js)

```js
// Cattura SyntaxError e runtime errors prima del mount
window.addEventListener('error', (event) => {
    const msg = `ERROR: ${event.error?.message || event.message}`;
    console.error(msg, event.error);
    alert(msg);  // Visibile su telefono per debug
}, true);

try {
    const app = mount(App, { target: document.getElementById('app') })
    console.log("App mounted successfully!")
} catch (e) {
    alert(`Mount Error: ${e.message}`)
}
```

### Diagnostica Schermo Bianco

Se il telefono mostra schermo bianco:

1. **Apri DevTools** → Console → controlla errori
2. **Prova build di produzione**:
   ```bash
   npm run build
   npm run preview
   # Accedi da http://192.168.XX.XXX:4173
   ```
3. **Se l'alert appare**, c'è un SyntaxError nei moduli ES
4. **Prova altro browser** (Chrome vs Safari su iOS)

## 🔄 Svelte 5 & Modern JavaScript

### Svelte 5 Runes

Il progetto usa **Svelte 5 Runes** per reattività state-driven:

```svelte
<script>
    let activeNav = $state(window.location.pathname)
    let isMenuOpen = $state(false)
    let hasBackground = $state(false)
    
    let currentRoute = $derived(getRoute(pathname))
</script>
```

**Evitare:**
- ~~`on:click`~~ → Usare `onclick={...}`
- ~~Stores `writable()`~~ → Usare `$state()`
- ~~`reactive`~~ → Usare `$derived()`

### Rune Disponibili

- `$state(value)` — Mutabile, reattivo
- `$derived(expr)` — Calcolato e cached
- `$effect(fn)` — Side effect reattivo
- `$props()` — Default props type-safe

## 🚀 Build & Deploy

### Build di Produzione

```bash
npm run build
```

Genera file ottimizzati in `dist/`:
- `.html` minificato
- `.js` bundle (tree-shaken)
- `.css` minificato
- Source map opzionali

### Preview Locale

```bash
npm run preview
```

Simula il server di produzione su `http://localhost:4173` — ottimo per testare la build prima di deployare.

### Deployment

Il progetto è una **SPA statica** — deployabile su:

- **Vercel**, **Netlify** (drag & drop `dist/`)
- **GitHub Pages** (aggiungere `base: "/repo-name/"`  in vite.config.js)
- **AWS S3 + CloudFront**
- **Qualsiasi server web** (serve `dist/` con fallback 404 → `/index.html`)

## 📦 Dipendenze

```json
{
  "devDependencies": {
    "@sveltejs/vite-plugin-svelte": "^7.0.0",
    "svelte": "^5.55.5",
    "vite": "^8.0.10"
  }
}
```

**Zero runtime dependencies** — tutta la logica è vanilla JavaScript.

## 🎓 Tecnologie & Approcci

| Aspetto | Soluzione |
|---------|----------|
| **Framework UI** | Svelte 5 (Runes + reactivity) |
| **Build** | Vite 8 (zero-config, super veloce) |
| **CSS** | CSS3 nativo (custom properties + clamp) |
| **Routing** | History API (client-side only) |
| **Tema** | Data attribute + CSS variables |
| **Cookies** | Vanilla JS (no library) |
| **Accessibilità** | ARIA roles + focus-visible + keyboard nav |
| **Mobile** | Responsive design + touch optimized |

## 🎯 Convenzioni Codice

### Naming

- **Components**: PascalCase (`Header.svelte`, `Button.svelte`)
- **Pages**: PascalCase (`Contacts.svelte`, `index.svelte`)
- **Styles**: kebab-case (`.contact-us-container`, `.mobile-menu`)
- **JS utils**: camelCase (`getSavedTheme`, `navigateTo`)

### Organizzazione File

```
Component/
├── Component.svelte      # Logica + template
├── Component.css         # Stili isolati
└── assets/               # SVG, immagini specifiche
```

### CSS Classi

- `.component-name` per root
- `.component-name-child` per nested (BEM-like)
- Aggiungere media query alla fine del file
- Commentare sezioni con `/* ===== SECTION NAME ===== */`

## 🤝 Contribuire

### Workflow

1. **Crea branch** per feature: `git checkout -b feature/nome`
2. **Test locale**: `npm run dev` + mobile preview
3. **Build test**: `npm run build && npm run preview`
4. **Commit**: Messaggi chiari (`feat:`, `fix:`, `docs:`)
5. **Push** e open PR

## 🔗 Link Utili

- [Svelte 5 Docs](https://svelte.dev)
- [Vite Docs](https://vitejs.dev)
- [Svelte REPL](https://svelte.dev/repl)
- [Can I Use](https://caniuse.com) — Compatibilità browser

## 📄 Licenza

Progetto proprietario © **CIMA PROGETTI**