/* ============================================================
   TripsBack — Design system "Executive"
   Corporate-fintech: fiducia, precisione, efficienza.
   E' l'UNICO foglio di base del sito: global.css non esiste piu' (le sue sei
   regole vive sono nella sezione "Base" qui sotto). Si carica dopo i vendor e
   PRIMA del CSS di pagina, cosi' una pagina puo' specializzare senza dover
   alzare la specificita' per farsi sentire. Vedi sm/lib_page/_head.php.
   Le classi con hook JS della barra di ricerca (.js-*, .tb-search-*) sono
   mantenute: cambia solo lo stile, non il contratto col JavaScript.
   ============================================================ */

/* Il contratto di questo foglio sta in docs/design/DESIGN.md. Se cambi un token
   qui, cambia anche la' — o il documento comincia a mentire. */

:root {
    /* Colori */
    --tb-ink:          #0E1A33;   /* navy: titoli e testo */
    --tb-ink-hover:    #1C2C4E;   /* navy in hover — bianco sopra: 12.9:1 */
    --tb-ink-soft:     #566079;   /* testo secondario (>=4.5:1 su bianco) */
    --tb-bg:           #FFFFFF;
    --tb-panel:        #F2F5FA;   /* superfici fredde */
    --tb-panel-2:      #E8EDF6;
    --tb-blue:         #2455FF;   /* azione primaria — bianco sopra: 5.50:1 */
    /* SOLO come SUPERFICIE (il fondo del bottone in hover), mai come testo.
       Non segue il tema, e non deve: il bianco che ci sta sopra e' verificato
       contro DI LUI. Usato come `color:` su una pagina scura dava 2,36:1 — e ci
       stava, su "Password dimenticata" e "Crea account". Il blu che fa il testo
       e' --tb-blue-ink, che il tema lo segue. */
    --tb-blue-deep:    #163FCC;   /* hover  — bianco sopra: 8.02:1 */
    --tb-blue-press:   #0F2E99;   /* active — bianco sopra: 11.22:1 */
    --tb-blue-soft:    #EAF0FF;
    /* IL BLU COME TESTO, separato dal blu come SUPERFICIE — stessa ragione di
       --tb-ink / --tb-ink-fill. Un bottone blu porta il proprio contrasto con
       se': il bianco sopra sta a 5.50:1 e non dipende dalla pagina. Un LINK
       blu no, dipende dal fondo — e su quello scuro #2455FF cade a 3.34:1.
       Qui vale esattamente --tb-blue: il tema chiaro non cambia. */
    --tb-blue-ink:     var(--tb-blue);
    --tb-emerald:      #0E9E6E;   /* cashback (riempimenti) */
    --tb-emerald-ink:  #0B7E58;   /* cashback come TESTO su bianco */
    --tb-emerald-soft: #E4F6EF;
    --tb-line:         #E2E7F0;   /* e' IL FILETTO che separa le superfici, non l'ombra */

    /* --- I TOKEN DI RIEMPIMENTO, e perche' esistono ------------------------
       --tb-ink faceva due mestieri: il colore del TESTO (106 volte `color:`) e
       la SUPERFICIE navy piena con testo bianco sopra (20 volte `background:`).
       Finche' il sito ha un tema solo la cosa non si vede. Con due temi si
       vede subito: in modalita' TripsBack il testo deve schiarirsi e la
       superficie deve restare scura, e un token solo non puo' andare in due
       direzioni — ribaltarlo darebbe bianco su bianco su venti bottoni.
       Qui valgono esattamente quanto prima, quindi il tema chiaro non cambia di
       un pixel; e' il blocco scuro piu' sotto a mandarli da due parti diverse.
       STESSA REGOLA per l'emerald: --tb-emerald-ink e' il verde come TESTO,
       --tb-emerald-fill e' il verde come PILLOLA con il bianco sopra. */
    --tb-ink-fill:       var(--tb-ink);
    --tb-ink-fill-hover: var(--tb-ink-hover);
    --tb-emerald-fill:   var(--tb-emerald-ink);
    --tb-emerald-fill-ink: #FFFFFF;
    /* Lo spotlight dell'hero della home. Sta fra i token e non in home.css
       perche' e' un colore di SUPERFICIE, e i colori di superficie cambiano
       con il tema. Il colore di sfumatura e' un token a parte, e non
       `transparent`, per la ragione per cui l'aveva scritto cosi' chi ha fatto
       l'hero: la sfumatura verso il trasparente passa dal grigio sui motori che
       non interpolano in alfa premoltiplicata. */
    --tb-hero-glow:      #EAF0FA;
    --tb-hero-glow-fade: rgb(234 240 250 / 0);

    /* Stati. Le coppie erano gia' in uso, scritte a mano: #FCE8E6/#A4271B compariva
       7 volte fra auth, account, payout e checkout senza avere un nome. Rapporti
       CALCOLATI: danger-ink su danger-soft 6.18:1, amber-ink su amber-soft 5.43:1. */
    --tb-danger:       #C0392B;   /* icone e bordi su fondo chiaro */
    --tb-danger-ink:   #A4271B;   /* testo d'errore */
    --tb-danger-soft:  #FCE8E6;
    --tb-amber-ink:    #8A5A00;   /* testo "in attesa" */
    --tb-amber-soft:   #FFF4E0;
    /* L'oro #E2A400 su bianco sta a 2.20:1: le stelle sparivano a chi ha poca vista,
       ed e' l'unico posto in cui si legge la categoria. Questo tiene la tinta
       (40deg contro 44) e sale a 5.10:1. */
    --tb-star:         #966400;

    /* Colori per le SUPERFICI SCURE (.tb-slab, hero della home).
       Sul navy --tb-danger sta a 3.18:1 e non regge il testo: serve la variante
       luminosa. Rapporti CALCOLATI su --tb-ink #0E1A33:
       emerald-bright 9.45:1, danger-bright 7.77:1, on-dark 11.16:1, bianco 17.29:1. */
    /* IL VERDE SULLE SUPERFICI SCURE, e perche' non e' piu' #31D992.
       Quel verde era menta al neon (croma OKLCH 0,166) e faceva le cifre PIU'
       GRANDI della pagina: il saldo dell'esempio nell'hero, il "30%" del riquadro
       del portafoglio. Menta al neon + fondo blu profondo + numero enorme e' la
       grammatica di un exchange di criptovalute, non di un sito che vende notti
       d'albergo — e il riquadro del 30% era, alla lettera, la card del rendimento.
       Stesso posto nella scala (luminosita' 0,80, tinta 158), croma sceso a 0,105:
       -37%. Resta verde, resta "soldi", smette di brillare. Calcolato: 9,69:1 sul
       navy dello slab, 7,14:1 sulla grafite del tema scuro. */
    --tb-emerald-bright: #80D3A4;
    --tb-danger-bright:  #FF8E80;
    --tb-on-dark:        #C7D0E2;   /* testo secondario su navy */
    /* Il TERZO gradino: etichette e note su superficie scura. Mancava, e il piede
       se l'era scritto da solo tre volte (#8C97AD, #A8B2C6, #D5DBE7). Col tema
       scuro la superficie piena si SCHIARISCE (--tb-ink-fill sale a #223353) e
       quel grigio cadeva a 4.29:1: un token che nessuno aveva è un contrasto che
       nessuno ricalcola. Qui 4.96:1 sul navy chiaro, 6.81:1 su quello profondo. */
    --tb-on-dark-dim:    #98A3B8;
    /* Il blu su superficie scura. NON segue il tema, come tutti i token di
       questo gruppo: il piede e' navy sia nel chiaro sia nello scuro, quindi il
       marchio ci sta sopra alle stesse condizioni in tutti e due. Puntarlo a
       --tb-blue-ink lo faceva diventare #2455FF sul navy del piede, cioe' blu
       scuro su blu scuro (3.14:1). Qui 6.87:1 sul navy profondo. */
    --tb-blue-on-dark:   #7C9DFF;

    /* LA SUPERFICIE CHE SI SOLLEVA dentro la barra di ricerca: il segmento
       aperto, e quello col focus. Nel tema chiaro e' il bianco su fondo grigio,
       ed e' per questo che era scritta come --tb-bg.
       Sullo scuro quella stessa regola la farebbe scendere: --tb-bg (#0B1426) e'
       piu' SCURO della barra (--tb-panel, #16243F), quindi il segmento aperto
       sprofondava invece di alzarsi. Un token separato perche' il concetto e'
       "sali di un gradino", non "prendi il colore della pagina". */
    --tb-raise:          var(--tb-bg);
    --tb-raise-shadow:   0 1px 2px rgb(14 26 51 / 6%), 0 8px 20px -10px rgb(14 26 51 / 28%);
    --tb-on-dark-line:   rgb(255 255 255 / 12%);

    /* Raggi */
    --tb-r-card: 12px;
    --tb-r-btn:  10px;
    --tb-r-pill: 999px;
    --tb-r-slab: 16px;

    /* --- ELEVAZIONE: un'ombra sola. ---------------------------------------
       Prima ce n'erano tre (sm/md/lg) usate 33 volte, e sette card diverse
       portavano ciascuna la sua ombrellina. Quando tutto galleggia un po',
       niente galleggia: il senso di "premium" nasce dal contrasto fra piatto
       e sollevato, non dalla quantita' d'ombra.
       REGOLA: piatto di default, a separare e' --tb-line. L'ombra e' riservata
       a cio' che sta DAVVERO sopra al piano (dropdown, slab, sticky, pin della
       mappa, barra di ricerca) e al sollevamento in hover delle card cliccabili. */
    --tb-shadow: 0 1px 2px rgb(14 26 51 / 5%), 0 10px 24px -14px rgb(14 26 51 / 22%);
    --tb-scrim:  rgb(14 26 51 / 55%);

    /* Movimento: solo ease-out esponenziali. Niente rimbalzi, niente elastico. */
    --tb-ease: cubic-bezier(0.16, 1, 0.3, 1);
    --tb-dur-fast: 140ms;
    --tb-dur:      200ms;
    /* Il passo lungo e la curva del VIAGGIO: li usa solo il pannello di ricerca,
       l'unico oggetto del sito che si sposta davvero da un punto a un altro.

       --tb-ease (una expo) qui non andava: e' cosi' sbilanciata in avanti che
       copriva meta' strada nei primi 45ms, e il pannello sembrava SCATTARE al
       suo posto invece di andarci. --tb-glide distribuisce il movimento —
       a un terzo del tempo e' a poco piu' di meta' strada — e il pannello
       PLANA. Nessun rimbalzo: la curva e' monotona, non supera mai l'arrivo. */
    --tb-glide:    cubic-bezier(0.32, 0.72, 0, 1);
    --tb-dur-slow: 380ms;

    /* Spaziatura: base 4px. */
    --tb-s-1: 4px;   --tb-s-2: 8px;   --tb-s-3: 12px;  --tb-s-4: 16px;  --tb-s-5: 20px;
    --tb-s-6: 24px;  --tb-s-7: 32px;  --tb-s-8: 48px;  --tb-s-9: 64px;

    /* --- TIPOGRAFIA: per RUOLO, non per taglia. ---------------------------
       La scala xs/sm/md/lg/xl/2xl e' t-shirt sizing, e il difetto non e'
       estetico ma operativo: quando un token si chiama "grande" invece di
       "titolo di sezione", nessuno sa quando usarlo — ed e' per questo che nel
       CSS sono scappati 10px, 11px, 15px, 0.82rem, 1.06rem, 2.6rem...

       Uso:  font: var(--tb-t-body);   (peso  dimensione/interlinea  famiglia)

       DUE TRAPPOLE:
       1. lo shorthand `font:` AZZERA font-variant. `font-variant-numeric:
          tabular-nums` va dichiarato DOPO, mai prima, o le cifre tabulari
          spariscono senza un errore.
       2. `letter-spacing` NON fa parte dello shorthand: sta nei --tb-tr-*. */
    --tb-font: "Hanken Grotesk", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif;

    --tb-t-hero-figure:    800 3.5rem/1     var(--tb-font);  /* 56 — IL SALDO. L'unico picco del prodotto. */
    --tb-t-hero-figure-sm: 800 2.5rem/1     var(--tb-font);  /* 40 — sotto i 620px */
    --tb-t-figure:         800 1.375rem/1.2 var(--tb-font);  /* 22 — cifre della striscia */
    --tb-t-page-title:     800 1.75rem/1.15 var(--tb-font);  /* 28 — h1 d'app */
    --tb-t-section:        700 1.375rem/1.2 var(--tb-font);  /* 22 */
    --tb-t-card-title:     700 1.125rem/1.3 var(--tb-font);  /* 18 */
    --tb-t-body:           400 1rem/1.55    var(--tb-font);  /* 16 */
    --tb-t-body-strong:    600 1rem/1.55    var(--tb-font);  /* 16 */
    --tb-t-meta:           400 0.875rem/1.45 var(--tb-font); /* 14 */
    --tb-t-label:          600 0.875rem/1.3 var(--tb-font);  /* 14 — etichetta di campo */
    --tb-t-button:         600 0.875rem/1   var(--tb-font);  /* 14 */
    --tb-t-button-lg:      600 1rem/1       var(--tb-font);  /* 16 — CTA a tutta larghezza */
    --tb-t-caption:        400 0.8125rem/1.4 var(--tb-font); /* 13 */
    --tb-t-badge:          700 0.8125rem/1.3 var(--tb-font); /* 13 */
    --tb-t-micro:          700 0.6875rem/1.3 var(--tb-font); /* 11 — occhielli maiuscoli */
    /* Registro MARKETING: solo home.php. Nell'app non entra — un'app la si guarda
       sempre alla stessa distanza, quindi scala fissa e niente clamp(). */
    --tb-t-marketing-hero: 800 clamp(2rem, 5vw, 3rem)/1.05 var(--tb-font);

    --tb-tr-tight:  -0.02em;   /* titoli */
    --tb-tr-figure: -0.035em;  /* il saldo */
    --tb-tr-micro:   0.06em;   /* occhielli maiuscoli */

    /* DEPRECATI: scala per taglia. Restano perche' 191 dichiarazioni nelle pagine
       ancora li usano; si migrano a --tb-t-* pagina per pagina. Non usarli nel
       codice nuovo. */
    --tb-fs-xs:  0.8125rem;  /* 13 */
    --tb-fs-sm:  0.875rem;   /* 14 */
    --tb-fs-md:  1rem;       /* 16 */
    --tb-fs-lg:  1.125rem;   /* 18 */
    --tb-fs-xl:  1.375rem;   /* 22 */
    --tb-fs-2xl: 1.75rem;    /* 28 */
    --tb-fs-3xl: 2.25rem;    /* 36 */
    --tb-fs-4xl: 3rem;       /* 48 */

    /* --- Z-INDEX: una scala semantica, non numeri scelti a mano. -----------
       Prima erano 60, 80, 100, 120, 999, 1200, 1300, 2000, 2100: ogni valore
       nato per vincere contro quello che aveva accanto. I nomi dicono l'ordine,
       e l'ordine e' quello vero della pagina, dal basso verso l'alto.
       I <dialog> aperti con showModal() NON servono qui: il browser li mette nel
       "top layer", sopra qualunque z-index. E' anche il motivo per cui li usiamo. */
    --tb-z-sub:        60;   /* sotto-navigazione appiccicata (dettaglio) */
    --tb-z-sticky:     80;   /* barra dei filtri (ricerca) */
    --tb-z-header:    100;   /* header del sito */
    --tb-z-dropdown:  200;   /* ospiti, autocomplete: sopra l'header che li contiene */
    --tb-z-datepicker:300;   /* flatpickr: sopra i dropdown, li sovrasta quando si apre */
    --tb-z-overlay:   400;   /* mappa a schermo pieno sul telefono */
    --tb-z-overlay-top:410;  /* il bottone per chiuderla */
    --tb-z-loader:    500;   /* velo di caricamento */
    /* toastr (vendor) sta a 999999 e non lo tocchiamo: un toast deve stare sopra
       tutto, quindi il numero assurdo per una volta e' anche quello giusto. */

    --tb-header-h: 68px;
    --tb-container: 1200px;
    --tb-touch: 44px;        /* area minima toccabile: vedi DESIGN.md, "Touch target" */
}

/* --- Base -------------------------------------------------------------
   Queste sei regole arrivano da global.css, che non esiste piu'. Erano l'unica
   parte viva di quel foglio: tutto il resto ridefiniva header, piede e barra di
   ricerca con la grafica precedente, e veniva riscritto qui sotto poche righe
   dopo. Un foglio caricato su ogni pagina per essere annullato su ogni pagina.

   Bootstrap ne copre una parte col suo reboot, ma non queste: `a` senza colore
   ne' sottolineatura (Bootstrap le vuole blu e sottolineate), e `img`/`svg` a
   blocco — senza, sotto ogni immagine resta la riga di base del testo, cioe'
   qualche pixel di aria che nessuno ha chiesto. */

*, *::before, *::after { box-sizing: border-box; }

html, body { margin: 0; padding: 0; }

body {
    font: var(--tb-t-body);
    color: var(--tb-ink);
    background: var(--tb-bg);
    -webkit-font-smoothing: antialiased;
    /* Nasconde le barre orizzontali che nascono da un elemento che sborda di
       poco. E' anche il motivo per cui i pannelli della barra di ricerca stanno
       nel top layer (`popover`): dentro il flusso, questo li ritaglierebbe. */
    overflow-x: hidden;
}

a { color: inherit; text-decoration: none; }

img, svg { max-width: 100%; display: block; }

main { position: relative; }

h1, h2, h3, h4 {
    color: var(--tb-ink);
    letter-spacing: var(--tb-tr-tight);
    text-wrap: balance;
    margin: 0 0 0.5em;
}

/* h1 = titolo di pagina d'APP, 28px. Prima era 48px/800, e ogni pagina privata lo
   disfaceva a mano (account.css lo commentava pure: "il titolo cede il palcoscenico
   al saldo"). Se ogni pagina deve annullare il default, il default e' sbagliato.
   L'unico h1 che vuole davvero essere grande e' l'hero della home: ha la sua classe. */
h1 { font: var(--tb-t-page-title); }
/* font-weight: 750 non esisteva. Il font viene chiesto a Google a pesi discreti
   (400;500;600;700;800): il browser ripiegava su 700 o lo sintetizzava. */
h2 { font: var(--tb-t-section); }
h3 { font: var(--tb-t-card-title); }
.tb-hero-title { font: var(--tb-t-marketing-hero); }

.tb-muted { color: var(--tb-ink-soft); }
.tb-container { max-width: var(--tb-container); margin: 0 auto; padding: 0 24px; }

:where(a, button, input, select, textarea):focus-visible {
    outline: 2px solid var(--tb-blue);
    outline-offset: 2px;
    border-radius: 4px;
}

/* Testo per i soli lettori di schermo.
   ATTENZIONE: e' position:absolute, quindi viene ritagliato solo dagli antenati
   che stanno fra lui e il suo blocco contenitore. Dentro un contenitore con
   overflow (una tabella che scorre) il contenitore deve avere position:relative,
   altrimenti questo 1px sfugge al ritaglio e allarga la pagina. */
.tb-sr-only {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}

/* --- Bottoni ---------------------------------------------------------- */

/* min-height, non padding: l'area toccabile cresce, il disegno no. Prima nessun
   bottone del prodotto arrivava a 44px — e i peggiori erano quelli che convertono
   (la CTA che sceglie la camera stava a ~34px). */
.tb-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    min-height: var(--tb-touch);
    font: var(--tb-t-button);
    padding: 11px 16px;
    border-radius: var(--tb-r-btn);
    border: 1px solid var(--tb-line);
    background: var(--tb-bg);
    color: var(--tb-ink);
    cursor: pointer;
    text-decoration: none;
    transition: background var(--tb-dur-fast) var(--tb-ease),
                border-color var(--tb-dur-fast) var(--tb-ease),
                color var(--tb-dur-fast) var(--tb-ease);
}
.tb-btn:hover  { background: var(--tb-panel); border-color: var(--tb-panel-2); }
.tb-btn:active { transform: translateY(1px); }

.tb-btn-primary         { background: var(--tb-blue);       border-color: var(--tb-blue);       color: #fff; }
.tb-btn-primary:hover   { background: var(--tb-blue-deep);  border-color: var(--tb-blue-deep);  color: #fff; }
.tb-btn-primary:active  { background: var(--tb-blue-press); border-color: var(--tb-blue-press); color: #fff; }

.tb-btn-ink        { background: var(--tb-ink-fill);       border-color: var(--tb-ink-fill);       color: #fff; }
.tb-btn-ink:hover  { background: var(--tb-ink-fill-hover); border-color: var(--tb-ink-fill-hover); color: #fff; }

.tb-btn-ghost       { background: transparent; border-color: transparent; color: var(--tb-ink); }
.tb-btn-ghost:hover { background: var(--tb-panel); }

/* Piu' piccolo di disegno, non di bersaglio: font e padding calano, i 44px restano. */
.tb-btn-sm { padding: 8px 12px; font: var(--tb-t-caption); font-weight: 600; }

/* Lo stato disabilitato era `opacity: .55`, che su un bottone blu produce un azzurro
   slavato dal contrasto IMPREVEDIBILE. In un sistema dove i rapporti li calcoliamo
   col righello, uno stato si nomina e si colora — non si sbiadisce.
   Superficie panel-2 con testo ink-soft: 5.00:1, deterministico. */
.tb-btn[disabled],
.tb-btn[aria-disabled="true"] {
    background: var(--tb-panel-2);
    border-color: var(--tb-panel-2);
    color: var(--tb-ink-soft);
    cursor: not-allowed;
    transform: none;
}

/* --- Chip / tag ------------------------------------------------------- */

.tb-chip {
    display: inline-flex; align-items: center; gap: 6px;
    font-size: var(--tb-fs-xs); font-weight: 500;
    color: var(--tb-ink-soft);
    background: var(--tb-bg);
    border: 1px solid var(--tb-line);
    border-radius: var(--tb-r-pill);
    padding: 6px 11px;
    white-space: nowrap;
}
.tb-chip-on { color: #fff; background: var(--tb-ink-fill); border-color: var(--tb-ink-fill); font-weight: 600; }
.tb-chip-locked { color: var(--tb-ink-soft); background: var(--tb-panel); cursor: pointer; }

.tb-tag {
    display: inline-flex; align-items: center; gap: 5px;
    font-size: var(--tb-fs-xs); color: var(--tb-ink-soft);
    background: var(--tb-panel); border-radius: 7px; padding: 4px 9px;
}

/* --- Card ------------------------------------------------------------- */

/* Piatta. A separarla dalla pagina e' il filetto, non un'ombrellina.
   (Era definita e non la usava nessuno: sette card riscritte a mano nelle pagine.) */
.tb-card {
    background: var(--tb-bg);
    border: 1px solid var(--tb-line);
    border-radius: var(--tb-r-card);
}

/* --- Campo di testo ----------------------------------------------------
   Ne esistevano QUATTRO (.auth-input, .checkout-input, .po-input, .summary-field)
   con quattro altezze diverse (49/44/41/42px) e TRE stili di focus. Uno solo.

   Il focus e' `:focus-visible` con outline, e basta: niente ring a box-shadow.
   .auth-input usava `:focus` (quindi si accendeva anche col mouse) e ci metteva
   sopra un ring che si SOMMAVA all'outline globale — doppio anello, su una pagina
   sola. E `font: inherit` (non `font-family: inherit`): senza l'interlinea il
   campo si accorcia, ed era la causa dei 41px di .po-input. */
.tb-input {
    display: block;
    width: 100%;
    box-sizing: border-box;
    /* Obbligatorio. Dentro una griglia (i campi data del riepilogo) un elemento ha
       min-width: auto, cioe' non scende sotto il proprio contenuto minimo — e un
       <input type="date"> a 16px e' largo. A 320px sfondava il viewport, e siccome
       body ha overflow-x: hidden non si sarebbe visto: si perdeva in silenzio. */
    min-width: 0;
    min-height: var(--tb-touch);
    padding: 11px 13px;
    font: var(--tb-t-body);
    /* Obbligatori: text-transform e letter-spacing si EREDITANO, e lo shorthand
       `font:` non li tocca. Dentro un'etichetta maiuscola (checkout) il campo
       scriverebbe in maiuscolo mentre l'utente digita. */
    text-transform: none;
    letter-spacing: normal;
    color: var(--tb-ink);
    background: var(--tb-bg);
    border: 1px solid var(--tb-line);
    border-radius: var(--tb-r-btn);
    transition: border-color var(--tb-dur-fast) var(--tb-ease);
}
.tb-input::placeholder     { color: var(--tb-ink-soft); }
.tb-input:hover            { border-color: var(--tb-ink-soft); }
.tb-input:focus-visible    { border-color: var(--tb-blue); }
.tb-input[aria-invalid="true"] { border-color: var(--tb-danger); }
.tb-input[disabled]        { background: var(--tb-panel); color: var(--tb-ink-soft); cursor: not-allowed; }

/* ============================================================================
   SELECT2 — la pelle.

   Ogni <select> del sito ci passa (app.js, initSelect2). Il motivo e' che un menu
   a tendina disegnato dal sistema operativo e' l'unico pezzo d'interfaccia che non
   sa niente del nostro tema: sul tema scuro resta bianco, e su Windows e Android
   non somiglia a nient'altro nella pagina.

   NESSUN COLORE SCRITTO A MANO qui sotto. Select2 arriva con la sua tavolozza
   (bianco, `#aaa`, il blu `#5897fb` della voce evidenziata): se anche uno solo di
   quelli restasse, il tema scuro lo scoprirebbe subito. Tutto passa dai token,
   quindi la tendina segue la modalita' senza che nessuno se ne ricordi.

   Il foglio di Select2 e' caricato PRIMA (vedi _head.php): a parita' di
   specificita' vince chi arriva dopo, e queste regole ripetono il suo stesso
   prefisso `--default` proprio per pareggiare la specificita' invece di alzarla
   con degli !important.

   La tendina la monta Select2 in fondo a <body>, fuori da main: la classe del
   tema sta su <body>, quindi i token li vede lo stesso.
   ---------------------------------------------------------------------------- */

/* Il controllo chiuso: e' un .tb-input, e deve sembrarlo. */
.select2-container--default .select2-selection--single {
    box-sizing: border-box;
    height: auto;
    min-height: var(--tb-touch);
    display: flex;
    align-items: center;
    padding: 0 38px 0 13px;
    background: var(--tb-bg);
    border: 1px solid var(--tb-line);
    border-radius: var(--tb-r-btn);
    cursor: pointer;
    transition: border-color var(--tb-dur-fast) var(--tb-ease);
}
.select2-container--default .select2-selection--single:hover { border-color: var(--tb-ink-soft); }
.select2-container--default .select2-selection--single .select2-selection__rendered {
    padding: 0;
    line-height: 1.35;
    color: var(--tb-ink);
    font: var(--tb-t-body);
    text-transform: none;   /* stessa ragione di .tb-input: si eredita */
    letter-spacing: normal;
}
.select2-container--default .select2-selection--single .select2-selection__placeholder { color: var(--tb-ink-soft); }

/* La freccia. Quella di Select2 e' un triangolo fatto con i bordi, quindi il suo
   colore va scritto a mano quattro volte (chiuso, aperto, e i due temi). Qui e'
   un chevron di `currentColor`: un colore solo, e segue il tema da se'. */
.select2-container--default .select2-selection--single .select2-selection__arrow {
    position: absolute;
    top: 0; right: 12px;
    height: 100%; width: 12px;
    display: flex; align-items: center; justify-content: center;
    color: var(--tb-ink-soft);
}
.select2-container--default .select2-selection--single .select2-selection__arrow b { display: none; }
.select2-container--default .select2-selection--single .select2-selection__arrow::after {
    content: "";
    width: 8px; height: 8px;
    margin-top: -4px;
    border-right: 2px solid currentColor;
    border-bottom: 2px solid currentColor;
    border-radius: 1px;
    transform: rotate(45deg);
    transition: transform var(--tb-dur-fast) var(--tb-ease);
}
.select2-container--open.select2-container--default .select2-selection--single .select2-selection__arrow::after {
    margin-top: 4px;
    transform: rotate(-135deg);
}
.select2-container--open.select2-container--default .select2-selection--single { border-color: var(--tb-blue); }

/* Il focus da tastiera. Select2 sposta il fuoco su un elemento suo, quindi il
   :focus-visible di sistema non lo raggiunge: lo stesso anello, disegnato qui. */
.select2-container--default .select2-selection--single:focus,
.select2-container--default.select2-container--focus .select2-selection--single {
    outline: 2px solid var(--tb-blue);
    outline-offset: 2px;
}

/* La tendina. E' un pannello che GALLEGGIA, come gli altri del sito: staccata dal
   controllo e con il bordo tutto intorno, non incollata sotto con un lato in meno. */
.select2-container--default .select2-dropdown {
    background: var(--tb-bg);
    border: 1px solid var(--tb-line);
    border-radius: var(--tb-r-card);
    box-shadow: var(--tb-shadow);
    overflow: hidden;
}
.select2-container--default .select2-dropdown--below { margin-top: 6px; }
.select2-container--default .select2-dropdown--above  { margin-top: -6px; }

.select2-container--default .select2-results > .select2-results__options {
    padding: 6px;
    max-height: 280px;
    overscroll-behavior: contain;   /* la ruota non deve scorrere la pagina sotto */
}
.select2-container--default .select2-results__option {
    padding: 10px 12px;
    min-height: var(--tb-touch);
    display: flex;
    align-items: center;
    border-radius: var(--tb-r-btn);
    color: var(--tb-ink);
    font: var(--tb-t-body);
    text-transform: none;
    letter-spacing: normal;
}
.select2-container--default .select2-results__option--highlighted[aria-selected],
.select2-container--default .select2-results__option--highlighted {
    background: var(--tb-panel);
    color: var(--tb-ink);
}
/* La voce GIA' scelta. Non e' "quella su cui sei col dito": quella e' la riga
   sopra. Due stati diversi, due segni diversi — se no, aprendo la tendina non si
   sa piu' qual era la scelta di prima. */
.select2-container--default .select2-results__option[aria-selected="true"],
.select2-container--default .select2-results__option--selected {
    background: var(--tb-blue-soft);
    color: var(--tb-blue-ink);
    font-weight: 600;
}
.select2-container--default .select2-results__option[aria-disabled="true"] { color: var(--tb-ink-soft); }
.select2-container--default .select2-results__message { color: var(--tb-ink-soft); padding: 10px 12px; }

/* Il campo di ricerca, che compare solo sulle liste lunghe (app.js). */
.select2-container--default .select2-search--dropdown { padding: 8px 8px 2px; }
.select2-container--default .select2-search--dropdown .select2-search__field {
    box-sizing: border-box;
    padding: 9px 11px;
    color: var(--tb-ink);
    background: var(--tb-panel);
    border: 1px solid var(--tb-line);
    border-radius: var(--tb-r-btn);
    font: var(--tb-t-body);
}
.select2-container--default .select2-search--dropdown .select2-search__field:focus-visible {
    outline: 2px solid var(--tb-blue);
    outline-offset: 1px;
}

/* La barra dei filtri della ricerca e' alta 44px e stretta: li' il select sta in
   riga con le pillole e non prende tutta la larghezza. */
/* Misurata, non tirata a indovinare: a 190px "Cashback: dal piu' alto" andava a
   capo e la voce diventava alta 70px in mezzo a due da 44. Lo spazio a sinistra
   nella barra c'e' (l'etichetta "Ordina per" galleggia in 230px vuoti). */
.sr-sort .select2-container { width: auto !important; min-width: 232px; }
.sr-sort .select2-container--default .select2-selection--single {
    background: var(--tb-bg);
    font-weight: 600;
    font-size: var(--tb-fs-sm);
}

.tb-label { display: block; margin-bottom: 6px; font: var(--tb-t-label); color: var(--tb-ink); }
/* Il messaggio d'errore e' TESTO, non solo un bordo rosso: il colore da solo non
   e' informazione (PRODUCT.md, accessibilita'). */
.tb-field-error {
    display: none; margin-top: 6px;
    font: var(--tb-t-caption); color: var(--tb-danger-ink);
}
.tb-field-error.is-on { display: flex; align-items: center; gap: 6px; }
.tb-field-error svg { width: 14px; height: 14px; flex: none; }

/* --- STATI ------------------------------------------------------------------
   Il movimento racconta uno stato (PRODUCT.md, principio 5). Quindi prima gli
   stati esistono, poi si animano. Queste sono le primitive che mancavano: senza
   di loro, ogni animazione sarebbe decorazione.
   ---------------------------------------------------------------------------- */

/* --- Bottone occupato --------------------------------------------------
   Prima l'attesa si comunicava scambiando l'etichetta ("Attendere…"), che sposta
   il testo e non dice che qualcosa sta girando. Qui l'etichetta resta al suo
   posto e scompare, e al suo posto gira un anello: il bottone non cambia
   larghezza, quindi la pagina non salta.
   aria-busy e aria-live li mette il JS: senza, chi usa uno screen reader non
   sente nulla. */
.tb-btn.is-busy {
    position: relative;
    cursor: progress;
    pointer-events: none;
    /* Obbligatorio, e non e' ridondante con la riga sotto: l'etichetta di un bottone
       e' quasi sempre un NODO DI TESTO nudo, e visibility su ':> *' tocca solo i figli
       ELEMENTO. Senza color:transparent il testo resta visibile e si sovrappone
       all'anello che gira. */
    color: transparent;
}
.tb-btn.is-busy > * { visibility: hidden; }   /* <svg>, <span>: figli elemento */

/* OCCUPATO NON E' DISABILITATO. Sono due stati diversi e vanno letti diversi:
   "sta lavorando" e "e' morto". Ma SM.ui.busy() mette disabled sul bottone — e
   deve farlo, o un doppio invio parte col tasto Invio — e la regola del
   disabilitato gli rubava la superficie: il bottone blu diventava grigio, e
   l'utente leggeva "non funziona" invece di "la mia richiesta e' partita".
   Stessa specificita' di .tb-btn[disabled] (0,2,0), ma dichiarato dopo: vince
   l'ordine, ed e' l'unica ragione per cui questo blocco sta QUI e non piu' su. */
.tb-btn.is-busy                    { background: var(--tb-bg);   border-color: var(--tb-line); }
.tb-btn-primary.is-busy            { background: var(--tb-blue); border-color: var(--tb-blue); }
.tb-btn-ink.is-busy                { background: var(--tb-ink-fill);  border-color: var(--tb-ink-fill); }
.tb-slab .tb-btn-primary.is-busy   { background: var(--tb-emerald-bright); border-color: var(--tb-emerald-bright); }
.tb-dialog .tb-btn-danger.is-busy  { background: var(--tb-danger); border-color: var(--tb-danger); }

.tb-btn.is-busy::after {
    content: '';
    position: absolute; inset: 0; margin: auto;
    width: 17px; height: 17px;
    /* Il colore NON puo' essere currentColor: l'abbiamo appena reso trasparente per
       nascondere l'etichetta, e l'anello sparirebbe insieme a lei. Va detto a mano,
       una volta per variante. */
    border: 2px solid var(--tb-ink);
    border-right-color: transparent;   /* l'arco mancante e' cio' che rende visibile la rotazione */
    border-radius: 50%;
    animation: tb-spin 620ms linear infinite;
}
.tb-btn-primary.is-busy::after,
.tb-btn-ink.is-busy::after { border-color: #fff; border-right-color: transparent; }
/* Sul navy dello slab il bottone primario e' emerald con testo navy: l'anello segue. */
.tb-slab .tb-btn-primary.is-busy::after { border-color: var(--tb-ink); border-right-color: transparent; }
@keyframes tb-spin { to { transform: rotate(360deg); } }

/* TRAPPOLA: la regola globale in fondo a questo foglio spegne ogni animation con
   !important. Senza questo blocco, chi ha il movimento ridotto vedrebbe l'anello
   fermo E l'etichetta nascosta: un bottone VUOTO. Qui l'attesa torna a dirsi con
   la superficie inerte e l'etichetta al suo posto; aria-busy fa il resto per chi
   usa uno screen reader. */
@media (prefers-reduced-motion: reduce) {
    .tb-btn.is-busy > *      { visibility: visible; }
    .tb-btn.is-busy::after   { content: none; }
    .tb-btn.is-busy          { background: var(--tb-panel-2); border-color: var(--tb-panel-2); color: var(--tb-ink-soft) !important; }
}

/* --- Skeleton ----------------------------------------------------------
   La regola: skeleton al posto degli spinner in mezzo al contenuto. Uno skeleton
   dice DOVE arrivera' la roba, uno spinner dice solo "aspetta".
   Vale solo se copre un'attesa VERA: quello del dettaglio era un setTimeout(360)
   su HTML gia' completo, cioe' una bugia con l'aria di una cortesia. */
.tb-skeleton {
    position: relative;
    overflow: hidden;
    background: var(--tb-panel-2);
    border-radius: var(--tb-r-btn);
    /* Un blocco vuoto non ha altezza: senza questo lo skeleton non si vede. */
    min-height: 1em;
}
.tb-skeleton::after {
    content: '';
    position: absolute; inset: 0;
    transform: translateX(-100%);
    background: linear-gradient(90deg, transparent, rgb(255 255 255 / 65%), transparent);
    animation: tb-shimmer 1.4s var(--tb-ease) infinite;
}
@keyframes tb-shimmer { to { transform: translateX(100%); } }
.tb-skeleton-text { height: 0.8em; margin: 0.28em 0; border-radius: 4px; }
.tb-skeleton-text.is-short { width: 45%; }
.tb-skeleton-text.is-mid   { width: 70%; }

/* --- Stato vuoto -------------------------------------------------------
   Uno stato vuoto insegna l'interfaccia, non annuncia il vuoto: dice cosa manca,
   perche', e da dove si comincia. Prima ce n'erano sette, tutti diversi. */
.tb-empty {
    display: grid;
    justify-items: center;
    gap: 6px;
    padding: 44px 24px;
    text-align: center;
    background: var(--tb-bg);
    border: 1px solid var(--tb-line);
    border-radius: var(--tb-r-card);
}
.tb-empty-icon {
    width: 40px; height: 40px; margin-bottom: 6px;
    display: grid; place-items: center;
    color: var(--tb-ink-soft);
    background: var(--tb-panel);
    border-radius: var(--tb-r-btn);
}
.tb-empty-icon svg { width: 20px; height: 20px; }
.tb-empty h2, .tb-empty h3 { margin: 0; font: var(--tb-t-card-title); color: var(--tb-ink); }
.tb-empty p { margin: 0; max-width: 46ch; font: var(--tb-t-meta); color: var(--tb-ink-soft); text-wrap: pretty; }
.tb-empty .tb-btn { margin-top: 12px; }
/* Variante compatta: dentro una sezione che ha gia' il suo titolo. */
.tb-empty-sm { padding: 28px 24px; }
.tb-empty-sm p { font: var(--tb-t-meta); }

/* --- Avvisi ------------------------------------------------------------
   Ce n'erano sette implementazioni. Il colore non e' mai l'unica informazione:
   c'e' sempre un'icona e c'e' sempre il testo. */
.tb-alert {
    display: flex; align-items: flex-start; gap: 11px;
    padding: 13px 15px;
    border: 1px solid transparent;
    border-radius: var(--tb-r-btn);
    font: var(--tb-t-meta);
}
.tb-alert svg { width: 18px; height: 18px; flex: none; margin-top: 1px; }
.tb-alert strong { display: block; font: var(--tb-t-body-strong); font-size: var(--tb-fs-sm); }
.tb-alert p { margin: 2px 0 0; text-wrap: pretty; }

.tb-alert-info { background: var(--tb-blue-soft);    border-color: color-mix(in srgb, var(--tb-blue) 20%, transparent); color: var(--tb-ink); }
.tb-alert-info svg { color: var(--tb-blue-ink); }
.tb-alert-ok   { background: var(--tb-emerald-soft); border-color: color-mix(in srgb, var(--tb-emerald) 22%, transparent); color: var(--tb-emerald-ink); }
.tb-alert-warn { background: var(--tb-amber-soft);   border-color: color-mix(in srgb, var(--tb-amber-ink) 22%, transparent); color: var(--tb-amber-ink); }
.tb-alert-err  { background: var(--tb-danger-soft);  border-color: color-mix(in srgb, var(--tb-danger) 24%, transparent);   color: var(--tb-danger-ink); }

/* --- Badge di stato ----------------------------------------------------
   Era copiato byte per byte fra account.css e payout.css. */
.tb-badge {
    display: inline-flex; align-items: center; gap: 5px;
    padding: 3px 10px;
    border-radius: var(--tb-r-pill);
    font: var(--tb-t-badge);
    white-space: nowrap;
}
.tb-badge-ok      { background: var(--tb-emerald-soft); color: var(--tb-emerald-ink); }
.tb-badge-pending { background: var(--tb-amber-soft);   color: var(--tb-amber-ink); }
.tb-badge-fail    { background: var(--tb-danger-soft);  color: var(--tb-danger-ink); }
.tb-badge-muted   { background: var(--tb-panel-2);      color: var(--tb-ink-soft); }

/* --- Dialogo di conferma -----------------------------------------------
   Sostituisce window.confirm(), che non si puo' tradurre, non si puo' stilare e
   dice "localhost dice:" davanti a una domanda sui soldi di qualcuno.
   <dialog> + showModal(): il browser lo mette nel top layer (nessuno z-index),
   intrappola il focus e chiude con Escape senza che dobbiamo scrivere nulla. */
.tb-dialog {
    width: min(440px, calc(100vw - 32px));
    padding: 0;
    border: 1px solid var(--tb-line);
    border-radius: var(--tb-r-card);
    background: var(--tb-bg);
    color: var(--tb-ink);
    box-shadow: var(--tb-shadow);
}
.tb-dialog::backdrop { background: var(--tb-scrim); }
.tb-dialog-body { padding: 22px 22px 0; }
.tb-dialog h2 { margin: 0 0 8px; font: var(--tb-t-card-title); }
.tb-dialog p  { margin: 0; font: var(--tb-t-meta); color: var(--tb-ink-soft); text-wrap: pretty; }
.tb-dialog-foot {
    display: flex; justify-content: flex-end; gap: 8px;
    padding: 20px 22px 22px;
}
.tb-dialog .tb-btn-danger {
    background: var(--tb-danger); border-color: var(--tb-danger); color: #fff;
}
.tb-dialog .tb-btn-danger:hover { background: #A4271B; border-color: #A4271B; color: #fff; }

@media (prefers-reduced-motion: no-preference) {
    .tb-dialog[open]            { animation: tb-dialog-in 220ms var(--tb-ease); }
    .tb-dialog[open]::backdrop  { animation: tb-fade-in 220ms var(--tb-ease); }
}
@keyframes tb-dialog-in { from { opacity: 0; transform: translateY(8px) scale(0.98); } }
@keyframes tb-fade-in   { from { opacity: 0; } }

/* --- Slab: la superficie scura dell'area privata -----------------------
   Il saldo non e' una statistica in un riquadro fra tanti: e' un oggetto, e
   sta su una superficie sua. Riusa il navy dell'hero della home, cosi' un
   utente che scende dalla home ritrova la stessa materia.
   Su questa superficie valgono --tb-emerald-bright / --tb-danger-bright:
   le varianti da fondo chiaro non arrivano a 4.5:1 sul navy. */

.tb-slab {
    position: relative;              /* obbligatorio: ritaglia il glow e gli abspos figli */
    isolation: isolate;
    overflow: hidden;
    background: var(--tb-ink-fill);
    color: #fff;
    border-radius: var(--tb-r-slab);
    padding: 26px 28px;
    box-shadow: var(--tb-shadow);
}

/* Un alone dell'emerald del cashback, non un gradiente decorativo: dice
   "qui dentro c'e' il tuo denaro" e si ferma al 14% di opacita'.
   Il colore si prende dal TOKEN. Prima era #31D992 scritto a mano, e quando il
   verde e' cambiato l'alone e' rimasto indietro: un colore copiato e' un colore
   che prima o poi non e' piu' quello. */
.tb-slab::before {
    content: '';
    position: absolute;
    inset: -60% 30% 20% -25%;
    background: radial-gradient(closest-side, color-mix(in srgb, var(--tb-emerald-bright) 14%, transparent), transparent 78%);
    pointer-events: none;
    z-index: -1;
}

.tb-slab-label {
    font-size: var(--tb-fs-xs);
    font-weight: 600;
    color: var(--tb-on-dark);
}
.tb-slab-head {
    display: flex; align-items: center; justify-content: space-between;
    gap: 12px; margin-bottom: 18px;
}
.tb-slab-chip {
    width: 34px; height: 34px; flex: none;
    display: grid; place-items: center;
    border-radius: 9px;
    background: rgb(255 255 255 / 8%);
}
.tb-slab-chip svg { width: 18px; height: 18px; flex: none; color: var(--tb-emerald-bright); }

/* Le valute non si sommano: si affiancano, divise da un filetto. */
.tb-slab-figures { display: flex; flex-wrap: wrap; gap: 0 34px; }
.tb-slab-figure { min-width: 0; padding-right: 34px; }
.tb-slab-figure + .tb-slab-figure {
    padding-left: 34px; padding-right: 0;
    border-left: 1px solid var(--tb-on-dark-line);
}
.tb-slab-cur {
    display: block; margin-bottom: 2px;
    font-size: var(--tb-fs-xs); font-weight: 700; letter-spacing: 0.06em;
    color: var(--tb-on-dark);
}
/* Il momento eroe della pagina. 56px contro i 28px del titolo: e' il saldo a
   comandare, non l'intestazione. Scala fissa (non clamp): in un'app si guarda
   sempre alla stessa distanza. */
.tb-slab-amount {
    display: block;
    font-size: 3.5rem; line-height: 1; font-weight: 800;
    letter-spacing: -0.035em;
    color: var(--tb-emerald-bright);
    font-variant-numeric: tabular-nums;
    overflow-wrap: anywhere;
}
.tb-slab-amount.is-negative { color: var(--tb-danger-bright); }
.tb-slab-amount.is-zero     { color: #fff; }
/* Il sottotitolo racconta il denaro che NON e' ancora prelevabile, una tappa per
   riga. Il grassetto e' BIANCO, non emerald: l'emerald dice "questo denaro e'
   tuo", e in maturazione o in arrivo non lo e' ancora. */
.tb-slab-sub {
    display: block; margin-top: 10px;
    font-size: var(--tb-fs-sm); line-height: 1.5; color: var(--tb-on-dark);
}
.tb-slab-sub b { color: #fff; font-weight: 700; font-variant-numeric: tabular-nums; }

.tb-slab-foot {
    display: flex; align-items: center; justify-content: space-between;
    flex-wrap: wrap; gap: 14px;
    margin-top: 24px; padding-top: 18px;
    border-top: 1px solid var(--tb-on-dark-line);
}
.tb-slab-note { margin: 14px 0 0; font-size: var(--tb-fs-xs); color: var(--tb-on-dark); max-width: 62ch; }

/* Saldo sotto zero: si spiega dentro lo slab, non in un riquadro rosso a parte.
   Il rosso da fondo chiaro (--tb-danger) sul navy sta a 3.18:1: qui serve la
   variante luminosa, e il corpo del testo va ancora piu' chiaro. */
.tb-slab-alert {
    display: flex; gap: 12px; align-items: flex-start;
    background: rgb(255 142 128 / 10%);
    border: 1px solid rgb(255 142 128 / 30%);
    border-radius: var(--tb-r-card);
    padding: 14px 16px; margin-bottom: 22px;
}
.tb-slab-alert svg { width: 20px; height: 20px; flex: none; color: var(--tb-danger-bright); margin-top: 2px; }
.tb-slab-alert strong { display: block; font-size: var(--tb-fs-sm); color: var(--tb-danger-bright); }
.tb-slab-alert p { margin: 4px 0 0; font-size: var(--tb-fs-sm); color: #FFE3DE; text-wrap: pretty; }

/* Bottone primario sul navy: la superficie blu del brand stacca dal navy solo
   3.14:1, appena sopra la soglia delle superfici UI, e l'azione si perde nel
   fondo. Sul buio l'azione diventa emerald (9.45:1) con il testo in navy: e' il
   colore del cashback, e questo bottone serve a prendersi il cashback. */
.tb-slab .tb-btn-primary {
    background: var(--tb-emerald-bright); border-color: var(--tb-emerald-bright);
    color: var(--tb-ink); font-weight: 700;
}
.tb-slab .tb-btn-primary:hover { background: #58E4A9; border-color: #58E4A9; }
.tb-slab .tb-btn-primary:active { transform: translateY(1px); }
.tb-slab :where(a, button):focus-visible { outline-color: #fff; }

/* Entrata: un solo movimento, sull'unico elemento che lo merita. Il testo e'
   visibile per default; l'animazione lo accompagna, non lo rivela.
   prefers-reduced-motion la spegne (regola globale in fondo al foglio). */
@keyframes tb-slab-in {
    from { opacity: 0; transform: translateY(10px); }
    to   { opacity: 1; transform: none; }
}
.tb-slab-amount { animation: tb-slab-in 480ms var(--tb-ease) both; }

@media (max-width: 620px) {
    .tb-slab { padding: 22px 20px; }
    .tb-slab-amount { font-size: 2.5rem; letter-spacing: -0.03em; }
    .tb-slab-figures { gap: 0; display: block; }
    .tb-slab-figure { padding: 0; }
    .tb-slab-figure + .tb-slab-figure {
        padding: 16px 0 0; margin-top: 16px;
        border-left: 0; border-top: 1px solid var(--tb-on-dark-line);
    }
}

/* --- Striscia di cifre: quattro numeri, un contenitore, filetti veri -----
   Sostituisce la griglia di riquadri identici. Il gap di 1px sopra lo sfondo
   della linea disegna i divisori: restano perfetti anche quando la griglia
   va a capo, cosa che un border-left non fa. */

.tb-figures {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(170px, 100%), 1fr));
    gap: 1px;
    background: var(--tb-line);
    border: 1px solid var(--tb-line);
    border-radius: var(--tb-r-card);
    overflow: hidden;
}
.tb-figure {
    min-width: 0;
    background: var(--tb-bg);
    padding: 16px 18px;
}
.tb-figure-label { display: block; font-size: var(--tb-fs-xs); font-weight: 600; color: var(--tb-ink-soft); }
.tb-figure-value {
    display: block; margin-top: 2px;
    font-size: var(--tb-fs-xl); font-weight: 800; line-height: 1.2;
    color: var(--tb-ink);
    font-variant-numeric: tabular-nums;
    overflow-wrap: anywhere;
}
.tb-figure-note { display: block; margin-top: 4px; font-size: var(--tb-fs-xs); color: var(--tb-ink-soft); }
.tb-figure-cash .tb-figure-value,
.tb-figure-cash .tb-figure-note { color: var(--tb-emerald-ink); }

/* Sul telefono `auto-fit` con una traccia minima da 170px cade a UNA colonna:
   dentro il contenitore restano 342px, due tracce da 170 piu' il filetto ne
   vogliono 341, e basta il padding della pagina a far saltare il conto. Il
   risultato erano tre numeri da due cifre incolonnati uno sotto l'altro, alti
   una schermata e mezza: la "striscia" non era piu' una striscia.

   Qui le colonne si dichiarano, invece di sperare che ci stiano. Se le cifre
   sono in numero dispari l'ultima prende tutta la riga: meglio una cella larga
   che una mezza cella vuota accanto. */
@media (max-width: 640px) {
    .tb-figures { grid-template-columns: 1fr 1fr; }
    .tb-figures > .tb-figure:last-child:nth-child(odd) { grid-column: 1 / -1; }
    .tb-figure { padding: 12px 14px; }
    .tb-figure-value { font-size: var(--tb-fs-lg); }
}

/* --- Righe: un contenitore, filetti fra le voci ------------------------
   Non quattro card identiche impilate. Una lista e' una lista. */

.tb-rows {
    list-style: none; margin: 0; padding: 0;
    background: var(--tb-bg);
    border: 1px solid var(--tb-line);
    border-radius: var(--tb-r-card);
    overflow: hidden;
}
.tb-row {
    display: flex; align-items: center; justify-content: space-between;
    gap: 20px; padding: 18px 20px;
    transition: background var(--tb-dur-fast) var(--tb-ease);
}
.tb-row + .tb-row { border-top: 1px solid var(--tb-line); }
.tb-row:hover { background: var(--tb-panel); }

/* --- Rating ----------------------------------------------------------- */

.tb-rating {
    display: inline-flex; align-items: center; justify-content: center;
    min-width: 38px; height: 28px; padding: 0 8px;
    background: var(--tb-ink-fill); color: #fff;
    border-radius: 8px; font-weight: 700; font-size: var(--tb-fs-sm);
    font-variant-numeric: tabular-nums;
}

/* --- Cashback --------------------------------------------------------- */

.tb-cashback {
    display: inline-flex; align-items: center; gap: 6px;
    font-size: var(--tb-fs-xs); font-weight: 700;
    color: var(--tb-emerald-ink);
    background: var(--tb-emerald-soft);
    border-radius: var(--tb-r-pill);
    padding: 5px 10px;
    font-variant-numeric: tabular-nums;
}
/* emerald-ink, non emerald: bianco su --tb-emerald sta a 3.42:1, sotto la
   soglia 4.5:1 richiesta per il testo piccolo. Su emerald-ink sale a 5.07:1. */
.tb-cashback-solid { background: var(--tb-emerald-fill); color: var(--tb-emerald-fill-ink); }

/* --- Prezzo -----------------------------------------------------------
   .tb-price          prezzo visibile (utente loggato)
   .tb-price-locked   segnaposto per utenti anonimi: il numero NON è mai
                      il prezzo reale, è un placeholder inerte (il prezzo
                      non viene proprio inviato al browser).
   ---------------------------------------------------------------------- */

.tb-price { font-size: var(--tb-fs-xl); font-weight: 800; letter-spacing: -0.01em; font-variant-numeric: tabular-nums; }
.tb-price small { font-size: var(--tb-fs-xs); font-weight: 500; color: var(--tb-ink-soft); }

.tb-price-locked { display: flex; flex-direction: column; gap: 6px; align-items: flex-start; }
.tb-price-locked .tb-price-blur {
    display: inline-flex; align-items: center; gap: 8px;
    font-size: var(--tb-fs-xl); font-weight: 800; color: var(--tb-ink);
    user-select: none;
}
.tb-price-locked .tb-price-blur .tb-blur {
    filter: blur(5px);
    letter-spacing: 0.02em;
    opacity: .55;
}
.tb-price-locked .tb-lock { color: var(--tb-ink-soft); flex: none; }
/* Area toccabile a norma (44px): cresce la scatola, non il carattere.
   Stava a ~20px ed e' il link che porta alla registrazione dalla card di
   ricerca — cioe' il gesto che trasforma un anonimo in un iscritto, fatto
   col pollice da chi sta in piedi in stazione. */
.tb-price-locked .tb-price-cta {
    font-size: var(--tb-fs-xs); font-weight: 600; color: var(--tb-blue-ink); text-decoration: none;
    display: inline-flex; align-items: center;
    min-height: var(--tb-touch);
}
.tb-price-locked .tb-price-cta:hover { text-decoration: underline; }

/* Banner "tariffe riservate" in cima ai risultati */
.tb-gate-banner {
    display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
    background: var(--tb-panel);
    border: 1px solid var(--tb-line);
    border-radius: var(--tb-r-card);
    padding: 14px 18px;
}
.tb-gate-banner .tb-gate-text { flex: 1 1 320px; }
.tb-gate-banner strong { display: block; font-size: var(--tb-fs-sm); }
.tb-gate-banner p { margin: 2px 0 0; font-size: var(--tb-fs-xs); color: var(--tb-ink-soft); }
.tb-gate-banner .tb-gate-actions { display: flex; gap: 8px; }

/* --- Header ----------------------------------------------------------- */

.tb-header {
    position: sticky; top: 0; z-index: 100;
    background: color-mix(in srgb, var(--tb-bg) 88%, transparent);
    -webkit-backdrop-filter: saturate(1.3) blur(10px);
    backdrop-filter: saturate(1.3) blur(10px);
    border-bottom: 1px solid var(--tb-line);
}
.tb-header-inner {
    max-width: var(--tb-container);
    margin: 0 auto; padding: 0 24px;
    min-height: var(--tb-header-h);
    display: flex; align-items: center; gap: 16px;
}

/* line-height e white-space arrivano da global.css. Non erano ridondanti: qui
   non erano dichiarati, quindi il marchio prendeva l'interlinea del corpo (1.55)
   e cresceva di due pixel, spingendo in giu' tutta la pagina. Un logo e' una
   riga sola per definizione: 1.06 e nessun a capo. */
.tb-logo { display: inline-flex; align-items: center; gap: 9px; font-weight: 800; font-size: var(--tb-fs-lg);
    line-height: 1.06; white-space: nowrap;
    letter-spacing: -0.02em; color: var(--tb-ink); text-decoration: none; flex: none; }
.tb-logo-mark { width: 26px; height: 26px; border-radius: 8px; background: var(--tb-blue); color: #fff;
    display: grid; place-items: center; font-size: 14px; font-weight: 800; }
.tb-logo-trips { color: var(--tb-ink); }
.tb-logo-back  { color: var(--tb-blue-ink); }

.tb-nav { display: flex; align-items: center; gap: 4px; margin-left: 10px; }
/* Le pagine con barra di ricerca in testata cedono la navigazione alla barra:
   i link restano nel footer. Senza questo la barra scende a 439px e tronca. */
.tb-header-with-search .tb-nav { display: none; }
.tb-nav a { font-size: var(--tb-fs-sm); font-weight: 500; color: var(--tb-ink-soft);
    text-decoration: none; padding: 8px 11px; border-radius: 8px; }
.tb-nav a:hover { color: var(--tb-ink); background: var(--tb-panel); }
.tb-nav a[aria-current="page"] { color: var(--tb-ink); font-weight: 600; }

.tb-header-spacer { flex: 1; }
.tb-header-actions { display: flex; align-items: center; gap: 8px; }
.tb-mini-link { font-size: var(--tb-fs-sm); font-weight: 500; color: var(--tb-ink-soft); text-decoration: none; padding: 8px 10px; border-radius: 8px; }
.tb-mini-link:hover { color: var(--tb-ink); background: var(--tb-panel); }

/* Wallet pill nell'header (utente loggato) */
.tb-wallet-pill {
    display: inline-flex; align-items: center; gap: 7px;
    font-size: var(--tb-fs-xs); font-weight: 700;
    color: var(--tb-emerald-ink); background: var(--tb-emerald-soft);
    border: 1px solid color-mix(in srgb, var(--tb-emerald) 22%, transparent);
    border-radius: var(--tb-r-pill); padding: 6px 12px; text-decoration: none;
    font-variant-numeric: tabular-nums;
}
.tb-wallet-pill:hover { background: color-mix(in srgb, var(--tb-emerald-soft) 70%, #fff); }
/* Una <svg> senza width intrinseca dentro un inline-flex e' un flex item con
   min-width:auto e collassa a 0: l'icona diventerebbe invisibile. */
.tb-wallet-pill svg { flex: none; }
/* Saldo sotto zero (storno dopo un payout): il verde del cashback mentirebbe. */
.tb-wallet-pill.is-negative {
    color: var(--tb-danger); background: color-mix(in srgb, var(--tb-danger) 8%, #fff);
    border-color: color-mix(in srgb, var(--tb-danger) 24%, transparent);
}
.tb-wallet-pill.is-negative:hover { background: color-mix(in srgb, var(--tb-danger) 12%, #fff); }

/* Switch lingua */
.tb-lang { display: inline-flex; border: 1px solid var(--tb-line); border-radius: var(--tb-r-pill); overflow: hidden; background: var(--tb-panel); }
.tb-lang a { font-size: 12px; font-weight: 600; color: var(--tb-ink-soft); padding: 6px 10px; text-decoration: none; line-height: 1; display: grid; place-items: center; }
.tb-lang a[aria-current="true"] { background: var(--tb-ink-fill); color: #fff; }

/* Toggle mobile */
/* LE MISURE ARRIVANO DA global.css, e senza di loro il bottone scendeva sotto
   la soglia: 40x34 invece di 44x44. E' il bersaglio con cui si apre il menu sul
   telefono — cioe' l'unico modo di navigare li' dentro — quindi e' esattamente
   il posto in cui i 44px non si negoziano (DESIGN.md, "Touch target"). */
.tb-menu-toggle { display: none; flex-direction: column; align-items: center; justify-content: center;
    width: var(--tb-touch); height: var(--tb-touch); border-radius: var(--tb-r-card);
    gap: 4px; background: none; border: 0; padding: 10px; cursor: pointer; }
/* `flex: none` e' obbligatorio: senza, il flex shrink azzera l'altezza delle
   barrette e il bottone sparisce. Lo scriveva anche `margin: 0`, che serviva a
   disfare il "margin: 4px auto" di global.css — 24px di margini verticali in un
   pulsante con 24px di contenuto. Quel foglio non c'e' piu' e il margine resta
   solo come dichiarazione di intenti: le barrette non ne vogliono. */
.tb-menu-toggle span { display: block; width: 20px; height: 2px; margin: 0; flex: none; background: var(--tb-ink); border-radius: 2px; }

/* --- Barra di ricerca nell'header (hook JS invariati) ------------------ */

.tb-header-search-wrap { display: flex; justify-content: center; flex: 1; min-width: 0; }
.tb-top-search, .tb-search-form {
    display: flex; align-items: stretch;
    background: var(--tb-bg);
    border: 1px solid var(--tb-line);
    border-radius: var(--tb-r-pill);
    box-shadow: var(--tb-shadow);
    padding: 4px 4px 4px 6px;
    max-width: 720px; width: 100%;
}
.tb-search-segment {
    display: flex; flex-direction: column; justify-content: center;
    padding: 4px 14px; min-width: 0; flex: 1;
    border-radius: var(--tb-r-pill);
}
.tb-search-segment:hover { background: var(--tb-panel); }
/* display, line-height e margin-bottom arrivavano da global.css. Senza,
   l'occhiello prende l'interlinea del corpo: da 13px di altezza passa a 18, e
   i tre segmenti della barra si allungano di due pixel ciascuno. */
.tb-search-label { display: block; font-size: 10px; line-height: 1.1; margin-bottom: 3px;
    font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--tb-ink-soft); }
.tb-text-input, .tb-field-button {
    font: inherit; font-size: var(--tb-fs-sm); font-weight: 600; color: var(--tb-ink);
    background: transparent; border: 0; padding: 0; text-align: left; cursor: pointer;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    /* Da global.css: senza `width: 100%` il bottone si stringe sul testo e
       l'ellissi non ha piu' niente da tagliare, quindi la destinazione lunga
       allarga il segmento invece di accorciarsi.
       Il `line-height: 1.2` che stava insieme a queste due NON si porta dietro:
       aveva la stessa specificita' di questa regola e perdeva gia' prima, per
       ordine di caricamento. Rimetterlo accorcerebbe i campi di sei pixel —
       una modifica mai vista da nessuno, mascherata da restauro. */
    width: 100%; outline: none;
}
.tb-text-input::placeholder { color: var(--tb-ink-soft); font-weight: 500; }
.tb-search-icon, .tb-search-submit {
    flex: none; display: inline-flex; align-items: center; justify-content: center; gap: 7px;
    min-height: var(--tb-touch);   /* stava a 42px: e' il bottone piu' premuto del sito */
    background: var(--tb-blue); color: #fff; border: 0; border-radius: var(--tb-r-pill);
    font: inherit; font-size: var(--tb-fs-sm); font-weight: 600; padding: 10px 18px; cursor: pointer;
    /* L'etichetta NON va a capo. Senza questa riga, nella barra stretta
       dell'header "Cerca hotel" si spezzava su due righe e la pillola, con
       raggio 999px, si richiudeva in un BLOB TONDO. Oltre a essere brutto era
       proprio la forma da non avere: un orb circolare colorato incastonato a
       destra nella barra e' la firma riconoscibile di un concorrente diretto,
       ed e' territorio trade dress. Il bottone resta una pillola con la scritta. */
    white-space: nowrap;
    /* Difendeva da global.css, che sotto i 768px imponeva `width: 100%` alle
       lenti pensando a una barra impilata a griglia: qui la barra resta in riga
       fino a 768px, e un bottone al 100% con flex:none sfondava il viewport.
       Quel foglio non c'e' piu'. Resta perche' `auto` e' anche la larghezza
       giusta, non solo l'antidoto. */
    width: auto;
}
.tb-search-icon:hover, .tb-search-submit:hover { background: var(--tb-blue-deep); }

/* LA LENTE HA UNA MISURA, e va data QUI — sulla primitiva, non sulla variante.
   Nel markup l'<svg> porta solo il viewBox: nessuna dimensione intrinseca.
   Un rimpiazzato senza misura vale 300x150px, e come flex item con
   `align-items: center` si prende tutto lo spazio che trova.

   Finche' la misura e' esistita solo in `.hm-searchbar .tb-search-submit svg`
   (home.css), la barra dell'header ne era scoperta: sotto i 768px il bottone
   andava a `width:100%`, la lente si gonfiava a 207x207 e il bottone diventava
   alto 227px. Con l'header `sticky`, la testata occupava 491px su 844 — il 58%
   dello schermo, sempre — e su ricerca e dettaglio copriva il contenuto.

   Era per giunta esattamente la forma vietata dal commento qui sopra: un orb
   blu tondo. Una regola scritta sulla variante non protegge la primitiva. */
.tb-search-icon svg, .tb-search-submit svg { flex: none; width: 18px; height: 18px; }

.tb-header .dot { width: 1px; align-self: center; height: 24px; background: var(--tb-line); }

/* =======================================================================
   LA BARRA SUL TELEFONO: UNA RIGA CHE RIASSUME, UN FOGLIO CHE MODIFICA
   =======================================================================
   Sul telefono i tre segmenti si impilano, e siccome .tb-header e' `sticky`
   quella pila restava addosso allo schermo per tutta la navigazione. Su una
   ricerca gia' fatta e' spazio speso per un'informazione che l'utente ha
   appena scritto lui.

   Quindi: quando la ricerca c'e' gia', la barra si RIASSUME in una riga
   ("Paris · 15-18 set · 1 ospite"); quando la si tocca, si APRE a schermo
   intero e torna la barra vera, con i suoi tre segmenti e il suo pannello.

   Nessun oggetto nuovo: il foglio E' la stessa `<form>`, con un'altra misura.
   E' la stessa idea delle due varianti hero/header — un vocabolario solo,
   piu' taglie — e vale anche qui: il bottone che cerca resta una pillola con
   la scritta, non diventa mai un cerchio. ------------------------------- */

/* Su schermi larghi non esistono proprio. */
.tb-search-compact, .tb-sheet-head { display: none; }

@media (max-width: 860px) {

    /* `has-compact` la mette app.js insieme a togliere `hidden` dal bottone:
       le due cose viaggiano sempre appaiate, quindi la riga non puo' comparire
       dove non funzionerebbe. Senza JavaScript nessuna delle due arriva, e
       resta la barra impilata di sempre — che si sa arrangiare da sola. */
    .tb-top-search.has-compact:not(.is-sheet) {
        padding: 0; border-radius: var(--tb-r-pill); overflow: hidden;
    }
    .tb-top-search.has-compact:not(.is-sheet) > .tb-search-segment,
    .tb-top-search.has-compact:not(.is-sheet) > .tb-search-submit { display: none; }

    /* UNA regola sola decide se la riga si vede, e porta dentro tutte e tre le
       condizioni: c'e' il JS (`has-compact`), il foglio e' chiuso (`:not(.is-sheet)`),
       il bottone e' stato scoperto (`:not([hidden])`).

       Con due regole contrapposte non funzionava, e per un motivo che si vede
       solo contando: quella che mostrava pesava (0,4,0) — `:not([hidden])` e' un
       selettore d'attributo — contro i (0,3,0) di quella che nascondeva. Vinceva
       la prima, e la riga riassuntiva restava dentro al foglio, sopra la sua
       testata, spingendo tutto il resto piu' giu'. */
    .tb-top-search.has-compact:not(.is-sheet) > .tb-search-compact:not([hidden]) {
        display: flex; align-items: center; gap: var(--tb-s-3);
        width: 100%; min-height: 52px; padding: 8px 8px 8px 16px;
        background: none; border: 0; text-align: left; cursor: pointer;
        font: inherit; color: var(--tb-ink);
    }

    .tb-search-compact-icon { flex: none; width: 18px; height: 18px; color: var(--tb-blue-ink); }

    /* min-width:0 su tutti e due gli anelli della catena: senza, un nome di
       citta' lungo allarga il flex item invece di troncarsi, e la riga sfonda. */
    .tb-search-compact-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
    .tb-search-compact-where {
        font: var(--tb-t-body-strong);
        white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    }
    .tb-search-compact-meta {
        font: var(--tb-t-caption); color: var(--tb-ink-soft);
        white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    }
    .tb-search-compact-meta:empty { display: none; }
    .tb-search-compact-edit {
        flex: none; font: var(--tb-t-button); color: var(--tb-blue-ink);
        padding: 10px 14px; border-radius: var(--tb-r-pill); background: var(--tb-blue-soft);
    }

    /* --- Il foglio ----------------------------------------------------- */

    /* Sotto l'header (z-header 100) starebbe la barra da modificare dietro a
       quella da leggere: qui il foglio E' la pagina, e prende il livello dei
       velluti a schermo pieno. */
    .tb-top-search.is-sheet {
        position: fixed; inset: 0; z-index: var(--tb-z-overlay);
        flex-direction: column; align-items: stretch;
        width: auto; max-width: none; margin: 0; padding: 0;
        border: 0; border-radius: 0; box-shadow: none;
        background: var(--tb-bg);
        overflow-y: auto; overscroll-behavior: contain;
    }
    .tb-top-search.is-sheet .tb-sheet-head {
        position: sticky; top: 0; z-index: 1;
        display: flex; align-items: center; justify-content: space-between; gap: var(--tb-s-3);
        padding: var(--tb-s-3) var(--tb-s-3) var(--tb-s-3) var(--tb-s-5);
        background: var(--tb-bg); border-bottom: 1px solid var(--tb-line);
    }
    .tb-sheet-title { font: var(--tb-t-card-title); letter-spacing: var(--tb-tr-tight); }
    .tb-sheet-close {
        flex: none; display: grid; place-items: center;
        width: var(--tb-touch); height: var(--tb-touch);
        background: var(--tb-panel); border: 0; border-radius: var(--tb-r-pill);
        color: var(--tb-ink); cursor: pointer;
    }
    .tb-sheet-close svg { width: 20px; height: 20px; }
    .tb-sheet-close:hover { background: var(--tb-panel-2); }

    /* Nel foglio i segmenti sono campi veri: bordo, aria per il pollice, e
       niente `flex: 1` — devono stare alla loro altezza, non spartirsi quella
       dello schermo. */
    .tb-top-search.is-sheet .tb-search-segment {
        flex: none; gap: 2px;
        margin: var(--tb-s-3) var(--tb-s-4) 0;
        padding: 10px 14px; min-height: 62px;
        border: 1px solid var(--tb-line); border-radius: var(--tb-r-btn);
    }
    /* Il filetto fra i segmenti presuppone due scatole attaccate: qui sono
       staccate, e resterebbe un trattino a mezz'aria fra l'una e l'altra. */
    .tb-top-search.is-sheet .tb-search-segment + .tb-search-segment::before { content: none; }
    .tb-top-search.is-sheet .tb-search-segment.is-open {
        border-color: var(--tb-blue); box-shadow: 0 0 0 1px var(--tb-blue);
    }
    /* Il campo "dove" deve poter ricevere il tocco su tutta la sua altezza. */
    .tb-top-search.is-sheet .tb-text-input,
    .tb-top-search.is-sheet .tb-field-button { padding: 6px 0; font-size: var(--tb-fs-md); }

    .tb-top-search.is-sheet .tb-search-submit {
        margin: var(--tb-s-5) var(--tb-s-4) var(--tb-s-4);
        width: auto; min-height: 52px; font: var(--tb-t-button-lg);
    }
}

/* Il foglio copre la pagina: quella sotto non deve scorrere sotto il dito.
   La classe la mette e la toglie app.js. */
body.tb-sheet-open { overflow: hidden; }

/* E QUI la trappola, che e' costata un foglio schiacciato dentro la testata.

   `backdrop-filter` (come `transform` e `filter`) crea un BLOCCO CONTENITORE per
   i discendenti `position: fixed`. La barra vive dentro .tb-header, che ha il suo
   `backdrop-filter: blur(10px)`: quindi `inset: 0` non si misurava sul viewport
   ma sulla testata, e il foglio "a schermo intero" nasceva alto 145px, largo
   quanto l'header, con i campi fuori dai bordi.

   E' lo stesso scoglio che il pannello aggira salendo nel top layer col
   `popover`. Il foglio non puo' fare altrettanto — e' la <form> stessa, e dentro
   ci sta gia' un popover — quindi si toglie di mezzo il filtro finche' il foglio
   e' aperto. Non si perde niente: sotto c'e' il foglio, non la pagina da sfocare. */
body.tb-sheet-open .tb-header {
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
}

/* =======================================================================
   BARRA DI RICERCA: LO SPOTLIGHT
   =======================================================================
   Il modo in cui la barra dice "sei qui". Quando un segmento e' aperto la
   guida si SPEGNE (diventa --tb-panel) e il segmento attivo si SOLLEVA in
   bianco: il contrasto lo isola senza bisogno di un bordo colorato.

   E' movimento che racconta uno stato, non decorazione: PRODUCT.md e' netto
   ("mai una coreografia; l'utente sta sbrigando, non guardando"), quindi i
   tempi stanno nei 140-260ms, non nei 450ms di chi vende sogni.

   Il bottone d'invio resta una PILLOLA CON L'ETICHETTA in ogni stato. Non
   diventa mai un cerchio: quello e' il tratto riconoscibile di un altro
   marchio nel nostro stesso settore, ed e' territorio trade dress. -------- */

/* .tb-search-form e' la primitiva: ce l'hanno sia la barra dell'hero
   (.hm-searchbar) sia quella dell'header (.tb-top-search), che restano solo
   varianti di misura. Un solo vocabolario, due taglie. */
.tb-search-form { transition: background var(--tb-dur) var(--tb-ease); }
.tb-search-form[data-open] { background: var(--tb-panel); }

/* In errore la barra va a capo e il messaggio prende una riga tutta sua, sotto i
   segmenti, senza toccarne l'altezza. `flex-wrap` si accende SOLO qui: a barra
   sana non deve poter mandare a capo niente per sbaglio.
   (Il pannello e' fuori flusso — position:fixed, top layer — quindi non entra
   in questo conto. E siccome il messaggio allunga il form, il pannello, che si
   ancora al fondo del form, scende da solo insieme a lui.) */
.tb-search-form.has-error { flex-wrap: wrap; }
.tb-search-form .tb-field-error { flex: 0 0 100%; padding: 0 var(--tb-s-3) var(--tb-s-1); }

/* Il filetto fra i segmenti. Non e' un box-shadow a tutta altezza: e' una riga
   alta poco piu' di meta' segmento, centrata. Un tratto che arriva a filo del
   bordo superiore e inferiore taglia la barra in tre scatole; uno piu' corto la
   lascia leggere come un oggetto solo, diviso.

   Sparisce quando la guida si spegne: due segnali di separazione insieme
   (filetto + rilievo del segmento sollevato) fanno rumore, non gerarchia. */
.tb-search-segment { position: relative; }
.tb-search-form .tb-search-segment + .tb-search-segment::before {
    content: ''; position: absolute; left: 0; top: 50%;
    width: 1px; height: 55%; transform: translateY(-50%);
    background: var(--tb-line);
    transition: opacity var(--tb-dur) var(--tb-ease);
}
.tb-search-form[data-open] .tb-search-segment + .tb-search-segment::before { opacity: 0; }

.tb-search-segment {
    transition: background var(--tb-dur) var(--tb-ease),
                box-shadow var(--tb-dur) var(--tb-ease);
}
.tb-search-form[data-open] .tb-search-segment.is-open {
    background: var(--tb-raise);
    box-shadow: var(--tb-raise-shadow);
}
/* Sulla guida spenta il hover deve solo accennare, se no compete con l'attivo. */
.tb-search-form[data-open] .tb-search-segment:not(.is-open):hover {
    /* Un accenno, non un secondo attivo: meta' strada verso la superficie
       sollevata. Era `rgb(255 255 255 / 55%)`, che sullo scuro schiariva verso
       il bianco invece che verso il gradino successivo. */
    background: color-mix(in srgb, var(--tb-raise) 55%, transparent);
}

/* IL BUDGET E' L'UNICO SEGMENTO SENZA PANNELLO, e per questo era anche l'unico
   senza focus visibile: gli altri si accendono perche' app.js apre la loro
   tendina e mette `.is-open`, qui non si apre niente e il campo restava con
   `outline: none` e nient'altro. Chi naviga col Tab arrivava sul budget e non
   vedeva dove fosse finito.

   Non si aggiunge un anello nuovo: si riusa il rilievo che il sistema gia' usa
   per dire "sei qui dentro". `:focus-within` perche' il focus lo prende
   l'input, ma la cosa che si vede e' il segmento. */
.tb-search-budget:focus-within {
    background: var(--tb-raise);
    box-shadow: var(--tb-raise-shadow);
}
.tb-search-budget:focus-within .tb-search-label { color: var(--tb-blue-ink); }


/* --- Il pannello ------------------------------------------------------- */
/* popover = top layer: non lo ritaglia ne' un overflow:hidden dell'antenato
   ne' l'overflow-x:hidden che body si porta dietro (sezione "Base"). Posizione via
   JS (rect del segmento), perche' anchor-positioning non e' ancora ovunque.

   IL PANNELLO E' UNO SOLO, e questa e' la scelta che conta. Con tre pannelli
   separati, passare da "dove" a "quando" e' una tendina che sparisce e un'altra
   che compare: si legge come due eventi. Con un guscio solo che SCIVOLA sotto il
   nuovo segmento cambiando forma, si legge come un oggetto che ti segue — ed e'
   l'unica cosa che separa una barra di ricerca fatta bene da un dropdown.

   Diviso in due strati per un motivo preciso: il POSIZIONATORE (.tb-sb-panel)
   fa il viaggio (transform + width), il GUSCIO (.tb-sb-shell) fa l'ingresso
   (opacita' + risalita). Sono due animazioni sulla stessa proprieta' transform:
   su un elemento solo si sarebbero mangiate a vicenda. */
/* ATTENZIONE a `top` e `left`: vanno dichiarati, e NON vanno rimessi in
   discussione da una scorciatoia `inset` scritta dopo.

   Qui c'era `inset: auto auto auto 0` in coda a `top: 0; left: 0`. `inset` e' la
   scorciatoia di top/right/bottom/left, arriva dopo, e quindi rimetteva `top` ad
   AUTO. Un elemento `fixed` con `top: auto` si piazza nella sua POSIZIONE
   STATICA — cioe' li' dove sarebbe finito nel flusso, dentro il form, a meta'
   pagina — e il nostro translateY ci si SOMMA sopra. Il pannello usciva in fondo
   alla pagina, fuori dallo schermo.

   Non se n'era accorto nessuno perche' Chromium risolve `top: auto` a 0 per gli
   elementi nel top layer e mascherava l'errore. Firefox no: sulla home dava
   top: 421px (la posizione del form) + 497 di translate = 918px, con un viewport
   alto 900. Provare su un motore solo non e' provare. */
.tb-sb-panel {
    position: fixed; top: 0; left: 0; margin: 0;
    z-index: 120; padding: 0; border: 0; background: transparent;
    /* Il viaggio. Le tre facce hanno larghezze diverse, quindi la larghezza fa
       parte del movimento: senza, il guscio scatterebbe di misura a meta' strada. */
    transform: translate(var(--sb-x, 0px), var(--sb-y, 0px));
    width: var(--sb-w, 420px);
    transition: transform var(--tb-dur-slow) var(--tb-glide),
                width     var(--tb-dur-slow) var(--tb-glide);
}
/* Alla PRIMA apertura non c'e' nessun viaggio da fare: il pannello deve nascere
   gia' sotto il suo segmento, non arrivarci scivolando dall'angolo in alto. */
.tb-sb-panel.is-fermo { transition: none; }

/* Doppia serratura, di proposito. Dove `popover` esiste, e' lo stile UA
   ([popover]:not(:popover-open){display:none}) a tenerlo chiuso e il pannello
   sale nel top layer. Dove non esiste, l'attributo e' inerte e resta `hidden`
   a comandare: il JS li muove tutti e due, e la barra funziona comunque. */
.tb-sb-panel[hidden] { display: none; }

/* Il guscio: la scatola bianca. Scorre il CORPO, non il piede — prima l'overflow
   stava sul contenitore intero e il bottone "Fatto" del calendario scorreva via
   oltre il bordo dello schermo: c'era, ma non lo si poteva premere. */
.tb-sb-shell {
    display: flex; flex-direction: column;
    max-height: var(--sb-maxh, 70vh);
    background: var(--tb-bg); border: 1px solid var(--tb-line);
    border-radius: var(--tb-r-card); box-shadow: var(--tb-shadow);
    color: var(--tb-ink); overflow: hidden;
}

/* Le facce si danno il cambio: una sola alla volta. */
.tb-sb-pane { display: flex; flex-direction: column; min-height: 0; }
.tb-sb-pane[hidden] { display: none; }
/* Attenzione a `overflow-y: auto` qui: per specifica costringe anche `overflow-x`
   da `visible` ad `auto`, e questo rende il corpo un contenitore a SCORRIMENTO.
   Conseguenza non ovvia: il corpo smette di contribuire alla larghezza intrinseca
   del pannello, quindi `max-content` non "vede" piu' il calendario. E' il motivo
   per cui la larghezza della faccia "quando" si stima e si misura a mano in
   app.js invece di lasciarla calcolare al browser. */
.tb-sb-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: var(--tb-s-4); }

.tb-sb-foot {
    flex: none;
    display: flex; align-items: center; justify-content: space-between; gap: var(--tb-s-4);
    padding: var(--tb-s-3) var(--tb-s-4);
    border-top: 1px solid var(--tb-line);
}

/* Quante notti / quanti ospiti: e' informazione, ed e' l'unica cosa che il piede
   del pannello ha il diritto di dire. Su una riga: "1 adulto, 1 / camera"
   spezzato in due sembra un errore, non una nota. */
.tb-sb-note {
    font-size: var(--tb-fs-sm); color: var(--tb-ink-soft);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.tb-sb-note b { color: var(--tb-ink); font-weight: 600; font-variant-numeric: tabular-nums; }

/* L'input tecnico di flatpickr: serve al plugin, non all'utente. */
.tb-flatpickr-anchor {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip-path: inset(50%); border: 0;
}

/* DUE VELOCITA'. E' il trucco, e senza di esso il resto non serve a niente:
   il guscio VIAGGIA lento (340ms, e si posa) mentre il contenuto CAMBIA svelto
   (140ms). Se viaggiassero allo stesso passo sembrerebbe una diapositiva; cosi'
   sembra una cosa che ha una massa. */
@media (prefers-reduced-motion: no-preference) {
    .tb-sb-panel:popover-open .tb-sb-shell { animation: tb-sb-in var(--tb-dur) var(--tb-ease) both; }
    .tb-sb-pane:not([hidden])              { animation: tb-fade-in var(--tb-dur-fast) linear both; }

    /* Lo sfalsamento delle scorciatoie: 22ms l'una dall'altra, sei voci = 132ms,
       finito prima che il guscio si sia posato. E' dentro UNA lista, che e' il
       solo posto in cui uno stagger e' informazione ("sono voci di un elenco")
       invece che coreografia. --i lo mette il PHP. */
    .tb-sb-pane[data-pane="where"]:not([hidden]) .tb-sb-item {
        animation: tb-sb-item-in 240ms var(--tb-ease) both;
        animation-delay: calc(var(--i, 0) * 22ms);
    }
}

/* Il guscio nasce OPACO e fermo: l'animazione lo anima, non lo rivela. E' il
   motivo per cui qui sotto non c'e' nessun blocco di ripiego per il movimento
   ridotto, e non e' una dimenticanza: la regola globale in fondo al foglio
   (`* { animation: none !important }`) spegne tutto, e con l'animazione spenta
   il pannello resta semplicemente com'e' nato — visibile. Se invece l'avessimo
   nascosto di base e "rivelato" con i keyframe, con quella regola attiva non
   sarebbe comparso mai piu'. */
@keyframes tb-sb-in {
    from { opacity: 0; transform: translateY(-10px) scale(0.98); }
    to   { opacity: 1; transform: none; }
}
@keyframes tb-sb-item-in {
    from { opacity: 0; transform: translateY(6px); }
    to   { opacity: 1; transform: none; }
}

/* --- Pannello DOVE: suggerimenti -------------------------------------- */
.tb-sb-group + .tb-sb-group { margin-top: var(--tb-s-4); }
.tb-sb-group-title {
    display: block; margin: 0 0 var(--tb-s-2); padding: 0 var(--tb-s-2);
    font-size: var(--tb-fs-xs); font-weight: 600; color: var(--tb-ink-soft);
}
/* La lista dell'autocomplete vive nello stesso pannello delle scorciatoie, e
   quindi si veste allo stesso modo: due elenchi che fanno la stessa cosa non
   possono avere due aspetti. (I nomi .tb-ac-* restano quelli che scrive
   autocomplete.js; qui li facciamo solo sedere al tavolo giusto.) */
.tb-sb-suggest, .tb-ac-list { display: flex; flex-direction: column; gap: 2px; }
.tb-sb-item, .tb-ac-list .tb-ac-item {
    display: flex; align-items: center; gap: var(--tb-s-3); width: 100%;
    padding: 6px var(--tb-s-2); border: 0; border-radius: var(--tb-r-btn);
    background: transparent; font: inherit; color: var(--tb-ink); text-align: left; cursor: pointer;
    transition: background var(--tb-dur-fast) var(--tb-ease);
}
.tb-sb-item:hover, .tb-sb-item.is-active,
.tb-ac-list .tb-ac-item:hover, .tb-ac-list .tb-ac-item.is-active { background: var(--tb-panel); }

.tb-sb-item-icon, .tb-ac-list .tb-ac-icon {
    flex: none; display: inline-flex; align-items: center; justify-content: center;
    width: 32px; height: 32px; border-radius: var(--tb-r-btn);
    background: var(--tb-panel); color: var(--tb-ink-soft);
}
.tb-sb-item:hover .tb-sb-item-icon, .tb-sb-item.is-active .tb-sb-item-icon,
.tb-ac-list .tb-ac-item:hover .tb-ac-icon, .tb-ac-list .tb-ac-item.is-active .tb-ac-icon {
    background: var(--tb-blue-soft); color: var(--tb-blue-ink);
}
.tb-sb-item-icon svg, .tb-ac-list .tb-ac-icon svg { width: 18px; height: 18px; }

.tb-sb-item-text, .tb-ac-list .tb-ac-text { display: flex; flex-direction: column; min-width: 0; }
.tb-sb-item-label, .tb-ac-list .tb-ac-label { font-size: var(--tb-fs-sm); font-weight: 600; }
.tb-sb-item-sub, .tb-ac-list .tb-ac-sub { font-size: var(--tb-fs-xs); color: var(--tb-ink-soft); }

/* --- "Vicino a me" ------------------------------------------------------
   Sta in cima al pannello DOVE, sopra le recenti e le scorciatoie, perche' e'
   l'unica voce che non chiede di sapere gia' la risposta. Ed e' un'AZIONE, non
   un posto: il filetto sotto lo separa dagli elenchi, che invece sono elenchi
   di posti. */
.tb-sb-geo {
    position: relative;
    margin-bottom: var(--tb-s-3);
    padding-bottom: var(--tb-s-3);
    border-bottom: 1px solid var(--tb-line);
    border-radius: var(--tb-r-btn) var(--tb-r-btn) 0 0;
}
.tb-sb-geo[hidden] { display: none; }   /* [hidden] perde contro display:flex */

/* Scelta: l'icona si accende come su hover, e ci resta. Dice "e' questa la
   destinazione", che e' l'unica cosa che il campo di testo non riesce a dire —
   li' c'e' scritto "La tua posizione", e sembra una frase, non una scelta. */
.tb-sb-geo.is-on .tb-sb-item-icon { background: var(--tb-blue-soft); color: var(--tb-blue-ink); }

/* Non ha funzionato. Il bottone resta premibile (riprovare e' gratis) e la
   riga sotto dice cosa fare adesso, non cos'e' fallito. */
.tb-sb-geo.is-ko .tb-sb-item-sub  { color: var(--tb-danger-ink); }
.tb-sb-geo.is-ko .tb-sb-item-icon { background: var(--tb-danger-soft); color: var(--tb-danger); }

.tb-sb-geo-spin {
    flex: none; width: 16px; height: 16px; margin-left: auto;
    border: 2px solid var(--tb-line); border-top-color: var(--tb-blue);
    border-radius: 50%;
    opacity: 0;
    animation: tb-spin 640ms linear infinite;
}
.tb-sb-geo.is-cerca .tb-sb-geo-spin { opacity: 1; }

@keyframes tb-spin { to { transform: rotate(360deg); } }

/* Un anello fermo non dice "sto cercando": dice "sono rotto". Con il movimento
   ridotto la regola globale in fondo al foglio spegne l'animazione, quindi qui
   togliamo proprio l'anello — a dirlo resta la riga di testo ("Cerco dove
   sei…"), che e' poi quella che portava l'informazione anche prima. */
@media (prefers-reduced-motion: reduce) {
    .tb-sb-geo-spin { display: none; }
}

/* I tre stati dell'autocomplete dentro il pannello: sto cercando / non ho
   trovato / non riesco a cercare. Sono righe che si leggono, non si cliccano.
   Sotto di loro restano le scorciatoie (la via d'uscita), e il filetto dice che
   sono due cose diverse: sopra la risposta, sotto cosa puoi fare. */
.tb-ac-list .tb-ac-state {
    display: flex; align-items: center; gap: var(--tb-s-3);
    padding: var(--tb-s-2) var(--tb-s-2) var(--tb-s-3);
    margin-bottom: var(--tb-s-2);
    border-bottom: 1px solid var(--tb-line);
    font-size: var(--tb-fs-sm); color: var(--tb-ink-soft);
}
.tb-ac-list .tb-ac-state.is-error { color: var(--tb-danger-ink); }
.tb-ac-list .tb-ac-retry {
    margin-left: auto; background: transparent; border: 1px solid var(--tb-line);
    border-radius: var(--tb-r-btn); padding: 6px 12px;
    font: inherit; font-size: var(--tb-fs-xs); font-weight: 600;
    color: var(--tb-ink); cursor: pointer;
}
.tb-ac-list .tb-ac-retry:hover { border-color: var(--tb-ink); }

/* --- Pannello CHI: contatori ------------------------------------------ */
.tb-who-row {
    display: flex; align-items: center; justify-content: space-between; gap: var(--tb-s-6);
    padding: var(--tb-s-3) 0;
}
.tb-who-row + .tb-who-row { border-top: 1px solid var(--tb-line); }
.tb-who-title { font-size: var(--tb-fs-sm); font-weight: 600; }
.tb-stepper { display: inline-flex; align-items: center; gap: var(--tb-s-3); }
.tb-stepper-btn {
    width: 32px; height: 32px; border-radius: 50%; border: 1px solid var(--tb-line);
    /* Il peso arriva da global.css: senza, il "+" e il "-" ereditano 400 dal
       corpo e in un cerchio da 32px diventano due trattini smilzi. */
    background: var(--tb-bg); color: var(--tb-ink); font-size: 16px; font-weight: 800; line-height: 1; cursor: pointer;
    display: inline-flex; align-items: center; justify-content: center;
    transition: border-color var(--tb-dur-fast) var(--tb-ease),
                color var(--tb-dur-fast) var(--tb-ease);
}
.tb-stepper-btn:hover:not(:disabled) { border-color: var(--tb-ink); }
/* Il limite si vede PRIMA di premere: un bottone spento e' una risposta, un
   bottone acceso che non fa niente e' un bug agli occhi di chi lo preme. */
.tb-stepper-btn:disabled { opacity: .4; cursor: not-allowed; }
.tb-stepper-value {
    min-width: 2ch; text-align: center; font-size: var(--tb-fs-sm); font-weight: 600;
    font-variant-numeric: tabular-nums;
}
.tb-who-done {
    background: var(--tb-ink-fill); color: #fff; border: 0; border-radius: var(--tb-r-btn);
    padding: 10px 18px; font: inherit; font-weight: 600; cursor: pointer;
    flex: none; white-space: nowrap;
    /* width e margin-top vanno DICHIARATI, non lasciati stare: global.css (che
       carica prima) mette `.tb-who-done { width: 100% }`, e la cascata non
       azzera cio' che non riscrivi. Finche' il bottone era comprimibile non si
       notava; con `flex: none` quel 100% si e' preso tutta la riga e la nota
       "6 notti" e' sparita dal piede del calendario. */
    width: auto; margin-top: 0;
    transition: background var(--tb-dur-fast) var(--tb-ease);
}
.tb-who-done:hover { background: var(--tb-ink-fill-hover); }

/* --- Pannello QUANDO: il calendario ----------------------------------- */
/* flatpickr resta (i18n e range gia' risolti), ma lo montiamo INLINE dentro
   il pannello invece di lasciarlo galleggiare per conto suo: cosi' i tre
   passi condividono un solo guscio, una sola ombra, una sola animazione. */
/* Niente `width` qui: la calcola flatpickr (stile inline) misurando le colonne
   dei giorni, e sovrascriverla e' il modo piu' rapido per ritrovarsi un
   calendario largo due pixel. Qui gli togliamo solo la pelle: il guscio,
   l'ombra e il bordo ce li mette gia' il pannello. */
.tb-sb-cal .flatpickr-calendar.inline {
    box-shadow: none; border: 0; margin: 0; background: transparent;
}
.tb-sb-cal .flatpickr-months { padding-bottom: var(--tb-s-2); }
.tb-sb-cal .flatpickr-month { color: var(--tb-ink); }
.tb-sb-cal .flatpickr-current-month { font-size: var(--tb-fs-sm); font-weight: 600; }
.tb-sb-cal .flatpickr-weekday { color: var(--tb-ink-soft); font-size: var(--tb-fs-xs); font-weight: 600; }
.tb-sb-cal .flatpickr-prev-month, .tb-sb-cal .flatpickr-next-month { fill: var(--tb-ink); }
.tb-sb-cal .flatpickr-day {
    color: var(--tb-ink); border-radius: var(--tb-r-btn); border: 0;
    font-weight: 500;
}
.tb-sb-cal .flatpickr-day:hover { background: var(--tb-panel); }
.tb-sb-cal .flatpickr-day.today { box-shadow: inset 0 0 0 1px var(--tb-line); }
.tb-sb-cal .flatpickr-day.inRange {
    background: var(--tb-blue-soft); box-shadow: -5px 0 0 var(--tb-blue-soft), 5px 0 0 var(--tb-blue-soft);
    border-radius: 0;
}
.tb-sb-cal .flatpickr-day.startRange,
.tb-sb-cal .flatpickr-day.endRange,
.tb-sb-cal .flatpickr-day.selected {
    background: var(--tb-blue); color: #fff; font-weight: 600;
}
.tb-sb-cal .flatpickr-day.flatpickr-disabled { color: var(--tb-ink-soft); opacity: .35; }

/* --- Footer ----------------------------------------------------------- */

.tb-footer { background: var(--tb-ink-fill); color: #fff; margin-top: 64px; padding: 48px 0 28px; }
.tb-footer .tb-container { display: grid; grid-template-columns: 1.6fr repeat(4, 1fr); gap: 32px; }
.tb-footer-brand .tb-logo { color: #fff; }
.tb-footer-brand .tb-logo-trips { color: #fff; }
.tb-footer-brand .tb-logo-back { color: var(--tb-blue-on-dark); }
.tb-footer-brand p { margin: 12px 0 0; font-size: var(--tb-fs-sm); color: var(--tb-on-dark); max-width: 34ch; }
.tb-footer h4 { font-size: 11px; letter-spacing: .08em; text-transform: uppercase; color: var(--tb-on-dark-dim); font-weight: 700; margin: 0 0 12px; }
.tb-footer ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 9px; }
.tb-footer a { font-size: var(--tb-fs-sm); color: var(--tb-on-dark); text-decoration: none; }
.tb-footer a:hover { color: #fff; }
.tb-footer-bottom {
    max-width: var(--tb-container); margin: 34px auto 0; padding: 18px 24px 0;
    border-top: 1px solid rgb(255 255 255 / 10%);
    display: flex; justify-content: space-between; gap: 16px; flex-wrap: wrap;
    font-size: var(--tb-fs-xs); color: var(--tb-on-dark-dim);
}

/* --- Responsive ------------------------------------------------------- */

@media (max-width: 1080px) {
    .tb-nav { display: none; }
    .tb-header-search-wrap { order: 3; flex-basis: 100%; padding-bottom: 12px; }
    .tb-header-inner { flex-wrap: wrap; padding-top: 10px; }
}

@media (max-width: 860px) {
    :root { --tb-fs-4xl: 2.25rem; --tb-fs-3xl: 1.875rem; --tb-fs-2xl: 1.5rem; }
    /* margin-left:auto porta il bottone al bordo destro, dove il pollice lo
       cerca (nel DOM segue il logo). Lo spacer va nascosto: con flex:1 si
       mangia lo spazio libero prima che il margine auto possa assorbirlo. */
    .tb-menu-toggle { display: flex; margin-left: auto; }
    .tb-header-spacer { display: none; }
    .tb-header-actions {
        display: none; order: 5; flex-basis: 100%;
        flex-direction: column; align-items: stretch; gap: 6px; padding-bottom: 14px;
    }
    /* app.js mette la classe is-open sull'header (#tbHeader), non sul pannello.
       Con .tb-header-actions.is-open il selettore non trovava mai nulla: il
       bottone cambiava aria-expanded e il menu restava chiuso su ogni telefono. */
    .tb-header.is-open .tb-header-actions { display: flex; }
    .tb-header-actions .tb-btn { width: 100%; justify-content: center; }
    /* .tb-mini-link e' un <a> inline: width e justify-content non lo toccano.
       Nel menu deve incolonnarsi come gli altri link, non restare a meta' riga. */
    .tb-header-actions .tb-mini-link { display: block; width: 100%; padding: 11px 12px; }
    .tb-lang { align-self: flex-start; margin: 4px 0 6px; }

    /* Sotto gli 860px la nav non ha altro posto dove stare, e sulle pagine con
       la barra di ricerca e' nascosta a ogni larghezza: senza questo i tre link
       non sono raggiungibili da telefono. Batte per specificita' (0,3,0) sia
       .tb-header-with-search .tb-nav sia il .tb-nav della media query sopra. */
    .tb-header.is-open .tb-nav {
        display: flex; order: 4; flex-basis: 100%;
        flex-direction: column; align-items: stretch;
        margin-left: 0; padding: 4px 0 10px;
        border-bottom: 1px solid var(--tb-line);
    }
    .tb-header.is-open .tb-nav a { padding: 11px 12px; }

    .tb-footer .tb-container { grid-template-columns: 1fr 1fr; }
}

/* Stesso breakpoint di global.css: sotto i 768px la barra si impila, cosi' le
   regole legacy (bordi sui segmenti, bottone a tutta larghezza) tornano coerenti.
   width:100% va dato SOLO dentro le barre che impilano davvero: la searchbar
   della home (.hm-searchbar) resta in riga fino a 640px e un bottone a tutta
   larghezza li' sfonderebbe il viewport. */
@media (max-width: 768px) {
    /* In riga la barra e' una pillola, e 999px su una scatola alta 52 e' la sua
       forma. Impilata la scatola diventa alta 251, e 999px su 251 NON e' piu' un
       raggio: e' un'ELLISSE — un ovale bianco gigante col bottone blu che esce
       dalla curva in basso.

       Qui c'era anche `.tb-search-form.hm-searchbar`, per pareggiare a (0,2,0) i
       due punti di home.css e vincere arrivando dopo. Non funziona piu', e non
       deve: questo foglio ora si carica PRIMA, quindi a parita' di specificita'
       l'ultima parola sulla home ce l'ha la home — che e' il senso dell'ordine
       nuovo. Il raggio della barra dell'hero se lo rimette a posto home.css, nel
       suo @media. Qui restano le varianti che una pagina non possiede. */
    .tb-search-form.tb-top-search,
    .tb-top-search, .tb-search-form { flex-direction: column; border-radius: var(--tb-r-card); padding: 8px; }

    .tb-top-search .tb-search-segment,
    .tb-search-form .tb-search-segment { border-radius: var(--tb-r-btn); border-bottom: 0; padding-bottom: 4px; }

    /* Il filetto VERTICALE fra i segmenti: separa due scatole affiancate, e
       impilate non c'e' piu' niente da separare in quella direzione. Restavano
       tre trattini a mezz'aria sul fianco sinistro di QUANDO e OSPITI.
       Lo spegne anche home.css, a 640px. Qui si spegne a 768, che e' dove la
       barra si impila davvero, e vale per tutte le varianti: e' il posto che sa
       che i segmenti sono incolonnati. Le due regole dicono la stessa cosa,
       quindi chi delle due vince non cambia niente. */
    .tb-search-form .tb-search-segment + .tb-search-segment::before { content: none; }

    .tb-top-search .tb-search-icon, .tb-top-search .tb-search-submit,
    .tb-search-form .tb-search-icon, .tb-search-form .tb-search-submit {
        justify-content: center; margin-top: 6px; width: 100%;
    }
    .tb-header .dot { display: none; }
}

@media (max-width: 560px) {
    .tb-footer .tb-container { grid-template-columns: 1fr; }
}

/* --- QUELLO CHE SI TOCCA COL POLLICE ---------------------------------------
   --tb-touch (44px) e' scritto in DESIGN.md dal primo giorno, ma valeva solo
   dove qualcuno si era ricordato di applicarlo. Misurando le pagine vere su un
   iPhone, tredici bersagli per schermata stavano sotto: il logo (26px), i
   filtri del portafoglio (34px), le linguette del dettaglio (38px), i campi
   della barra (26px).

   Col mouse un bersaglio da 26px si prende, col pollice no: si sbaglia, si
   torna indietro, e la colpa sembra dell'utente. Qui si dichiara una volta
   sola, per famiglia, invece che pagina per pagina. */
@media (max-width: 860px) {
    .tb-logo { min-height: var(--tb-touch); }

    /* I contatori del pannello ospiti e gli altri bottoni tondi piccoli. */
    .tb-chip, .tb-mini-link { min-height: var(--tb-touch); display: inline-flex; align-items: center; }


    /* I campi della barra impilata (hero della home e ripiego senza JS).
       L'etichetta sta sopra, quindi l'altezza del bottone e' solo quella del
       testo: 26px. Il tocco pero' capita sul bottone, non sul segmento. */
    .tb-search-form .tb-field-button,
    .tb-search-form .tb-text-input,
    .tb-search-form .tb-budget-input { min-height: 34px; }
    .tb-search-form .tb-search-segment { min-height: 58px; justify-content: center; }

    /* SAFARI SU IOS INGRANDISCE LA PAGINA quando si tocca un campo di testo con
       font-size sotto i 16px, e non la rimpicciolisce piu' da sola: si resta
       dentro una pagina zoomata, spostata di lato, a scrivere. Non e' un'opzione
       da disattivare — l'unico modo di evitarlo e' non scendere sotto i 16.

       .tb-input ci sta gia' (--tb-t-body e' 1rem). Il campo "dove" della barra
       no: nell'hero la sua misura e' calc(1.05rem - 0.15rem * var(--p)), e a
       --p = 1 vale 0.9rem = 14.4px.

       Dove morde davvero: nella fascia 768-860px. Sul telefono vero l'aggancio
       e' spento (home.js: `matchMedia('(min-width: 768px)')`), quindi --p resta
       0 e il campo sta a 16.8px gia' di suo; da 768 in su l'aggancio riparte e
       il campo si stringe sotto soglia. E' una fascia che esiste — un telefono
       grande di traverso, un tablet piccolo — e li' la pagina zoomava.

       `max()` e non un valore fisso: sopra i 16px la misura calcolata resta,
       cosi' l'animazione dell'aggancio continua a funzionare — si ferma solo
       dove comincerebbe a fare danno. */
    .tb-search-form .tb-text-input,
    .tb-search-form .tb-field-button,
    /* Anche i due campi data del ripiego senza JavaScript: stanno dentro un
       [hidden] e di norma non si vedono, ma quando si vedono sono l'unico modo
       di scegliere le date — cioe' esattamente il momento sbagliato per far
       saltare la pagina a un ingrandimento. */
    .tb-date-fallback input { font-size: max(16px, 1rem); }

    /* Leaflet disegna i suoi comandi a 30px e non sa niente del nostro token. */
    .leaflet-control-zoom a { width: 38px !important; height: 38px !important; line-height: 38px !important; }
}

/* --- Il piede sul telefono -------------------------------------------------
   Su schermo largo il piede e' una griglia a cinque colonne e i link stanno
   comodi. Impilati su una colonna diventano una lista da toccare, e con
   `gap: 9px` su un testo da 14px ogni voce era alta 18px: un terzo dei 44px
   che ci vuole per un pollice. Sono dieci link presenti su ogni pagina del
   sito, quindi e' il difetto piu' ripetuto che ci sia.

   L'area cliccabile la si allarga con `padding` sul link, non con `gap` sulla
   lista: il vuoto fra due voci non si tocca, e allargandolo si allontanano solo
   i bersagli invece di ingrandirli. */
@media (max-width: 860px) {
    .tb-footer { padding: 36px 0 20px; margin-top: 48px; }
    .tb-footer ul { gap: 0; }
    .tb-footer li a { display: block; padding: 11px 0; }

    /* 11px per un occhiello maiuscolo passa a 48cm dal viso, non a 30. */
    .tb-footer h4 { font-size: var(--tb-fs-xs); margin-bottom: 4px; }

    .tb-footer-bottom { margin-top: 24px; gap: 8px; }
}

/* --- IL VELO DI CARICAMENTO --------------------------------------------------
   Serve in un posto solo: la scheda dell'hotel, che aspetta davvero il fornitore
   (fino a 30 secondi). Vedi sm/lib_page/_loader.php.

   Arriva da global.css, e non era un semplice trasloco: usava l'arancione del
   marchio vecchio e stava a `z-index: 999`, un numero scelto a mano quando la
   scala semantica esisteva gia' — --tb-z-loader era li', definito e non usato.
   Adesso il velo sta nella scala insieme a tutto il resto. */

.tb-loader {
    position: fixed;
    inset: 0;
    display: grid;
    place-items: center;
    background: var(--tb-scrim);
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition: opacity 200ms var(--tb-ease);
    z-index: var(--tb-z-loader);
}
.tb-loader.is-active { opacity: 1; visibility: visible; pointer-events: auto; }

.tb-loader-box {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 15px 18px;
    background: var(--tb-bg);
    border: 1px solid var(--tb-line);
    border-radius: var(--tb-r-card);
    box-shadow: var(--tb-shadow);
    font-weight: 600;
    color: var(--tb-ink);
}

.tb-loader .spinner {
    width: 20px;
    height: 20px;
    border: 3px solid var(--tb-line);
    border-top-color: var(--tb-blue);
    border-radius: 50%;
    animation: tb-spin 850ms linear infinite;
}
@keyframes tb-spin { to { transform: rotate(360deg); } }

/* A movimento ridotto l'anello si toglie invece di restare fermo: un cerchio
   immobile non dice "sto caricando", dice "e' rotto". Resta il testo, che era
   gia' l'unica parte comprensibile delle due. */
@media (prefers-reduced-motion: reduce) {
    .tb-loader .spinner { display: none; }
}

/* --- Il ripiego senza JavaScript per le date --------------------------------
   Due campi data nativi al posto del calendario. Anche questo veniva da
   global.css, ed e' l'unico pezzo di quel foglio che valeva la pena leggere. */

.tb-date-fallback {
    position: absolute;
    top: calc(100% + 10px);
    left: 50%;
    transform: translateX(-50%);
    z-index: var(--tb-z-dropdown);
    display: grid;
    gap: 11px;
    width: min(320px, 90vw);
    padding: 14px;
    background: var(--tb-bg);
    border: 1px solid var(--tb-line);
    border-radius: var(--tb-r-card);
    box-shadow: var(--tb-shadow);
}

/* Il `display: grid` qui sopra BATTE la regola `[hidden]` del browser (che e'
   solo `display: none`, senza classi): l'attributo `hidden` sul div, da solo,
   non nasconderebbe piu' niente. A tenerlo giu' era il reset di Bootstrap
   (`[hidden] { display: none !important }`) — cioe' un foglio di terze parti
   che non sa di essere l'unica cosa che regge questo pezzo di interfaccia.
   Bloccalo (o togli Bootstrap) e i due campi comparirebbero in mezzo alla
   pagina, sotto il calendario vero. Lo dichiariamo qui, dove sta il danno. */
.tb-date-fallback[hidden] { display: none; }

.tb-date-fallback label {
    display: grid;
    gap: 5px;
    font: var(--tb-t-caption);
    color: var(--tb-ink-soft);
}

.tb-date-fallback input[type="date"] {
    border: 1px solid var(--tb-line);
    border-radius: var(--tb-r-btn);
    padding: 8px 10px;
    color: var(--tb-ink);
}

@media (max-width: 768px) {
    /* Sul telefono si ancora in basso: il pollice sta li', e un pannello
       agganciato al campo finirebbe sotto la tastiera appena si apre. */
    .tb-date-fallback {
        position: fixed;
        top: auto;
        bottom: max(12px, env(safe-area-inset-bottom));
        width: min(420px, calc(100vw - 20px));
        border-radius: var(--tb-r-slab);
    }
}

/* --- Correzione a un foglio di terze parti ----------------------------------
   flatpickr si disegna a z-index 999 di suo, che nella nostra scala vorrebbe
   dire "sopra tutto tranne i toast". Il numero non e' piu' scelto a occhio: e'
   il gradino che la scala gli assegna, sopra i pannelli della barra (200) e
   sotto la mappa a schermo pieno (400).

   Qui accanto stava anche `.select2-container { width: 100% !important }`.
   E' andata via col foglio: select2 non viene inizializzato da nessuna parte —
   nel nostro JavaScript non esiste una sola chiamata `.select2(`. */
.flatpickr-calendar { z-index: var(--tb-z-datepicker); }

/* --- MOVIMENTO ---------------------------------------------------------------
   PRODUCT.md, principio 5: "Il movimento racconta uno stato. Mai una coreografia
   di caricamento: l'utente sta sbrigando, non guardando."

   Quindi niente rivelazioni allo scroll, niente entrate di sezione, niente
   sequenze al caricamento della pagina. Il movimento esiste in tre posti soltanto,
   e ognuno dice una cosa che l'utente ha bisogno di sapere:

     1. IL SALDO entra (480ms). E' l'unico momento che ha diritto di emozionare.
     2. LO SCHELETRO pulsa, e le card entrano a scaglioni quando arrivano davvero:
        e' l'unica attesa vera del prodotto (fino a 30 secondi).
     3. LE RISPOSTE al tocco: hover, focus, pressione, il bottone che lavora.

   Tutto il resto sta fermo.
   -------------------------------------------------------------------------- */

/* La pressione si sente: 1px, e basta. Nessun rimbalzo, nessuna scala elastica —
   sono coreografia, e qui si sta sbrigando qualcosa. */
.tb-chip:active,
.tb-btn:not([disabled]):active { transform: translateY(1px); }

/* Le righe rispondono al passaggio, cosi' si capisce quale si sta per aprire. */
.tb-row, .tb-chip, .tb-tag, .tb-wallet-pill, .tb-cashback {
    transition: background-color var(--tb-dur-fast) var(--tb-ease),
                border-color var(--tb-dur-fast) var(--tb-ease),
                color var(--tb-dur-fast) var(--tb-ease),
                transform var(--tb-dur-fast) var(--tb-ease);
}

/* Il campo che si accende sotto il cursore, prima ancora del focus. */
.tb-input { transition: border-color var(--tb-dur-fast) var(--tb-ease); }

/* Gli avvisi non compaiono di scatto: un errore che appare senza preavviso si
   legge come un difetto della pagina, non come una risposta a quello che hai fatto. */
@media (prefers-reduced-motion: no-preference) {
    .tb-alert,
    .tb-field-error.is-on { animation: tb-alert-in 200ms var(--tb-ease); }
}
@keyframes tb-alert-in {
    from { opacity: 0; transform: translateY(-4px); }
}

/* Il movimento ridotto non e' una preferenza estetica: e' una richiesta medica.
   Qui si spegne TUTTO, comprese le animazioni scritte altrove — ed e' il motivo
   per cui il bottone occupato e l'anello dell'autocomplete hanno, ciascuno, il
   loro blocco di ripiego piu' su: senza, mostrerebbero un anello fermo e un
   bottone vuoto. */
@media (prefers-reduced-motion: reduce) {
    * { transition: none !important; animation: none !important; }
}

/* ============================================================================
   MODALITA' TRIPSBACK — il tema scuro.

   Non e' una preferenza di sistema e non e' un interruttore di gusto: e' il
   SEGNALE che il sito sta lavorando in modalita' cashback. Si accende quando si
   accende la modalita' e si spegne con lei, quindi non ascolta
   prefers-color-scheme — chi tiene il telefono in scuro ma prenota senza
   cashback deve vedere il tema chiaro, o il colore smette di voler dire
   qualcosa. La classe la mette il server in _head.php, cosi' la pagina nasce
   gia' del colore giusto e non c'e' il lampo bianco del primo paint.

   SI RIDEFINISCONO SOLO I TOKEN. Nessuna regola di componente e' duplicata qui
   sotto (le due eccezioni sono dichiarate e spiegate): tutto il resto del foglio
   legge le variabili e si adatta da solo. Il giorno in cui qualcuno aggiunge una
   card nuova, questa e' gia' scura senza che nessuno se ne ricordi.

   NON E' PIU' BLU, e il motivo va scritto o qualcuno lo rimette. Il fondo era
   #0B1426, un navy saturo, e il verde del cashback era menta al neon: quelle due
   cose insieme, con le cifre piu' grandi della pagina in verde, sono la grammatica
   visiva di un exchange di criptovalute. Non un'impressione — il riquadro "30%"
   del portafoglio era la card del rendimento, con la stessa forma e lo stesso
   colore. Un sito che vende notti d'albergo non deve somigliarci.
   Adesso la base e' una GRAFITE CALDA (tinta OKLCH 75, croma 0,008-0,011): quasi
   neutra, appena verso l'ambra. Non e' un ripiego elegante — sotto le card ci
   sono FOTOGRAFIE di camere, e un fondo saturo le tinge tutte del proprio colore.
   Il caldo appena accennato e' anche la scena giusta: le 22:40, una lampada, uno
   che decide dove dormire.

   RAPPORTI CALCOLATI, non stimati, sul fondo #13100D:
     ink #F5F4F1 17.24:1   ink-soft #B4B0AA 8.79:1   emerald-ink #80D3A4 10.63:1
     danger-ink #F89A8E 9.03:1   amber-ink #F2C476 11.68:1   star #F1C45E 11.55:1
     ink su ink-fill #36322C 11.58:1   bianco sulla pillola verde 5.24:1
   Le ventinove coppie misurate passano tutte AA; la piu' stretta e' il bianco sul
   blu, che sta a 5.50:1 in tutti e due i temi perche' il blu NON cambia.

   PERCHE' IL BLU RESTA IDENTICO. Un bottone e' una superficie chiusa: il
   contrasto del bianco col suo fondo non dipende dal colore della pagina, ed e'
   gia' verificato (5.50 / 8.02 / 11.22). Schiarirlo per "staccare di piu'" dal
   fondo scuro avrebbe abbassato il bianco sotto 4.5:1 — si sarebbe pagato in
   leggibilita' un problema che non c'era: sul fondo scuro il blu stacca gia' a
   3.34:1.
   ============================================================================ */

body.tb-mode-tripsback {
    /* Il testo si schiarisce, la superficie piena resta scura: e' il motivo per
       cui piu' su i due mestieri di --tb-ink sono diventati due token. */
    --tb-ink:            #F5F4F1;
    --tb-ink-hover:      #FFFFFF;
    --tb-ink-soft:       #B4B0AA;
    --tb-ink-fill:       #36322C;   /* piu' CHIARA del fondo: una superficie piena
                                       su fondo scuro sale, non scende. */
    --tb-ink-fill-hover: #46413B;

    /* Lo slab e il piede leggono --tb-ink-fill, quindi qui NON restano navy:
       diventano grafite anche loro, un gradino sopra la pagina. E' voluto. Un
       blocco blu saturo su una pagina calda non e' "il colore del marchio", e'
       un oggetto arrivato da un altro sito — e nel tema scuro sarebbe rimasto
       l'ultimo pezzo di quel navy da cui questa modalita' e' scappata. Il blu del
       marchio resta dove conta: sui bottoni. */
    --tb-bg:      #13100D;
    --tb-panel:   #211E1A;
    --tb-panel-2: #2E2A25;
    --tb-line:    rgb(255 255 255 / 13%);

    --tb-blue-soft:      #1E2941;
    /* Il blu si alza solo dove fa il TESTO. Calcolato: 7.11:1 sul fondo,
       5.98:1 sui pannelli, 4.87:1 sulla superficie piena — passa ovunque,
       e resta riconoscibile come il blu del marchio. */
    --tb-blue-ink:       #87AAFC;
    /* Sullo scuro lo spotlight e' un RIALZO, non uno sbiancamento: il testo
       secondario ci deve restare leggibile sopra. --tb-ink-soft su questo sta
       a 6.29:1 (calcolato), --tb-ink a 11.77:1. */
    /* Sale di un gradino sopra la barra, non scende al colore della pagina. */
    --tb-raise:          #3B3731;
    --tb-raise-shadow:   0 1px 2px rgb(0 0 0 / 35%), 0 10px 24px -12px rgb(0 0 0 / 60%);
    --tb-hero-glow:      #28241E;
    --tb-hero-glow-fade: rgb(40 36 30 / 0);

    /* Il cashback resta la cosa piu' viva della pagina, ma la pillola PIENA
       torna a essere verde scuro con il bianco sopra, come nel tema chiaro. Prima
       era l'opposto — verde acceso con il testo quasi nero — ed e' esattamente la
       forma del bottone "compra" di un exchange: la stessa pillola diceva due cose
       diverse nei due temi, e quella scura ne diceva una che non e' nostra.
       Calcolato: bianco su --tb-emerald-fill 5,24:1. */
    --tb-emerald:        #80D3A4;
    --tb-emerald-ink:    #80D3A4;
    --tb-emerald-soft:   #1C2F25;
    --tb-emerald-fill:   #297A55;
    --tb-emerald-fill-ink: #FFFFFF;

    --tb-danger:      #F4877A;
    --tb-danger-ink:  #F89A8E;
    --tb-danger-soft: #43201C;
    --tb-amber-ink:   #F2C476;
    --tb-amber-soft:  #3A2B11;
    --tb-star:        #F1C45E;

    /* Un'ombra nera su un fondo gia' scuro non si vede: quello che separa le
       superfici qui e' il filetto chiaro, e l'ombra serve solo a dare profondita'
       ai pochi oggetti che stanno davvero sopra il piano. */
    --tb-shadow: 0 1px 2px rgb(0 0 0 / 40%), 0 14px 34px -18px rgb(0 0 0 / 70%);
    --tb-scrim:  rgb(2 6 14 / 72%);

    background: var(--tb-bg);
    color: var(--tb-ink);
}

/* LE DUE ECCEZIONI, e non ce ne sono altre.

   1. Le superfici che erano BIANCHE per scritta esplicita (#fff / #FFFFFF nel
      CSS di pagina) e non attraverso --tb-bg. Sono la barra di ricerca, i suoi
      pannelli e le tendine: nate bianche perche' in tema chiaro il bianco su
      grigio chiaro e' il modo di dire "questo galleggia". In scuro devono dire
      la stessa cosa con l'altro estremo. */
body.tb-mode-tripsback .tb-search-form,
body.tb-mode-tripsback .tb-sb-shell,
body.tb-mode-tripsback .tb-sb-panel,
body.tb-mode-tripsback .tb-header,
body.tb-mode-tripsback .flatpickr-calendar,
body.tb-mode-tripsback .tb-ac-panel {
    background: var(--tb-panel);
    color: var(--tb-ink);
}
body.tb-mode-tripsback .tb-search-form { border: 1px solid var(--tb-line); }

/*  2. Le fotografie. Su fondo scuro le foto degli hotel "bucano" la pagina
       perche' sono l'unica cosa luminosa rimasta; un velo appena percettibile le
       riporta dentro l'atmosfera senza toccarne i colori. Si toglie in hover:
       chi sta guardando quella card la vuole vedere com'e'. */
body.tb-mode-tripsback .sr-media img,
body.tb-mode-tripsback .detail-gallery img {
    filter: brightness(0.94);
    transition: filter var(--tb-dur) var(--tb-ease), transform .3s var(--tb-ease);
}
body.tb-mode-tripsback .sr-card:hover .sr-media img,
body.tb-mode-tripsback .sr-card:focus-within .sr-media img {
    filter: none;
}
@media (prefers-reduced-motion: reduce) {
    body.tb-mode-tripsback .sr-media img,
    body.tb-mode-tripsback .detail-gallery img { transition: none; }
}

/* ============================================================================
   L'INTERRUTTORE DELLE DUE MODALITA'

   E' una <label> con dentro una checkbox vera, non un div con un onclick: cosi'
   la barra spaziatrice la commuta, il focus si vede, i lettori di schermo la
   annunciano come "casella di controllo, selezionata", e SOPRATTUTTO il form la
   spedisce da sola. Senza JavaScript la modalita' funziona lo stesso.

   Il trucco del campo nascosto prima della checkbox: due campi con lo STESSO
   nome, e PHP tiene l'ultimo che arriva. Checkbox spenta -> parte solo il campo
   nascosto ('normale'); accesa -> parte anche lei e vince ('tripsback'). E' il
   modo classico di far dire "no" a una checkbox, che altrimenti quando e' spenta
   non dice niente.
   ============================================================================ */

/* IL GUSCIO. Tiene insieme interruttore, barra e importi rapidi senza che
   nessuno dei tre entri dentro la pillola. In testata non ha righe da impilare e
   non deve toccare niente: li' e' trasparente al layout (display: contents), cosi'
   .tb-header-search-wrap continua a vedere il form come suo figlio diretto e le
   sue misure restano quelle di sempre. */
.tb-searchbar-wrap { display: contents; }
.tb-searchbar-wrap.is-hero {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--tb-s-3);
    width: 100%;
}

.tb-mode {
    display: flex;
    align-items: center;
    gap: var(--tb-s-3);
    flex-wrap: wrap;
}
.tb-mode-switch {
    display: inline-flex;
    align-items: center;
    gap: 11px;
    cursor: pointer;
    user-select: none;
    padding: 7px 14px 7px 8px;
    border-radius: var(--tb-r-pill);
    border: 1px solid var(--tb-line);
    background: var(--tb-bg);
    transition: border-color var(--tb-dur) var(--tb-ease), background var(--tb-dur) var(--tb-ease);
    /* L'area toccabile minima non e' negoziabile: sotto i 44px sul telefono si
       manca l'interruttore e si finisce nella modalita' sbagliata. */
    min-height: var(--tb-touch);
}
.tb-mode-switch:hover { border-color: var(--tb-emerald); }
/* Anche il binario si accende. Prima rispondeva solo la cornice esterna, cioe'
   la parte che NON sembra il comando: il pollice va sull'interruttore e il
   feedback compariva a otto pixel di distanza. */
.tb-mode-switch:hover .tb-mode-track { border-color: var(--tb-emerald); }
.tb-mode-switch:hover .tb-mode-check:checked + .tb-mode-track { filter: brightness(1.08); }
.tb-mode-switch:active .tb-mode-track { transform: scale(0.96); }

/* La checkbox vera resta SOPRA il binario, invisibile ma cliccabile e
   raggiungibile: nascosta con display:none sparirebbe dal flusso della
   tastiera, e con opacity:0 senza posizione resterebbe a occupare spazio. */
.tb-mode-check {
    position: absolute;
    width: 46px; height: 26px;
    margin: 0;
    opacity: 0;
    cursor: pointer;
}
.tb-mode-track {
    position: relative;
    flex: none;
    width: 46px; height: 26px;
    border-radius: var(--tb-r-pill);
    background: var(--tb-panel-2);
    border: 1px solid var(--tb-line);
    transition: background var(--tb-dur) var(--tb-ease),
                border-color var(--tb-dur) var(--tb-ease),
                filter var(--tb-dur-fast) var(--tb-ease),
                transform var(--tb-dur-fast) var(--tb-ease);
}
.tb-mode-knob {
    position: absolute;
    top: 2px; left: 2px;
    width: 20px; height: 20px;
    border-radius: 50%;
    background: #fff;
    box-shadow: 0 1px 3px rgb(14 26 51 / 35%);
    transition: transform var(--tb-dur) var(--tb-ease);
}
.tb-mode-check:checked + .tb-mode-track {
    background: var(--tb-emerald-fill);
    border-color: var(--tb-emerald-fill);
}
.tb-mode-check:checked + .tb-mode-track .tb-mode-knob { transform: translateX(20px); }
/* Il focus si prende sul binario, che e' la cosa che si vede: la checkbox e'
   trasparente e un anello intorno a lei sembrerebbe un anello intorno al nulla. */
.tb-mode-check:focus-visible + .tb-mode-track {
    outline: 2px solid var(--tb-blue);
    outline-offset: 2px;
}
@media (prefers-reduced-motion: reduce) {
    .tb-mode-knob, .tb-mode-track, .tb-mode-switch { transition: none; }
    /* La compressione alla pressione e' l'unica cosa che si toglie del tutto:
       senza transizione sarebbe uno scatto, e uno scatto e' peggio di niente. */
    .tb-mode-switch:active .tb-mode-track { transform: none; }
    .tb-budget-chip { transition: none; }
}

.tb-mode-text { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.tb-mode-title {
    font: var(--tb-t-label);
    color: var(--tb-ink);
    display: inline-flex; align-items: center; gap: 6px;
}
.tb-mode-title svg { width: 14px; height: 14px; flex: none; color: var(--tb-emerald-ink); }
.tb-mode-sub {
    font: var(--tb-t-caption);
    color: var(--tb-ink-soft);
}
/* Spenta, la riga non deve promettere niente: il fulmine verde e il sottotitolo
   raccontano il cashback, e con la modalita' spenta il cashback non c'e'. */
.tb-searchbar-wrap:has(.tb-mode-check:not(:checked)) .tb-mode-title svg { color: var(--tb-ink-soft); }

/* L'ATTESA FRA IL TOCCO E LA PAGINA NUOVA.

   Sulla lista dei risultati l'interruttore ricarica: per il tempo del viaggio al
   server la pagina resta quella di prima. Prima qui si ribaltava il tema subito,
   e si vedeva un chiaro incompleto — foto e mappa non prendono il colore da un
   token e restavano scure — su una pagina che stava per essere buttata via.
   Adesso non si ridipinge niente (vedi app.js): si smorza. La levetta si e'
   gia' mossa da sola; questo dice che il resto sta arrivando. */
body.tb-mode-attesa { cursor: progress; }
body.tb-mode-attesa main {
    opacity: .5;
    transition: opacity 160ms cubic-bezier(.22,1,.36,1);
    pointer-events: none;   /* un secondo tocco manderebbe due ricariche */
}
@media (prefers-reduced-motion: reduce) {
    body.tb-mode-attesa main { transition: none; }
}

/* ---- IL BUDGET A NOTTE ----------------------------------------------------
   Compare e sparisce con la modalita', in CSS e senza JavaScript: :has() legge
   la checkbox dallo stesso form. Il campo NON si disabilita quando e' nascosto —
   resta compilato, cosi' chi spegne e riaccende la modalita' ritrova la cifra
   che aveva scritto invece di riscriverla. In modalita' normale il server lo
   ignora comunque (tb_modalita_parametri).                                    */
/* Nell'hero risponde subito alla checkbox, senza JavaScript e senza aspettare
   l'invio. In testata la checkbox non c'e': li' la verita' e' la classe che il
   server ha messo su <body>, che e' la stessa cosa un istante dopo. */
.tb-searchbar-wrap:has(.tb-mode-check:not(:checked)) .tb-search-budget { display: none; }
body.tb-mode-normale .tb-top-search .tb-search-budget { display: none; }

/* L'occhiello del budget e' l'unico a due parole: senza questo va a capo e alza
   di dodici pixel tutta la barra, segmenti compresi. */
.tb-search-budget .tb-search-label { white-space: nowrap; }

.tb-budget-field {
    display: flex;
    align-items: center;
    gap: 4px;
}
.tb-budget-cur {
    font: var(--tb-t-body-strong);
    color: var(--tb-ink-soft);
    flex: none;
}
.tb-budget-input {
    width: 100%;
    min-width: 0;
    border: 0;
    background: transparent;
    padding: 0;
    font: var(--tb-t-body-strong);
    color: var(--tb-ink);
    /* Le frecce del number rubano larghezza a un campo che ne ha poca e non
       servono: qui si scrive una cifra, non si sale di uno alla volta. */
    appearance: textfield;
}
.tb-budget-input::-webkit-outer-spin-button,
.tb-budget-input::-webkit-inner-spin-button { appearance: none; margin: 0; }
.tb-budget-input:focus { outline: none; }
.tb-budget-input::placeholder { color: var(--tb-ink-soft); opacity: 1; }

/* Gli importi rapidi. Solo nell'hero: nella barra in testata la cifra e' gia'
   scelta e queste sei pillole ruberebbero la riga alla ricerca. */
.tb-budget-quick {
    display: flex;
    align-items: center;
    gap: var(--tb-s-2);
    flex-wrap: wrap;
    margin-top: var(--tb-s-3);
}
.tb-budget-quick-label {
    font: var(--tb-t-caption);
    color: var(--tb-ink-soft);
}
.tb-budget-chip {
    border: 1px solid var(--tb-line);
    background: var(--tb-bg);
    color: var(--tb-ink);
    border-radius: var(--tb-r-pill);
    padding: 7px 14px;
    font: var(--tb-t-button);
    cursor: pointer;
    min-height: 34px;
    transition: border-color var(--tb-dur-fast) var(--tb-ease), background var(--tb-dur-fast) var(--tb-ease);
}
.tb-budget-chip:hover { border-color: var(--tb-blue); background: var(--tb-blue-soft); }
/* LA CIFRA SCELTA. Prende la stessa superficie sollevata del segmento che la
   mostra (--tb-raise): la pillola e il campo dicono la stessa cosa, quindi si
   somigliano. Il filetto blu e' il segnale di "selezionato" che il sistema usa
   gia' sui campi col focus, non un colore nuovo.
   Prima usava --tb-ink-fill, cioe' il navy pieno: nel tema chiaro leggeva bene
   (scuro su bianco), nello scuro finiva a un passo dal fondo della pillola
   spenta e la selezione spariva. */
.tb-budget-chip[aria-pressed="true"] {
    background: var(--tb-raise);
    border-color: var(--tb-blue-ink);
    color: var(--tb-ink);
    box-shadow: inset 0 0 0 1px var(--tb-blue-ink);
    font-weight: 700;
}
.tb-budget-chip[aria-pressed="true"]:hover { background: var(--tb-raise); }
.tb-searchbar-wrap:has(.tb-mode-check:not(:checked)) .tb-budget-quick { display: none; }

/* Gli importi rapidi sul telefono. 34px col mouse vanno bene, col pollice no:
   stessa soglia delle altre pillole (--tb-touch), stessa media query.

   Sta QUI e non nel blocco condiviso piu' su, dove starebbe meglio in teoria:
   la regola base del chip e' scritta sopra queste righe, e a parita' di
   specificita' vince l'ultima. Messa la' non aveva alcun effetto — misurato:
   i chip restavano a 34px. */
@media (max-width: 860px) {
    .tb-budget-chip { min-height: var(--tb-touch); }
}
.tb-budget-quick { margin-top: 0; }

/* --- Il dialogo che chiede il budget dalla barra dei filtri --------------
   Riusa .tb-budget-quick / .tb-budget-chip / .tb-budget-field della barra: le
   pillole hanno gia' il loro gestore, e un secondo componente uguale sarebbe un
   secondo componente da tenere allineato. Qui cambia solo il contorno — nella
   barra il campo vive dentro un segmento che ha gia' il suo fondo, in un dialogo
   no, e un campo senza bordo non si vede che e' un campo. */
.tb-dialog-budget { width: min(520px, calc(100vw - 32px)); }   /* misurato: a 460 "€ 300" andava a capo da solo */
.tb-dialog-budget .tb-budget-quick { margin-top: 16px; }
/* Il minimo sta sull'INPUT, non sul riquadro: e' l'input la cosa che si tocca, e
   con il minimo sul riquadro restava alto 42 (44 meno i due bordi). */
.tb-dialog-budget .tb-budget-input { min-height: var(--tb-touch); }
.tb-dialog-budget .tb-budget-field {
    margin-top: 12px;
    padding: 0 13px;
    background: var(--tb-bg);
    border: 1px solid var(--tb-line);
    border-radius: var(--tb-r-btn);
    transition: border-color var(--tb-dur-fast) var(--tb-ease);
}
.tb-dialog-budget .tb-budget-field:focus-within { border-color: var(--tb-blue); }
.tb-dialog-budget .tb-budget-input {
    font: var(--tb-t-body);
    padding: 0;
    align-self: stretch;   /* il campo riempie il riquadro: 44px veri, non 24 */
}
/* Le pillole qui sono piu' alte che nella barra (34px). Non e' un'incoerenza per
   distrazione: nella barra sono una scorciatoia accanto a un campo, qui SONO la
   risposta alla domanda del dialogo, e un bersaglio da 34px in un modale e' il
   posto sbagliato dove risparmiare dieci pixel. 44 e' lo standard dichiarato in
   DESIGN.md; e' la barra a fare eccezione, non questo. */
.tb-dialog-budget .tb-budget-chip { min-height: var(--tb-touch); }
.tb-dialog-budget .tb-field-error { margin-top: 8px; }

/* ============================================================================
   STAMPA: il tema scuro non esiste sulla carta.

   La ricevuta e' il vero deliverable del prodotto (DESIGN.md, breakpoint
   `print`): l'utente la allega alla nota spese. Senza questo blocco, chi arriva
   alla ricevuta con la modalita' TripsBack accesa stampa testo chiaro su carta
   bianca — inchiostro sprecato e un documento illeggibile, scoperto solo dopo
   averlo stampato.

   Si rimettono i valori CHIARI, non si tolgono i token: le regole di componente
   leggono le variabili e tornano a posto da sole, comprese quelle delle pagine.
   ============================================================================ */
@media print {
    body.tb-mode-tripsback {
        --tb-ink:            #0E1A33;
        --tb-ink-hover:      #1C2C4E;
        --tb-ink-soft:       #566079;
        --tb-ink-fill:       #0E1A33;
        --tb-ink-fill-hover: #1C2C4E;
        --tb-bg:             #FFFFFF;
        --tb-panel:          #F2F5FA;
        --tb-panel-2:        #E8EDF6;
        --tb-line:           #E2E7F0;
        --tb-blue-soft:      #EAF0FF;
        --tb-emerald:        #0E9E6E;
        --tb-emerald-ink:    #0B7E58;
        --tb-emerald-soft:   #E4F6EF;
        --tb-emerald-fill:   #0B7E58;
        --tb-emerald-fill-ink: #FFFFFF;
        --tb-danger:         #C0392B;
        --tb-danger-ink:     #A4271B;
        --tb-danger-soft:    #FCE8E6;
        --tb-amber-ink:      #8A5A00;
        --tb-amber-soft:     #FFF4E0;
        --tb-star:           #966400;
        --tb-hero-glow:      #EAF0FA;
        --tb-hero-glow-fade: rgb(234 240 250 / 0);
        --tb-blue-ink:       #2455FF;
        --tb-raise:          #FFFFFF;
        --tb-raise-shadow:   none;
        background: #FFFFFF;
        color: var(--tb-ink);
    }
    /* Il velo sulle foto e' un accorgimento da schermo: sulla carta toglie
       soltanto inchiostro alle uniche immagini del documento. */
    body.tb-mode-tripsback .sr-media img,
    body.tb-mode-tripsback .detail-gallery img { filter: none; }
}
