Files
termanager2/resources/css/app.css
Francesco Picone 2fb9838a0e ++ Il mio gruppo: il numero del territorio apre l'anteprima
Il numero diventa un pulsante che apre una finestra con la miniatura e il
collegamento al PDF. La miniatura passa dalla rotta nuova
mio-gruppo.miniatura, con la stessa regola del PDF: solo i territori del
pacchetto del gruppo sorvegliato.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 16:27:50 +02:00

1844 lines
56 KiB
CSS

@import "tailwindcss";
/* Carattere servito dall'applicazione, non da un CDN esterno: questo
gestionale tiene nomi e indirizzi di persone, e una richiesta a un dominio
di terze parti a ogni pagina caricata sarebbe un dato in uscita che nessuno
ha chiesto. Il pacchetto e' una dipendenza npm, quindi finisce nel bundle e
funziona anche senza rete. */
@import "@fontsource-variable/figtree";
/* ═══════════════════════════════════════════════════════════════════════════
TerManager2 — sistema visivo
I token stanno qui e in nessun altro posto. Ridefinire le scale `gray` e
`indigo` di Tailwind e' deliberato: le trentasette viste dell'applicazione
sono scritte con le utility (`text-gray-600`, `bg-indigo-50`), e cambiare
la scala le riallinea tutte insieme invece di costringere a riscriverle una
per una — con il rischio, a ogni vista dimenticata, di lasciare in giro il
grigio di prima accanto a quello nuovo.
Due scelte di fondo:
I grigi sono caldi. Il grigio di serie di Tailwind tira al blu e, sommato
a un accento indaco, dava a tutta l'interfaccia una
dominante fredda da pannello di controllo. Su carta
questi elenchi diventano moduli che passano di mano:
un fondo caldo li avvicina a quello che sono.
L'accento e' uno. Prima ce n'erano cinque (indaco, verde, blu, rosso,
ambra) usati come decorazione. Ora il colore vuol
dire qualcosa: indaco = azione, verde = fatto,
ambra = in sospeso, rosso = distrugge dati. Se non
rientra in queste quattro, e' grigio.
═══════════════════════════════════════════════════════════════════════════ */
@theme {
--font-sans: "Figtree Variable", ui-sans-serif, system-ui, -apple-system,
"Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
/* Grigi caldi: una sola famiglia, nessuna mescolanza caldo/freddo. */
--color-gray-50: #f7f6f4;
--color-gray-100: #efedea;
--color-gray-200: #e3e0da;
--color-gray-300: #cfcbc2;
--color-gray-400: #a8a29a;
--color-gray-500: #837d74;
--color-gray-600: #625c54;
--color-gray-700: #4a453f;
--color-gray-800: #302c28;
--color-gray-900: #1c1a17;
--color-gray-950: #12100e;
/* Indaco smorzato: stessa identita' di prima, meno stridente. */
--color-indigo-50: #eeeef9;
--color-indigo-100: #dedef3;
--color-indigo-200: #c3c2e8;
--color-indigo-300: #a09ed8;
--color-indigo-400: #7c79c5;
--color-indigo-500: #605cb2;
--color-indigo-600: #4a45a8;
--color-indigo-700: #3b3789;
--color-indigo-800: #2f2c6c;
--color-indigo-900: #262350;
--color-indigo-950: #16142f;
}
:root {
--tm-fondo: #f7f6f4;
--tm-superficie: #ffffff;
--tm-superficie-alt: #faf9f7;
--tm-bordo: #e3e0da;
--tm-bordo-forte: #cfcbc2;
--tm-testo: #1c1a17;
--tm-testo-medio: #4a453f;
--tm-testo-tenue: #837d74;
--tm-accento: #4a45a8;
--tm-accento-scuro: #3b3789;
--tm-accento-tenue: #eeeef9;
--tm-ok: #2f6f4e;
--tm-ok-tenue: #e8f2ec;
--tm-attesa: #a06a22;
--tm-attesa-tenue: #fbf1e2;
--tm-pericolo: #b3352c;
--tm-pericolo-tenue: #fbeceb;
/* Le ombre portano la tinta del fondo invece del nero puro: su una
superficie calda un'ombra neutra sporca di grigio. */
--tm-ombra-1: 0 1px 2px rgba(43, 37, 28, .05);
--tm-ombra-2: 0 2px 4px rgba(43, 37, 28, .05), 0 6px 16px -8px rgba(43, 37, 28, .10);
--tm-ombra-3: 0 8px 28px -10px rgba(43, 37, 28, .18);
--tm-raggio: 14px;
--tm-raggio-interno: 10px;
}
html.tm-app,
body {
background: var(--tm-fondo);
color: var(--tm-testo);
}
body {
font-family: var(--font-sans);
font-synthesis-weight: none;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
}
/* I titoli devono avere peso e stare stretti: alla dimensione di prima, con
spaziatura di serie, si leggevano come testo qualsiasi in grassetto. */
h1, h2, h3 {
letter-spacing: -.018em;
text-wrap: balance;
}
/* Le cifre incolonnate vogliono larghezza fissa, altrimenti in un elenco di
date e numeri di territorio le colonne ballano riga per riga. */
table, .tm-tabella, .tm-cifre {
font-variant-numeric: tabular-nums;
}
p { text-wrap: pretty; }
/* Alpine nasconde con x-cloak solo se il foglio di stile lo dice: la regola non
arriva col pacchetto. Senza, gli elementi marcati x-cloak (le barre di
avanzamento, i messaggi d'errore) lampeggiano a ogni caricamento prima che
Alpine parta. */
[x-cloak] { display: none !important; }
html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
html { scroll-behavior: auto; }
}
/* Chi naviga da tastiera deve poter saltare la barra laterale invece di
percorrerla a ogni pagina. */
.tm-salta {
position: absolute;
left: -9999px;
z-index: 100;
padding: 10px 16px;
border-radius: var(--tm-raggio-interno);
background: var(--tm-accento);
color: #fff;
font-size: 14px;
font-weight: 600;
}
.tm-salta:focus {
left: 12px;
top: 12px;
}
.tm-solo-lettori {
position: absolute;
width: 1px; height: 1px;
padding: 0; margin: -1px;
overflow: hidden;
clip: rect(0 0 0 0);
white-space: nowrap;
border: 0;
}
/* ─── Superfici ────────────────────────────────────────────────────────────
Una card esiste quando l'elevazione dice qualcosa. Il bordo fa il lavoro
principale, l'ombra e' appena percepibile: bordo + ombra marcata + fondo
bianco insieme e' il riquadro di serie che si vede ovunque. */
.card-hover {
transition: transform .18s ease, box-shadow .18s ease;
}
.card-hover:hover {
transform: translateY(-2px);
box-shadow: var(--tm-ombra-3);
}
/* Bordo d'accento sulle schede di riepilogo: quattro significati, non cinque
tinte decorative. */
.card-accent-indigo { border-left: 3px solid var(--tm-accento); }
.card-accent-green { border-left: 3px solid var(--tm-ok); }
.card-accent-blue { border-left: 3px solid var(--tm-accento); }
.card-accent-red { border-left: 3px solid var(--tm-pericolo); }
.card-accent-amber { border-left: 3px solid var(--tm-attesa); }
.table-striped tbody tr:nth-child(even) {
background-color: var(--tm-superficie-alt);
}
/* La testata era un gradiente indaco a 45 gradi — la firma piu' riconoscibile
di un'interfaccia generata. Adesso e' una tinta piena e profonda, con un solo
velo verticale appena accennato per non essere piatta come un francobollo. */
.header-gradient {
background: linear-gradient(180deg, #333072 0%, #2b2860 100%);
}
.sidebar-active {
background: var(--tm-accento-tenue);
border-right: 3px solid var(--tm-accento);
color: var(--tm-accento-scuro);
font-weight: 600;
}
.page-enter {
animation: fadeSlideIn .28s cubic-bezier(.22, .61, .36, 1);
}
@keyframes fadeSlideIn {
from { opacity: 0; transform: translateY(6px); }
to { opacity: 1; transform: translateY(0); }
}
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
gap: 10px;
padding: 2.5rem 1rem;
color: var(--tm-testo-tenue);
}
.empty-state svg {
width: 44px;
height: 44px;
opacity: .35;
}
.badge-pulse {
animation: pulse 2s infinite;
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: .7; }
}
/* ─── Impaginazione ───────────────────────────────────────────────────────── */
.tm-pagina-testata {
display: flex;
flex-wrap: wrap;
align-items: flex-end;
justify-content: space-between;
gap: 16px;
margin-bottom: 28px;
}
.tm-pagina-titolo {
margin: 0;
font-size: clamp(1.5rem, 1.2rem + 1vw, 1.9rem);
font-weight: 600;
line-height: 1.15;
color: var(--tm-testo);
}
.tm-pagina-nota {
margin: 6px 0 0;
max-width: 62ch;
font-size: 14px;
line-height: 1.6;
color: var(--tm-testo-medio);
}
.tm-card {
background: var(--tm-superficie);
border: 1px solid var(--tm-bordo);
border-radius: var(--tm-raggio);
box-shadow: var(--tm-ombra-1);
/* Il basso ottico vuole un filo piu' del sopra, altrimenti il blocco
sembra appoggiato storto. */
padding: 20px 22px 24px;
margin-bottom: 20px;
}
.tm-card-testata {
margin-bottom: 18px;
}
/* Scheda che apre la pagina: è il presupposto di tutto quello che segue, e
deve leggersi come tale prima ancora di aver letto il titolo. Il rilievo
glielo danno la barra d'accento e il fondo appena caldo, non un colore
acceso — che a fianco di un avviso vero ne ruberebbe la voce. */
.tm-card-primaria {
position: relative;
padding-left: 26px;
background: linear-gradient(180deg, var(--tm-superficie-alt) 0%, var(--tm-superficie) 60%);
box-shadow: var(--tm-ombra-2);
}
.tm-card-primaria::before {
content: "";
position: absolute;
left: 0;
top: -1px;
bottom: -1px;
width: 4px;
border-radius: var(--tm-raggio) 0 0 var(--tm-raggio);
background: var(--tm-accento);
}
/* Finché il KML manca, l'accento diventa ambra: è un lavoro da fare. */
.tm-card-manca::before { background: var(--tm-attesa); }
.tm-card-manca {
border-color: #e8d3ae;
background: linear-gradient(180deg, var(--tm-attesa-tenue) 0%, var(--tm-superficie) 65%);
}
.tm-card-testata-icona {
display: flex;
align-items: flex-start;
gap: 14px;
}
.tm-card-icona {
display: inline-flex;
align-items: center;
justify-content: center;
flex: none;
width: 40px;
height: 40px;
border-radius: var(--tm-raggio-interno);
border: 1px solid var(--tm-bordo);
background: var(--tm-superficie);
color: var(--tm-accento);
}
.tm-card-icona svg { width: 21px; height: 21px; }
.tm-card-manca .tm-card-icona { color: var(--tm-attesa); border-color: #e8d3ae; }
/* Chiosa accanto all'etichetta di un campo: spiega dove finisce quel valore
senza spingere la spiegazione sotto, dove verrebbe letta dopo la scelta. */
.tm-campo-nota {
margin-left: 6px;
font-size: 11.5px;
font-weight: 500;
color: var(--tm-testo-tenue);
}
.tm-card-titolo {
display: flex;
align-items: center;
gap: 10px;
margin: 0;
font-size: 1.02rem;
font-weight: 600;
color: var(--tm-testo);
}
.tm-card-nota {
margin: 5px 0 0;
max-width: 68ch;
font-size: 13px;
line-height: 1.6;
color: var(--tm-testo-tenue);
}
.tm-conteggio {
display: inline-flex;
align-items: center;
min-width: 22px;
height: 22px;
padding: 0 7px;
border-radius: 999px;
background: var(--tm-superficie-alt);
border: 1px solid var(--tm-bordo);
font-size: 12px;
font-weight: 600;
color: var(--tm-testo-medio);
}
.tm-griglia-2 {
display: grid;
grid-template-columns: 1fr;
gap: 22px;
}
@media (min-width: 900px) {
.tm-griglia-2 { grid-template-columns: 1fr 1fr; gap: 28px; }
}
/* ─── Campi ───────────────────────────────────────────────────────────────── */
.tm-campo {
display: flex;
flex-direction: column;
gap: 7px;
}
.tm-campo > label {
font-size: 13px;
font-weight: 600;
color: var(--tm-testo-medio);
}
.tm-campo input[type="text"],
.tm-campo input[type="number"],
.tm-campo select,
.tm-elenco-pannello select {
width: 100%;
min-height: 40px;
padding: 8px 12px;
border: 1px solid var(--tm-bordo-forte);
border-radius: var(--tm-raggio-interno);
background: var(--tm-superficie);
color: var(--tm-testo);
font-family: inherit;
font-size: 14px;
transition: border-color .15s ease, box-shadow .15s ease;
}
.tm-campo input:focus,
.tm-campo select:focus,
.tm-elenco-pannello select:focus {
outline: none;
border-color: var(--tm-accento);
box-shadow: 0 0 0 3px var(--tm-accento-tenue);
}
.tm-campo input::placeholder { color: var(--tm-testo-tenue); }
.tm-campo textarea {
width: 100%;
min-height: 120px;
padding: 10px 12px;
border: 1px solid var(--tm-bordo-forte);
border-radius: var(--tm-raggio-interno);
background: var(--tm-superficie);
color: var(--tm-testo);
font-family: inherit;
font-size: 14px;
line-height: 1.55;
resize: vertical;
transition: border-color .15s ease, box-shadow .15s ease;
}
.tm-campo textarea:focus {
outline: none;
border-color: var(--tm-accento);
box-shadow: 0 0 0 3px var(--tm-accento-tenue);
}
.tm-campo textarea::placeholder { color: var(--tm-testo-tenue); }
/* Gruppo di campi: dà un nome a una parte della scheda senza trasformarla in
una scatola dentro la scatola — solo una riga di separazione e l'etichetta. */
.tm-gruppo {
display: flex;
flex-direction: column;
gap: 16px;
margin: 0;
padding: 0;
border: 0;
}
.tm-gruppo + .tm-gruppo {
padding-top: 20px;
border-top: 1px solid var(--tm-bordo);
}
.tm-gruppo > legend {
padding: 0;
margin-bottom: 2px;
font-size: 11.5px;
font-weight: 600;
letter-spacing: .05em;
text-transform: uppercase;
color: var(--tm-testo-tenue);
}
/* La riga "crea quello che manca": sta sotto la tendina a cui appartiene, e si
legge come una sua appendice invece che come un campo a sé. */
.tm-campo-crea {
gap: 8px;
padding-left: 10px;
border-left: 2px solid var(--tm-bordo);
}
.tm-campo-crea input { min-height: 34px; font-size: 13px; }
.tm-campo-riga {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 10px;
}
.tm-campo-riga input,
.tm-campo-riga select { flex: 1 1 180px; }
.tm-file {
width: 100%;
font-size: 14px;
color: var(--tm-testo-medio);
}
.tm-file::file-selector-button {
margin-right: 12px;
padding: 8px 14px;
border: 1px solid var(--tm-bordo-forte);
border-radius: var(--tm-raggio-interno);
background: var(--tm-superficie-alt);
color: var(--tm-testo-medio);
font-family: inherit;
font-size: 13px;
font-weight: 600;
cursor: pointer;
transition: background-color .15s ease;
}
.tm-file::file-selector-button:hover { background: var(--tm-bordo); }
.tm-campo-aiuto {
margin: 0;
max-width: 62ch;
font-size: 12.5px;
line-height: 1.55;
color: var(--tm-testo-tenue);
}
.tm-campo-aiuto-attesa { color: var(--tm-attesa); }
.tm-campo-errore {
margin: 0;
font-size: 12.5px;
font-weight: 500;
color: var(--tm-pericolo);
}
/* ─── Elenchi ─────────────────────────────────────────────────────────────── */
.tm-elenco {
list-style: none;
margin: 0;
padding: 0;
border-top: 1px solid var(--tm-bordo);
}
.tm-elenco-riga {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 10px 16px;
padding: 14px 2px;
border-bottom: 1px solid var(--tm-bordo);
}
.tm-elenco-intestazione {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 10px;
flex: 1 1 260px;
min-width: 0;
}
.tm-elenco-nome {
font-size: 14.5px;
font-weight: 600;
color: var(--tm-testo);
text-decoration: none;
border-bottom: 1px solid transparent;
transition: border-color .15s ease, color .15s ease;
}
.tm-elenco-nome:hover {
color: var(--tm-accento);
border-bottom-color: var(--tm-accento);
}
.tm-elenco-stato {
font-size: 12.5px;
color: var(--tm-testo-tenue);
}
.tm-elenco-stato-ok { color: var(--tm-ok); }
.tm-elenco-azioni {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 8px;
}
.tm-elenco-pannello {
flex: 1 1 100%;
display: flex;
flex-direction: column;
gap: 8px;
margin-top: 4px;
padding: 14px;
border: 1px solid var(--tm-bordo);
border-radius: var(--tm-raggio-interno);
background: var(--tm-superficie-alt);
}
/* ─── Assegnazione appena fatta: il link da mandare ──────────────────────── */
.tm-da-inviare {
display: flex;
flex-direction: column;
gap: 14px;
max-width: 48rem;
margin-bottom: 20px;
padding: 18px 20px;
border: 2px solid var(--tm-accento);
border-radius: var(--tm-raggio);
background: var(--tm-accento-tenue);
box-shadow: var(--tm-ombra-2);
}
/* Lo stesso riquadro come finestra sopra la pagina (invio del link dopo
l'assegnazione): sfondo pieno, perché sotto c'è il velo scuro. */
.tm-da-inviare-finestra {
width: 100%;
max-width: 34rem;
margin-bottom: 0;
background: var(--tm-superficie, #fff);
}
.tm-da-inviare-titolo {
margin: 0;
font-size: 16px;
font-weight: 700;
color: var(--tm-accento-scuro);
}
.tm-da-inviare-link {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 8px;
}
.tm-da-inviare-link code {
flex: 1 1 260px;
min-width: 0;
padding: 8px 12px;
border: 1px solid var(--tm-bordo);
border-radius: var(--tm-raggio-interno);
background: var(--tm-superficie);
font-size: 13px;
color: var(--tm-testo);
word-break: break-all;
cursor: text;
}
.tm-da-inviare-azioni { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
.tm-da-inviare-scelta {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
gap: 10px;
padding-top: 12px;
border-top: 1px solid var(--tm-bordo);
}
.tm-da-inviare-scelta p { margin: 0; font-size: 14px; font-weight: 600; color: var(--tm-testo); }
.tm-da-inviare-scelta > div { display: flex; flex-wrap: wrap; gap: 8px; }
/* ─── Ricerca e filtri sopra un elenco ───────────────────────────────────── */
.tm-filtri {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 10px;
margin-bottom: 14px;
}
.tm-filtri-cerca {
flex: 1 1 220px;
min-width: 0;
padding: 7px 11px;
border: 1px solid var(--tm-bordo-forte);
border-radius: var(--tm-raggio-interno);
background: var(--tm-superficie);
font-size: 14px;
color: var(--tm-testo);
}
.tm-filtri-cerca:focus {
outline: 2px solid var(--tm-accento);
outline-offset: 1px;
}
.tm-filtri-schede {
display: flex;
flex-wrap: wrap;
gap: 6px;
}
.tm-filtri-scheda {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 5px 10px;
border: 1px solid var(--tm-bordo);
border-radius: 999px;
background: var(--tm-superficie);
font-size: 13px;
font-weight: 500;
color: var(--tm-testo-medio);
cursor: pointer;
}
.tm-filtri-scheda:hover { border-color: var(--tm-bordo-forte); }
.tm-filtri-scheda:focus-visible {
outline: 2px solid var(--tm-accento);
outline-offset: 2px;
}
.tm-filtri-scheda-attiva {
border-color: var(--tm-accento);
background: var(--tm-accento-tenue);
color: var(--tm-accento-scuro);
}
.tm-filtri-scheda .tm-conteggio {
min-width: 18px;
height: 18px;
padding: 0 5px;
font-size: 11px;
}
/* ─── Etichette di stato ──────────────────────────────────────────────────── */
.tm-tag {
display: inline-flex;
align-items: center;
padding: 2px 8px;
border-radius: 5px;
border: 1px solid var(--tm-bordo-forte);
background: var(--tm-superficie-alt);
font-size: 11.5px;
font-weight: 600;
letter-spacing: .01em;
color: var(--tm-testo-medio);
}
.tm-tag-attesa {
border-color: #e8d3ae;
background: var(--tm-attesa-tenue);
color: var(--tm-attesa);
}
.tm-tag-ok {
border-color: #bcd9c9;
background: var(--tm-ok-tenue);
color: var(--tm-ok);
}
.tm-nota {
padding: 12px 14px;
border: 1px solid var(--tm-bordo);
border-radius: var(--tm-raggio-interno);
background: var(--tm-superficie-alt);
font-size: 13px;
color: var(--tm-testo-medio);
}
.tm-nota p { margin: 0 0 8px; }
.tm-nota-attesa {
border-color: #e8d3ae;
background: var(--tm-attesa-tenue);
color: var(--tm-attesa);
}
.tm-collegamento {
font-size: 13px;
font-weight: 500;
color: var(--tm-accento);
text-decoration: none;
border-bottom: 1px solid color-mix(in srgb, var(--tm-accento) 35%, transparent);
transition: border-color .15s ease;
}
.tm-collegamento:hover { border-bottom-color: var(--tm-accento); }
/* ─── Stato vuoto ─────────────────────────────────────────────────────────── */
.tm-vuoto {
display: flex;
flex-direction: column;
align-items: center;
gap: 12px;
padding: 40px 20px 44px;
text-align: center;
color: var(--tm-testo-tenue);
}
.tm-vuoto svg {
width: 40px;
height: 40px;
opacity: .3;
}
.tm-vuoto p {
margin: 0;
font-size: 14px;
}
/* ─── Tabelle ─────────────────────────────────────────────────────────────── */
.tm-tabella-scorre { overflow-x: auto; }
.tm-tabella {
width: 100%;
border-collapse: collapse;
font-size: 14px;
}
.tm-tabella thead th {
padding: 0 12px 10px 0;
border-bottom: 1px solid var(--tm-bordo);
text-align: left;
font-size: 11.5px;
font-weight: 600;
letter-spacing: .04em;
text-transform: uppercase;
color: var(--tm-testo-tenue);
}
.tm-tabella tbody td {
padding: 11px 12px 11px 0;
border-bottom: 1px solid var(--tm-bordo);
color: var(--tm-testo-medio);
vertical-align: middle;
}
.tm-tabella tbody tr:last-child td { border-bottom: 0; }
.tm-tabella-forte { font-weight: 600; color: var(--tm-testo) !important; }
.tm-tabella .cell-actions {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: flex-end;
gap: 8px;
padding-right: 0;
}
/* ─── Pulsanti ─────────────────────────────────────────────────────────────
Un solo sistema per tutta l'applicazione, definito qui e in nessun altro
posto. Si usa dal componente <x-btn>, mai scrivendo queste classi a mano.
Da dove veniamo: quattro vocabolari in circolazione contemporaneamente —
style= inline con i colori scritti a mano (piu' onmouseover per l'hover),
catene di utility Tailwind ripetute a memoria, .btn-action* in sei tinte, e
.btn-primary-* in due. La stessa azione cambiava aspetto da una pagina
all'altra, un "Rientra" era rosso quanto un "Elimina", e nessuno di questi
pulsanti aveva uno stato di focus: chi naviga da tastiera non vedeva dove si
trovava.
Due assi, ortogonali:
variante primary l'azione principale. Una sola per schermata o zona.
secondary tutto il resto (dettaglio, modifica, scarica, filtra)
danger SOLO dove si cancellano o si sovrascrivono dati
ghost annulla, chiudi, pulisci
tono solido il pieno. Per le azioni isolate.
tenue la tinta chiara. Per le azioni dentro le righe di un
elenco, dove cinquanta pulsanti pieni urlerebbero.
La dimensione `sm` e' quella delle righe di elenco; `icona` toglie il testo e
lascia il quadrato.
Le regole stanno fuori da @layer, quindi vincono sulle utility di Tailwind:
un pulsante non puo' essere ritoccato per meta' con le classi. */
.tm-btn {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 6px;
min-height: 40px;
padding: 10px 16px;
border-radius: var(--tm-raggio-interno);
border: 1px solid transparent;
font-family: inherit;
font-size: 14px;
font-weight: 600;
line-height: 1.2;
white-space: nowrap;
text-decoration: none;
cursor: pointer;
transition: background-color .15s ease, border-color .15s ease,
color .15s ease, transform .1s ease;
}
.tm-btn svg {
width: 16px;
height: 16px;
flex: none;
}
/* Un premuto che si sente: senza, il pulsante resta un rettangolo che non
risponde finche' la pagina non torna dal server. */
.tm-btn:active:not(:disabled) { transform: translateY(1px); }
/* Un anello unico per ogni variante: il colore del focus non deve dipendere
da quello del pulsante, altrimenti su rosso o su bianco cambia visibilita'
proprio dove serve di piu'. Il doppio contorno (chiaro + scuro) lo tiene
leggibile sia sulle card bianche sia sui riquadri colorati. */
.tm-btn:focus-visible,
.tm-console-btn:focus-visible,
.tm-nav-zona:focus-visible,
.tm-editor-torna:focus-visible,
.tm-collegamento:focus-visible,
.tm-elenco-nome:focus-visible {
outline: 3px solid var(--tm-accento);
outline-offset: 2px;
box-shadow: 0 0 0 5px #fff;
}
.tm-btn:disabled,
.tm-btn[aria-disabled="true"] {
opacity: .45;
cursor: not-allowed;
}
.tm-btn-primary { background: var(--tm-accento); border-color: var(--tm-accento-scuro); color: #fff; }
.tm-btn-primary:hover:not(:disabled) { background: var(--tm-accento-scuro); }
.tm-btn-danger { background: var(--tm-pericolo); border-color: #8e2a23; color: #fff; }
.tm-btn-danger:hover:not(:disabled) { background: #8e2a23; }
.tm-btn-secondary { background: var(--tm-superficie); border-color: var(--tm-bordo-forte); color: var(--tm-testo-medio); }
.tm-btn-secondary:hover:not(:disabled) { background: var(--tm-superficie-alt); border-color: var(--tm-testo-tenue); color: var(--tm-testo); }
.tm-btn-ghost {
background: transparent;
border-color: transparent;
color: var(--tm-testo-medio);
min-height: 32px;
padding: 4px 8px;
font-size: 13px;
font-weight: 500;
text-decoration: underline;
text-underline-offset: 3px;
}
.tm-btn-ghost:hover:not(:disabled) { color: var(--tm-testo); background: #efedea; }
/* Tono tenue: stessa gerarchia, voce piu' bassa. Nelle righe di un elenco i
pulsanti sono tanti quanti i record, e il pieno li trasforma in rumore —
soprattutto il rosso, che smette di significare "attenzione" quando compare
cinquanta volte di fila. */
.tm-btn-tenue { border-color: transparent; font-weight: 600; }
.tm-btn-tenue.tm-btn-primary { background: var(--tm-accento-tenue); color: var(--tm-accento-scuro); }
.tm-btn-tenue.tm-btn-primary:hover:not(:disabled) { background: #dedef3; }
.tm-btn-tenue.tm-btn-danger { background: var(--tm-pericolo-tenue); color: var(--tm-pericolo); }
.tm-btn-tenue.tm-btn-danger:hover:not(:disabled) { background: #f6dcda; }
.tm-btn-tenue.tm-btn-secondary { background: #efedea; color: var(--tm-testo-medio); }
.tm-btn-tenue.tm-btn-secondary:hover:not(:disabled) { background: #e3e0da; color: var(--tm-testo); }
/* Tono velato: per i comandi che stanno SOPRA una superficie colorata — oggi
solo la testata. Un pulsante bianco o indaco lì sopra sarebbe una toppa; qui
il colore lo dà lo sfondo e il pulsante si limita a velarlo. Il focus diventa
bianco, perche' l'anello indaco su indaco non si distingue. */
.tm-btn-velato {
background: rgba(255, 255, 255, .12);
border-color: transparent;
color: rgba(255, 255, 255, .92);
}
.tm-btn-velato:hover:not(:disabled) { background: rgba(255, 255, 255, .22); color: #fff; }
.tm-btn-velato:focus-visible {
outline: 3px solid #fff;
outline-offset: 2px;
box-shadow: 0 0 0 5px rgba(0, 0, 0, .35);
}
.tm-btn-sm { min-height: 32px; padding: 6px 12px; font-size: 13px; gap: 5px; }
.tm-btn-sm svg { width: 14px; height: 14px; }
/* Solo icona: quadrato, senza testo. Serve sempre un aria-label, altrimenti chi
usa un lettore di schermo trova un pulsante senza nome. */
.tm-btn-icona { padding-left: 8px; padding-right: 8px; }
.tm-btn-sm.tm-btn-icona { padding-left: 7px; padding-right: 7px; }
/* ─── Zone della pagina ────────────────────────────────────────────────────
Ogni sezione e' un bersaglio di navigazione: premendo un pulsante o una voce
dell'indice la pagina ci si porta sopra e la zona lampeggia, cosi' e' chiaro
*dove* e' finita l'attenzione invece di dover indovinare cosa e' cambiato.
scroll-margin-top tiene la testata della zona sotto la barra dell'indice,
che e' appiccicata in alto: senza, l'ancora finirebbe coperta. */
.tm-zona {
scroll-margin-top: 84px;
}
/* Lampeggio d'arrivo. Non usa `outline` perche' si somma male ai bordi delle
card; box-shadow non occupa spazio e non fa saltare il layout. */
.tm-zona-evidenziata {
animation: tmEvidenzia 1.6s ease-out;
}
@keyframes tmEvidenzia {
0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--tm-accento) 60%, transparent); }
12% { box-shadow: 0 0 0 7px color-mix(in srgb, var(--tm-accento) 32%, transparent); }
100% { box-shadow: 0 0 0 0 transparent; }
}
/* Zona con un'operazione in corso: resta marcata finche' dura, cosi' anche
tornando sulla pagina dopo un ricaricamento si vede subito chi sta lavorando. */
.tm-zona-attiva {
box-shadow: 0 0 0 2px var(--tm-accento);
}
/* Chi ha chiesto meno animazioni riceve comunque il segnale, fermo. */
@media (prefers-reduced-motion: reduce) {
.tm-zona-evidenziata { animation: none; box-shadow: 0 0 0 3px var(--tm-accento); }
.tm-btn, .card-hover, .page-enter { transition: none; animation: none; }
}
/* Indice delle zone, appiccicato in alto. */
.tm-nav-zone {
position: sticky;
top: 0;
z-index: 20;
display: flex;
flex-wrap: wrap;
gap: 6px;
padding: 10px 12px;
margin: -4px 0 0;
border: 1px solid var(--tm-bordo);
border-radius: var(--tm-raggio);
background: rgba(255, 255, 255, .9);
backdrop-filter: blur(8px);
}
.tm-nav-zona {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 5px 10px;
border-radius: 999px;
border: 1px solid var(--tm-bordo);
background: var(--tm-superficie);
color: var(--tm-testo-medio);
font-size: 12px;
font-weight: 500;
text-decoration: none;
cursor: pointer;
transition: background-color .15s ease, border-color .15s ease, color .15s ease;
}
.tm-nav-zona:hover { background: var(--tm-accento-tenue); border-color: var(--tm-accento); color: var(--tm-accento-scuro); }
.tm-nav-zona-pericolo { color: var(--tm-pericolo); border-color: #edc9c6; }
.tm-nav-zona-pericolo:hover { background: var(--tm-pericolo-tenue); border-color: var(--tm-pericolo); color: #8e2a23; }
/* ─── Console delle operazioni ─────────────────────────────────────────────
Una sola finestra per tutte le operazioni lunghe, agganciata in fondo alla
finestra del browser: quello che sta succedendo non deve uscire dallo schermo
mentre si scorre la pagina. Chiusa e' una striscia alta 44px. */
.tm-console {
position: fixed;
left: 0;
right: 0;
bottom: 0;
z-index: 45;
display: flex;
flex-direction: column;
background: #17161f;
border-top: 1px solid #2c2a38;
box-shadow: 0 -8px 28px -14px rgba(20, 16, 12, .6);
color: #e6e3dd;
}
.tm-console-testata {
display: flex;
align-items: center;
gap: 10px;
padding: 8px 12px;
min-height: 44px;
}
.tm-console-titolo {
display: inline-flex;
align-items: center;
gap: 8px;
background: none;
border: 0;
padding: 0;
color: #e6e3dd;
font-family: inherit;
font-size: 13px;
font-weight: 600;
cursor: pointer;
}
.tm-console-btn {
background: transparent;
border: 1px solid #3d3a4a;
border-radius: 8px;
padding: 4px 10px;
color: #cfcbc2;
font-family: inherit;
font-size: 12px;
cursor: pointer;
transition: background-color .15s ease, color .15s ease;
}
.tm-console-btn:hover { background: #2c2a38; color: #fff; }
/* Il corpo scorre; l'altezza e' in vh perche' su un portatile basso una
finestra fissa in pixel si mangerebbe mezza pagina. */
.tm-console-corpo {
max-height: min(38vh, 340px);
overflow-y: auto;
padding: 4px 12px 12px;
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
font-size: 12px;
line-height: 1.55;
}
.tm-console-riga { display: flex; gap: 8px; white-space: pre-wrap; word-break: break-word; }
.tm-console-ora { color: #837d74; flex: none; }
.tm-console-sorgente { color: #a09ed8; flex: none; }
.tm-console-riga-errore .tm-console-testo { color: #e8a09a; font-weight: 600; }
.tm-console-riga-ok .tm-console-testo { color: #8fd0ac; }
.tm-console-riga-attesa .tm-console-testo { color: #e2bd7e; }
.tm-console-barra {
flex: 1;
height: 6px;
min-width: 60px;
border-radius: 999px;
background: #2c2a38;
overflow: hidden;
}
.tm-console-barra > div {
height: 100%;
border-radius: 999px;
background: #7c79c5;
transition: width .3s ease;
}
.tm-console-barra-ok > div { background: #3f8b64; }
.tm-console-barra-errore > div { background: #c9564c; }
.tm-console-torna {
align-self: center;
margin: 0 12px 8px;
background: #2f2c6c;
border: 1px solid var(--tm-accento);
border-radius: 999px;
padding: 3px 12px;
color: #dedef3;
font-family: inherit;
font-size: 11px;
cursor: pointer;
}
@media (max-width: 640px) {
.tm-console-corpo { max-height: 45vh; font-size: 11px; }
.tm-console-sorgente { display: none; }
}
/* ─── Editor delle piantine, a schermo intero ──────────────────────────────
La mappa prende tutta la finestra e i comandi stanno in una striscia sottile
in alto. Tagliare un confine su una cartografia grande un terzo di schermo
vuol dire sbagliarlo, e questo disegno finisce stampato su un modulo che poi
gira di mano in mano. */
.tm-schermo {
height: 100dvh;
display: flex;
flex-direction: column;
}
.tm-editor {
display: flex;
flex-direction: column;
height: 100%;
min-height: 0;
}
.tm-editor-barra {
display: flex;
align-items: center;
gap: 10px;
flex: none;
padding: 8px 14px;
background: var(--tm-superficie);
border-bottom: 1px solid var(--tm-bordo);
box-shadow: var(--tm-ombra-1);
z-index: 10;
}
.tm-editor-torna {
display: inline-flex;
align-items: center;
gap: 5px;
flex: none;
padding: 5px 8px 5px 4px;
border-radius: 8px;
color: var(--tm-testo-medio);
font-size: 13.5px;
font-weight: 600;
text-decoration: none;
transition: background-color .15s ease, color .15s ease;
}
.tm-editor-torna:hover { background: var(--tm-superficie-alt); color: var(--tm-testo); }
.tm-editor-torna svg { width: 17px; height: 17px; }
.tm-editor-sep {
width: 1px;
height: 22px;
flex: none;
background: var(--tm-bordo);
}
.tm-editor-titolo {
display: flex;
align-items: center;
gap: 9px;
flex: 1 1 auto;
min-width: 0;
}
.tm-editor-titolo h1 {
margin: 0;
font-size: 15px;
font-weight: 600;
color: var(--tm-testo);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.tm-editor-salvato {
font-size: 12px;
color: var(--tm-testo-tenue);
white-space: nowrap;
}
.tm-editor-azioni {
display: flex;
align-items: center;
gap: 8px;
flex: none;
}
/* Le tre zone: elenco, mappa, pannello. Elenco e pannello galleggiano sopra
la mappa invece di restringerla: se togliessero spazio, aprirli per cambiare
un nome sposterebbe il disegno sotto il puntatore. */
.tm-editor-corpo {
position: relative;
flex: 1 1 auto;
min-height: 0;
/* Lo spazio che elenco e pannello aperti tolgono ai lati: barra degli
strumenti e controlli della mappa stanno nella parte libera, invece di
finire sotto (o sopra) un pannello. */
--libero-sx: 12px;
--libero-dx: 12px;
}
.tm-editor-corpo.con-elenco { --libero-sx: calc(min(270px, 100vw - 24px) + 24px); }
.tm-editor-corpo.con-pannello { --libero-dx: calc(min(370px, 100vw - 24px) + 24px); }
.tm-mappa .leaflet-left { left: calc(var(--libero-sx) - 12px); }
.tm-mappa .leaflet-right { right: calc(var(--libero-dx) - 12px); }
.tm-editor-mappa {
position: absolute;
inset: 0;
}
.tm-mappa {
position: absolute;
inset: 0;
background: #efedea;
}
.tm-editor-nota {
position: absolute;
left: 50%;
bottom: 18px;
transform: translateX(-50%);
z-index: 500;
max-width: min(92vw, 460px);
margin: 0;
padding: 9px 14px;
border: 1px solid #e8d3ae;
border-radius: 999px;
background: var(--tm-attesa-tenue);
box-shadow: var(--tm-ombra-2);
font-size: 12.5px;
text-align: center;
color: var(--tm-attesa);
}
.tm-editor-nota a { color: inherit; font-weight: 600; }
/* ── Barra degli strumenti di disegno ── */
.tm-strumenti {
position: absolute;
top: 12px;
left: var(--libero-sx);
right: var(--libero-dx);
z-index: 650;
display: flex;
align-items: center;
gap: 6px;
width: fit-content;
margin-inline: auto;
padding: 5px;
border: 1px solid var(--tm-bordo);
border-radius: 12px;
background: var(--tm-superficie);
box-shadow: var(--tm-ombra-3);
overflow-x: auto;
}
.tm-strumenti:empty { display: none; }
.tm-strumento {
flex: none;
min-height: 34px;
padding: 6px 12px;
border: 1px solid transparent;
border-radius: 8px;
background: none;
font: inherit;
font-size: 13px;
font-weight: 600;
color: var(--tm-testo-medio);
white-space: nowrap;
cursor: pointer;
transition: background-color .15s ease, color .15s ease;
}
.tm-strumento:hover { background: var(--tm-superficie-alt); color: var(--tm-testo); }
.tm-strumento:focus-visible { outline: 2px solid var(--tm-accento); outline-offset: 1px; }
.tm-strumento-principale { background: var(--tm-accento); color: #fff; }
.tm-strumento-principale:hover { background: var(--tm-accento-scuro); color: #fff; }
.tm-strumenti-modo {
flex: none;
padding: 0 8px 0 6px;
font-size: 12px;
font-weight: 600;
letter-spacing: .04em;
text-transform: uppercase;
color: var(--tm-pericolo);
}
/* ── Elenco ── */
.tm-editor-elenco {
position: absolute;
top: 12px;
left: 12px;
bottom: 12px;
z-index: 600;
width: min(270px, calc(100vw - 24px));
display: flex;
flex-direction: column;
border: 1px solid var(--tm-bordo);
border-radius: var(--tm-raggio);
background: var(--tm-superficie);
box-shadow: var(--tm-ombra-3);
overflow: hidden;
}
.tm-editor-elenco-cerca {
flex: none;
padding: 10px;
border-bottom: 1px solid var(--tm-bordo);
}
.tm-editor-elenco-cerca input {
width: 100%;
padding: 8px 10px;
border: 1px solid var(--tm-bordo-forte);
border-radius: 8px;
font: inherit;
font-size: 13.5px;
}
.tm-editor-elenco-righe {
flex: 1 1 auto;
margin: 0;
padding: 6px;
list-style: none;
overflow-y: auto;
}
.tm-editor-elenco-voce {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
width: 100%;
min-height: 38px;
padding: 7px 10px;
border: 0;
border-radius: 8px;
background: none;
font: inherit;
font-size: 13.5px;
text-align: left;
color: var(--tm-testo);
cursor: pointer;
}
.tm-editor-elenco-voce:hover { background: var(--tm-superficie-alt); }
.tm-editor-elenco-voce.is-selezionata { background: var(--tm-accento-tenue); color: var(--tm-accento-scuro); font-weight: 600; }
.tm-editor-elenco-stato {
flex: none;
font-size: 11px;
font-weight: 600;
color: var(--tm-testo-tenue);
}
.tm-stato-bozza, .tm-stato-modificata { color: var(--tm-attesa); }
.tm-stato-pubblicata { color: var(--tm-ok); }
.tm-editor-elenco-vuoto {
padding: 14px 10px;
font-size: 13px;
color: var(--tm-testo-tenue);
}
/* ── Pannello della piantina ── */
.tm-editor-pannello {
position: absolute;
top: 12px;
right: 12px;
bottom: 12px;
z-index: 600;
width: min(370px, calc(100vw - 24px));
display: flex;
flex-direction: column;
border: 1px solid var(--tm-bordo);
border-radius: var(--tm-raggio);
background: var(--tm-superficie);
box-shadow: var(--tm-ombra-3);
overflow: hidden;
}
.tm-editor-pannello-testata {
display: flex;
align-items: center;
justify-content: space-between;
gap: 10px;
flex: none;
padding: 12px 16px;
border-bottom: 1px solid var(--tm-bordo);
}
.tm-editor-pannello-testata h2 {
margin: 0;
font-size: 14px;
font-weight: 600;
}
.tm-editor-chiudi {
background: none;
border: 0;
padding: 2px 6px;
border-radius: 7px;
color: var(--tm-testo-tenue);
font-size: 20px;
line-height: 1;
cursor: pointer;
transition: background-color .15s ease, color .15s ease;
}
.tm-editor-chiudi:hover { background: var(--tm-superficie-alt); color: var(--tm-testo); }
.tm-editor-pannello-corpo {
display: flex;
flex-direction: column;
gap: 20px;
padding: 16px;
overflow-y: auto;
}
.tm-editor-pannello-piede {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: flex-end;
gap: 10px;
padding-top: 16px;
border-top: 1px solid var(--tm-bordo);
}
.tm-editor-aiuto {
margin: 0;
font-size: 12.5px;
line-height: 1.55;
color: var(--tm-testo-tenue);
}
.tm-stato-piantina p { margin: 0; font-size: 13px; line-height: 1.5; color: var(--tm-testo-medio); }
.tm-azioni-riga {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 12px;
}
.tm-azioni-riga:empty { display: none; }
.tm-passi {
margin: 0;
padding-left: 20px;
font-size: 13.5px;
line-height: 1.6;
color: var(--tm-testo-medio);
}
.tm-collegamento-piccolo {
align-self: flex-start;
padding: 0;
border-top: 0;
border-left: 0;
border-right: 0;
background: none;
font: inherit;
font-size: 12.5px;
cursor: pointer;
}
.tm-solo-stretto { display: none; }
/* Tablet: l'elenco si apre a richiesta e copre la mappa per il tempo della
scelta. */
@media (max-width: 1099px) {
.tm-editor-elenco { width: min(300px, calc(100vw - 24px)); }
.tm-editor-corpo.con-elenco { --libero-sx: calc(min(300px, 100vw - 24px) + 24px); }
}
/* Telefono e tablet in verticale: il pannello sale dal basso. */
@media (max-width: 720px) {
.tm-editor-barra { flex-wrap: wrap; }
.tm-editor-titolo { order: 3; flex-basis: 100%; }
.tm-editor-azioni .tm-btn span { display: none; }
.tm-solo-stretto { display: inline-flex; }
.tm-editor-pannello {
top: auto;
left: 0;
right: 0;
bottom: 0;
width: auto;
height: min(62dvh, 520px);
border-radius: var(--tm-raggio) var(--tm-raggio) 0 0;
}
/* Elenco e pannello qui coprono la mappa per intero o dal basso: la
barra resta in alto, sopra il foglio del pannello. */
.tm-editor-corpo,
.tm-editor-corpo.con-elenco,
.tm-editor-corpo.con-pannello { --libero-sx: 12px; --libero-dx: 12px; }
/* A destra dei pulsanti dello zoom, e su più righe invece di uscire
dallo schermo. */
.tm-strumenti { left: 58px; flex-wrap: wrap; }
.tm-mappa .leaflet-left { left: 0; }
/* Il foglio copre crediti e scala della mappa finché è aperto, invece di
averli stampati sopra i campi. */
.tm-editor-pannello { z-index: 1001; }
}
/* Dita, non puntatore: vertici e maniglie di leaflet-draw più grandi, così
si prendono senza zoomare al massimo. */
@media (pointer: coarse) {
.leaflet-editing-icon,
.leaflet-touch-icon {
width: 22px !important;
height: 22px !important;
margin-left: -11px !important;
margin-top: -11px !important;
}
.tm-strumento { min-height: 42px; padding: 8px 14px; }
}
/* ─── Finestra di pubblicazione ───────────────────────────────────────────── */
.tm-modale-sfondo {
position: fixed;
inset: 0;
z-index: 800;
display: flex;
align-items: center;
justify-content: center;
padding: 16px;
background: rgba(28, 26, 23, .45);
}
.tm-modale {
display: flex;
flex-direction: column;
width: 100%;
max-width: 460px;
max-height: calc(100dvh - 32px);
border-radius: var(--tm-raggio);
background: var(--tm-superficie);
box-shadow: var(--tm-ombra-3);
overflow: hidden;
}
.tm-modale-larga { max-width: 820px; }
.tm-modale-testata {
display: flex;
align-items: center;
justify-content: space-between;
gap: 10px;
padding: 14px 18px;
border-bottom: 1px solid var(--tm-bordo);
}
.tm-modale-testata h2 { margin: 0; font-size: 15px; font-weight: 600; }
.tm-modale-corpo {
display: flex;
flex-direction: column;
gap: 12px;
padding: 18px;
overflow-y: auto;
}
.tm-modale-piede {
display: flex;
flex-wrap: wrap;
justify-content: flex-end;
gap: 8px;
padding: 12px 18px;
border-top: 1px solid var(--tm-bordo);
}
.tm-anteprima-pdf {
width: 100%;
height: min(62dvh, 640px);
border: 1px solid var(--tm-bordo);
border-radius: var(--tm-raggio-interno);
background: var(--tm-superficie-alt);
}
.tm-attesa {
display: flex;
align-items: flex-start;
gap: 14px;
padding: 18px 4px;
}
.tm-attesa-titolo { margin: 0 0 4px; font-size: 14px; font-weight: 600; }
.tm-attesa-giro {
flex: none;
width: 22px;
height: 22px;
border: 3px solid var(--tm-accento-tenue);
border-top-color: var(--tm-accento);
border-radius: 50%;
animation: tm-giro .9s linear infinite;
}
@keyframes tm-giro { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .tm-attesa-giro { animation-duration: 3s; } }
.tm-nota-errore {
border-color: #edc9c6;
background: var(--tm-pericolo-tenue);
color: var(--tm-pericolo);
}
/* ─── Avvisi galleggianti (componente <x-avvisi>) ───────────────────── */
.tm-avvisi {
position: fixed;
top: 14px;
left: 50%;
transform: translateX(-50%);
z-index: 900;
display: flex;
flex-direction: column;
gap: 8px;
width: min(92vw, 520px);
pointer-events: none;
}
.tm-avviso {
display: flex;
align-items: center;
gap: 10px;
padding: 11px 14px;
border-radius: var(--tm-raggio-interno);
border: 1px solid var(--tm-bordo);
background: var(--tm-superficie);
box-shadow: var(--tm-ombra-3);
font-size: 13.5px;
pointer-events: auto;
}
.tm-avviso svg { width: 18px; height: 18px; flex: none; }
.tm-avviso-ok { border-color: #bcd9c9; background: var(--tm-ok-tenue); color: var(--tm-ok); }
.tm-avviso-errore { border-color: #edc9c6; background: var(--tm-pericolo-tenue); color: var(--tm-pericolo); }
.tm-avviso-chiudi {
margin-left: auto;
background: none;
border: 0;
padding: 0 4px;
color: inherit;
font-size: 19px;
line-height: 1;
opacity: .6;
cursor: pointer;
}
.tm-avviso-chiudi:hover { opacity: 1; }
/* ─── Responsive list tables ───────────────────────────────────────────────
Under 640px (a phone held in portrait; rotate to landscape and the width
grows past the breakpoint, restoring the normal table) every table with the
`table-cards` class reflows: the header is hidden and each row becomes a
card, with each cell shown as "LABEL … value" (the label comes from the
cell's data-label attribute). Cells with no data-label (the actions column,
marked `.cell-actions`) span the row full width. */
@media (max-width: 640px) {
table.table-cards,
table.table-cards tbody {
display: block;
width: 100%;
}
table.table-cards thead {
display: none;
}
table.table-cards tr {
display: block;
border: 1px solid var(--tm-bordo);
border-radius: var(--tm-raggio-interno);
margin-bottom: 12px;
padding: 4px 2px;
background: var(--tm-superficie);
}
/* zebra striping would fight the card borders */
table.table-cards.table-striped tbody tr:nth-child(even) {
background: var(--tm-superficie);
}
table.table-cards td {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
width: 100%;
text-align: right;
padding: 6px 12px;
border: none !important;
}
table.table-cards td[data-label]::before {
content: attr(data-label);
flex: 0 0 auto;
margin-right: auto;
text-align: left;
font-size: 11px;
font-weight: 600;
color: var(--tm-testo-tenue);
text-transform: uppercase;
letter-spacing: .04em;
}
/* Actions row: full width, buttons wrapped to the right */
table.table-cards td.cell-actions {
justify-content: flex-end;
flex-wrap: wrap;
margin-top: 2px;
padding-top: 10px;
border-top: 1px solid var(--tm-bordo) !important;
}
/* Riga di separazione di un gruppo (l'anno teocratico negli storici):
resta un titolo, non diventa una scheda. */
table.table-cards tr.tm-riga-gruppo {
border: none;
background: transparent;
padding: 0;
margin: 16px 0 6px;
}
table.table-cards tr.tm-riga-gruppo th {
display: block;
padding: 0 2px;
}
/* Cells spanning all columns (empty state, inline edit form) stay full
width and block, so their inner layout isn't squeezed by the flex row. */
table.table-cards td[colspan] {
display: block;
text-align: center;
}
}
/* ─── Campo di scelta con ricerca (<x-scelta>) ──────────────────────────────
Al posto delle tendine di territori e proclamatori. Pensato anche per il
telefono: testo a 16px (sotto, iOS ingrandisce la pagina al tocco), voci
alte almeno 44px, elenco che scorre dentro mezzo schermo. I selettori
battono `.tm-campo input[type="text"]` dell'editor delle piantine. */
.tm-scelta {
position: relative;
width: 100%;
}
.tm-scelta-campo {
position: relative;
display: flex;
align-items: center;
}
.tm-scelta input.tm-scelta-input {
width: 100%;
min-height: 44px;
padding: 8px 76px 8px 12px;
border: 1px solid var(--tm-bordo-forte);
border-radius: var(--tm-raggio-interno);
background: var(--tm-superficie);
color: var(--tm-testo);
font-family: inherit;
font-size: 16px;
line-height: 1.3;
transition: border-color .15s ease, box-shadow .15s ease;
}
@media (min-width: 640px) {
.tm-scelta input.tm-scelta-input { min-height: 40px; font-size: 14px; }
}
.tm-scelta input.tm-scelta-input:focus {
outline: none;
border-color: var(--tm-accento);
box-shadow: 0 0 0 3px var(--tm-accento-tenue);
}
.tm-scelta input.tm-scelta-input:disabled {
padding-right: 12px;
background: var(--tm-superficie-alt);
color: var(--tm-testo-medio);
}
.tm-scelta input.tm-scelta-input::placeholder { color: var(--tm-testo-tenue); }
.tm-scelta-pulisci,
.tm-scelta-apri {
position: absolute;
top: 50%;
display: flex;
align-items: center;
justify-content: center;
width: 36px;
height: 36px;
margin-top: -18px;
border: 0;
border-radius: 8px;
background: transparent;
color: var(--tm-testo-tenue);
cursor: pointer;
}
.tm-scelta-pulisci { right: 38px; }
.tm-scelta-apri { right: 2px; }
.tm-scelta-pulisci:hover,
.tm-scelta-apri:hover { color: var(--tm-testo); background: var(--tm-superficie-alt); }
.tm-scelta-pulisci svg,
.tm-scelta-apri svg { width: 18px; height: 18px; transition: transform .15s ease; }
.tm-scelta-apri svg.tm-scelta-giu { transform: rotate(180deg); }
.tm-scelta-elenco {
position: absolute;
z-index: 40;
top: calc(100% + 4px);
left: 0;
right: 0;
max-height: min(50vh, 20rem);
margin: 0;
padding: 4px;
overflow-y: auto;
overscroll-behavior: contain;
-webkit-overflow-scrolling: touch;
list-style: none;
border: 1px solid var(--tm-bordo);
border-radius: var(--tm-raggio-interno);
background: var(--tm-superficie);
box-shadow: var(--tm-ombra-3);
}
.tm-scelta-voce {
display: flex;
flex-wrap: wrap;
align-items: baseline;
column-gap: 8px;
row-gap: 2px;
min-height: 44px;
padding: 10px 12px;
border-radius: 8px;
color: var(--tm-testo);
font-size: 15px;
cursor: pointer;
-webkit-tap-highlight-color: transparent;
}
@media (min-width: 640px) {
.tm-scelta-voce { min-height: 36px; padding: 7px 10px; font-size: 14px; }
}
.tm-scelta-voce-attiva { background: var(--tm-accento-tenue); }
.tm-scelta-voce-scelta .tm-scelta-etichetta { font-weight: 700; color: var(--tm-accento-scuro); }
.tm-scelta-voce-speciale { color: var(--tm-testo-medio); }
.tm-scelta-voce-spenta { cursor: not-allowed; color: var(--tm-testo-tenue); }
.tm-scelta-voce-spenta.tm-scelta-voce-attiva { background: var(--tm-superficie-alt); }
.tm-scelta-dettaglio { font-size: 13px; color: var(--tm-testo-tenue); }
.tm-scelta-motivo { flex-basis: 100%; font-size: 12px; color: var(--tm-attesa); }
.tm-scelta-forse {
padding: 1px 6px;
border-radius: 999px;
background: var(--tm-attesa-tenue);
color: var(--tm-attesa);
font-size: 11px;
font-weight: 600;
}
.tm-scelta-vuoto {
padding: 12px;
color: var(--tm-testo-tenue);
font-size: 14px;
}
/* ─── Elenco dei territori assegnati (pagina Assegna) ───────────────────────
Classi brevi al posto delle catene di utility: le righe sono ~80 e ogni
byte si moltiplica (ElencoAssegnati, AssegnaPrestazioniTest). */
.tm-assegnato { padding: 16px 20px; }
.tm-assegnato svg { width: 16px; height: 16px; fill: none; stroke: currentColor; flex: none; }
.tm-assegnato-testa {
display: flex; flex-wrap: wrap; align-items: flex-start; justify-content: space-between;
gap: 8px 24px;
}
.tm-assegnato-numero { color: #4f46e5; font-size: 14px; font-weight: 700; }
.tm-assegnato-numero:hover { text-decoration: underline; }
/* Il numero come pulsante ("Il mio gruppo": apre l'anteprima): stesso aspetto. */
button.tm-assegnato-numero {
background: none; border: 0; padding: 0; cursor: pointer;
font-family: inherit; line-height: inherit;
}
button.tm-assegnato-numero:focus-visible {
outline: 2px solid var(--tm-accento); outline-offset: 2px; border-radius: 2px;
}
.tm-assegnato-zona {
margin-left: 6px; padding: 2px 6px; border-radius: 4px;
background: #f3f4f6; color: #9ca3af; font-size: 12px;
}
.tm-assegnato-info { color: #6b7280; font-size: 12px; }
.tm-assegnato-info b { color: #1f2937; font-size: 14px; font-weight: 500; }
.tm-assegnato-giorni {
padding: 2px 8px; border-radius: 999px;
background: #f3f4f6; color: #6b7280; font-weight: 600;
}
.tm-assegnato-giorni.tm-g-presto { background: #fffbeb; color: #d97706; }
.tm-assegnato-giorni.tm-g-tardi { background: #fef2f2; color: #dc2626; }
.tm-assegnato-sospeso {
display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
margin-top: 12px; padding: 6px 12px; border: 1px solid #fde68a; border-radius: 6px;
background: #fffbeb; color: #92400e; font-size: 12px; font-weight: 600;
}
.tm-assegnato-link { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 12px; }
.tm-assegnato-link > * { flex: none; }
.tm-assegnato-link code {
flex: 1 1 0; min-width: 0; padding: 8px 12px;
border: 1px solid #e5e7eb; border-radius: 6px; background: #f9fafb;
color: #4b5563; font-size: 12px; word-break: break-all; user-select: all; cursor: text;
}
.tm-assegnato-senza { margin-top: 8px; color: #d1d5db; font-size: 12px; }
/* Pulsante copia: la spunta al posto dell'icona per due secondi. */
.tm-copia svg + svg, .tm-copia.tm-copiato svg:first-child { display: none; }
.tm-copia.tm-copiato svg + svg { display: block; color: #16a34a; }