2d7e3c591e
Quasi tutto il testo dell'app stava fra 600 e 800: etichette, valori, indirizzi, conteggi, voci di elenco. Un grassetto ovunque non segnala niente, e la pagina Profilo era il caso peggiore — ogni riga gridava come un titolo. La scala ora ha quattro gradini, documentati nei token: 400 corpo, metadati, valori descrittivi 500 etichette di campo, voci di lista, testo dei controlli 600 stati brevi (badge, voce attiva), nomi in una riga di elenco 700 titoli, uno solo per blocco Sopra il 700 non si sale: l'800 dei titoli di card e dell'avatar e' sceso a 700. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
277 lines
6.9 KiB
CSS
277 lines
6.9 KiB
CSS
/* =============================================================================
|
|
SteUP — Base
|
|
Reset, shell applicativa, tipografia e comportamenti "da app nativa".
|
|
========================================================================== */
|
|
|
|
*,
|
|
*::before,
|
|
*::after {
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
html {
|
|
height: 100%;
|
|
overflow: hidden;
|
|
/* La WebView non deve comportarsi come un browser: niente rimbalzo elastico
|
|
ai bordi, niente pull-to-refresh, niente zoom a doppio tocco. */
|
|
overscroll-behavior: none;
|
|
touch-action: manipulation;
|
|
-webkit-text-size-adjust: 100%;
|
|
}
|
|
|
|
body {
|
|
height: 100%;
|
|
margin: 0;
|
|
overflow: hidden;
|
|
background-color: var(--workspace);
|
|
color: var(--ink);
|
|
font-family: var(--font-sans);
|
|
font-size: var(--body-lg-size);
|
|
line-height: var(--body-lg-height);
|
|
font-weight: 400;
|
|
/* Inter: cifre a larghezza fissa, cosi' i contatori non "ballano" mentre
|
|
si aggiornano, e forme delle lettere piu' leggibili in piccolo. */
|
|
font-feature-settings: "tnum" 1, "cv05" 1;
|
|
-webkit-font-smoothing: antialiased;
|
|
text-rendering: optimizeLegibility;
|
|
|
|
/* Niente selezione del testo, niente menu contestuale al tocco lungo,
|
|
niente lampo grigio sul tap: sono i tre segnali che tradiscono una
|
|
pagina web dentro un'app. */
|
|
user-select: none;
|
|
-webkit-user-select: none;
|
|
-webkit-touch-callout: none;
|
|
-webkit-tap-highlight-color: transparent;
|
|
cursor: default;
|
|
}
|
|
|
|
/* Il contenuto dei dati resta selezionabile: un barcode o un codice servono
|
|
anche da copiare. */
|
|
.selectable,
|
|
input,
|
|
textarea {
|
|
user-select: text;
|
|
-webkit-user-select: text;
|
|
-webkit-touch-callout: default;
|
|
}
|
|
|
|
#app {
|
|
height: 100dvh;
|
|
overflow: hidden;
|
|
}
|
|
|
|
img {
|
|
max-width: 100%;
|
|
display: block;
|
|
}
|
|
|
|
[hidden] {
|
|
display: none !important;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
Tipografia — scala fissa (STILE_UI §4)
|
|
La gerarchia si fa con peso e dimensione, mai con il maiuscolo spaziato.
|
|
-------------------------------------------------------------------------- */
|
|
|
|
.t-headline-md {
|
|
font-size: var(--headline-md-size);
|
|
line-height: var(--headline-md-height);
|
|
font-weight: 700;
|
|
letter-spacing: -0.02em;
|
|
}
|
|
|
|
.t-headline-sm {
|
|
font-size: var(--headline-sm-size);
|
|
line-height: var(--headline-sm-height);
|
|
font-weight: 700;
|
|
letter-spacing: -0.02em;
|
|
}
|
|
|
|
.t-title-lg {
|
|
font-size: var(--title-lg-size);
|
|
line-height: var(--title-lg-height);
|
|
font-weight: 700;
|
|
letter-spacing: -0.01em;
|
|
}
|
|
|
|
.t-title-md {
|
|
font-size: var(--title-md-size);
|
|
line-height: var(--title-md-height);
|
|
font-weight: 700;
|
|
}
|
|
|
|
.t-body-lg {
|
|
font-size: var(--body-lg-size);
|
|
line-height: var(--body-lg-height);
|
|
font-weight: 400;
|
|
}
|
|
|
|
.t-body-md {
|
|
font-size: var(--body-md-size);
|
|
line-height: var(--body-md-height);
|
|
font-weight: 400;
|
|
}
|
|
|
|
.t-label-lg {
|
|
font-size: var(--label-lg-size);
|
|
line-height: 1.25;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.t-label-md {
|
|
font-size: var(--label-md-size);
|
|
line-height: 1.25;
|
|
font-weight: 500;
|
|
}
|
|
|
|
/* Identificativo tecnico sopra il titolo di una card (STILE_UI §4) */
|
|
.t-ident {
|
|
font-size: var(--label-sm-size);
|
|
line-height: 1.3;
|
|
font-weight: 700;
|
|
letter-spacing: 0.3px;
|
|
color: var(--ink-muted);
|
|
}
|
|
|
|
.t-muted {
|
|
color: var(--ink-muted);
|
|
}
|
|
|
|
/* Il testo secondario si distingue per colore, mai per opacita'. */
|
|
.t-meta {
|
|
font-size: var(--body-md-size);
|
|
line-height: var(--body-md-height);
|
|
font-weight: 400;
|
|
color: var(--ink-muted);
|
|
}
|
|
|
|
/* Prosa: righe non piu' lunghe di 65-75 caratteri. */
|
|
.t-prose {
|
|
max-width: 68ch;
|
|
text-wrap: pretty;
|
|
}
|
|
|
|
h1, h2, h3 {
|
|
text-wrap: balance;
|
|
margin: 0;
|
|
}
|
|
|
|
h1, h2, h3, h4, h5, h6, p {
|
|
margin: 0;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
Shell applicativa
|
|
-------------------------------------------------------------------------- */
|
|
|
|
.app-shell {
|
|
display: flex;
|
|
flex-direction: column;
|
|
height: 100dvh;
|
|
overflow: hidden;
|
|
background-color: var(--workspace);
|
|
}
|
|
|
|
/* Area scorrevole unica della schermata. Lo scroll con inerzia e il
|
|
contenimento evitano che il gesto "sfondi" sulla pagina sottostante. */
|
|
.app-scroll {
|
|
flex: 1;
|
|
min-height: 0;
|
|
overflow-y: auto;
|
|
overflow-x: hidden;
|
|
-webkit-overflow-scrolling: touch;
|
|
overscroll-behavior: contain;
|
|
scrollbar-width: none;
|
|
}
|
|
|
|
.app-scroll::-webkit-scrollbar {
|
|
display: none;
|
|
}
|
|
|
|
/* Contenitore di pagina (STILE_UI §6.1): su telefono e' trasparente, su
|
|
schermo largo tiene una colonna leggibile invece di allargarsi all'infinito. */
|
|
.page-width {
|
|
width: 100%;
|
|
max-width: var(--content-max);
|
|
margin-inline: auto;
|
|
padding-inline: var(--space-md);
|
|
}
|
|
|
|
/* Spazio in coda per non finire sotto la barra di navigazione flottante. */
|
|
.page-body {
|
|
padding-bottom: calc(var(--nav-clearance) + env(safe-area-inset-bottom, 0px));
|
|
}
|
|
|
|
/* Pagine senza barra di navigazione (login, form a schermo pieno). */
|
|
.page-body--flush {
|
|
padding-bottom: calc(var(--space-lg) + env(safe-area-inset-bottom, 0px));
|
|
}
|
|
|
|
.stack {
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.stack-xs { gap: var(--space-xs); }
|
|
.stack-10 { gap: var(--space-10); }
|
|
.stack-sm { gap: var(--space-sm); }
|
|
.stack-md { gap: var(--space-md); }
|
|
.stack-lg { gap: var(--space-lg); }
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
Focus
|
|
Visibile e coerente ovunque, senza sporcare il tocco: solo da tastiera.
|
|
-------------------------------------------------------------------------- */
|
|
|
|
:focus {
|
|
outline: none;
|
|
}
|
|
|
|
:focus-visible {
|
|
outline: 2px solid var(--focus-ring);
|
|
outline-offset: 2px;
|
|
border-radius: var(--radius-compact);
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
Risposta al tocco
|
|
Feedback fisico immediato (principio "Feedback immediato a ogni scan"):
|
|
l'elemento cede sotto il dito e torna. Niente stati basati sull'hover, che
|
|
su un touch screen non esiste e lascia elementi "accesi" dopo il tocco.
|
|
-------------------------------------------------------------------------- */
|
|
|
|
.pressable {
|
|
transition: transform var(--duration-fast) var(--ease-out),
|
|
background-color var(--duration-fast) var(--ease-out);
|
|
}
|
|
|
|
.pressable:active {
|
|
transform: scale(0.98);
|
|
}
|
|
|
|
@media (hover: hover) and (pointer: fine) {
|
|
.pressable:hover {
|
|
background-color: var(--surface-muted);
|
|
}
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
Movimento ridotto — non e' opzionale
|
|
-------------------------------------------------------------------------- */
|
|
|
|
@media (prefers-reduced-motion: reduce) {
|
|
*,
|
|
*::before,
|
|
*::after {
|
|
animation-duration: 0.01ms !important;
|
|
animation-iteration-count: 1 !important;
|
|
transition-duration: 0.01ms !important;
|
|
scroll-behavior: auto !important;
|
|
}
|
|
|
|
.pressable:active {
|
|
transform: none;
|
|
}
|
|
}
|