Commit Graph
104 Commits
Author SHA1 Message Date
Ivan CacciariandCursor 46f5c28237 Rinomina il bilancio home in Bilancio W-L.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-05 22:57:17 +02:00
Ivan CacciariandCursor 1e8168d413 Rinomina il bilancio home in Bilancio vittorie.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-05 22:52:52 +02:00
Ivan CacciariandCursor 61c6aaaaed Toglie la proposta automatica dei palloni sugli allenamenti.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-05 22:44:25 +02:00
Ivan CacciariandCursor 033c45df4d Apre Tesseramento dal widget Completa profilo in home.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-05 22:38:48 +02:00
Ivan CacciariandCursor 2345a45f14 Allinea le notifiche del profilo al canale intero e stacca Esci in rosso chiaro.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-05 22:31:56 +02:00
Ivan CacciariandCursor ce1c7cfd4b Alleggerisce il cambio tab delle sottosezioni togliendo exit e molle.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-05 22:24:57 +02:00
Ivan CacciariandCursor e9755d364c Aggiunge sottosezioni a swipe nel profilo, con stagione e serie unite.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-05 22:07:58 +02:00
Ivan CacciariandCursor f4398fce25 Aggiunge lo stemma in home e ravviva blu allenamenti e verde compleanni.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-05 21:31:41 +02:00
Ivan CacciariandCursor ede02b7575 Aggiunge sottosezioni a swipe su Squadra e Classifica.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-05 21:18:19 +02:00
davideandClaude Opus 5 c089d9e8ba Dà profondità alle superfici e trasforma la barra in vetro
Fondo pagina, carte e `secondary` stavano dentro tre punti di luminosità:
carta e fondo avevano un rapporto di contrasto di 1.04, cioè erano lo stesso
bianco. Le carte non si leggevano come carte, e l'unica cosa che le staccava
era `shadow-card` — 6% di nero, che su un telefono al sole non esiste. Da qui
l'impressione che fondo, barra ed elementi fossero «tre bianchi».

La rampa dei neutri è ridistanziata: fondo 0.93, carta 1.0, `secondary` 0.90.
Carta e fondo passano a 1.23, un elemento dentro una carta sta a 1.35 dalla
carta ed è più scuro di essa, come nelle liste raggruppate di iOS. 0.93 è il
fondo più scuro possibile senza toccare altro: il limite lo impone
`text-accent` appoggiato sul fondo, che a 0.92 scenderebbe sotto 4.5.

Due colori vanno corretti di conseguenza, altrimenti la modifica peggiora la
leggibilità: l'accento scende a 0.54 (a 0.58 come testo faceva 4.07 sul nuovo
fondo; ora fa 4.62, e migliora anche il bianco che ci sta sopra, da 4.65 a
5.51) e `muted-foreground` a 0.48. Verificati convertendo le oklch in sRGB e
calcolando i rapporti, non a occhio.

`--destructive` e `--ring` erano *lo stesso identico colore* dell'accento:
«elimina», «selezionato» e «ho il focus qui» davano il medesimo segnale. Il
distruttivo resta rosso ma più scuro e cupo, il focus viene dal neutro.

Le ombre passano da una a tre quote: `shadow-card` per il contenuto,
`shadow-chrome` per barra, drawer e toast (più profonda, più il filo chiaro sul
bordo alto), `shadow-alza` neutra per l'hover — `premi` metteva un alone rosso
sotto ogni riga di classifica.

La barra ora usa `vetro`: fondo al 62% invece dell'85%, così ci si vede
attraverso, più tre ombre interne che sono il bordo illuminato. L'85% di
`materiale` esiste per tenere allineati WebKit e Blink (608f2ed) su una fascia
larga quanto lo schermo; su una pillola di 60 px lo scarto non si legge.

Dietro `@supports`, un `feDisplacementMap` distorce davvero il fondale: solo
Blink accetta un filtro SVG in `backdrop-filter`, e WebKit ignorando l'url
scarterebbe anche il blur. Miglioria progressiva, non l'effetto principale.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-05 20:02:13 +02:00
davideandClaude Opus 5 bb4fb624f5 Mette lo stemma della squadra nell'intestazione del profilo
In alto a destra sul profilo c'era `/icon-192.png`, cioè l'icona della PWA: ha
dentro il nome dell'app, e come marchio in una schermata dell'app stessa non
dice niente. Lì serve lo stemma della squadra.

`TeamLogo` prende una prop `src` con l'icona come default, così cambia solo la
chiamata del profilo. L'icona della PWA resta quella dappertutto altrove
(ripiego di `LinkProfilo`, schermata di caricamento, manifest, apple-touch-icon):
sulla home dello schermo è giusto che l'app si presenti come «CrAPP».

Il file arrivava come `logo_nerorosso.jpg` ma è un SVG: rinominato con
l'estensione giusta, altrimenti verrebbe servito come JPEG e non si vedrebbe.
Sta in `public/`, che è la cartella servita così com'è.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-05 19:35:44 +02:00
davideandClaude Opus 5 37a04e5103 Rimette «Home» come etichetta della prima voce
`5c49294` aveva rinominato la voce in «Oggi» per dire cosa contiene la
schermata, ma il nome che la squadra usa è «Home».

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-05 19:24:54 +02:00
davideandClaude Opus 5 383643392a Porta il profilo in alto a destra e lascia quattro voci nella barra
La barra aveva cinque voci e la quinta era il profilo, che non è una
destinazione di pari livello con Oggi, Calendario, Squadra e Classifica: è la
propria scheda, e su iOS si cerca in alto a destra. Toglierla dalla barra
restituisce anche un quinto di larghezza alle altre quattro.

`LinkProfilo` mostra l'avatar del giocatore e porta a `/profilo`. Sta in
`PageHeader`, quindi compare su calendario, squadra, classifica e profilo, più
l'hero della home che ha un'intestazione propria. Se l'avatar non è stato
caricato `Avatar` ricade sulle iniziali; se il giocatore non c'è ancora (primo
render) resta il logo, così il posto non resta vuoto.

Sulla pagina del profilo l'avatar sarebbe un link a sé stessa: `PageHeader`
prende una prop `azione` e lì si passa il logo della squadra.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-05 19:22:08 +02:00
davideandClaude Opus 5 fabee4df1d Stacca la barra di navigazione dal fondo
La barra era una striscia a filo schermo con la sfumatura al bordo superiore
(scroll edge effect). Ora è una pillola staccata: il `<nav>` esterno tiene solo
posizione, safe area e margine laterale, mentre il materiale, il raggio, il bordo
e l'ombra passano al contenitore interno.

`pointer-events-none` sul wrapper e `pointer-events-auto` sulla pillola: ai lati
della barra i tocchi devono raggiungere il contenuto sotto, non una striscia
trasparente larga quanto lo schermo.

Via `bordo-sfumato`: la sfumatura serve a mascherare il taglio netto di una barra
attaccata al bordo, e su una che galleggia non ha più niente da mascherare.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-05 19:17:36 +02:00
davideandClaude Opus 5 c8cd8c9720 Rinomina il titolo della home in CRAP Volley
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-05 15:20:59 +02:00
davideandClaude Opus 5 6e05f5134f Non taglia più l'anello del giorno corrente
Regressione mia, introdotta con lo swipe in 9b28a86: la griglia è avvolta in
un `overflow-hidden` che serve a nascondere il mese che entra ed esce di lato.
L'anello del giorno corrente però è `ring-2 ring-offset-1`, quindi disegna 3 px
FUORI dai bordi della cella: sulla prima riga quei 3 px cadono oltre il bordo
del riquadro di ritaglio e vengono tagliati. Sarebbe successo lo stesso
sull'ultima riga e sulle colonne di bordo, se oggi fosse caduto di lunedì o di
domenica.

`p-1` sul contenitore che ritaglia dà all'anello i suoi 4 px di aria dentro il
riquadro; `-mx-1` e `mt-1` al posto di `mt-2` rimettono la griglia esattamente
dov'era, quindi le celle non si spostano di un pixel: cambia solo dove passa il
bordo di ritaglio.

Non si può usare `overflow-x: hidden` da solo: in CSS, se un asse è `hidden` e
l'altro `visible`, quello visibile diventa `auto` e ritaglia comunque, per
giunta creando uno scroll container.

Scartato anche `ring-inset`, che non può essere tagliato per costruzione: nei
giorni in cui oggi coincide con un evento l'anello scuro finirebbe appiccicato
al colore pieno, senza lo stacco bianco che ha adesso.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-05 15:15:36 +02:00
davideandClaude Opus 5 1685d0b57a Ripristina il fondo diviso sui giorni con più tipi di evento
Avevo sostituito la cella divisa con fondo neutro e puntini colorati. Si
perdeva l'informazione a colpo d'occhio: il colore dice subito che tipo di
impegno c'è, i puntini vanno cercati.

Torna la resa di main: `linear-gradient(135deg, …)` con gli stop duplicati,
che non è una sfumatura ma bande a taglio netto in diagonale, una per tipo. Il
conteggio resta per **tipo** e non per numero di eventi: due partite nello
stesso giorno restano una cella rossa piena, si divide solo se i tipi sono
diversi.

`coloreTipo` sale a livello di modulo: era ricostruito per ogni cella, cioè
una trentina di volte per mese a ogni render.

Nota sul contrasto, per chi tornerà qui. Il numero sta direttamente sulle
bande con un alone bianco in `drop-shadow`, ed è una scelta di resa esplicita:
il colore deve restare pieno fino al bordo. Ha un costo, però, perché nel
frattempo success e training sono stati scuriti da 0.62 a 0.53 per far passare
il testo bianco dei chip: il numero scuro sulle bande scende da 5.6:1 a 3.9:1
sul blu e da 5.7:1 a 4.0:1 sul verde. Se un giorno la leggibilità dà fastidio,
la leva è una parola — `text-foreground` -> testo bianco sulle sole celle
divise, che risale a ~4.9:1.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-05 15:15:11 +02:00
davideandClaude Opus 5 608f2eda2f Rende il materiale della barra coerente fra WebKit e Blink
A parità di CSS la barra sembrava piena su Safari e trasparente su Chrome
Android. Il colore di fondo era lo stesso sui due: la differenza veniva tutta
dal blur. WebKit rende `backdrop-filter: blur()` molto più denso e "latteo"
di Blink, e `saturate(180%)` amplificava lo scarto — con un fondo al 72%
l'aspetto dipendeva quasi solo dal filtro, cioè dalla parte su cui i due
motori non sono d'accordo.

Il materiale ora si regge sul colore (85%) e usa il blur come rifinitura: la
profondità resta, la differenza fra i due motori quasi sparisce perché pesa
molto meno. `saturate` scende a 150% per la stessa ragione.

`color-mix` passa da `in oklab` a `in srgb`: mescolare con `transparent`, che
è nero con alpha 0, dipende da come il motore premoltiplica, e in srgb è
implementato in modo molto più uniforme.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-05 14:52:51 +02:00
davideandClaude Opus 5 78ae3fbbd7 Allinea la barra di navigazione fra iOS e Android
L'altezza della barra era dedotta dai padding delle voci e poi ricopiata a
occhio altrove: `pb-24` nel contenitore delle pagine, `pb-28` nella
celebrazione badge. Su iPhone i conti tornavano per 2 px — barra ~60 px più
34 px di safe area contro 96 px riservati — quindi bastava un inset diverso
(orizzontale, o un modello con home indicator più alta) perché l'ultimo
elemento della pagina finisse sotto la barra. Solo su iOS: su Android
avanzavano 36 px.

Ora la geometria sta in due token, `--altezza-nav` e `--pad-sicura-fondo`, e
le utility `spazio-nav` e `pad-sicura-fondo` la leggono da lì. La striscia
toccabile ha altezza fissa, così misura uguale sui due sistemi e sotto varia
solo l'inset: `max(env(safe-area-inset-bottom), 0.5rem)` dà ad Android un
respiro minimo dove iOS mette la home indicator. Identiche al pixel non
possono essere — quell'inset esiste per un motivo fisico che Android non ha —
ma la differenza è ora un margine in più, non un allineamento diverso.

`100vh` diventa `100dvh` ovunque: su iOS Safari `vh` misura il viewport con la
toolbar collassata, cioè più alto di quello visibile, e le schermate a tutta
altezza risultavano più lunghe dello schermo. `dvh` segue la toolbar.

Aggiunto il ripiego per Chrome su Android, che disattiva `backdrop-filter`
senza accelerazione hardware: senza, su quei device la barra restava
semitrasparente e il contenuto si leggeva attraverso.

Resta fuori portata una differenza sola: in Safari non installata la toolbar
di sistema sta in basso e collassa allo scroll, quindi la barra si muove con
essa. Su Chrome la toolbar è in alto. Si risolve installando la PWA.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-05 14:50:32 +02:00
davideandClaude Opus 5 5a534547ae Riformatta i file che prettier segnalava da prima
`npm run format` ha toccato anche tre file estranei a questo lavoro:
`presenze.ts` aveva un errore prettier che `npm run lint` già segnalava, gli
altri due erano solo a capo nelle tabelle markdown. Stanno qui da soli per non
sporcare i commit di merito.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-05 12:43:02 +02:00
davideandClaude Opus 5 26bacbf700 Registra DD-021 e DD-022 e allinea la documentazione
DD-021 (molle interrompibili con motion) e DD-022 (l'app è solo chiara)
motivano le due scelte che un domani sembreranno arbitrarie: perché è entrata
una libreria di animazione dopo averne tolte 45, e perché il tema scuro è
stato cancellato invece che completato.

DD-021 riporta il numero misurato e scomodo: il bundle client cresce da 267 a
308 KB gzip. Togliere dipendenze mai importate non lo riduce, perché il
tree-shaking già le escludeva; il guadagno è sulle 50 dipendenze dirette che
diventano 21.

ARCHITECTURE e README non descrivevano più lo stack reale (Radix/shadcn) e la
sezione UI ignorava la primitiva Card e il sistema di molle. Tolto anche
`hooks/` dall'albero del progetto: la cartella non esiste più.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-05 12:42:55 +02:00
davideandClaude Opus 5 9b28a86f7c Aggiunge lo swipe al calendario e ripulisce le schermate
Calendario: il mese si cambiava solo con due frecce da 36 px. Ora si scorre,
e il punto d'arrivo si sceglie proiettando la velocità di rilascio invece che
dalla posizione del dito, così un colpo secco «lancia» il mese. La griglia
entra ed esce dallo stesso lato del gesto, `dragElastic` dà resistenza
progressiva al bordo al posto di uno stop netto.

Le celle con più tipi di evento generavano un gradiente a fette e ci mettevano
sopra un'ombra bianca sul numero per tenerlo leggibile: un cerotto su un
problema di contrasto. Ora fondo neutro e un puntino per tipo, con il numero
sempre su superficie piena. L'etichetta accessibile dice quanti eventi ci
sono, non solo che ce ne sono.

Profilo: le quattro switch «Notifiche convocazioni», «Promemoria allenamenti»,
«Cambi orario» e «Bacheca squadra» erano `defaultChecked` e non facevano
niente — promettevano una funzione che non esiste. Via anche la conferma
nativa prima di *cambiare* la foto: non è un'azione distruttiva, e chiedere
conferma per tutto insegna a rispondere sì senza leggere. Resta su quella che
la rimuove, che è irreversibile.

Home: la sezione «Da confermare» mostrava titolo e contenitore vuoto quando
non c'era altro da confermare, mentre tutte le altre sezioni hanno un empty
state.

Squadra: i badge in riga avevano solo `title=`, che su touch non appare mai —
aggiunto il testo per gli screen reader. I filtri per criterio erano alti
~26 px.

Più, in tutte le schermate: la primitiva `Card` al posto delle classi
ripetute, i bersagli sotto i 44 px portati in misura e il floor tipografico a
12 px.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-05 12:42:45 +02:00
davideandClaude Opus 5 5c49294ad1 Introduce la primitiva Card e sistema tocco e accessibilità dei componenti
`rounded-3xl bg-card p-4 shadow-card` era ricopiato a mano 22 volte: cambiare
raggio od ombra voleva dire toccare venti file. `Card` in `ui-bits.tsx` è ora
l'unica definizione delle superfici, con la gerarchia dei raggi scritta invece
che implicita (contenitore 3xl, elemento interno 2xl, controllo full).

Tocco e tastiera:
- i chip presenza di `EventoCard` erano alti ~28 px ed è il controllo più
  toccato dell'app: ora `min-h-11`, con 8 px di spazio fra l'uno e l'altro;
- stessa cura per il link «Apri partita», la chiusura di `CelebrazioneBadge` e
  il titolo di `SezioneTendina`;
- `aria-pressed` sui controlli a stato, `aria-controls` sulle tendine (che
  avevano `aria-expanded` senza il pannello a cui si riferisce), `aria-busy`
  sui caricamenti;
- `BottomNav`: lo stato attivo era comunicato solo dal colore. Ora cambia
  anche il peso del testo, compare una barretta sopra l'icona e c'è
  `aria-current="page"`. La voce «Home» diventa «Oggi», che dice cosa
  contiene. La barra è un materiale traslucido con bordo sfumato al posto
  della riga netta.
- `Barra` espone `role="progressbar"` con i valori.

Il testo sotto i 12 px è sparito (108 occorrenze fra `text-[9px]`,
`text-[10px]` e `text-[11px]`): sotto quella soglia la leggibilità cala e su
iOS non scala con Dynamic Type. La gerarchia la fanno peso e maiuscolo.

`Avatar` aveva `alt="Foto di 12"` quando il fallback è il numero di maglia —
non descrive niente e il nome è già scritto accanto, quindi alt vuoto. Aggiunti
`width`/`height` per non far saltare il layout al caricamento.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-05 12:42:24 +02:00
davideandClaude Opus 5 1ff650ecd5 Aggiunge i test della proiezione del momento
`proietta()` decide dove atterra uno swipe, quindi è la funzione che rompe il
gesto se sbaglia: il test copre segno, simmetria, linearità nella velocità e
il valore atteso della decelerazione esponenziale (1000 px/s -> ~499 px).
Copre anche i preset di `molla`, per evitare che un rimbalzo finisca per
sbaglio sul default o che una durata esca dalla scala utile.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-05 12:42:11 +02:00
davideandClaude Opus 5 e7863ab950 Passa le animazioni a molle interrompibili
Il movimento era fatto con `@keyframes` e transizioni a durata fissa: nessuna
di quelle animazioni può essere afferrata a metà. Se l'utente scorre o tocca
mentre una è in corso, quella va avanti per conto suo e per ripartire deve
prima finire.

`lib/molla.ts` raccoglie i parametri, che sono i due di Apple in «Designing
Fluid Interfaces» — rimbalzo e durata, non massa/rigidità/smorzamento.
`molla.ui` (nessun sorpasso) è il default; `molla.slancio` si usa solo dopo un
gesto che portava già inerzia. `proietta()` calcola dove finirebbe un elemento
lanciato, con la stessa decelerazione esponenziale dello scroll iOS.

Nei tre componenti:
- `Reveal` compare quando entra davvero nel viewport. Prima partiva al mount,
  quindi gli elementi sotto la piega consumavano l'animazione a vuoto e
  l'utente li trovava già fermi. Il ritardo massimo scende da 480 a 200 ms.
- `Barra` anima `scaleX` invece di `width`: la larghezza rifà il layout a ogni
  frame, la trasformazione la gestisce il compositore.
- `Numero` usa una molla al posto dell'interpolazione a durata fissa: se il
  dato cambia a metà conteggio il numero cambia rotta da dov'è invece di
  ripartire da capo. Sparisce la prop `durata`, che nessuno passava.

`lib/motion.ts` resta solo per il rilevamento del movimento ridotto (che qui
guarda anche `deviceMemory`, cosa che `useReducedMotion` non fa) e per i
coriandoli.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-05 12:42:01 +02:00
davideandClaude Opus 5 18c6205e06 Rimuove 43 componenti shadcn inutilizzati e installa motion
Dei 45 componenti in `src/components/ui/` solo `drawer` e `sonner` erano
importati da qualche parte. Gli altri 43 — e con loro ~45 dipendenze: tutti i
`@radix-ui/*`, recharts, react-hook-form, date-fns, embla, cmdk, input-otp,
react-day-picker, react-resizable-panels, class-variance-authority,
tw-animate-css — erano superficie di aggiornamento e di sicurezza pagata a
vuoto. Stessa sorte per `src/hooks/use-mobile.tsx`, mai importato. `zod`
resta: lo usano tre route API.

Le dipendenze dirette passano da 50 a 21. Il bundle client NON cala per
questo: quel codice non era importato e il tree-shaking già lo escludeva.

Nella direzione opposta entra `motion`, l'unica aggiunta: serve per le molle
interrompibili che nessuna `@keyframes` CSS può dare (vedi DD-021). Costa ~42
KB gzip, che le rimozioni non compensano — il bundle client passa da 267 a
308 KB gzip.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-05 12:41:49 +02:00
davideandClaude Opus 5 230ea1d156 Sistema i meta della PWA e traduce le schermate di sistema
`viewport-fit=cover` mancava, quindi `env(safe-area-inset-bottom)` valeva
sempre 0: il codice safe-area della BottomNav c'era già ma era inerte, e su
iPhone in standalone la barra finiva sotto la home bar.

`theme-color` e `background_color` erano `#111111` su un'app con fondo quasi
bianco: barra di stato nera e splash nero prima di una UI chiara.

`lang="en"` su un'app interamente in italiano: gli screen reader leggevano
tutto con fonetica inglese. Con esso 404 e schermata d'errore, che erano
rimaste in inglese.

L'anteprima social puntava a un'immagine di preview Lovable su R2 ormai
scaduta e dichiarava `twitter:site @Lovable`: ora usa l'icona della squadra,
con `summary` al posto di `summary_large_image` visto che l'unica immagine
disponibile è quadrata.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-05 12:41:36 +02:00
davideandClaude Opus 5 38e0185325 Corregge i contrasti della palette e toglie il tema scuro
I colori di stato non passavano WCAG AA con il testo bianco sopra: success
3.39:1, training 3.49:1, info ~3.7:1 (chip «Presente», «Allenamento», celle
del calendario). Le luminosità sono abbassate fino a superare 4.5:1.

I gradi dei badge erano il caso peggiore: `text-oro` su bianco sta a 1.9:1 e
`text-argento` a 2.5:1, cioè illeggibili. Nascono i token `--oro-testo`,
`--argento-testo` e `--bronzo-testo` per il testo, mentre le varianti chiare
restano dove servono davvero, su sfondi e bordi.

Il blocco `.dark` non veniva mai applicato — nessun interruttore, nessun
`prefers-color-scheme` — ed era anche incoerente: l'accento diventava
grigio-blu e mancavano success, warning, info, training, i metalli, i due
gradienti e le due ombre. Un tema mai attivato non si accorge di rompersi,
quindi via, con `color-scheme: light` dichiarato esplicitamente.

Nello stesso file:
- `:focus-visible` globale, prima non c'era nessuna regola di focus;
- tracking del display specifico per taglia (`font-display-sm/lg`): un solo
  valore per tutte le dimensioni è sbagliato da qualche parte;
- utility `materiale` e `bordo-sfumato` per la chrome traslucida, con
  `prefers-reduced-transparency` e `prefers-contrast`;
- movimento ridotto: dissolvenza breve invece dell'azzeramento di ogni
  transizione, così resta un feedback che spiega cosa è cambiato;
- rimossi i token di chart e sidebar (i componenti che li usavano non ci sono
  più) e l'import di tw-animate-css, che non era usato da nessuna classe.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-05 12:41:25 +02:00
davideandClaude Sonnet 5 7433391c30 Aggiunge la skill apple-design per il lavoro sull'interfaccia
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-05 12:02:30 +02:00
davideandClaude Opus 5 822180bffc Riscrive AGENTS.md e riallinea la documentazione allo stato reale.
I riferimenti ai documenti in AGENTS.md erano rotti: una venticinquina di link
nella forma docs/[README.md](http://README.md), che spezzavano il nome del file
a meta e puntavano a domini inesistenti. Ora sono percorsi relativi verificati,
con CHANGELOG.md e DESIGN_DECISIONS.md sotto docs/ e PROJECT_STATE.md in root.

Tolte da AGENTS.md le sezioni Architettura, Documentazione e Struttura della
documentazione: duplicavano ARCHITECTURE.md e docs/README.md con uno stack ormai
parziale, contro la regola "ogni informazione ha una sola casa" che docs/README.md
stesso impone. Aggiunti invece i comandi, bun e la guardia minimumReleaseAge:
Codex e Cursor leggono solo AGENTS.md e non avevano modo di sapere come si
verifica una modifica. Scritta la checklist "Fine lavoro" che CLAUDE.md citava
senza che esistesse.

Nuova regola: chi aggiunge o modifica una funzione scrive o aggiorna il test nello
stesso lavoro, i test devono essere verdi e la doc del modulo va aggiornata se il
comportamento cambia (DD-020). Serve perche con main come branch di lavoro non
c'e piu un ambiente di prova tra il codice e i giocatori.

Il flusso git documentato non descriveva piu la realta: main e arrivato a 43
commit di vantaggio su develop, rimasto fermo. DD-003 e ora sostituita da DD-019:
il branch dei commit lo decide l'utente, l'assistente al massimo consiglia un
branch dedicato e non committa, non pusha e non apre PR di propria iniziativa.

Allineati di conseguenza ARCHITECTURE.md (sezione branch), README.md (flusso,
install con bun, comandi di test e lint), ROADMAP.md e TODO.md (le voci spuntate
sono in produzione, non su develop) e PROJECT_STATE.md (auth e profilo giocatore
in produzione, 20 migration fino a M9, passaggi 1-3 e 5 fatti).

Corretti poi sei disallineamenti tra documentazione e codice, ognuno verificato
sul sorgente:

- badge.md e obiettivi-squadra.md dicevano che le serie sono inerti e che
  serieAllenamenti e sempre 0, quindi badge e obiettivo "Continuita di squadra"
  non sbloccabili. Falso da 7237e8f: presenze.ts:48 le calcola e rosa.ts:64-67 le
  attacca al Giocatore. Il limite che resta e un altro, ora scritto: risposto_il
  non e ricostruibile prima di m9, quindi sulle risposte vecchie serieConferme e
  un'approssimazione.
- TODO.md e PROJECT_STATE.md davano il tracciamento tesseramento CSI come da
  fare, mentre ROADMAP, CHANGELOG e DATABASE lo davano per fatto. Lo e:
  admin.tsx:264-278 registra numero e data, :472 mostra Tesserato/Da tesserare,
  :676 il contatore.
- collegamento-csi.md indicava il check di parsing in src/lib/csi-core.test.ts;
  sta in test/unit/csi-core.test.ts, in src/lib non esiste nessun .test.ts.
- profilo-giocatore.md annunciava cinque aree del profilo e ne elencava sette.
- "Segnala un bug" e "Suggerisci una nuova funzionalita" (profilo.tsx:259-276,
  commit 72a9864) non erano documentati da nessuna parte, contro DD-002: ora
  stanno in profilo-giocatore.md e nel CHANGELOG.

npm run test: 28/28 file ok. npm run lint: 12 problemi, identici a prima di
questa modifica e tutti in src/, non toccato qui.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-04 23:24:22 +02:00
davideandClaude Opus 5 7237e8ff39 Calcola davvero le serie di presenze e sblocca badge e obiettivo.
I tre contatori (serieAllenamenti, seriePartite, serieConferme) e streak erano
zero fisso in useRosa(): la sezione Serie di presenze del profilo mostrava sempre
progresso nullo, i badge legati alla costanza erano impossibili da sbloccare e
l'obiettivo Continuita di squadra restava a 0/12.

serieConsecutiva() e serieConferme() (src/lib/presenze.ts) derivano le serie dagli
eventi passati e da risposte_presenze gia in cache, senza query aggiuntive.

Migration m9: nuova colonna risposto_il con l'istante della prima risposta, resa
immutabile da un trigger, confrontata con eventi_app.creato_il per le conferme
entro 24 ore. Serviva perche aggiornato_il registra l'ultima modifica, quindi chi
rispondeva subito e cambiava idea dopo risultava lento.

Corregge anche la barra di progresso, che misurava valore/prossimo e tornava
indietro a ogni traguardo raggiunto (2/3 = 67%, poi 3/6 = 50%).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-04 22:46:04 +02:00
Ivan CacciariandCursor 952f7b43d3 Sposta Completa il tuo profilo sopra Prossimo impegno in home.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-04 12:50:43 +02:00
Ivan CacciariandCursor 438076c572 Rende collassabili badge e tesseramento nel profilo e toglie Scout Live dalla home.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-04 12:43:53 +02:00
Ivan CacciariandCursor fe1ac5434c Alleggerisce Squadra e Classifica con sezioni a tendina e limita i prossimi eventi a 4.
Rimuove anche Scout Live dalle statistiche di squadra per snellire la schermata.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-04 12:01:13 +02:00
Ivan CacciariandCursor 9aef361bf0 Sposta lo storico match in Classifica e rimuove i risultati ufficiali duplicati.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-04 11:40:03 +02:00
davide f70430e1bf Retro-documenta i moduli v1.0 mancanti in docs/modules/
Presenze, Serie di presenze, Scout Live, Pagelle, MVP, Badge, Palloni,
Obiettivi di squadra, Infortuni, Notifiche: chiudono il debito di
documentazione tracciato in TODO.md (DD-002). Le sei route API
pubbliche vengono descritte dentro il modulo a cui appartengono.
2026-09-03 15:10:18 +02:00
davide 72a9864e94 Aggiunge segnalazione bug e richiesta funzionalità dal profilo
I template GitHub guidano chi apre una issue a fornire titolo,
descrizione strutturata ed eventuali screenshot invece di un campo
libero. Dal profilo, prima di "Esci", due link aprono direttamente
il template giusto su GitHub.
2026-09-03 14:46:38 +02:00
davide 2db2086c10 Aggiunge licenza 2026-09-03 14:23:56 +02:00
davide ac4a4a96e8 Blocca il salvataggio se il numero di maglia è già assegnato
Prima era solo un warning e il salvataggio procedeva comunque,
generando doppioni non voluti in rosa.
2026-09-03 14:22:11 +02:00
davide 6286c18a72 Sostituisce l'input libero del ruolo con un menu a tendina
Evita ruoli scritti in modo incoerente (maiuscole, refusi) sia in
modifica che in aggiunta giocatore.
2026-09-03 14:17:30 +02:00
davideandClaude Sonnet 5 70b4123452 Forza la revalidazione dell'avatar dopo la sostituzione della foto
Con cacheControl: "60" l'immagine sostituita poteva restare quella
vecchia per un minuto se la CDN davanti allo storage non varia la
cache in base alla query string di cache-busting (?v=).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-03 14:05:50 +02:00
davideandClaude Sonnet 5 0c2a6c5330 Chiede conferma prima di cambiare o rimuovere la foto profilo
Entrambe le azioni avvenivano subito, senza possibilità di annullare
per errore.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-03 13:58:32 +02:00
davideandClaude Sonnet 5 5c9ffb84e8 Filtri classifica giocatori tutti su una riga senza scroll
Rinomina "Cacche/partita" in "Cacche" e passa i pill da flex-wrap a
flex-nowrap con flex-1/truncate, così entrano tutti su una riga sola
senza andare a capo né richiedere swipe orizzontale.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-03 13:41:16 +02:00
davideandClaude Sonnet 5 988eb6d575 Evita lo scroll orizzontale nei filtri della classifica giocatori
I pill (Presenze, Media voto, MVP, Palloni, Cacche/partita) andavano su
una riga scrollabile orizzontalmente; ora vanno a capo con flex-wrap.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-03 13:36:52 +02:00
davideandClaude Sonnet 5 0710d143a9 Documenta l'applicazione della migration M4 in produzione
Il gate "M4 non applicabile finché la squadra non è collegata" è superato:
il login era già l'unica via d'accesso lato app, quindi i giocatori non
ancora collegati non erano comunque impattati dal residuo di accesso anon
che M4 chiudeva. Aggiorna anche DD-018, ormai stale: l'email dei giocatori
si imposta da /admin, non solo via migration.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-03 13:28:23 +02:00
davideandClaude Sonnet 5 9c173df753 Corregge riferimenti alla migration M3, mai applicata
M3 esisteva solo come bozza archiviata in docs/archive/migrations/: il bucket
profili-giocatore è creato dalla migration M2 insieme alla tabella. Allinea
PROJECT_STATE.md (12 -> 18 migration), DATABASE.md, CHANGELOG.md, TODO.md,
DESIGN_DECISIONS.md, test/README.md e il test di integrazione dei profili.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-03 11:00:27 +02:00
davideandClaude Mythos a07c8104d5 Aggiorna docs/modules/collegamento-csi.md: fallback non è più sui dati demo
I dati dimostrativi in crapp-data.ts sono stati rimossi (DD-015); il fallback
reale oggi è classifica vuota (o ultimo dato in cache) e risultati dallo
Scout Live locale.

Co-Authored-By: Claude Mythos <noreply@anthropic.com>
2026-09-03 10:40:03 +02:00
davide 224bb93beb Chiude DD-015: la rosa non è più hardcoded
Aggiorna DESIGN_DECISIONS.md (DD-015 da "In valutazione" ad "Accettata",
con le conseguenze reali: fallback nascita e crapp-data.ts come solo
seed/fallback), DATABASE.md, ARCHITECTURE.md e PROJECT_STATE.md di
conseguenza.
2026-09-03 10:17:13 +02:00
davide 923d1fe762 Aggiorna i test per le nuove firme con rosa esplicita
completaTurni() e csvScoutMatch() prendono ora la rosa come parametro
invece di leggerla dalla lista statica di crapp-data.ts.
2026-09-03 10:17:07 +02:00
davide 4c0ea66126 Aggancia Squadra, Presenze, Pagelle, Scout e calendario alla rosa reale
convocatiEvento() e compleanniEventi() prendono ora la rosa come parametro
invece di leggere la lista statica; csvScoutMatch() idem. Le schermate di
gestione eventi, dettaglio allenamento/partita, calendario e scout live,
più i widget di presenze/pagelle/voto MVP/voto social/sondaggio
cacche/turno palloni, passano tutte la rosa letta da useRosa() o
useGiocatoriSquadra(): un giocatore aggiunto o disattivato dalla dashboard
admin ora si riflette ovunque.
2026-09-03 10:17:03 +02:00