/**
 * V1.40 — Public App del visitatore.
 *
 * Stessi token Hearth dell'admin, ma niente shell gestionale: la mappa
 * occupa il viewport e tutto il resto ci galleggia sopra.
 */

/* ---------- catena delle altezze ----------

   Deterministica dall'alto: html e body hanno un'altezza esplicita, il
   root del visitatore ci si aggancia, e da li in giu' e' tutto
   `position: absolute; inset: 0`. Nessun `height: 100%` appeso a un
   parent che l'altezza non ce l'ha.                                    */

html, body { height: 100%; }

body {
  margin: 0;
  overflow: hidden;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-ui);
}

/* Il root riempie il contenitore che gli tocca: il viewport sulla pagina
   pubblica, il frame sulla preview admin. */
.visitor {
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden;
}

/* V1.41b — la pagina PUBBLICA e' sempre viewport intero, su ogni
   larghezza: niente colonna centrata, niente max-width, niente margini.
   Il vincolo eventuale del frame vive sotto `.visitor-preview` e non
   deve poter arrivare qui. */
.visitor-public .visitor {
  position: fixed;
  inset: 0;
  width: auto;
  height: auto;
  max-width: none;
  margin: 0;
}

/* ---------- mappa ---------- */

.visitor-map-stage {
  position: absolute;
  inset: 0;
}

.visitor-map { position: absolute; inset: 0; }

/* ---------- DOM interno di MapController ----------

   V1.52 — LA GEOMETRIA NON E' PIU' QUI.

   Radice, canvas MapLibre, piani e ancoraggio dei marker vivono una
   volta sola in `assets/css/map/map-core.css`, che questa pagina carica
   prima di questo file; le misure dei marker in `map/map-markers.css`.

   Fino alla V1.51b le stesse regole erano copiate qui, in
   public-preview.css, in brochure.css e nell'editor. Quattro copie
   della stessa geometria vogliono dire che cancellarne una non produce
   nessun errore: solo una mappa che non si vede. E' successo.

   Qui restano soltanto le decisioni VISIVE del visitatore.
   ---------------------------------------------------------------- */

.visitor,
.visitor-preview {
  --map-canvas-bg: #F2F0E9;
  --map-marker-size: 30px;
  --map-marker-icon-size: 18px;
  --map-marker-dot-size: 9px;
  /* Il raggio non si dichiara piu' qui: il marker e' una goccia, e la
     sua silhouette appartiene a `map/map-markers.css`. Una pagina che
     la ritoccava otteneva un quadrato con una scheggia sotto. */
  --map-marker-bg: rgba(255, 255, 255, .97);
  --map-marker-shadow: 0 5px 12px rgba(36, 49, 42, .16);
  --map-cluster-size: 31px;
  --map-spider-color: rgba(36, 49, 42, .30);
  /* Il controller raster posiziona la piastrellatura da se'. */
  --map-tiles-inset: auto;
}

/* Fallback raster (map-controller-raster.js): posizione e dimensioni le
   gestisce il controller, per coprire la diagonale quando la mappa e'
   ruotata. Il CSS da' solo il colore di fondo. */
.native-map-tiles { background: #EEEDE8; }

/* Il ritocco cromatico della basemap: la cartografia sta sotto il
   contenuto, non ci compete. */
.native-map-tile { filter: saturate(.62) brightness(1.055) contrast(.91); }

/* I comandi della mappa sulla pagina pubblica sono quelli di
   VisitorApp (`.visitor-map-controls`). Non serve nasconderli: questa
   pagina non carica map/map-controls.css, e il core li tiene spenti. */

/* ---------- marker ----------

   V1.52 — posizionamento e misure arrivano da map/map-core.css e
   map/map-markers.css; le misure le sceglie il blocco di variabili in
   cima a questo file. Qui restano le sole differenze del visitatore.
   ---------------------------------------------------------------- */

/* Sulla mappa pubblica un marker si tocca per aprirlo: non si trascina. */
.native-point-marker { cursor: pointer; }

/*
  La selezione NON ingrandisce e non solleva.

  `scale(1.06)` cresceva intorno al centro del corpo, e la punta —
  che sta sotto — scendeva con lui: selezionare uno stand lo spostava
  di un pixel dalla sua coordinata. La punta e' un contratto, non un
  dettaglio estetico. Il cerchio della selezione lo da' gia'
  `map-markers.css`, e non tocca la geometria.
*/

/* Il cluster: misura e forma dal contratto, qui solo il colore. */
.festamap-cluster-marker {
  background: var(--text);
  color: white;
  box-shadow: 0 5px 13px rgba(36, 49, 42, .20);
}

.festamap-cluster-marker strong { font-size: 9px; }
.festamap-cluster-marker span { display: none; }

/* L'attribuzione OSM resta — e' dovuta — e la sua geometria e' del
   core: qui solo dove sta e come si vede su questa superficie. */
.visitor,
.visitor-preview {
  --map-attribution-right: 8px;
  --map-attribution-bottom: calc(7px + env(safe-area-inset-bottom, 0px));
  --map-attribution-padding: 3px 5px;
  --map-attribution-radius: 6px;
  --map-attribution-bg: rgba(255, 255, 255, .82);
  --map-attribution-color: #69736C;
  --map-attribution-size: 8px;
}

/* V1.60 — la posizione la tiene l'AdvancedMarkerElement che lo ospita:
   qui resta solo come si vede. Il margine negativo serviva a centrarlo
   su coordinate scritte a mano, che non esistono piu'. */
.map-user-position {
  width: 18px;
  height: 18px;
  border: 3px solid #fff;
  border-radius: 50%;
  background: var(--hearth-blue);
  box-shadow: 0 0 0 4px rgba(49, 91, 255, .22);
  pointer-events: none;
}

.visitor-map-controls {
  position: absolute;
  right: 12px;

  /* `--visitor-dock` e' l'altezza misurata della superficie del
     Programma: i comandi salgono di quel tanto, e non ci finiscono
     sotto. Zero quando non c'e'. */
  bottom: calc(16px + var(--visitor-dock, 0px) + env(safe-area-inset-bottom, 0px));
  z-index: 6;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.visitor-map-button {
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: rgba(255, 253, 248, .95);
  color: var(--text);
  font-size: 17px;
  font-weight: 800;
  cursor: pointer;
  box-shadow: var(--shadow-soft);
}

.visitor-map-button:disabled { opacity: .55; }

.visitor-map-empty {
  position: absolute;
  left: 50%;
  bottom: 96px;
  z-index: 5;
  transform: translateX(-50%);
  padding: 9px 14px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: rgba(255, 253, 248, .96);
  font-size: 12px;
  font-weight: 700;
  box-shadow: var(--shadow-soft);
}

/* ====================================================================
   SITO IN ARRIVO

   Una pagina sola, centrata, su carta: chi arriva dal QR di una
   locandina deve capire in due secondi di essere nel posto giusto e che
   deve tornare. Niente mappa sotto, niente comandi: non c'e' ancora
   niente da comandare.
   ==================================================================== */
/*
  IL CARTELLO SCORRE, LA MAPPA NO.

  `.visitor` e' il guscio di un'applicazione di mappa: `position: fixed`
  e `overflow: hidden`, perche' una mappa occupa lo schermo e non si
  scorre. Questa pagina pero' non e' una mappa, e' un documento: con la
  copertina, un nome lungo e due paragrafi supera l'altezza di un
  telefono, e dentro quel guscio restava tagliata senza modo di
  arrivare in fondo.

  Quindi si scorre QUI DENTRO, senza toccare il guscio: la mappa
  continua a non scorrere, come deve.

  `margin: auto` su un figlio flex, e non `place-items: center`: il
  centraggio per allineamento, quando il contenuto e' piu' alto del
  contenitore, taglia la parte di SOPRA e la rende irraggiungibile —
  si scorre e non si torna mai al titolo. Con `margin: auto` il
  contenuto resta centrato finche' ci sta, e appena non ci sta parte
  dall'alto e scorre tutto.
*/
.visitor-soon {
  position: absolute;
  inset: 0;
  display: flex;
  overflow-y: auto;
  padding: 28px 20px calc(28px + env(safe-area-inset-bottom, 0px));
  -webkit-overflow-scrolling: touch;
}

.visitor-soon-body {
  max-width: 34rem;
  margin: auto;
  text-align: center;
}

/* La copertina dell'evento: la stessa immagine della locandina da cui
   si arriva. Larga quanto il testo, non a tutta pagina: e' un
   riferimento, non una vetrina. */
.visitor-soon-cover {
  overflow: hidden;
  margin: 0 0 22px;
  border-radius: var(--radius-md);
  background: var(--surface-soft);
}

/*
  V1.74 — IL RIQUADRO NON IMPONE UNA FORMA.

  Qui dentro arriva una locandina, e una locandina e' quasi sempre
  verticale: un rettangolo 16/9 le avrebbe tagliato la testa e i piedi
  proprio nella pagina che serve a farla riconoscere. La forma la porta
  l'immagine — `.media-slot` la scrive in `--media-aspect` appena il
  file e' arrivato — e il tetto in altezza impedisce a una locandina
  molto stretta di spingere il titolo sotto la piega.
*/
.visitor-soon-cover .media-slot { max-height: 52vh; }

.visitor-soon-kicker {
  display: block;
  color: var(--muted);
  font-size: 11px;
  font-weight: 800;
  letter-spacing: .12em;
  text-transform: uppercase;
}

.visitor-soon-title {
  margin: 10px 0 0;
  font-family: var(--font-display);
  font-size: 30px;
  line-height: 1.1;
}

.visitor-soon-facts {
  margin: 10px 0 0;
  color: var(--text);
  font-size: 13px;
  font-weight: 700;
}

.visitor-soon-text {
  margin: 18px 0 0;
  font-size: 15px;
  line-height: 1.55;
}

.visitor-soon-note {
  margin: 22px 0 0;
  padding-top: 18px;
  border-top: 1px solid var(--line);
  color: var(--muted);
  font-size: 13px;
  line-height: 1.5;
}

/* ---------- barra superiore ---------- */

.visitor-top {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  z-index: 8;
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: calc(10px + env(safe-area-inset-top, 0px)) 12px 10px;
  background: linear-gradient(
    to bottom,
    rgba(255, 248, 227, .97) 62%,
    rgba(255, 248, 227, 0)
  );
  pointer-events: none;
}

.visitor-top > * { pointer-events: auto; }

.visitor-title-row {
  display: flex;
  align-items: flex-start;
  gap: 10px;
}

.visitor-title { min-width: 0; flex: 1; }

.visitor-title h1 {
  margin: 0;
  font-family: var(--font-display);
  font-size: 19px;
  line-height: 1.15;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.visitor-subtitle {
  margin: 2px 0 0;
  color: var(--muted);
  font-size: 11px;
  font-weight: 700;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.visitor-title-actions {
  flex: none;
  display: flex;
  gap: 6px;
}

.visitor-chip-button {
  min-height: 32px;
  padding: 6px 11px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: rgba(255, 255, 255, .96);
  color: var(--text);
  font-size: 11px;
  font-weight: 800;
  cursor: pointer;
}

.visitor-search { position: relative; }

.visitor-search-input {
  width: 100%;
  min-height: 42px;
  padding: 11px 38px 11px 14px;
  border: 1px solid var(--line);
  border-radius: 999px;
  outline: 0;
  background: rgba(255, 255, 255, .97);
  color: var(--text);
  font-size: 14px;
  box-shadow: var(--shadow-soft);
}

.visitor-search-input:focus {
  border-color: var(--hearth-red);
  box-shadow: 0 0 0 3px rgba(244, 77, 65, .1);
}

.visitor-search-clear {
  position: absolute;
  top: 50%;
  right: 8px;
  width: 28px;
  height: 28px;
  transform: translateY(-50%);
  border: 0;
  border-radius: 50%;
  background: var(--line);
  color: var(--text);
  font-size: 15px;
  line-height: 1;
  cursor: pointer;
}

.visitor-filters {
  display: flex;
  gap: 6px;
  overflow-x: auto;
  padding-bottom: 2px;
  scrollbar-width: none;
}

.visitor-filters::-webkit-scrollbar { display: none; }

.visitor-chip {
  flex: none;
  min-height: 30px;
  padding: 5px 11px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: rgba(255, 255, 255, .95);
  color: var(--text);
  font-size: 11px;
  font-weight: 800;
  white-space: nowrap;
  cursor: pointer;
}

.visitor-chip.is-active {
  border-color: var(--hearth-ink);
  background: var(--hearth-ink);
  color: var(--hearth-cream);
}

.visitor-chip-reset {
  border-style: dashed;
  color: var(--muted);
}

.visitor-chip-divider {
  flex: none;
  width: 1px;
  margin: 4px 2px;
  background: var(--line-strong);
}

/* ---------- risultati ricerca ---------- */

/*
  V1.70 — I RISULTATI STANNO SOTTO IL CAMPO, NON A UNA MISURA DAL BORDO.

  Erano collocati con `top: 148px` — piu' altre due misure diverse per
  desktop e orizzontale — che indovinavano l'altezza della testata. Ma
  quell'altezza cambia: un nome lungo va a capo, il notch di un telefono
  spinge la barra piu' in basso, il testo ingrandito la allunga. Quando
  cresceva, questo pannello bianco restava fermo e finiva sopra il
  titolo dell'evento.

  Adesso e' figlio della riga di ricerca, che e' `position: relative`:
  `top: 100%` vuol dire "appena sotto il campo", e vale su ogni
  schermo senza che nessuno debba aggiornare un numero.
*/
.visitor-results {
  position: absolute;
  left: 0;
  right: 0;
  top: calc(100% + 8px);
  z-index: 7;
  max-height: min(48vh, 420px);
  overflow-y: auto;
  padding: 8px;
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  background: rgba(255, 253, 248, .98);
  box-shadow: var(--shadow);
}

.visitor-results-head,
.visitor-results-more {
  padding: 4px 8px;
  color: var(--muted);
  font-size: 10px;
  font-weight: 800;
  letter-spacing: .06em;
  text-transform: uppercase;
}

.visitor-results-empty {
  margin: 0;
  padding: 14px 8px;
  color: var(--muted);
  font-size: 13px;
}

.visitor-results-list {
  margin: 0;
  padding: 0;
  list-style: none;
}

.visitor-result {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 9px 8px;
  border: 0;
  border-radius: 12px;
  background: transparent;
  color: inherit;
  text-align: left;
  cursor: pointer;
}

.visitor-result:hover,
.visitor-result:focus-visible { background: var(--surface-soft); }

.visitor-result-number {
  flex: none;
  width: 30px;
  height: 30px;
  display: grid;
  place-items: center;
  border-radius: 10px;
  background: var(--hearth-ink);
  color: var(--hearth-cream);
  font-size: 11px;
  font-weight: 900;
}

.visitor-result-body { min-width: 0; }
.visitor-result-body strong { display: block; font-size: 13px; }

.visitor-result-body small {
  display: block;
  color: var(--muted);
  font-size: 11px;
}

/* ---------- dettaglio: bottom sheet mobile ---------- */

/*
  V1.63 — LA SCHEDA E' ALTA QUANTO IL SUO CONTENUTO.

  Fino a qui era `height: 95dvh` per tutte: uno stand con tre righe di
  descrizione occupava lo schermo quasi intero, con sotto una distesa di
  vuoto, e la mappa spariva comunque.

  Ora l'altezza la decide il contenuto, e il tetto e' il limite oltre il
  quale la scheda smette di crescere e comincia a scorrere dentro di se'.
  E' la differenza fra una scheda che si adatta e un pannello che copre.

  `height: auto` piu' `max-height` e' la regola; `height` non torna.
*/
.visitor-sheet {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 20;
  height: auto;
  max-height: 88dvh;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  border-radius: 24px 24px 0 0;
  background: var(--surface);
  box-shadow: 0 -18px 44px rgba(17, 17, 17, .18);
  transform: translateY(100%);

  /*
    Il fondo non finisce sotto la barra di sistema dei telefoni senza
    tasto: l'ultima riga di una scheda e' spesso la sua azione.
  */
  padding-bottom: env(safe-area-inset-bottom, 0px);

  /*
    Si anima la posizione, non l'altezza. Una transizione su `height`
    con `auto` non parte, e su `max-height` produrrebbe uno scatto
    quando il contenuto cambia: la scheda cresce e basta.
  */
  transition: transform .24s ease;
}

.visitor-sheet.is-open { transform: translateY(0); }

/* Trascinata in alto dalla maniglia: puo' arrivare a tutto lo schermo. */
.visitor-sheet.is-expanded { max-height: 100dvh; }

/* V1.42b — nessuna fascia dedicata sopra la hero.
   Il chrome resta sticky (cosi maniglia e chiusura restano raggiungibili
   scorrendo) ma non occupa spazio nel flusso: alto 0, con i suoi
   elementi in overlay. Prima erano 34px di fondo opaco che spingevano
   giu l'immagine. */
.visitor-sheet-chrome {
  position: sticky;
  top: 0;
  z-index: 3;
  height: 0;
  min-height: 0;
  overflow: visible;
  background: none;
}

.visitor-sheet-handle {
  position: absolute;
  top: 8px;
  left: 50%;
  transform: translateX(-50%);
  width: 42px;
  height: 4px;
  border-radius: 999px;
  /* Sopra una foto scura la maniglia deve restare leggibile. */
  background: rgba(255, 253, 248, .85);
  box-shadow: 0 1px 4px rgba(17, 17, 17, .28);
}

/* Overlay sopra la hero: e' cio' che permette di togliere la fascia.
   Fondo cream semi-opaco + ombra, cosi ha contrasto sia su foto chiare
   sia su foto scure. */
.visitor-sheet-close {
  position: absolute;
  top: 8px;
  right: 10px;
  /* Sopra il contenuto: copertine e hero sono .media-slot posizionati e,
     venendo dopo nel DOM, coprirebbero il bottone. */
  z-index: 3;
  width: 32px;
  height: 32px;
  border: 1px solid rgba(231, 222, 200, .9);
  border-radius: 50%;
  background: rgba(255, 253, 248, .92);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  box-shadow: 0 2px 10px rgba(17, 17, 17, .18);
  color: var(--text);
  font-size: 17px;
  line-height: 1;
  cursor: pointer;
}

/* Senza hero il testo partirebbe sotto il bottone che galleggia. */
.visitor-sheet-body:not(.has-hero) .visitor-detail-content { padding-top: 48px; }

.visitor-hero { background: var(--surface-soft); }

.visitor-detail-content { padding: 14px 18px 4px; }

.visitor-detail-kicker {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin-bottom: 6px;
  color: var(--hearth-red);
  font-size: 10px;
  font-weight: 900;
  letter-spacing: .1em;
  text-transform: uppercase;
}

.visitor-detail-number {
  padding: 2px 7px;
  border-radius: 999px;
  background: var(--hearth-ink);
  color: var(--hearth-cream);
  letter-spacing: .04em;
}

.visitor-status {
  padding: 2px 8px;
  border-radius: 999px;
  letter-spacing: .04em;
}

.visitor-status.is-live { background: var(--sage); color: var(--sage-strong); }
.visitor-status.is-soon { background: var(--hearth-red-soft); color: var(--hearth-red); }
.visitor-status.is-ended { background: var(--line); color: var(--muted); }

.visitor-detail-title {
  margin: 0 0 8px;
  font-family: var(--font-display);
  font-size: 24px;
  line-height: 1.15;
}

.visitor-detail-description {
  margin: 0 0 14px;
  font-size: 15px;
  line-height: 1.55;

  /*
    GLI A CAPO CHE L'ORGANIZZATORE HA SCRITTO SONO CONTENUTO.

    La descrizione arriva da un campo di testo libero, e chi la compila
    ci mette righe separate ed elenchi puntati: "• Antipasto", a capo,
    "• Primo". Il DOM li conserva — il testo entra con `textContent` —
    ma `white-space: normal` li collassa in spazi, e sulla scheda
    pubblicata l'elenco tornava una frase unica.

    `pre-line` e non `pre-wrap`: tiene gli a capo, ma continua a
    collassare le sequenze di spazi e a mandare a capo da solo. Una
    doppia spaziatura battuta per sbaglio non deve aprire un buco, e
    una riga lunga deve continuare ad andare a capo dentro la scheda.
  */
  white-space: pre-line;
}

.visitor-block {
  padding: 12px 0;
  border-top: 1px solid var(--line);
}

.visitor-block h3 {
  margin: 0 0 6px;
  color: var(--muted);
  font-size: 10px;
  font-weight: 900;
  letter-spacing: .1em;
  text-transform: uppercase;
}

.visitor-block p { margin: 0 0 4px; font-size: 14px; line-height: 1.5; }

/*
  V1.76 — il box prenotazione della categoria.

  L'altezza di partenza e' una stima: il documento dentro misura se
  stesso e la corregge (vedi `buildEmbed` in visitor-app.js). Serve
  comunque, perche' fra l'apertura della scheda e la prima misura un
  iframe senza altezza sarebbe una riga vuota, e il widget sembrerebbe
  non essersi caricato.
*/
.visitor-embed {
  display: block;
  width: 100%;
  height: 320px;
  margin-top: 8px;
  border: 0;
  background: transparent;
}

.visitor-menu { margin: 4px 0 0; padding: 0; list-style: none; }
.visitor-menu li { padding: 7px 0; border-bottom: 1px dashed var(--line); }
.visitor-menu li:last-child { border-bottom: 0; }

.visitor-menu-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  font-size: 14px;
}

.visitor-menu-price { flex: none; font-weight: 800; }
.visitor-menu small { color: var(--muted); font-size: 12px; }

/*
  V1.89 — UNA DEFINIZIONE SOLA.

  `.visitor-action` era scritta due volte in questo stesso foglio: qui
  la forma (pastiglia in linea, centrata verticalmente) e piu' sotto,
  fra le azioni del Programma, la misura. La seconda vinceva su cio'
  che le due dichiaravano insieme e lasciava il resto alla prima —
  compreso l'allineamento orizzontale, che nessuna delle due diceva.
  Risultato: un bottone largo con il testo appoggiato a sinistra.

  Adesso e' una regola sola, e il testo sta in mezzo.
*/
.visitor-action {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 42px;
  flex: 1 1 auto;

  /*
    Il margine serve alle azioni del dettaglio, che stanno nel flusso
    normale una accanto all'altra; quelle del Programma vivono in una
    riga flex con il proprio `gap` e lo sommano, come hanno sempre
    fatto.
  */
  margin: 8px 8px 0 0;
  padding: 0 18px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
  color: var(--text);
  font: inherit;
  font-size: 14px;
  font-weight: 800;
  cursor: pointer;
}

.visitor-gallery { padding: 12px 18px calc(24px + env(safe-area-inset-bottom, 0px)); }

.visitor-gallery-title {
  margin-bottom: 8px;
  color: var(--muted);
  font-size: 10px;
  font-weight: 900;
  letter-spacing: .1em;
  text-transform: uppercase;
}

.visitor-gallery-strip {
  display: flex;
  gap: 10px;
  overflow-x: auto;
  padding-bottom: 4px;
}

.visitor-gallery-item {
  flex: none;
  width: 150px;
  border-radius: var(--radius-sm);
  overflow: hidden;
}

/* ---------- info evento ---------- */

.visitor-info {
  position: fixed;
  inset: auto 0 0 0;
  z-index: 22;
  max-height: 88dvh;
  overflow-y: auto;
  border-radius: 24px 24px 0 0;
  background: var(--surface);
  box-shadow: 0 -18px 44px rgba(17, 17, 17, .18);
}

/* Stessa barra sticky della sheet di dettaglio: tiene il bottone di
   chiusura sopra la copertina e lo lascia raggiungibile anche a
   pannello scorso. */
.visitor-info-chrome {
  position: sticky;
  top: 0;
  z-index: 2;
  min-height: 34px;
}

.visitor-info-cover { background: var(--surface-soft); }
.visitor-info-body { padding: 16px 18px calc(26px + env(safe-area-inset-bottom, 0px)); }

.visitor-info-body h2 {
  margin: 0 0 6px;
  font-family: var(--font-display);
  font-size: 22px;
}

.visitor-info-meta {
  margin: 0 0 3px;
  color: var(--muted);
  font-size: 12px;
  font-weight: 700;
}

.visitor-info-body p { font-size: 14px; line-height: 1.55; }

/* ---------- stato iniziale ---------- */

.visitor-placeholder {
  display: grid;
  gap: 12px;
  padding: 22px;
  height: 100%;
  align-content: start;
}

.visitor-placeholder-bar,
.visitor-placeholder-map {
  border-radius: var(--radius-md);
  background: linear-gradient(
    100deg,
    var(--surface-soft) 30%,
    var(--line) 50%,
    var(--surface-soft) 70%
  );
  background-size: 220% 100%;
  animation: visitorShimmer 1.4s linear infinite;
}

.visitor-placeholder-bar { height: 54px; }
.visitor-placeholder-map { height: min(60vh, 460px); }

@keyframes visitorShimmer {
  from { background-position: 140% 0; }
  to { background-position: -40% 0; }
}

@media (prefers-reduced-motion: reduce) {
  .visitor-placeholder-bar,
  .visitor-placeholder-map { animation: none; }
  .visitor-sheet { transition: none; }
}

.visitor-missing .visitor-placeholder {
  place-content: center;
  text-align: center;
}

.visitor-missing h1 {
  margin: 0 0 8px;
  font-family: var(--font-display);
  font-size: 26px;
}

.visitor-missing p { margin: 0; color: var(--muted); font-size: 14px; }

/* ---------- navigazione verso un elemento (V1.42b) ---------- */

.visitor-nav-cta {
  width: 100%;
  min-height: 46px;
  margin: 0 0 12px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  border: 0;
  border-radius: 14px;
  background: var(--accent);
  color: #FFFFFF;
  font-family: var(--font-ui);
  font-size: 14px;
  font-weight: 800;
  cursor: pointer;
  box-shadow: var(--shadow-soft);
}

.visitor-nav-cta:active { transform: translateY(1px); }

/* La navigazione a piedi ha senso col telefono in mano: su desktop la
   CTA sparisce invece di promettere una cosa che li non serve. */
@media (min-width: 681px) {
  .visitor-nav-cta { display: none; }
}

.visitor-nav-card {
  position: fixed;
  left: 12px;
  right: 12px;
  top: calc(12px + env(safe-area-inset-top, 0px));
  z-index: 26;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: 16px;
  background: rgba(255, 253, 248, .97);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  box-shadow: var(--shadow);
}

.visitor-nav-card.is-error { border-color: var(--accent-soft); }

.visitor-nav-text {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.visitor-nav-text strong {
  overflow: hidden;
  font-size: 13px;
  font-weight: 800;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.visitor-nav-meta { color: var(--muted); font-size: 12px; font-weight: 600; }

.visitor-nav-actions { display: flex; gap: 6px; }

.visitor-nav-recenter,
.visitor-nav-stop {
  min-height: 34px;
  padding: 0 12px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
  color: var(--text);
  font-family: var(--font-ui);
  font-size: 12px;
  font-weight: 800;
  cursor: pointer;
}

.visitor-nav-stop {
  border-color: transparent;
  background: var(--accent-soft);
  color: var(--accent);
}

/* Su desktop la card resta compatta a sinistra, come il resto della UI. */
@media (min-width: 681px) {
  .visitor-nav-card {
    left: 16px;
    right: auto;
    top: 16px;
    width: min(420px, 44vw);
  }
}

/* In landscape stretto la card non deve mangiarsi la mappa. */
@media (max-height: 460px) and (orientation: landscape) {
  .visitor-nav-card { padding: 7px 10px; }
  .visitor-nav-meta { font-size: 11px; }
}

/* ---------- toast ---------- */

.visitor-toast {
  position: fixed;
  left: 50%;
  bottom: calc(22px + env(safe-area-inset-bottom, 0px));
  z-index: 30;
  transform: translate(-50%, 12px);
  padding: 10px 15px;
  border-radius: 999px;
  background: var(--hearth-ink);
  color: var(--hearth-cream);
  font-size: 12px;
  font-weight: 700;
  opacity: 0;
  pointer-events: none;
  transition: opacity .18s ease, transform .18s ease;
}

.visitor-toast.is-visible { opacity: 1; transform: translate(-50%, 0); }

/* ---------- desktop: card flottante, mappa intera ---------- */

@media (min-width: 681px) {
  .visitor-top {
    left: 16px;
    right: auto;
    top: 16px;
    width: min(380px, 42vw);
    padding: 14px;
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    background: rgba(255, 253, 248, .97);
    box-shadow: var(--shadow);
  }

  .visitor-sheet {
    top: 16px;
    right: 16px;
    left: auto;
    bottom: 16px;
    width: min(400px, 38vw);
    height: auto;

    /* Su desktop la scheda e' un pannello laterale staccato dai bordi:
       il tetto tiene conto dei 16px sopra e sotto, cosi' un contenuto
       lungo scorre dentro invece di uscire dallo schermo. */
    max-height: calc(100dvh - 32px);
    border-radius: var(--radius-lg);
    transform: translateX(calc(100% + 24px));
  }

  .visitor-sheet.is-open { transform: translateX(0); }
  .visitor-sheet.is-expanded { max-height: calc(100dvh - 32px); }
  .visitor-sheet-handle { display: none; }

  .visitor-info {
    inset: 16px auto 16px 16px;
    width: min(420px, 44vw);
    max-height: calc(100dvh - 32px);
    border-radius: var(--radius-lg);
  }
}

/* ---------- landscape mobile: la mappa resta usabile ---------- */

@media (max-height: 460px) and (orientation: landscape) {
  .visitor-top { padding-top: 6px; padding-bottom: 6px; gap: 6px; }
  .visitor-title h1 { font-size: 15px; -webkit-line-clamp: 1; }
  .visitor-subtitle { display: none; }
  .visitor-results { max-height: 40dvh; }
  /* V1.63 — anche qui l'altezza la decide il contenuto. In orizzontale
     lo spazio verticale e' pochissimo, quindi il tetto e' l'intero
     schermo, ma una scheda corta resta corta. */
  .visitor-sheet,
  .visitor-sheet.is-expanded { max-height: 100dvh; }
}

/* ====================================================================
   IL PROGRAMMA

   Vive nella stessa superficie del pannello informazioni: e' lo stesso
   gesto — qualcosa che sale dal fondo e si chiude — e non merita un
   componente diverso. Qui c'e' solo cio' che le righe del programma
   hanno in piu': l'orario, lo stato e il colore dell'appuntamento.
   ==================================================================== */
/*
  Il pannello del Programma e' il pannello informazioni con un'altra
  etichetta ARIA: stessa superficie, stesso gesto. La classe esiste per
  poterlo riconoscere e per il giorno in cui i due si separeranno.
*/
.visitor-program { }

/*
  IL GIORNO E' UN'INTESTAZIONE, NON UNA CHIUSURA.

  Con lo stesso spazio sopra e sotto, "GIO 24 SET" sembrava la coda
  dell'elenco precedente invece della testa di quello dopo. La
  gerarchia la fa lo spazio: molto prima, poco dopo, e il filetto
  attaccato all'intestazione — non alle righe.
*/
/*
  La superficie dell'elenco e' quella condivisa `.visitor-info`: qui
  resta solo il nome con cui la si riconosce, perche' il foglio che
  sale dal fondo e' lo stesso del Programma e delle informazioni.
*/
.visitor-list { background: var(--surface); }

/*
  V1.83 — L'ELENCO HA LA STESSA FORMA DEL PROGRAMMA.

  Sono due elenchi sullo stesso bordo dello schermo, e devono leggersi
  uguali: le regole stanno scritte una volta e valgono per tutti e due.
  Due copie della stessa forma vogliono dire due posti in cui
  correggere la stessa spaziatura, e uno dei due resta indietro.
*/
.visitor-program-group,
.visitor-list-group {
  margin: 26px 0 0;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--line, rgba(17, 17, 17, .12));
  color: var(--text);
  font-size: 11px;
  font-weight: 800;
  letter-spacing: .12em;
  text-transform: uppercase;
}

/* La prima intestazione non ha niente sopra da cui staccarsi. */
.visitor-program-group:first-of-type,
.visitor-list-group:first-of-type { margin-top: 12px; }

/* Poco spazio fra l'intestazione e cio' che introduce: sono la stessa
   cosa, e devono leggersi insieme. */
.visitor-program-group + .visitor-program-row,
.visitor-list-group + .visitor-list-row { border-top: 0; }

.visitor-program-row,
.visitor-list-row {
  display: grid;
  width: 100%;
  gap: 2px;
  padding: 11px 0 12px;
  border: 0;
  border-top: 1px solid var(--line, rgba(17, 17, 17, .1));
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.visitor-program-row:hover,
.visitor-list-row:hover { background: var(--surface-soft); }

.visitor-program-head,
.visitor-list-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
}

.visitor-program-time {
  color: var(--muted);
  font-size: 12px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
}

/*
  Lo stato prende il colore dell'appuntamento — lo stesso della sua
  linea sulla mappa — solo quando sta accadendo. Colorare anche gli
  altri vorrebbe dire non mettere in evidenza niente.
*/
.visitor-program-state {
  color: var(--muted);
  font-size: 12px;
  font-weight: 800;
}

.visitor-program-state[data-status="live"],
.visitor-program-state[data-status="started"] {
  color: var(--program-color, var(--accent));
}

.visitor-program-state[data-status="ended"] { opacity: .5; }

.visitor-program-name,
.visitor-list-name {
  font-family: var(--font-display);
  font-size: 17px;
  font-weight: 700;
}

/*
  Il numero del banco: e' come lo si cerca sul posto — "il 14" — e
  nell'elenco deve venire prima del nome, non dopo.
*/
.visitor-list-number {
  flex: none;
  color: var(--muted);
  font-size: 12px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
}

/* La testata dell'elenco: il numero accanto al nome, non agli estremi
   come l'orario di un appuntamento. */
.visitor-list-head { justify-content: flex-start; }

.visitor-list-count {
  margin: 2px 0 0;
  color: var(--muted);
  font-size: 12px;
}

/*
  La riga e' una griglia, e una griglia prende per default la larghezza
  del contenuto: senza questo la descrizione lunga allargava la colonna
  invece di troncarsi, e usciva dal foglio.
*/
.visitor-list-row { grid-template-columns: minmax(0, 1fr); }

.visitor-list-note {
  margin: 2px 0 0;
  overflow: hidden;
  color: var(--muted);
  font-size: 13px;
  line-height: 1.4;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.visitor-program-where,
.visitor-program-estimate {
  margin: 2px 0 0;
  color: var(--muted);
  font-size: 12px;
  font-weight: 700;
}

.visitor-program-text {
  margin: 6px 0 0;
  font-size: 14px;
  line-height: 1.5;
}

.visitor-program-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 10px;
}

/* ====================================================================
   LE TAPPE DI UNA PROCESSIONE

   Una colonna di orari e una di nomi. Chi legge cerca UN'ORA — "a che
   ora passa da me?" — e gli orari incolonnati a sinistra si leggono
   tutti insieme; dietro al nome andrebbero cercati riga per riga.

   Nessun pallino, nessuna linea verticale disegnata: l'ordine lo dice
   gia' la sequenza, e una timeline decorativa qui aggiungerebbe solo
   inchiostro attorno a sei righe di testo.
   ==================================================================== */
/* I media dell'evento nelle Info: stessa grammatica della scheda di uno
   stand, perche' e' la stessa cosa — cio' che l'evento mostra di se'. */
.visitor-info-media {
  margin-top: 14px;
  border-radius: 12px;
  overflow: hidden;
}

/*
  QUANDO e IN CHE STATO stanno sulla stessa riga: rispondono alla stessa
  domanda, e separarli faceva leggere due volte lo stesso orario.
*/
.visitor-program-when-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin-top: 2px;
}

.visitor-program-when-row .visitor-program-detail-when { margin: 0; }

.visitor-stops { margin-top: 14px; }

.visitor-stop-list {
  display: grid;
  gap: 2px;
  margin: 6px 0 0;
  padding: 0;
  list-style: none;
}

.visitor-stop {
  display: grid;
  grid-template-columns: 4.6em minmax(0, 1fr);
  gap: 10px;
  padding: 7px 0;
  border-top: 1px solid var(--line);
}

.visitor-stop:first-child { border-top: 0; }

.visitor-stop-time {
  color: var(--muted);
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  line-height: 1.45;
}

.visitor-stop-body {
  display: grid;
  gap: 2px;
  min-width: 0;
}

.visitor-stop-name {
  font-size: 14px;
  font-weight: 600;
  line-height: 1.35;
}

/*
  IL CORTEO E' QUI. E' l'unica riga che cambia cosa si fa nei prossimi
  minuti, quindi e' l'unica che porta il colore della processione.
*/
.visitor-stop-state {
  color: var(--program-color, var(--muted));
  font-size: 12px;
  font-weight: 700;
}

/* Cio' che e' gia' passato resta leggibile ma arretra: non compete
   con la tappa verso cui il corteo sta andando. */
.visitor-stop[data-status="passed"] .visitor-stop-time,
.visitor-stop[data-status="passed"] .visitor-stop-name { opacity: .55; }

.visitor-stop-note {
  margin: 8px 0 0;
  color: var(--muted);
  font-size: 12px;
  line-height: 1.45;
}









@media (max-width: 420px) {
    }

/* ====================================================================
   IL PROGRAMMA DENTRO IL DETTAGLIO DI UN ELEMENTO

   Un appuntamento agganciato a questo luogo non ha un marker proprio,
   perche' coprirebbe il luogo. Si raggiunge da qui.
   ==================================================================== */
/* Il blocco del Programma dentro il dettaglio: righe fitte, senza il
   respiro fra paragrafi degli altri blocchi. */
.visitor-block-program p { margin: 0; }

/*
  QUANDO, POI COSA.

  In colonna e non affiancati: il titolo dell'appuntamento e' la cosa
  che si cerca, e in una riga a tre colonne finiva schiacciato fra la
  data a sinistra e lo stato a destra — piu' piccolo di entrambi, che
  e' l'opposto di cio' che conta.
*/
.visitor-program-line {
  display: grid;
  width: 100%;
  gap: 2px;
  padding: 10px 0;
  border: 0;
  border-bottom: 1px solid var(--line, rgba(17, 17, 17, .1));
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.visitor-program-line:last-child { border-bottom: 0; }

.visitor-program-line-time {
  color: var(--muted);
  font-size: 12px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
}

.visitor-program-line-name {
  font-family: var(--font-display);
  font-size: 16px;
  font-weight: 700;
}

.visitor-program-line-state {
  color: var(--muted);
  font-size: 11px;
  font-weight: 800;
}

.visitor-program-line-state[data-status="live"],
.visitor-program-line-state[data-status="started"] {
  color: var(--program-color, var(--accent));
}

/* ====================================================================
   LA SUPERFICIE DEL PROGRAMMA

   In fondo alla mappa, sopra il bordo inferiore. Due parti:

     BANNER    cosa accade adesso, o cosa sta per accadere. Si chiude.
     SOMMARIO  la porta al Programma. Non si chiude.

   Sta SOTTO la scheda di dettaglio (z 20) e sopra i comandi della
   mappa, che salgono di `--visitor-dock` per non finirci sotto.
   ==================================================================== */
.visitor-dock {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 18;
  display: grid;
  gap: 8px;

  /*
    Il fondo resta libero: li' Google disegna la propria attribuzione,
    e coprirla non e' una scelta di layout — e' una condizione d'uso
    della mappa.
  */
  padding: 0 12px calc(24px + env(safe-area-inset-bottom, 0px));
  pointer-events: none;
}

.visitor-dock > * { pointer-events: auto; }

/* --- banner ---------------------------------------------------------- */
.visitor-banner {
  display: grid;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: 16px;
  background: var(--surface, #FFFDF8);
  box-shadow: var(--shadow-soft);

  /* Due colonne: cio' che accade, e il comando. La terza era la X, e
     non c'e' piu' — chiudere lasciava una superficie a meta' che non
     corrispondeva a nessuno stato del programma. */
  grid-template-columns: 1fr auto;
}

/*
  In corso: un filetto sul fianco, del colore dell'appuntamento. Non un
  fondo pieno e non un battito — questa scheda sta sopra una mappa che
  si guarda camminando, e qualcosa che lampeggia in fondo allo schermo
  si nota una volta e poi disturba.
*/
.visitor-banner.is-live {
  border-left: 3px solid var(--program-color, var(--accent));
  padding-left: 10px;
}

.visitor-banner-body { display: grid; min-width: 0; gap: 1px; }

.visitor-banner-kicker {
  color: var(--muted);
  font-size: 10px;
  font-weight: 800;
  letter-spacing: .1em;
}

.visitor-banner.is-live .visitor-banner-kicker { color: var(--program-color, var(--accent)); }

.visitor-banner-title {
  overflow: hidden;
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 700;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.visitor-banner-meta {
  overflow: hidden;
  color: var(--muted);
  font-size: 12px;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.visitor-banner-action {
  min-height: 34px;
  padding: 0 14px;
  border: 0;
  border-radius: 999px;
  background: var(--ink, #151413);
  color: var(--paper, #FFFDF8);
  font: inherit;
  font-size: 12px;
  font-weight: 800;
  cursor: pointer;
}

/* --- sommario -------------------------------------------------------- */
.visitor-summary {
  display: flex;
  width: 100%;
  align-items: baseline;
  gap: 8px;
  padding: 9px 14px;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: rgba(255, 253, 248, .94);
  box-shadow: var(--shadow-soft);
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}

/*
  V1.83 — la riga dell'elenco quando sopra c'e' gia' il Programma: due
  superfici della stessa altezza si contendono lo stesso sguardo, e
  insieme mangiano la mappa.
*/
.visitor-summary.is-compact { padding: 7px 14px; }

.visitor-summary-count {
  flex: 0 0 auto;
  font-size: 12px;
  font-weight: 800;
}

.visitor-summary-next {
  overflow: hidden;
  flex: 1 1 auto;
  color: var(--muted);
  font-size: 12px;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.visitor-summary-cta {
  flex: 0 0 auto;
  margin-left: auto;
  color: var(--accent);
  font-size: 12px;
  font-weight: 800;
}

/* ====================================================================
   DESKTOP

   Non la stessa barra allargata a tutto schermo: una colonna stretta
   nell'angolo, accanto alla legenda. Su desktop la mappa e' grande e
   una fascia da bordo a bordo spreca lo spazio che la rende leggibile.
   ==================================================================== */
@media (min-width: 720px) {
  .visitor-dock {
    left: auto;
    right: 12px;
    width: min(380px, 36vw);
    padding-bottom: 16px;
  }

  /* Su desktop la superficie sta a destra: i comandi della mappa le
     stanno sopra, non sotto, e non serve alzarli. */
  .visitor-map-controls {
    bottom: calc(16px + var(--visitor-dock, 0px) + env(safe-area-inset-bottom, 0px));
  }

  }

/* ====================================================================
   IL DETTAGLIO DI UN SINGOLO APPUNTAMENTO

   Stessa scheda dello stand: sale dallo stesso bordo, si chiude allo
   stesso modo. Cambia cosa c'e' dentro, non dove si apre.
   ==================================================================== */
.visitor-program-eyebrow {
  color: var(--muted);
  font-size: 11px;
  font-weight: 800;
  letter-spacing: .12em;
  text-transform: uppercase;
}

.visitor-program-detail-when {
  margin: 6px 0 2px;
  color: var(--text);
  font-size: 13px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
}

/*
  V1.65 — LE PARTENZE di un appuntamento che si ripete.

  Sta sotto la riga del "quando", che parla della partenza che conta
  adesso, e dice le altre: gli orari incolonnati con la cifra tabulare,
  perche' si leggono confrontandoli, e i giorni sotto quando sono piu'
  di uno.
*/
.visitor-program-runs {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 8px;
  margin: 6px 0 0;
}

.visitor-program-runs-kicker {
  color: var(--muted);
  font-size: 11px;
  font-weight: 800;
  letter-spacing: .12em;
  text-transform: uppercase;
}

.visitor-program-runs-times {
  color: var(--text);
  font-size: 13px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
}

.visitor-program-runs-days {
  flex-basis: 100%;
  color: var(--muted);
  font-size: 12px;
  font-weight: 700;
}

.visitor-program-detail-meta {
  margin: 6px 0 0;
  color: var(--muted);
  font-size: 13px;
  font-weight: 700;
}

.visitor-program-detail .visitor-status { margin-top: 8px; }

/* --- PRESSO: la relazione, non un dato accanto a un altro ------------
   Un rettangolo tappabile con la freccia: si vede che porta da qualche
   parte prima di toccarlo. */
.visitor-venue-link {
  display: flex;
  width: 100%;
  align-items: center;
  gap: 8px;
  margin-top: 12px;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--surface-soft);
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.visitor-venue-link:hover { border-color: var(--text); }

.visitor-venue-kicker {
  flex: 0 0 auto;
  color: var(--muted);
  font-size: 12px;
  font-weight: 800;
}

.visitor-venue-name {
  overflow: hidden;
  flex: 1 1 auto;
  font-size: 14px;
  font-weight: 700;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* La freccia e' il verso della relazione: dall'appuntamento al luogo. */
.visitor-venue-link::after {
  content: '';
  width: 7px;
  height: 7px;
  flex: 0 0 auto;
  border-top: 2px solid var(--muted);
  border-right: 2px solid var(--muted);
  transform: rotate(45deg);
}

/* --- azioni: una principale, una di scorta --------------------------- */
.visitor-program-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 16px;
}

.visitor-action.is-primary {
  border-color: var(--ink, #151413);
  background: var(--ink, #151413);
  color: var(--paper, #FFFDF8);
}

.visitor-action:hover { border-color: var(--text); }


