# NOWY UI — guida di stile

Stile: **Apple attuale** — piatto, chiaro, arioso, fluido. Un solo colore d'accento (blu `#0071e3`),
grigi morbidi, superfici bianche con filo sottile (niente ombre pesanti), angoli arrotondati,
tipografia di sistema (SF / Inter). File: `app/static/nowy-ui.css`, `app/static/nowy-ui.js`.

## Principi
1. **Piatto**: niente ombre marcate, niente gradienti (tranne il marchio). Separazioni con filo `--nw-sep`.
2. **Fluido**: ogni azione dà un feedback immediato (barra di caricamento, spinner sul pulsante, toast).
   Le pagine entrano con dissolvenza (View Transitions). Mai "salti" o attese mute.
3. **Una azione primaria per schermata** (`btn-primary`), le altre tinta (`btn-outline-*` → pulsanti tinta).
4. **Italiano semplice** nelle etichette, niente codici tecnici a video (usare il filtro `|label`).
5. **Ogni tabella** ha Copia/Excel automatici (`table-export.js`); per escluderne una: `data-no-export`.

## Componenti
| Componente | Markup |
|---|---|
| Filtro a segmenti (stati, periodi) | `<div class="nw-seg"><a class="active" href="?">Tutte</a><a href="?status=X">Aperte <span class="count">4</span></a></div>` |
| Chip filtro (clienti, aree) | `<div class="nw-chips"><a class="nw-chip active" href="?">Tutti</a><a class="nw-chip" href="?client_id=1">Acqua & Sapone</a></div>` |
| Barra strumenti lista | `<div class="nw-toolbar"><div class="left">filtri</div><div class="right">azioni</div></div>` |
| Ricerca | `<div class="nw-search"><input class="form-control form-control-sm" placeholder="Cerca…"></div>` |
| KPI | `<a class="kpi" href="..."><div class="label">Consegne aperte</div><div class="value">12</div></a>` |
| Stato vuoto | `<div class="nw-empty"><i class="bi bi-inbox"></i><div class="title">Nessun borderò</div><div>Testo guida + azione</div></div>` |
| Badge stato | `<span class="badge text-bg-{{ badge(x.status) }}">{{ x.status|label }}</span>` |
| Pulsante pillola | `btn btn-primary btn-pill` |
| Didascalia KPI | `<div class="sub">rispetto a ieri</div>` dentro `.kpi` |
| Misuratore | `<div class="nw-meter warn"><span style="width:87%"></span></div>` (classi `warn`, `over`) |
| Cronologia | `<ul class="nw-timeline"><li><div class="when">30/09 10:22</div>Giro confermato</li></ul>` |
| Nessun risultato (ricerca) | `<div class="nw-noresult">Nessun risultato</div>` + classe `show` |

## Struttura pagina
- `{% block heading %}` titolo breve, `{% block subheading %}` una riga di contesto.
- `{% block actions %}` azioni principali della pagina (in alto a destra, max 1 primaria).
- Sotto: `nw-toolbar` (filtri + ricerca) → contenuto (card/tabelle) → stati vuoti con azione.

## Caricamento (obbligatorio sulle operazioni lente)
Aggiungere a `<form>` che fanno OCR, leggono Outlook, generano PDF, importano file:
```html
<form method="post" action="..." data-loading="Leggo la casella Outlook…"
      data-loading-sub="Cerco i borderò e li trasformo in consegne"
      data-steps="Collegamento a Outlook|Scarico gli allegati|Leggo i PDF (OCR)|Creo le consegne">
```
Gli upload `multipart/form-data` hanno già un overlay predefinito. `data-no-loading` per escludere.

## Messaggi
Le route rispondono con `?msg=...&lvl=success|warning|danger|info`: il layout li mostra come **toast**.

## Da non fare
- colori fuori palette, `style=` inline per colori/ombre, tabelle senza `table` class;
- intestazioni tabella in MAIUSCOLO; testi grigio chiaro su grigio;
- più di un `btn-primary` nella stessa area.

## Grafici (`nowy-charts.js`, Chart.js)
```html
<div class="card nw-chart-card"><div class="card-header">Colli consegnati <span class="hint">ultimi 14 giorni</span></div>
  <div class="card-body"><div class="nw-chart"><canvas id="c1"></canvas></div></div></div>
{% block scripts %}<script>
nwChart('c1', {type: 'bar', labels: {{ labels|tojson }}, series: [{name: 'Colli', data: {{ values|tojson }}}], unit: 'colli'});
</script>{% endblock %}
```
Regole (skill dataviz): colori nell'ordine della palette (mai ciclati, max 7 serie → "Altro");
**un solo asse y** (mai doppio asse); serie singola senza legenda; tempo → linea/barre, composizione →
barre impilate o ciambella (max 5 fette), confronto categorie → barre orizzontali; niente numeri su ogni
punto; stati (ok/attenzione/critico) con i colori `--nw-status-*` e sempre con etichetta.
Un KPI singolo è una tessera `.kpi`, non un grafico.

## Icone (v1.3)
- Menu laterale: **glifi senza sfondo, in rilievo** (sfumatura nel glifo + filo di luce + ombra minima), grigio ardesia a riposo,
  **blu accento** sulla voce attiva, salgono di 1px al passaggio. Markup: `<span class="ico"><i class="bi bi-...-fill"></i></span>`.
- Usare **sempre la variante piena** (`-fill`) di Bootstrap Icons, per peso visivo uniforme; niente mix pieno/contorno.
- Niente tessere colorate (scartate dall'utente); `.nav-multicolor` resta solo come opzione non usata.

## Componenti 1.5 (dai riferimenti Linear / Stripe / Vercel) — `{% import "_ui.html" as ui %}`
| Componente | Uso |
|---|---|
| Icona di stato alla Linear | `{{ ui.status(d.status) }}` (con etichetta) o `{{ ui.status(d.status, label=false) }}` — la forma dice lo stato: tratteggio = in attesa, cerchio = ricevuto, spicchio = pianificato/in corso, pieno con spunta = fatto, rosso con ! = errore |
| Metrica alla Stripe | `<div class="nw-metrics">{{ ui.metric('Valore maturato', value|money, current=v, previous=v_prev, previous_display=v_prev|money, series=[..], unit='€') }}</div>` — variazione % colorata + mini grafico |
| Variazione | `{{ ui.delta(current, previous, good='up'|'down') }}` |
| Titolo di sezione grande | `<h2 class="nw-h2">Andamento <span class="hint">ultimi 14 giorni</span></h2>` |
| Lista raggruppata alla Linear | `<div class="nw-list"><div class="nw-group"><div class="nw-group-head">{{ ui.status('RECEIVED', label=false) }} Ricevute <span class="n">9</span><i class="bi bi-chevron-down caret"></i></div><a class="nw-row" href="..."><span class="id">#12</span>{{ ui.status(..., label=false) }}<span class="title">Erba 1 <span class="muted">004601</span></span><span class="meta"><span class="nw-tag"><span class="dot" style="--c:var(--nw-series-1)"></span>Acqua & Sapone</span></span><span class="date">30 set</span></a></div></div>` — gruppi richiudibili al click |
| Striscia statistiche alla Vercel | `<div class="nw-statstrip"><div class="nw-statbox"><div><div class="t">Consegnate</div><div class="s">oggi</div></div><div class="v">{{ ui.status('DELIVERED', label=false) }} 12</div></div></div>` |
| Barra filtri a tendine | `<form class="nw-filterbar"><div class="nw-search">…</div><select class="form-select form-select-sm">…</select></form>` |

## NOWY UI 2.1 — navigazione istantanea, verbi semplici, identità (`v2/nowy-ui.css`, `v2/nowy-ui.js`)

### Navigazione (obbligatoria in ogni app NOWY)
- `<body hx-boost="true" hx-target="#nw-main" hx-select="#nw-main" hx-swap="outerHTML">`: cambia **solo** il pannello
  `<main class="content" id="nw-main">`; il menu laterale non viene mai ridisegnato (niente sfarfallio, scroll conservato).
- Il pannello porta `data-path`, `data-query` e `data-nav-counts='{"/anomalies": 3}'`: dopo ogni scambio il JS aggiorna voce
  attiva e pastiglie del menu. Le voci hanno `data-nav="/percorso"` e una `<span class="nw-count" data-count-for="…" hidden>`.
- Il server, se la richiesta è `HX-Request` + `HX-Boosted` (e non `HX-History-Restore-Request`), rende solo `<title>` + pannello
  (`nw_partial`): niente menu, niente `<head>`. `{% block scripts %}` sta **dentro** il pannello.
- `hx-history-elt` su `.layout`: la cronologia salva menu + pannello; barra di caricamento, overlay e toast restano fuori.
- Clic: voce del menu evidenziata subito (`.is-pending`), barra in alto che parte al clic; pannello attenuato solo se la
  risposta tarda più di 300 ms (`.nw-stale`, nessuno spostamento).
- Prefetch: passaggio del mouse sul menu (70 ms) o pressione di un link interno → la GET parte in anticipo; al clic htmx usa
  la risposta già pronta. Validità 10 s, monouso, azzerata da ogni invio di form / richiesta non GET. Link con `data-prefetch`
  sono precaricati anche al passaggio.
- Transizione: solo `#nw-main`, dissolvenza 90/140 ms, radice non catturata; niente animazioni con `prefers-reduced-motion`.
- Una risposta senza `id="nw-main"` (es. login per sessione scaduta) diventa una navigazione completa.

### Testi e gerarchia
- **Una sola azione primaria** (`btn-primary`) nella testata; le altre `btn-outline-secondary` o in un menu
  (`.dropdown` + `.dropdown-item`, es. «Esporta»).
- **Verbi che dicono cosa succede**: «Conferma consegna», «Conferma ricevimento», «Conferma arrivo merce»,
  «Correggi l'importo a mano», «Salva mezzo e autista», «Controlla righe». Mai «Registra», «Esegui», «Forza», «Anteprima» da soli.
- **Niente doppioni**: se un gruppo o un filtro dice già lo stato, la riga non lo ripete; le eccezioni sì (es. «Totali diversi»).
- **Riga di aiuto** (una frase) dove il passo non è ovvio: `{{ ui.hint("Testo…", "icona") }}` → `.nw-hint`.
  Procedure in passi: `<span class="nw-step">1</span>`.
- Stati sempre con `{{ ui.status(code) }}` (icona + etichetta), mai pillole `badge text-bg-*`.

### Identità NOWY
- Marchio: loghi NOWY ufficiali (2.2). `{{ ui.brand_mark(22) }}` = simbolo, `{{ ui.brand_wordmark(11) }}` = scritta,
  `{{ ui.brand_logo(120) }}` = logo intero. Maschere SVG in `brand/`: colore = testo del tema. Niente «N» disegnate a mano.
- Segno a tracciato (`--nw-route`, indaco → viola): voce attiva del menu (barretta a sinistra), barra di caricamento. Solo lì.
- Fuoco: doppio anello `--nw-focus-ring` (stacco del pannello + indaco) su pulsanti, campi, righe, voci di menu.
- Numeri tabellari in tabelle, KPI, pastiglie, date delle righe.
- Stato vuoto: ogni `.nw-empty` mostra la tessera dell'icona su un tracciato tratteggiato (partenza indaco → arrivo ad anello);
  macro `{{ ui.empty("Titolo", "Cosa fare", "icona") }}`.
- Token nuovi: `--nw-brand`, `--nw-brand-2`, `--nw-on-brand`, `--nw-route`, `--nw-focus-ring`, `--nw-hint-bg`,
  `--nw-dur-fast`, `--nw-dur`, `--nw-ease-out` (chiaro e scuro).
