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>
This commit is contained in:
+18
-3
@@ -19,10 +19,25 @@ export type Grado = "bronzo" | "argento" | "oro";
|
||||
|
||||
export const gradiOrdine: Grado[] = ["bronzo", "argento", "oro"];
|
||||
|
||||
/**
|
||||
* `text` usa i token `-testo` (varianti scurite): l'oro e l'argento chiari
|
||||
* stanno sotto 2.5:1 su bianco e come colore di testo sono illeggibili.
|
||||
* Le versioni chiare restano su sfondi e bordi, dove il contrasto non conta.
|
||||
*/
|
||||
export const gradoMeta: Record<Grado, { label: string; text: string; bg: string; ring: string }> = {
|
||||
bronzo: { label: "Bronzo", text: "text-bronzo", bg: "bg-bronzo/15", ring: "ring-bronzo/40" },
|
||||
argento: { label: "Argento", text: "text-argento", bg: "bg-argento/20", ring: "ring-argento/50" },
|
||||
oro: { label: "Oro", text: "text-oro", bg: "bg-oro/20", ring: "ring-oro/50" },
|
||||
bronzo: {
|
||||
label: "Bronzo",
|
||||
text: "text-bronzo-testo",
|
||||
bg: "bg-bronzo/15",
|
||||
ring: "ring-bronzo/40",
|
||||
},
|
||||
argento: {
|
||||
label: "Argento",
|
||||
text: "text-argento-testo",
|
||||
bg: "bg-argento/20",
|
||||
ring: "ring-argento/50",
|
||||
},
|
||||
oro: { label: "Oro", text: "text-oro-testo", bg: "bg-oro/20", ring: "ring-oro/50" },
|
||||
};
|
||||
|
||||
export type BadgeDef = {
|
||||
|
||||
+135
-80
@@ -1,8 +1,5 @@
|
||||
@import "tailwindcss" source(none);
|
||||
@source "../src";
|
||||
@import "tw-animate-css";
|
||||
|
||||
@custom-variant dark (&:is(.dark *));
|
||||
|
||||
@theme {
|
||||
--font-display: "Bebas Neue", ui-sans-serif, sans-serif;
|
||||
@@ -10,17 +7,26 @@
|
||||
}
|
||||
|
||||
/*
|
||||
* Design system definition.
|
||||
* Definizione del design system.
|
||||
*
|
||||
* The @theme inline block maps CSS custom properties to Tailwind utility
|
||||
* classes (e.g. --color-primary -> bg-primary, text-primary).
|
||||
* Il blocco @theme inline mappa le custom property sulle utility Tailwind
|
||||
* (es. --color-primary -> bg-primary, text-primary).
|
||||
*
|
||||
* The :root and .dark blocks define the actual color values using oklch.
|
||||
* All colors MUST use oklch format.
|
||||
* Il blocco :root definisce i valori reali in oklch. Tutti i colori DEVONO
|
||||
* essere in oklch.
|
||||
*
|
||||
* To add a new semantic color:
|
||||
* 1. Add the variable to :root (light value) and .dark (dark value)
|
||||
* 2. Register it in @theme inline as --color-<name>: var(--<name>)
|
||||
* L'app è solo chiara (DD: niente tema scuro finché non è completo per tutti
|
||||
* i token, gradienti e ombre comprese): `color-scheme: light` lo dichiara al
|
||||
* browser così form e scrollbar native restano coerenti.
|
||||
*
|
||||
* Per aggiungere un colore semantico:
|
||||
* 1. Aggiungi la variabile in :root
|
||||
* 2. Registrala in @theme inline come --color-<nome>: var(--<nome>)
|
||||
*
|
||||
* Contrasto: i token con suffisso `-testo` sono le varianti scurite da usare
|
||||
* come colore del testo; quelli senza suffisso servono per sfondi e bordi.
|
||||
* Non usare `text-oro`/`text-argento`/`text-bronzo`: hanno meno di 3:1 su
|
||||
* bianco. Vedi `gradoMeta` in lib/badges.ts.
|
||||
*/
|
||||
|
||||
@theme inline {
|
||||
@@ -51,22 +57,10 @@
|
||||
--color-input: var(--input);
|
||||
--color-ring: var(--ring);
|
||||
--color-ring-offset-background: var(--background);
|
||||
--color-chart-1: var(--chart-1);
|
||||
--color-chart-2: var(--chart-2);
|
||||
--color-chart-3: var(--chart-3);
|
||||
--color-chart-4: var(--chart-4);
|
||||
--color-chart-5: var(--chart-5);
|
||||
--color-sidebar: var(--sidebar);
|
||||
--color-sidebar-foreground: var(--sidebar-foreground);
|
||||
--color-sidebar-primary: var(--sidebar-primary);
|
||||
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
||||
--color-sidebar-accent: var(--sidebar-accent);
|
||||
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
||||
--color-sidebar-border: var(--sidebar-border);
|
||||
--color-sidebar-ring: var(--sidebar-ring);
|
||||
}
|
||||
|
||||
:root {
|
||||
color-scheme: light;
|
||||
--radius: 1rem;
|
||||
--background: oklch(0.985 0.002 240);
|
||||
--foreground: oklch(0.16 0.01 260);
|
||||
@@ -87,17 +81,23 @@
|
||||
--border: oklch(0.915 0.006 255);
|
||||
--input: oklch(0.915 0.006 255);
|
||||
--ring: oklch(0.58 0.22 27);
|
||||
--success: oklch(0.62 0.16 152);
|
||||
/* Luminosità scelte perché il testo bianco sopra superi 4.5:1 (WCAG AA). */
|
||||
--success: oklch(0.53 0.16 152);
|
||||
--success-foreground: oklch(0.99 0 0);
|
||||
--warning: oklch(0.78 0.15 78);
|
||||
--warning-foreground: oklch(0.18 0.02 60);
|
||||
--info: oklch(0.6 0.13 245);
|
||||
--info: oklch(0.54 0.13 245);
|
||||
--info-foreground: oklch(0.99 0 0);
|
||||
--training: oklch(0.62 0.2 245);
|
||||
--training: oklch(0.53 0.2 245);
|
||||
--training-foreground: oklch(0.99 0 0);
|
||||
/* Metalli: la variante chiara va su sfondi e bordi, la `-testo` sul testo
|
||||
(la chiara sta sotto 2.5:1 su bianco ed è illeggibile). */
|
||||
--bronzo: oklch(0.62 0.11 55);
|
||||
--argento: oklch(0.72 0.02 260);
|
||||
--oro: oklch(0.8 0.15 85);
|
||||
--bronzo-testo: oklch(0.55 0.11 55);
|
||||
--argento-testo: oklch(0.54 0.02 260);
|
||||
--oro-testo: oklch(0.55 0.15 85);
|
||||
--gradient-hero: linear-gradient(
|
||||
140deg,
|
||||
oklch(0.18 0.012 265),
|
||||
@@ -107,19 +107,6 @@
|
||||
--gradient-accent: linear-gradient(120deg, oklch(0.58 0.22 27), oklch(0.68 0.19 40));
|
||||
--shadow-card: 0 1px 2px oklch(0.16 0.01 260 / 6%), 0 12px 28px -18px oklch(0.16 0.01 260 / 35%);
|
||||
--shadow-pop: 0 18px 40px -20px oklch(0.58 0.22 27 / 55%);
|
||||
--chart-1: oklch(0.646 0.222 41.116);
|
||||
--chart-2: oklch(0.6 0.118 184.704);
|
||||
--chart-3: oklch(0.398 0.07 227.392);
|
||||
--chart-4: oklch(0.828 0.189 84.429);
|
||||
--chart-5: oklch(0.769 0.188 70.08);
|
||||
--sidebar: oklch(0.984 0.003 247.858);
|
||||
--sidebar-foreground: oklch(0.129 0.042 264.695);
|
||||
--sidebar-primary: oklch(0.208 0.042 265.755);
|
||||
--sidebar-primary-foreground: oklch(0.984 0.003 247.858);
|
||||
--sidebar-accent: oklch(0.968 0.007 247.896);
|
||||
--sidebar-accent-foreground: oklch(0.208 0.042 265.755);
|
||||
--sidebar-border: oklch(0.929 0.013 255.508);
|
||||
--sidebar-ring: oklch(0.704 0.04 256.788);
|
||||
}
|
||||
|
||||
@theme inline {
|
||||
@@ -137,6 +124,9 @@
|
||||
--color-bronzo: var(--bronzo);
|
||||
--color-argento: var(--argento);
|
||||
--color-oro: var(--oro);
|
||||
--color-bronzo-testo: var(--bronzo-testo);
|
||||
--color-argento-testo: var(--argento-testo);
|
||||
--color-oro-testo: var(--oro-testo);
|
||||
}
|
||||
|
||||
@utility bg-hero {
|
||||
@@ -155,9 +145,25 @@
|
||||
box-shadow: var(--shadow-pop);
|
||||
}
|
||||
|
||||
/*
|
||||
* Il tracking del display è specifico per taglia: Bebas Neue a corpo grande
|
||||
* legge troppo spaziato (serve tracking negativo), a corpo piccolo troppo
|
||||
* stretto (serve positivo). Un solo valore sarebbe sbagliato da qualche parte.
|
||||
* `font-display-lg` da text-3xl in su, `font-display-sm` sotto text-xl.
|
||||
*/
|
||||
@utility font-display {
|
||||
font-family: var(--font-display);
|
||||
letter-spacing: 0.02em;
|
||||
letter-spacing: 0.01em;
|
||||
}
|
||||
|
||||
@utility font-display-lg {
|
||||
font-family: var(--font-display);
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
|
||||
@utility font-display-sm {
|
||||
font-family: var(--font-display);
|
||||
letter-spacing: 0.04em;
|
||||
}
|
||||
|
||||
/* --- Micro-animazioni (solo CSS standard, nessuna dipendenza esterna) --- */
|
||||
@@ -258,10 +264,6 @@
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
|
||||
@utility anim-barra {
|
||||
transition: width 700ms cubic-bezier(0.22, 1, 0.36, 1);
|
||||
}
|
||||
|
||||
/* Feedback al tocco sulle card interattive (+ hover leggero su desktop). */
|
||||
@utility premi {
|
||||
transition:
|
||||
@@ -280,49 +282,98 @@
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Meno movimento non vuol dire nessun feedback: si tolgono spostamenti,
|
||||
* rimbalzi e ripetizioni, si tiene una dissolvenza breve che continua a
|
||||
* spiegare cosa è cambiato.
|
||||
*/
|
||||
@keyframes crapp-dissolvenza {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
animation-duration: 0.001ms !important;
|
||||
animation-iteration-count: 1 !important;
|
||||
transition-duration: 0.001ms !important;
|
||||
scroll-behavior: auto !important;
|
||||
}
|
||||
|
||||
.anim-reveal,
|
||||
.anim-pop,
|
||||
.anim-riga {
|
||||
animation: crapp-dissolvenza 200ms ease-out both !important;
|
||||
}
|
||||
|
||||
.premi {
|
||||
transition: opacity 120ms ease-out !important;
|
||||
}
|
||||
|
||||
.premi:active {
|
||||
transform: none;
|
||||
opacity: 0.72;
|
||||
}
|
||||
|
||||
.premi:hover {
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
|
||||
.dark {
|
||||
--background: oklch(0.129 0.042 264.695);
|
||||
--foreground: oklch(0.984 0.003 247.858);
|
||||
--card: oklch(0.208 0.042 265.755);
|
||||
--card-foreground: oklch(0.984 0.003 247.858);
|
||||
--popover: oklch(0.208 0.042 265.755);
|
||||
--popover-foreground: oklch(0.984 0.003 247.858);
|
||||
--primary: oklch(0.929 0.013 255.508);
|
||||
--primary-foreground: oklch(0.208 0.042 265.755);
|
||||
--secondary: oklch(0.279 0.041 260.031);
|
||||
--secondary-foreground: oklch(0.984 0.003 247.858);
|
||||
--muted: oklch(0.279 0.041 260.031);
|
||||
--muted-foreground: oklch(0.704 0.04 256.788);
|
||||
--accent: oklch(0.279 0.041 260.031);
|
||||
--accent-foreground: oklch(0.984 0.003 247.858);
|
||||
--destructive: oklch(0.704 0.191 22.216);
|
||||
--destructive-foreground: oklch(0.984 0.003 247.858);
|
||||
--border: oklch(1 0 0 / 10%);
|
||||
--input: oklch(1 0 0 / 15%);
|
||||
--ring: oklch(0.551 0.027 264.364);
|
||||
--chart-1: oklch(0.488 0.243 264.376);
|
||||
--chart-2: oklch(0.696 0.17 162.48);
|
||||
--chart-3: oklch(0.769 0.188 70.08);
|
||||
--chart-4: oklch(0.627 0.265 303.9);
|
||||
--chart-5: oklch(0.645 0.246 16.439);
|
||||
--sidebar: oklch(0.208 0.042 265.755);
|
||||
--sidebar-foreground: oklch(0.984 0.003 247.858);
|
||||
--sidebar-primary: oklch(0.488 0.243 264.376);
|
||||
--sidebar-primary-foreground: oklch(0.984 0.003 247.858);
|
||||
--sidebar-accent: oklch(0.279 0.041 260.031);
|
||||
--sidebar-accent-foreground: oklch(0.984 0.003 247.858);
|
||||
--sidebar-border: oklch(1 0 0 / 10%);
|
||||
--sidebar-ring: oklch(0.551 0.027 264.364);
|
||||
/* Superfici traslucide: se l'utente chiede meno trasparenza diventano piene. */
|
||||
@media (prefers-reduced-transparency: reduce) {
|
||||
.materiale {
|
||||
background-color: var(--color-card);
|
||||
backdrop-filter: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-contrast: more) {
|
||||
.materiale {
|
||||
background-color: var(--color-card);
|
||||
backdrop-filter: none;
|
||||
border-color: var(--color-foreground);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Chrome flottante in stile Apple: la barra è un materiale traslucido sotto
|
||||
* cui il contenuto scorre, con una sfumatura al bordo al posto della linea
|
||||
* netta (scroll edge effect).
|
||||
*/
|
||||
@utility materiale {
|
||||
background-color: color-mix(in oklab, var(--color-card) 72%, transparent);
|
||||
backdrop-filter: blur(20px) saturate(180%);
|
||||
-webkit-backdrop-filter: blur(20px) saturate(180%);
|
||||
}
|
||||
|
||||
@utility bordo-sfumato {
|
||||
&::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset-inline: 0;
|
||||
bottom: 100%;
|
||||
height: 1.25rem;
|
||||
pointer-events: none;
|
||||
background: linear-gradient(
|
||||
to top,
|
||||
color-mix(in oklab, var(--color-background) 85%, transparent),
|
||||
transparent
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/* Focus da tastiera sempre visibile: nessun controllo custom lo definiva. */
|
||||
@layer base {
|
||||
:focus-visible {
|
||||
outline: 2px solid var(--color-ring);
|
||||
outline-offset: 2px;
|
||||
border-radius: 0.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
@layer base {
|
||||
@@ -334,6 +385,10 @@
|
||||
background-color: var(--color-background);
|
||||
color: var(--color-foreground);
|
||||
font-family: var(--font-sans);
|
||||
line-height: 1.5;
|
||||
font-optical-sizing: auto;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
/* Niente pull-to-refresh accidentale né rimbalzo che scopre il fondo. */
|
||||
overscroll-behavior-y: contain;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user