ac501dc261
La regola valeva per qualunque elemento, e la WebView sposta il fuoco anche su contenitori non interattivi: dopo la chiusura di un dialog restava un anello azzurro intorno al titolo della testata, che indicava un bersaglio inesistente. Ora lo prendono link, bottoni, campi e gli elementi dichiaratamente tappabili. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
288 lines
7.4 KiB
CSS
288 lines
7.4 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;
|
|
}
|
|
|
|
/* L'anello segna un comando raggiunto da tastiera. Va messo sui controlli, non
|
|
su qualunque elemento che il motore decida di mettere a fuoco: la WebView
|
|
sposta il fuoco anche su contenitori non interattivi (per esempio la testata,
|
|
dopo la chiusura di un dialog) e li' l'anello indica un bersaglio che non
|
|
esiste. */
|
|
a:focus-visible,
|
|
button:focus-visible,
|
|
input:focus-visible,
|
|
select:focus-visible,
|
|
textarea:focus-visible,
|
|
[role="button"]:focus-visible,
|
|
[tabindex]:not([tabindex="-1"]):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;
|
|
}
|
|
}
|