/* ─────────────────────────────────────────────────────────────
   site.css — sistema di design di gabrieledifazio.com
   Estratto dallo <style> inline della home: stesso identico
   risultato visivo, ma il CSS e i font ora si possono mettere
   in cache e riusare su journal, pagine legali e back office.
   ───────────────────────────────────────────────────────────── */

@font-face {
  font-family: 'PPNueMontreal';
  src: url('/assets/fonts/PPNeueMontreal-Regular.woff2') format('woff2'),
       url('/assets/fonts/PPNeueMontreal-Regular.otf') format('opentype');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'PPNueMontreal';
  src: url('/assets/fonts/PPNeueMontreal-Medium.woff2') format('woff2'),
       url('/assets/fonts/PPNeueMontreal-Medium.otf') format('opentype');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

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

/* `hidden` deve vincere. È l'attributo con cui l'HTML dice «questo non
   c'è», ma il browser lo applica con un `display: none` di sua
   iniziativa, e qualunque regola scritta da noi — anche una sola
   classe, anche `.jc-controls { display: flex }` — lo batte, perché le
   regole del foglio di stile vengono prima di quelle del browser.

   Il risultato si è visto: cercando nel journal il carosello spariva e
   i suoi comandi restavano lì, «01 / 05» e le due frecce, a girare un
   tamburo che non c'era. Vale per tutto il sito, quindi sta qui, in
   cima, accanto all'azzeramento. */
[hidden] { display: none !important; }

:root {
  --bg-light: #eeeeef;
  --bg-dark: #0e1521;
  --navy: #0b1d3d;
  --text-light: #eeeeef;
  --text-dark: #0b1d3d;
}

html {
  scroll-behavior: smooth;
}

body {
  font-family: 'PPNueMontreal', sans-serif;
  font-weight: 400;
  background: var(--bg-light);
  color: var(--text-dark);
  overflow-x: hidden;
  cursor: none;
}

/* ─── SCROLL PROGRESS BAR ─── */
#scrollProgress {
  position: fixed;
  top: 0;
  left: 0;
  height: 2px;
  width: 0%;
  background: #0b1d3d;
  z-index: 9999;
  transition: width 0.1s ease, background 0.3s ease;
  pointer-events: none;
}
#scrollProgress.over-image {
  background: #eeeeef;
}

/* ─── CUSTOM CURSOR ─── */
.cursor {
  position: fixed;
  left: 0;
  top: 0;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: #0b1d3d;
  pointer-events: none;
  z-index: 10000;
  transform: translate(-50%, -50%);
  transition: width .2s ease, height .2s ease, opacity .2s ease;
}
.cursor.is-image,
body.lightbox-active .cursor {
  width: 30px;
  height: 30px;
  background: #eeeeef;
}
/* LA SCRITTA STA SEMPRE ALLA STESSA DISTANZA DAL BORDO.
   Non dal centro: dal bordo. È la differenza fra una distanza che si
   vede uniforme e una che si vede a caso, perché sotto il puntatore non
   c'è sempre la stessa cosa — il pallino è 22 px, sopra una fotografia
   diventa 30, e sui titoli del journal al suo posto compare l'anteprima
   dello scatto, che è 168. Con uno stacco fisso dal centro la scritta
   passava da «staccata» a «dentro l'immagine» senza che nulla lo
   annunciasse.
   `--cur-r` è il raggio di quello che c'è sotto in questo momento, e la
   sola cosa che cambia; `--cur-gap` è l'aria, ed è sempre quella. */
.cursor-label {
  --cur-r: 11px;
  --cur-gap: 20px;
  position: fixed;
  left: 0;
  top: 0;
  transform: translate(-50%, calc(var(--cur-r) + var(--cur-gap)));
  pointer-events: none;
  z-index: 10001;
  opacity: 0;
  transition: opacity .2s ease;
  font-family: 'PPNueMontreal', sans-serif;
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: #eeeeef;
  mix-blend-mode: difference;
}
.cursor.is-hover ~ .cursor-label,
.cursor-label.is-visible {
  opacity: 1;
}
/* I tre raggi, uno per ogni misura che il cursore può prendere. Se un
   giorno se ne aggiunge una quarta, la riga da scrivere è qui — e va
   scritta, o quella scritta tornerà a stare a una distanza sua. */
.cursor.is-image ~ .cursor-label,
body.lightbox-active .cursor-label { --cur-r: 15px; }
.cursor.is-previewing ~ .cursor-label { --cur-r: 84px; }
@media (hover: none) {
  .cursor, .cursor-label { display: none; }
  body { cursor: auto; }
}

/* ─── IMAGE SKELETON / PLACEHOLDER ─── */
.img-skel {
  position: relative;
}
.img-skel::before {
  content: "";
  position: absolute;
  inset: 0;
  background: #0b1d3d;
  z-index: 1;
  opacity: 1;
  transition: opacity 0.5s ease;
  pointer-events: none;
}
.img-skel.loaded::before {
  opacity: 0;
}
.img-skel > img {
  position: relative;
  z-index: 0;
}

/* ─── FADE IN ─── */
.fade-in {
  opacity: 0;
  transform: translateY(10px);
  transition: opacity 0.5s ease, transform 0.5s ease;
}
.fade-in.visible {
  opacity: 1;
  transform: translateY(0);
}

/* ─── LETTER-BY-LETTER REVEAL ─── */
.type-reveal {
  /* container just holds the split text */
}
.type-reveal .tr-char {
  opacity: 0;
  display: inline;
  transition: opacity 0.01s linear;
}
.type-reveal.revealed .tr-char {
  opacity: 1;
}
/* While still typing, keep characters hidden by default; JS toggles .visible on each */
.type-reveal .tr-char.visible {
  opacity: 1;
}

/* ─── HAMBURGER MENU ─── */
.hamburger-btn {
  position: fixed;
  top: 25px;
  right: 28px;
  /* Sopra il pannello del menu, che sta a 9500. */
  z-index: 9600;
  /* Misura di riferimento di tutto l'angolo in alto a destra:
     «WFPA | 2025» e «IT | EN» hanno lo stesso corpo, 17.06pt, che
     sono esattamente 22.75 px. Se questa cambia, cambiano anche
     quelle due. (22 → 24.2 → 22.75: +10%, poi −6%.) */
  width: 22.75px;
  height: 22.75px;
  border-radius: 50%;
  background: var(--navy);
  border: none;
  cursor: none;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 5px;
  padding: 0;
  /* 0,3 s era un numero preso a caso, fuori dalla tabella del sistema di
     disegno. 0,38 s sulla curva dei colori è quello che il sistema
     prescrive per un cambio di colore, ed è quasi la stessa durata della
     dissolvenza del fondo del visualizzatore: l'angolo in alto a destra
     diventa un evento solo invece di due. */
  transition: background var(--dur-s, .38s) var(--ease-soft, ease);
}
.hamburger-btn.over-image {
  background: #eeeeef;
}

/* Il pallino sta a 9600 e il visualizzatore a 2000: galleggia sopra, ed
   è giusto così, il menu deve restare raggiungibile. Ma è
   `background: var(--navy)` — #0b1d3d — su `rgba(14,21,33,.97)`: blu su
   quasi nero. Non era nascosto, era mimetizzato.

   Non c'è un aspetto nuovo da disegnare. Il sito questo problema lo
   risolve già: quando scorrendo il pallino passa sopra una fotografia
   diventa chiaro, ed è la regola qui sopra. Col visualizzatore aperto
   lo schermo È una fotografia, quindi è lo stesso caso.

   Perché non bastava quella regola: `over-image` la decide `check()` in
   site.js con `elementsFromPoint`, e quella funzione gira solo quando
   si scorre o si ridimensiona. Col visualizzatore aperto lo scorrimento
   è bloccato — `overflow: hidden` sul body — quindi non riparte mai, e
   il pallino resta del colore che aveva.

   Specificità controllata, non sperata: (0,2,1) — un selettore di tipo
   più due classi — contro (0,2,0) di `.over-image` e di `.open`. Vince
   ovunque la si metta. */
body.lightbox-active .hamburger-btn { background: var(--bg-light); }

/* Stessa causa, un piano più su: la barra perimetrale è var(--rail-ink),
   cioè lo stesso blu, a z-index 9999. Col visualizzatore aperto lo
   scorrimento è fermo, quindi la barra resta com'era — e su fondo scuro
   non si vede. */
body.lightbox-active .scroll-rail span { background: var(--rail-light); }
.hamburger-btn.over-image span {
  background: var(--navy);
}

.hamburger-btn span {
  display: block;
  width: 14px;
  height: 1px;
  background: var(--bg-light);
  transition: all 0.3s ease;
  transform-origin: center;
}

.hamburger-btn.open span:nth-child(1) {
  transform: translateY(6px) rotate(45deg);
}
.hamburger-btn.open span:nth-child(2) {
  opacity: 0;
  transform: scaleX(0);
}
.hamburger-btn.open span:nth-child(3) {
  transform: translateY(-6px) rotate(-45deg);
}

.nav-overlay {
  position: fixed;
  inset: 0;
  /* Sopra le polaroid trascinate, che arrivano a 9000. */
  z-index: 9500;
  background: rgba(11, 29, 61, 0.95);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  padding: 80px 60px;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.4s ease;
}

.hamburger-btn.open {
  background: var(--bg-light);
}

.nav-overlay.open {
  opacity: 1;
  pointer-events: all;
}

.nav-overlay a {
  font-family: 'PPNueMontreal', sans-serif;
  font-weight: 500;
  font-size: clamp(48px, 8vw, 80px);
  letter-spacing: -0.02em;
  color: var(--text-light);
  text-decoration: none;
  line-height: 1.15;
  opacity: 0;
  transform: translateY(20px);
  transition: opacity 0.4s ease, transform 0.4s ease, color 0.2s;
  display: block;
}

.nav-overlay.open a {
  opacity: 1;
  transform: translateY(0);
}
.nav-overlay.open a:nth-child(1) { transition-delay: 0.1s; }
.nav-overlay.open a:nth-child(2) { transition-delay: 0.18s; }
.nav-overlay.open a:nth-child(3) { transition-delay: 0.26s; }

.nav-overlay a:hover {
  color: rgba(238,238,239,0.4);
}

/* ─── HERO ─── */
#home {
  background: var(--bg-light);
  min-height: calc(100vh - 28px);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: flex-start;
  padding: 20px 28px 0 28px;
  position: relative;
}

/* Il titolo dell'apertura e il marchio delle altre pagine sono la
   stessa cosa scritta due volte, quindi sono una regola sola: se
   cambia il corpo qui, cambia in tutto il sito nello stesso istante.
   Tenerle separate voleva dire, prima o poi, un marchio di 50 px in
   una pagina e di 52 nell'altra — e la differenza si vede.

   In apertura è un `h1`, perché lì il nome del fotografo è il titolo
   della pagina. Nel blog no: quel posto è già del titolo
   dell'articolo, e due `h1` sulla stessa pagina sono un errore che
   costa in ricerca. Nel blog il marchio è un collegamento alla home,
   che è poi quello che uno si aspetta cliccando un logo. */
.hero-title,
.site-logo {
  font-family: 'PPNueMontreal', sans-serif;
  font-weight: 500;
  font-size: clamp(32px, 6vw, 52px);
  letter-spacing: -0.02em;
  line-height: 1.05;
  color: var(--navy);
  margin-bottom: 0;
}

/* Stesso angolo dell'apertura: 28 px da sinistra, 20 dall'alto —
   gli stessi che `#home` dà come margine interno al suo titolo.
   Scorre via con la pagina, come in apertura: il pallino del menu
   resta fisso, e per tornare indietro c'è quello. */
.site-logo {
  position: absolute;
  left: 28px;
  top: 20px;
  z-index: 100;
  display: block;
  text-decoration: none;
  transition: opacity var(--dur-s, .22s) var(--ease-soft, ease);
}
.site-logo:hover { opacity: .62; }

.vertical-text {
  position: absolute;
  right: 28px;
  top: 55px;
  writing-mode: vertical-rl;
  text-orientation: mixed;
  /* Stesso corpo del pallino del menu: 17.06pt = 22.75 px. */
  font-size: 17.06pt;
  letter-spacing: 0.15em;
  color: var(--navy);
  font-weight: 400;
  line-height: 1;
  text-transform: uppercase;
  transition: opacity 0.25s ease;
}

.hero-image-wrap {
  width: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  padding: 40px 0 20px;
  flex: 1;
}

.hero-image-wrap .hero-img-frame {
  position: relative;
  width: 100%;
  max-width: 1080px;
  display: inline-block;
}

.hero-image-wrap .hero-img-frame img {
  width: 100%;
  height: auto;
  display: block;
  cursor: none;
}

@media (min-width: 768px) {
  .hero-image-wrap {
    margin-top: -200px;
  }
  .hero-image-wrap .hero-img-frame {
    max-width: 600px;
  }
}

@media (max-width: 767px) {
  .hero-image-wrap {
    margin-top: -80px;
  }
}

.category-label {
  font-size: 12pt;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--navy);
  text-align: right;
  position: absolute;
  bottom: 46px;
  right: 28px;
  font-weight: 400;
}

/* ─── GALLERY GRID ─── */
.gallery-section {
  background: var(--bg-light);
  padding: 0;
}

.gallery-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 5px;
  padding-left: 5px;
  padding-right: 5px;
}

.gallery-grid .grid-item:nth-child(odd) {
}

.gallery-grid .grid-item:nth-child(even) {
}

.gallery-grid .grid-item {
  overflow: hidden;
  cursor: none;
  aspect-ratio: 1 / 1.31;
  position: relative;
}

.gallery-grid .grid-item img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform 0.5s ease;
}

.gallery-grid .grid-item:hover img {
  transform: scale(1.04);
}

/* ─── DARK SECTION ─── */
.dark-section {
  background: var(--bg-dark);
  position: relative;
}

/* ─── ABOUT ─── */
.portrait-wrap {
  width: 100%;
  position: relative;
  background: #eeeeef;
  padding-top: 220px;
  display: flex;
  justify-content: center;
  align-items: flex-start;
}

.portrait-wrap img {
  width: 100%;
  max-width: 100%;
  height: auto;
  display: block;
}

.portrait-wrap .portrait-img-frame {
  position: relative;
  width: 100%;
  max-width: 100%;
  display: block;
}

@media (min-width: 768px) {
  .portrait-wrap {
    padding-top: 250px;
  }
  .portrait-wrap img {
    max-width: 600px;
  }
  .portrait-wrap .portrait-img-frame {
    max-width: 600px;
  }
}

.about-text-wrap {
  background: url('https://www.gabrieledifazio.com/Gallery/GabrieleDiFazio_FoodPhotography_20261.png?_t=1776853057') center center / cover no-repeat;
}

@media (min-width: 768px) {
  .about-text-wrap {
    max-width: 600px;
    margin: 0 auto;
  }
}

.about-anchor {
  position: relative;
}

#about {
  position: absolute;
  top: -80px;
}

.about-label {
  font-family: 'PPNueMontreal', sans-serif;
  font-weight: 500;
  font-size: clamp(28px, 5vw, 42px);
  letter-spacing: -0.02em;
  color: var(--text-light);
  padding: 48px 28px 0 28px;
}

@media (min-width: 768px) {
  .about-label {
    text-align: center;
  }
}

.about-text {
  color: var(--text-light);
  font-weight: 400;
  font-size: clamp(13px, 2.2vw, 16px);
  line-height: 1.7;
  padding: 48px 48px 72px 48px;
  max-width: 550px;
  text-align: center;
  margin: 0 auto;
}

.about-text .born {
  margin-bottom: 24px;
  font-size: clamp(11px, 1.8vw, 14px);
  opacity: 0.7;
}

.about-text .quote {
  font-size: clamp(14px, 2.4vw, 18px);
  line-height: 1.55;
  margin-bottom: 28px;
}

.about-text p {
  margin-bottom: 20px;
}

.about-text .tagline {
  margin-top: 32px;
  font-size: clamp(12px, 2vw, 15px);
  opacity: 0.75;
  line-height: 1.6;
  font-style: italic;
}

.copyright-line {
  text-align: right;
  padding: 0 28px 8px 0;
  font-size: 9px;
  letter-spacing: 0.12em;
  color: rgba(238,238,239,0.5);
  font-weight: 400;
}

.portrait-vertical-text {
  position: absolute;
  right: 28px;
  top: 55px;
  writing-mode: vertical-rl;
  text-orientation: mixed;
  font-size: 17.06pt;
  letter-spacing: 0.15em;
  color: var(--navy);
  font-weight: 400;
  line-height: 1;
  text-transform: uppercase;
  z-index: 2;
}

@media (min-width: 768px) {
  .portrait-vertical-text {
    right: calc(50% - 300px + 28px);
  }
}

/* ─── CONTACT ─── */
#contact {
  background: #eeeeef;
  color: #0b1d3d;
  padding: 80px 28px 120px;
}

#contact .contact-title,
#contact .contact-submit {
  color: #0b1d3d;
}

#contact .contact-form input,
#contact .contact-form textarea {
  color: #0b1d3d;
}

#contact .contact-form label {
  color: rgba(11, 29, 61, 0.55);
}

#contact .contact-form .field {
  border-bottom: 1px solid rgba(11, 29, 61, 0.25);
}

/* IL FORM STA SU FONDO CHIARO, e questo blocco è l'unico posto che lo
   sa. Le regole generali di `.contact-form`, più su, sono scritte in
   chiaro su scuro — è il colore che il form aveva quando viveva su una
   sezione blu — e qui vengono ribaltate una per una. Ogni elemento
   nuovo del form ha bisogno della sua riga QUI, o nasce chiaro su
   chiaro: cioè invisibile, e invisibile in un modo che non si nota
   scrivendo il CSS, perché l'elemento c'è, occupa spazio ed è al suo
   posto. */
#contact .contact-form .field-riga { background: rgba(11, 29, 61, 0.85); }
#contact .contact-form .field:focus-within label,
#contact .contact-form .field:has(input:not(:placeholder-shown)) label,
#contact .contact-form .field:has(textarea:not(:placeholder-shown)) label {
  color: rgba(11, 29, 61, 0.9);
}

#contact .contact-submit { color: rgba(11, 29, 61, 0.4); }
#contact .cs-fill { color: var(--navy); }
#contact .contact-submit[disabled] { color: rgba(11, 29, 61, 0.4); }
#contact .contact-submit:focus-visible { outline-color: rgba(11, 29, 61, 0.5); }

#contact .contact-form input::placeholder,
#contact .contact-form textarea::placeholder {
  color: rgba(11, 29, 61, 0.35);
}

.contact-title {
  font-family: 'PPNueMontreal', sans-serif;
  font-weight: 500;
  font-size: clamp(28px, 5vw, 42px);
  letter-spacing: -0.02em;
  color: var(--text-light);
  margin-bottom: 88px;
  /* Al centro su tutti gli schermi. Era a sinistra sotto i 768 px e
     centrato sopra: due impaginazioni per la stessa parola, e sul
     telefono restava un titolo appoggiato al margine con sotto un form
     che comincia altrove. */
  text-align: center;
}

@media (min-width: 768px) {
  .contact-title {
    text-align: center;
  }
  .contact-submit-wrap {
    text-align: center !important;
  }
}

.contact-form {
  /* 620 e non 500: la domanda è cresciuta, e su 500 px una riga come
     «A che indirizzo ti rispondo?» andava a capo. */
  max-width: 620px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: 0;
}

/* La riga sotto il campo è ferma e spenta; sopra di lei ne cresce una
   accesa, da sinistra, quando il campo prende il fuoco. Due righe
   sovrapposte e non un bordo che cambia colore: un bordo si accende
   tutto insieme, e non è il modo in cui questo sito muove le cose —
   qui l'inchiostro arriva sempre da una parte e attraversa. */
.contact-form .field {
  position: relative;
  border-bottom: 1px solid rgba(238,238,239,0.2);
  padding: 18px 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.contact-form .field-riga {
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 1px;
  background: rgba(238,238,239,0.75);
  transform: scaleX(0);
  transform-origin: left center;
  pointer-events: none;
}
.contact-form .field:focus-within .field-riga { transform: scaleX(1); }

.contact-form label {
  font-size: 9px;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: rgba(238,238,239,0.45);
  font-weight: 400;
}

/* L'etichetta si schiarisce quando il campo è in mano, e resta chiara
   quando è pieno: `:placeholder-shown` è vero solo finché il campo è
   vuoto, quindi «non mostra il segnaposto» vuol dire «qualcuno ci ha
   scritto». Un campo compilato si distingue da uno lasciato indietro
   senza che nessuno debba rileggerli tutti.
   Serve `:has()` e non `~`: l'etichetta sta PRIMA del campo, e un
   fratello successivo guarda solo in avanti. */
.contact-form .field:focus-within label,
.contact-form .field:has(input:not(:placeholder-shown)) label,
.contact-form .field:has(textarea:not(:placeholder-shown)) label { color: rgba(238,238,239,0.8); }

.contact-form input,
.contact-form textarea {
  background: none;
  border: none;
  outline: none;
  color: var(--text-light);
  font-family: 'PPNueMontreal', sans-serif;
  font-weight: 400;
  font-size: clamp(14px, 2.2vw, 16px);
  padding: 4px 0;
  width: 100%;
  resize: none;
  /* Niente cursore I-beam del browser: usiamo solo il cursore custom */
  cursor: none;
  /* Caret nascosto di default; visibile solo quando il campo è in focus */
  caret-color: transparent;
}

.contact-form input:focus,
.contact-form textarea:focus {
  caret-color: currentColor;
}

.contact-form input::placeholder,
.contact-form textarea::placeholder {
  color: rgba(238,238,239,0.25);
}

.contact-form textarea {
  min-height: 100px;
}

/* ═══════════════════════════════════════════════════════════════
   IL FORM A PASSI
   Un campo alla volta. Non è un vezzo: quattro campi in fila sono
   quattro cose da fare prima di poter premere qualcosa, e si vede
   subito che sono quattro. Uno alla volta è una domanda a cui si
   risponde, poi un'altra — e intanto in fondo restano i numeri di
   quelle che mancano, che sono poche, e si vede anche quello.

   Tutto quello che segue vale SOLO sotto `.a-passi`, la classe che
   home.js mette al form quando trova il JavaScript vivo. Senza,
   restano i quattro campi in fila di prima, che funzionano: il form
   non dipende da questo, ci guadagna soltanto.
   ═══════════════════════════════════════════════════════════════ */

/* ── LE MISURE DEL FORM A PASSI ──
   Il primo giro era stretto: corpi da elenco telefonico, righe
   attaccate, e la domanda — che è la sola cosa da leggere — appena più
   grande del resto. Qui i numeri sono cresciuti tutti insieme e le
   distanze con loro: quando in pagina c'è UNA domanda alla volta, lo
   spazio intorno non è spreco, è la ragione per cui si legge. */

.contact-form.a-passi .field { padding: 0; border-bottom: 0; }

/* Un campo che non è ancora il suo turno non esiste per il tabulatore
   e non si vede: `hidden` lo toglie dal flusso, e la riga in cima al
   foglio lo rende non negoziabile. I campi restano nel documento —
   nessun testo creato dal JavaScript, come vuole il sito. */
.contact-form.a-passi .field[hidden] { display: none !important; }

.contact-form.a-passi .field.e-attivo {
  border-bottom: 1px solid rgba(11, 29, 61, 0.25);
  padding-bottom: 20px;
  /* Sopra e sotto: la domanda deve staccarsi dalle risposte già chiuse,
     o comincia attaccata alla riga di quella prima e le due si leggono
     come un blocco solo. */
  margin: 34px 0 26px;
}
.contact-form.a-passi .field.e-attivo input,
.contact-form.a-passi .field.e-attivo textarea {
  font-size: clamp(19px, 2.9vw, 24px);
  line-height: 1.45;
  padding: 2px 0;
}
.contact-form.a-passi .field.e-attivo textarea { min-height: 132px; }

/* Sul campo che tocca adesso l'etichetta è l'unica cosa scritta sopra,
   e si vede: dice di che campo si tratta, e il segnaposto dentro dice
   come rispondere.
   Le domande grandi in prima persona — «A che indirizzo ti rispondo?» —
   sono state provate e tolte: una riga da quaranta punti sopra ogni
   campo riempiva di rumore una pagina che vive di spazio vuoto, e diceva
   con dieci parole quello che l'etichetta dice con una. */
.contact-form.a-passi .field.e-attivo label {
  display: block;
  margin-bottom: 14px;
  color: rgba(11, 29, 61, 0.9);
}

/* Le risposte già date e le domande che mancano condividono la stessa
   griglia, così le une continuano le altre invece di sembrare due
   elenchi diversi. La colonna dell'etichetta è FISSA e non `auto`:
   «NOME», «EMAIL» e «OGGETTO» sono larghe diverso, e con una colonna
   che si adatta al contenuto le risposte partivano ognuna da un punto
   suo. Incolonnate si leggono come un elenco; sfalsate, come quattro
   righe qualsiasi. */
.contact-form.a-passi .field.e-fatto,
.contact-form.a-passi .field.e-atteso {
  display: grid;
  /* Sul telefono la colonna si stringe: 132 px su una riga larga 299
     lasciavano alla risposta meno spazio che all'etichetta, e un
     indirizzo di posta finiva subito nei puntini. */
  grid-template-columns: 96px 1fr;
  align-items: baseline;
  gap: 16px;
  padding: 15px 0;
}
/* 768 e non 600: il sito ha UN punto di rottura solo, e le misure in
   mezzo si danno con clamp() e min(). Un secondo valore, per quanto
   comodo, è un secondo sistema che qualcuno dovrà scoprire da solo. */
@media (min-width: 768px) {
  .contact-form.a-passi .field.e-fatto,
  .contact-form.a-passi .field.e-atteso {
    grid-template-columns: 132px 1fr;
    gap: 20px;
  }
}

.contact-form.a-passi .field.e-fatto {
  border-bottom: 1px solid rgba(11, 29, 61, 0.14);
  cursor: none;
}
.contact-form.a-passi .field.e-fatto .field-error,
.contact-form.a-passi .field.e-fatto .field-riga { display: none; }
.contact-form.a-passi .field.e-fatto label { margin: 0; }
.contact-form.a-passi .field.e-fatto input,
.contact-form.a-passi .field.e-fatto textarea {
  font-size: 17px;
  line-height: 1.3;
  color: var(--navy);
  padding: 0;
  min-height: 0;
  height: auto;
  pointer-events: none;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.contact-form.a-passi .field.e-fatto textarea { resize: none; }
.contact-form.a-passi .field.e-fatto:hover { border-bottom-color: rgba(11, 29, 61, 0.45); }

/* Quelle che mancano: solo il nome, spento. Sono lì per dire quanto
   manca — ed è poco. È la parte che invoglia: un form che mostra la
   fine è un form che si finisce. */
.contact-form.a-passi .field.e-atteso {
  border-bottom: 1px solid rgba(11, 29, 61, 0.09);
  opacity: .4;
}
.contact-form.a-passi .field.e-atteso .field-error,
.contact-form.a-passi .field.e-atteso .field-riga,
.contact-form.a-passi .field.e-atteso input,
.contact-form.a-passi .field.e-atteso textarea { display: none; }

/* Le etichette: più grandi e più spaziate di prima. A 9 px erano un
   segno grafico; a 11 sono una parola che si legge. */
.contact-form.a-passi label {
  font-size: 11px;
  letter-spacing: 0.18em;
}

/* Il bottone al centro, sotto tutto, con l'aria che gli spetta. */
.contact-form.a-passi + .contact-submit-wrap {
  text-align: center;
  margin-top: 64px;
}
@media (min-width: 768px) {
  .contact-form.a-passi + .contact-submit-wrap { text-align: center !important; }
}

/* ── IL RIEMPIMENTO AUTOMATICO DEL BROWSER ──
   Chrome, quando suggerisce un indirizzo salvato, dipinge il campo di
   azzurro — `rgb(232,240,254)` — e lo fa con una regola interna che
   nessun `background` normale riesce a scavalcare. Su un form che di
   fondo non ne ha uno, quel rettangolo azzurro arrivava come una
   macchia che non c'entrava niente con il sito.
   L'unico modo di coprirlo è un'ombra interna piena grande quanto il
   campo: non è un trucco nostro, è il rimedio che il browser lascia.
   Il colore del testo va rimesso a parte, perché anche quello viene
   riscritto — da qui `-webkit-text-fill-color`. La transizione
   lunghissima è la seconda metà del rimedio: Chrome riapplica il suo
   fondo con una transizione, e rinviarla di fatto la annulla. */
.contact-form input:-webkit-autofill,
.contact-form input:-webkit-autofill:hover,
.contact-form input:-webkit-autofill:focus,
.contact-form textarea:-webkit-autofill {
  -webkit-text-fill-color: var(--navy);
  -webkit-box-shadow: 0 0 0 1000px #eeeeef inset;
          box-shadow: 0 0 0 1000px #eeeeef inset;
  caret-color: var(--navy);
  transition: background-color 9999s ease-in-out 0s;
}

/* Il bottone sta in fondo al form e ne segue la colonna: stessa
   larghezza massima, stesso centraggio. Lo stacco e l'allineamento
   erano scritti in riga nell'HTML — `text-align:right; margin-top:48px`
   — e sono venuti via con il markup vecchio: senza il margine, il
   bottone saliva addosso alla riga dell'ultimo campo.
   `right` vale solo sul telefono: da 768 px in su c'è una regola
   `!important` qui sopra che lo centra, e centrato è come il sito l'ha
   sempre mostrato sul computer — quel `right` in riga non ha mai vinto. */
.contact-submit-wrap {
  max-width: 500px;
  margin: 48px auto 0;
  text-align: right;
}

/* IL BOTTONE «INVIA».
   La parola grande senza cornice resta: era la cosa giusta. Quello che
   mancava è che rispondesse — un `opacity: .6` al passaggio è un
   bottone che si spegne, e questo è l'unico gesto della pagina che
   qualcuno deve avere voglia di fare.
   Adesso l'inchiostro riempie la parola da sinistra, che è lo stesso
   movimento delle voci del menu (`.nav-word-fill`), e la freccia si
   allunga verso destra. Due copie della stessa parola, una spenta e una
   piena, e un clip che scopre la seconda: nessun testo creato dal
   JavaScript, nessuno nascosto. */
.contact-submit {
  margin-top: 0;
  background: none;
  border: none;
  color: rgba(238, 238, 239, 0.45);
  font-family: 'PPNueMontreal', sans-serif;
  font-weight: 500;
  font-size: clamp(28px, 5vw, 42px);
  letter-spacing: -0.02em;
  text-transform: uppercase;
  padding: 0;
  margin-right: 0;
  cursor: none;
  display: inline-flex;
  align-items: center;
  gap: 18px;
  -webkit-appearance: none;
  appearance: none;
}

.cs-parola { position: relative; display: inline-block; }
.cs-fill {
  position: absolute;
  left: 0;
  top: 0;
  color: var(--text-light);
  white-space: nowrap;
  clip-path: inset(0 100% 0 0);
  pointer-events: none;
}
.contact-submit:hover .cs-fill,
.contact-submit:focus-visible .cs-fill { clip-path: inset(0 0 0 0); }

.contact-submit:active .cs-parola { transform: translateY(1px); }
.contact-submit:focus { outline: none; }
.contact-submit:focus-visible {
  outline: 1px solid rgba(238, 238, 239, 0.5);
  outline-offset: 10px;
}

/* Mentre parte, e quando è partito. Il bottone smette di rispondere al
   passaggio — non c'è più niente da premere — e lo dice restando pieno
   invece di spegnersi. */
.contact-submit[disabled] { color: rgba(238, 238, 239, 0.45); }
.contact-submit.sta-inviando .cs-fill { clip-path: inset(0 0 0 0); }


/* ─── FORM VALIDATION (custom, matches site design) ─── */
.contact-form .field-error {
  display: block;
  max-height: 0;
  overflow: hidden;
  opacity: 0;
  margin-top: 0;
  font-family: 'PPNueMontreal', sans-serif;
  font-weight: 400;
  font-size: 9px;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: rgba(238,238,239,0.75);
  transition: opacity 0.35s ease, max-height 0.35s ease, margin-top 0.35s ease;
  pointer-events: none;
}

.contact-form .field.has-error .field-error {
  max-height: 20px;
  opacity: 1;
  margin-top: 6px;
}

.contact-form .field.has-error {
  border-bottom-color: rgba(238,238,239,0.55);
}

.contact-form .field.has-error label {
  color: rgba(238,238,239,0.85);
}

/* Override per la sezione #contact (sfondo chiaro #eeeeef) */
#contact .contact-form .field-error {
  color: rgba(11, 29, 61, 0.85);
}
#contact .contact-form .field.has-error {
  border-bottom-color: rgba(11, 29, 61, 0.7);
}
#contact .contact-form .field.has-error label {
  color: rgba(11, 29, 61, 0.85);
}

/* ─── FOOTER ─── */
.site-footer {
  background: #eeeeef;
  color: #0b1d3d;
  padding: 40px 18px 28px;
  font-family: 'PPNueMontreal', sans-serif;
  font-weight: 400;
}

.footer-grid {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  align-items: center;
  gap: 8px;
  margin-bottom: 32px;
  text-align: center;
  flex-wrap: nowrap;
}

.footer-link {
  color: #0b1d3d;
  text-decoration: none;
  font-size: clamp(8.5px, 2.6vw, 14px);
  letter-spacing: 0.01em;
  transition: opacity 0.2s ease;
  white-space: nowrap;
  flex: 0 1 auto;
}

@media (min-width: 768px) {
  .footer-link {
    font-size: clamp(13px, 1.4vw, 16px);
  }
}

.footer-link:hover {
  opacity: 0.6;
}

.footer-copy {
  font-size: 9px;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: rgba(11, 29, 61, 0.55);
  text-align: left;
  padding-top: 16px;
  border-top: 1px solid rgba(11, 29, 61, 0.15);
}

@media (min-width: 768px) {
  .site-footer {
    padding: 64px 48px 40px;
  }
  .footer-grid {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr;
    align-items: center;
    gap: 24px;
    text-align: left;
  }
  .footer-grid > .footer-link:nth-child(1) {
    justify-self: start;
    text-align: left;
  }
  .footer-grid > .footer-link:nth-child(2) {
    justify-self: center;
    text-align: center;
  }
  .footer-grid > .footer-link:nth-child(3) {
    justify-self: end;
    text-align: right;
  }
  .footer-copy {
    text-align: center;
  }
}

/* ─── COPYRIGHT TOAST ─── */
.copy-toast {
  position: fixed;
  z-index: 3000;
  background: rgba(11, 29, 61, 0.96);
  color: #eeeeef;
  font-family: 'PPNueMontreal', sans-serif;
  font-weight: 400;
  font-size: 12px;
  letter-spacing: 0.04em;
  line-height: 1.4;
  padding: 12px 16px;
  border-radius: 4px;
  max-width: 280px;
  box-shadow: 0 8px 32px rgba(0,0,0,0.3);
  opacity: 0;
  transform: translateY(6px);
  transition: opacity 0.25s ease, transform 0.25s ease;
  pointer-events: none;
  user-select: none;
}
.copy-toast.visible {
  opacity: 1;
  transform: translateY(0);
}

/* Disable image dragging globally */
img {
  -webkit-user-drag: none;
  user-drag: none;
  -webkit-touch-callout: none;
}

/* ─── LIGHTBOX — LA PILA DI FOTOGRAFIE ─────────────────────────────
   La galleria entra intera nel visualizzatore come una pila di stampe
   sul tavolo: quella scelta davanti, a fuoco e in luce, le altre
   dietro — sfocate, in ombra, e ognuna infilata sotto il bordo di
   quella che le sta sopra.

   L'incastro è la cosa importante, non la sfocatura. Il primo
   tentativo metteva le vicine ACCANTO, con un dito di fondo in mezzo:
   bello, ma la richiesta diceva «dietro», e due fotografie affiancate
   non stanno una dietro l'altra — stanno una accanto all'altra. Un
   bordo che passa sotto un altro è l'unico segno che vuol dire davvero
   «dietro», ed è più forte della sfocatura e della grandezza messe
   insieme.

   Le vicine SONO le frecce: i due pallini ai lati non ci sono più. */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 2000;
  background: rgba(14, 21, 33, 0.97);
  /* La pila esce dallo schermo da tutte e due le parti: qui la si
     taglia. Non è decorazione — senza, le lastre fuori campo aprono una
     zona scorrevole in orizzontale dentro il visualizzatore, e il
     sintomo (il telefono che scorre di lato) non somiglia per niente
     alla causa. */
  overflow: hidden;
  /* L'asse orizzontale è nostro, il resto resta al browser: così i due
     ascoltatori del tocco restano passivi e non serve nessun
     preventDefault. `pinch-zoom` è voluto — è un sito di fotografia.
     `overscroll-behavior` toglie di mezzo lo scorrimento dal bordo che
     su iPhone torna indietro nella cronologia. */
  touch-action: pan-y pinch-zoom;
  overscroll-behavior: contain;
  opacity: 0;
  pointer-events: none;
  /* motion.css la riscrive con le durate della tabella. */
  transition: opacity 0.35s ease;

  /* ── Le misure della pila. Tutte qui, tutte legate fra loro. ── */
  /* 90vh e 70vw, non più 76vh e 54vw. La fotografia a fuoco occupava il
     27% della larghezza dello schermo: chi clicca per vedere una
     fotografia più grande non si aspetta di trovarne una piccola in
     mezzo a un campo di fondo. Le vicine non hanno più bisogno di uno
     spazio riservato ai lati, perché adesso non stanno di fianco — si
     aprono a ventaglio DIETRO, e quello che ne spunta lo decide
     l'angolo, non la larghezza che avanza. */
  --lb-h:      90vh;   /* il tetto dell'altezza */
  --lb-w:      70vw;   /* il tetto della larghezza */
  --lb-recess: .88;    /* quanto arretra una vicina */
  /* L'apertura del ventaglio, per ogni passo di distanza dal centro: la
     prima vicina di 3,6°, la seconda di 7,2°. Sopra i 6° per passo le
     fotografie in fondo si coricano e la pila sembra un mazzo di carte
     buttato; sotto i 2° il ventaglio non si legge e restano tre
     rettangoli sovrapposti. */
  --lb-fan:    3.6deg;
  /* Quanto le vicine stanno raccolte dietro la fotografia a fuoco prima
     che il visualizzatore si apra. È da qui che parte l'entrata: a
     zero, chiuso, il ventaglio è un mazzo compatto; `.lightbox.open`
     riporta questa misura a 0 e le lastre si aprono. */
  --lb-raduna: 7vw;
  /* L'incastro non è scelto, è dedotto. Una lastra che arretra di r
     intorno al proprio centro tira indietro il bordo esterno di
     W(1−r)/2 per parte: fra due vicine si aprirebbe un filo di fondo, a
     meno che l'incastro non valga almeno W(1−r) per la lastra più larga
     che ci possa essere, che è --lb-w. Messo lì esatto, la pila non ha
     fessure per nessuna delle tre proporzioni della galleria e a nessuna
     finestra.
     Il secondo termine è una briglia per finestre assurde — 3840×600 e
     simili — dove l'incastro supererebbe la larghezza della lastra più
     stretta e le lastre si metterebbero in fila al contrario. Su nessuno
     schermo vero morde. */
  --lb-tuck: min(calc((1 - var(--lb-recess)) * var(--lb-w)),
                 calc(var(--lb-h) / 3));
  /* Sfocatura VISTA, non scritta: il filtro si calcola prima che la
     trasformazione rimpicciolisca la lastra, quindi il numero scritto va
     diviso per l'arretramento. Senza, la tabella diceva 4,5 e lo schermo
     faceva 3,87. */
  --lb-blur: clamp(3px, .28vw, 4.5px);
  /* L'ombra che la fotografia davanti getta su quella dietro: fitta dove
     le due si toccano, che si alza andando verso l'esterno. È fisica, e
     serve al disegno — la parte che si può cliccare è quella esterna, ed
     è quella che resta leggibile.
     Un'ombra portata VERA, sotto la fotografia a fuoco, è stata provata
     e buttata: su un fondo che è già al 97% del colore più scuro che il
     sito possiede, il blu al 72% viene fuori con la stessa luminosità
     del fondo. Non c'è spazio per un'ombra, e un quarto colore non
     esiste. */
  --lb-shade-in:  .62;
  --lb-shade-out: .32;
  --lb-open: .92;      /* l'entrata: vedi il commento sul palco */
}
.lightbox.open {
  opacity: 1;
  pointer-events: auto;
  --lb-open: 1;
  /* Il ventaglio si apre: le vicine escono da dietro la fotografia a
     fuoco e vanno al loro posto. Sono queste due righe, sole, a fare
     l'entrata — le lastre hanno già la loro transizione sul transform,
     e un valore che cambia dentro una `transform` si interpola come
     qualunque altro. */
  --lb-raduna: 0px;
}

/* IL VISUALIZZATORE CHIUSO NON DEVE POTER PRENDERE UN CLIC.
   `.lightbox` senza `.open` è già a `pointer-events: none`, ma in CSS un
   discendente dichiarato `auto` si riprende l'hit-test anche se
   l'antenato l'ha spento: le lastre in scena restavano cliccabili, e
   `opacity: 0` non toglie niente dall'hit-test — rende invisibile, non
   intoccabile.
   Il risultato era un pannello invisibile grande quanto mezzo schermo,
   fermo a z-index 2000 sopra la pagina: il puntatore che ci entrava
   accendeva l'etichetta «Precedente»/«Successivo» del cursore, e ogni
   clic in quella zona finiva dentro una lastra che non esisteva più.
   Da fuori si vedeva un sito che aveva smesso di rispondere. */
.lightbox:not(.open) .lb-slide { pointer-events: none; }
/* Il dialogo prende il fuoco all'apertura: il contorno del browser su un
   rettangolo grande quanto lo schermo non dice niente a nessuno. */
.lightbox:focus { outline: none; }

/* Il palco esiste per una ragione sola: la scala d'ingresso. Metterla
   sul nastro voleva dire scalarlo intorno al SUO centro — e il nastro è
   largo diciassettemila pixel, quindi il 3,5% spostava la fotografia a
   fuoco di centinaia di pixel. Il palco è grande quanto lo schermo, il
   suo centro è il centro dello schermo, e la scala fa quello che deve.
   Due elementi, due trasformazioni, un mestiere per ciascuna. */
.lightbox-stage {
  position: absolute;
  inset: 0;
  pointer-events: none;
  transform: scale(var(--lb-open, 1));
}

/* Il bordo sinistro del nastro sta al centro dello schermo:
   translateX(−centro della lastra scelta) la porta in mezzo.
   `width: max-content` perché un elemento in posizione assoluta con
   larghezza automatica si stringe allo spazio che gli avanza:
   cinquantadue lastre non ci starebbero. */
.lightbox-track {
  position: absolute;
  top: 50%;
  left: 50%;
  width: max-content;
  display: flex;
  align-items: center;
  pointer-events: none;
  transform: translate3d(0, -50%, 0);
}

/* La lastra È il riquadro della fotografia. Nessuna misura presa in
   JavaScript: --ar arriva da width/height dell'<img> della griglia, che
   picture() stampa sempre. Il riquadro ha la sua misura definitiva prima
   ancora che l'immagine parta, e quando arriva non muove niente. */
.lb-slide {
  position: relative;
  flex: 0 0 auto;
  width:  min(calc(var(--lb-h) * var(--ar, .667)), var(--lb-w));
  height: min(var(--lb-h), calc(var(--lb-w) / var(--ar, .667)));
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  -webkit-appearance: none;
  appearance: none;
  /* Il vuoto intorno resta del fondo, e il clic sul fondo chiude come ha
     sempre chiuso. Solo le lastre in scena prendono il clic. */
  pointer-events: none;
  transform: translateX(0) scale(1);
}
/* L'incastro. Un margine negativo, non un `gap`: i `gap` non vanno sotto
   zero, e qui le lastre si devono sovrapporre. */
.lb-slide + .lb-slide { margin-left: calc(var(--lb-tuck) * -1); }

/* Il riquadro ha un fondo suo, scuro e pieno. Serve da rete: se per un
   fotogramma la fotografia non ha pixel — una sorgente che cambia, una
   decodifica che finisce un istante dopo — si guarderebbe attraverso, e
   sotto il velo del visualizzatore, che è opaco al 97%, c'è la pagina,
   che è quasi bianca. Bastava quel 3% a far passare un lampo chiaro.
   Il colore è quello del velo, senza trasparenza: dove la fotografia
   c'è, e c'è sempre, questo fondo non si vede mai — il riquadro è
   calcolato sulle proporzioni vere, quindi l'immagine lo riempie esatto. */
.lb-slide { background-color: rgb(14, 21, 33); }

.lb-slide img {
  width: 100%;
  height: 100%;
  /* Rete di sicurezza: il riquadro è già esatto, ma se un giorno
     qualcuno aggiunge una fotografia senza width/height la si vede
     centrata invece che stirata. */
  object-fit: contain;
  display: block;
}

/* L'ombra portata. Il verso e la sfumatura cambiano con il lato, e la
   sosta a --lb-tuck mette il punto più fitto esattamente dove passa il
   bordo della fotografia davanti: il primo pixel che si vede della
   vicina è il più scuro, e da lì si schiarisce. La misura è divisa per
   l'arretramento per la stessa ragione della sfocatura. */
.lb-slide::after {
  content: "";
  position: absolute;
  inset: 0;
  opacity: 0;
  pointer-events: none;
  background: linear-gradient(var(--lb-verso, to right),
    rgba(14, 21, 33, var(--lb-shade-in)) 0,
    rgba(14, 21, 33, var(--lb-shade-in)) calc(var(--lb-tuck) / var(--lb-recess)),
    rgba(14, 21, 33, var(--lb-shade-out)) 100%);
}

/* Le due traslazioni tengono fermo il bordo che va sotto. Senza,
   l'arretramento tirava indietro proprio quel bordo e l'incastro
   cambiava con la larghezza della fotografia: preciso su un ritratto,
   sbagliato di cinquanta pixel su un paesaggio. Con la compensazione
   l'incastro è --lb-tuck e basta, per tutte e quarantaquattro.
   È scritta come calc e non come un numero a parte perché sono la stessa
   misura vista da due lati: se una cambia e l'altra no, la pila si apre. */
/* IL VENTAGLIO.
   `--lb-dir` è il verso della lastra rispetto al centro: +1 a sinistra,
   −1 a destra. Sta scritto una volta e governa tutte e tre le parti del
   movimento — la compensazione dell'incastro, il raduno dell'entrata e
   l'angolo — così una vicina di sinistra e una di destra non possono
   sfasarsi: sono la stessa formula col segno girato.

   `--d` è la distanza dal centro in numero di lastre, e la scrive
   `vesti()` in home.js. L'angolo cresce con lei: la prima vicina apre di
   --lb-fan, la seconda del doppio. È questo a fare il ventaglio invece
   di tre rettangoli paralleli.

   Il perno sta sul bordo INTERNO, in basso: il punto dove la lastra
   sparisce sotto quella davanti. Ruotando di lì le fotografie si aprono
   verso l'alto e verso l'esterno, come stampe sfogliate con il pollice
   tenendo fermo l'angolo. Con il perno al centro si sarebbero alzate
   anche dal lato nascosto, aprendo una fessura di fondo proprio dove
   l'incastro deve restare chiuso. */
.lb-slide.is-prev,
.lb-slide.is-next {
  transform:
    translateX(calc(var(--lb-dir) * (1 - var(--lb-recess)) / 2 * 100%))
    translateX(calc(var(--lb-dir) * var(--lb-raduna, 0px)))
    scale(var(--lb-recess))
    rotate(calc(var(--lb-fan, 0deg) * var(--d, 1) * var(--lb-dir) * -1));
}
.lb-slide.is-prev {
  --lb-verso: to left;
  --lb-dir: 1;
  transform-origin: 100% 100%;
}
.lb-slide.is-next {
  --lb-verso: to right;
  --lb-dir: -1;
  transform-origin: 0 100%;
}

/* Sfocatura e velo solo a chi ha davvero una fotografia dentro. Un filtro
   su cinquantadue elementi sarebbe cinquantadue livelli di composizione
   per disegnarne tre; e un velo su una lastra vuota sarebbe un rettangolo
   scuro dove non c'è niente. La classe la mette il JavaScript quando
   assegna la sorgente, cioè a quattro lastre di distanza: fuori dallo
   schermo, sempre. */
.lb-slide.is-armata { filter: blur(calc(var(--lb-blur) / var(--lb-recess))); }
.lb-slide.is-armata:not(.is-focus)::after { opacity: 1; }

/* Deve stare DOPO .is-armata: stessa specificità, decide l'ordine.
   blur(0px) e non `none`: fra `none` e una sfocatura non c'è
   interpolazione, e il passaggio salterebbe. */
.lb-slide.is-focus {
  transform: translateX(0) scale(1);
  filter: blur(0px);
}

/* In scena c'è la fotografia a fuoco e le due file dietro di lei: sono
   quelle che si vedono, e quelle che prendono il clic. La fotografia a
   fuoco lo prende e non ne fa niente — come oggi, dove cliccarla non
   chiude. È voluto: se il centro lasciasse passare il clic al fondo,
   cliccare la fotografia grande chiuderebbe il visualizzatore, e chi
   guarda una fotografia a pieno schermo non se lo aspetta. */
.lb-slide.is-scena { pointer-events: auto; }

/* ── L'INGRANDIMENTO ──
   Un clic sulla fotografia a fuoco e quella riempie lo schermo: è la
   ragione per cui la lastra a fuoco carica la variante grande da 2600 di
   lato lungo e non si accontenta della 900. Prima cliccarla non faceva
   niente — la si prendeva e la si lasciava cadere.

   Il fattore lo calcola home.js e lo scrive qui dentro come `--lb-zoom`:
   quanto manca a questa lastra, con la sua forma, per toccare il bordo
   più vicino della finestra. In CSS non si può, perché dipende dalle
   proporzioni della singola fotografia; in JavaScript è una divisione.

   Si scala, non si ricalcolano le misure: cambiare --lb-h e --lb-w
   cambierebbe la LARGHEZZA delle cinquantadue lastre, e il nastro —
   che si posiziona su offsetLeft — andrebbe rifatto da capo a ogni
   fotogramma dell'ingrandimento. */
/* La traslazione viene PRIMA della scala e si misura in pixel dello
   schermo, non della fotografia: così un pixel di trascinamento è un
   pixel di spostamento, qualunque sia l'ingrandimento. Scritta dopo la
   scala, sarebbe moltiplicata per essa e la fotografia scapperebbe da
   sotto il dito. */
.lightbox.is-zoom .lb-slide.is-focus {
  transform: translate3d(var(--lb-zx, 0px), var(--lb-zy, 0px), 0) scale(var(--lb-zoom, 1));
}
/* Da ingranditi il gesto è nostro su tutti e due gli assi: se restasse
   `pan-y`, il dito che porta la fotografia in basso scorrerebbe la
   pagina sotto invece di muovere l'immagine. */
.lightbox.is-zoom { touch-action: none; }

/* Il puntatore dice se c'è qualcosa da percorrere. La mano aperta invita
   a prendere, quella chiusa conferma la presa; se la fotografia sta
   tutta nello schermo non c'è niente da trascinare e resta il cursore
   del sito. Il cursore personalizzato è nascosto per un momento — qui
   serve quello di sistema, perché è lui a raccontare il gesto. */
.lightbox.is-zoom.e-percorribile .lb-slide.is-focus { cursor: grab; }
.lightbox.is-zoom.sta-trascinando .lb-slide.is-focus { cursor: grabbing; }

/* Il ventaglio si richiude e sparisce: da vicino le vicine sono rumore,
   e restando a fuoco spunterebbero da sotto i bordi della grande. */
.lightbox.is-zoom .lb-slide:not(.is-focus) {
  opacity: 0;
  pointer-events: none;
}
/* Il fondo si chiude del tutto. Con la fotografia a filo di schermo,
   quel 3% di trasparenza lasciava passare la pagina che scorre sotto. */
.lightbox.is-zoom { background: rgb(14, 21, 33); }

.lb-slide:focus { outline: none; }
.lb-slide:focus-visible {
  outline: 1px solid rgba(238, 238, 239, 0.7);
  outline-offset: 8px;
}

/* Dove il puntatore torna quello di sistema, torna anche qui. */
@media (hover: none) {
  .lb-slide.is-scena { cursor: pointer; }
}

/* La croce non è più display:none. Le due frecce erano gli unici elementi
   raggiungibili col tabulatore dentro il visualizzatore: toglierle e
   lasciare la croce spenta voleva dire un dialogo modale senza nessuna
   via d'uscita da tastiera. Sul computer non si vede finché non la si
   sfiora o non ci si arriva col tabulatore; sul telefono, dove non
   esiste né il passaggio né Esc, resta invisibile com'è oggi e si
   continua a chiudere toccando il fondo. */
.lightbox-close {
  position: fixed;
  top: 22px;
  left: 28px;                 /* 28 px: il margine di tutto il sito */
  width: 28px;
  height: 28px;
  padding: 0;
  border: 0;
  background: none;
  -webkit-appearance: none;
  appearance: none;
  font-family: 'PPNueMontreal', sans-serif;
  font-size: 22px;
  line-height: 1;
  color: rgba(238, 238, 239, 0);
  z-index: 2100;
}
.lightbox-close:hover { color: rgba(238, 238, 239, 0.7); }
.lightbox-close:focus { outline: none; }
.lightbox-close:focus-visible {
  color: rgba(238, 238, 239, 0.85);
  outline: 1px solid rgba(238, 238, 239, 0.5);
  outline-offset: 6px;
}

/* La barra in fondo: il numero, e ai lati i due tasti.
   È lei a stare fissa in basso, non più il contatore da solo — il
   contatore adesso è una delle tre cose in fila, e se restasse fisso per
   conto suo si sovrapporrebbe ai tasti invece di stargli in mezzo. */
.lightbox-barra {
  position: fixed;
  bottom: 22px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 2100;
  display: flex;
  align-items: center;
  gap: 14px;
  /* Il vuoto fra i tre resta del fondo, e il fondo chiude: solo i tasti
     prendono il clic. */
  pointer-events: none;
}

/* I tasti non esistono sul computer, dove il bersaglio per cambiare
   fotografia è mezza fotografia. Compaiono dove serve: su un puntatore
   che non è fine — il dito — o su uno schermo stretto. */
.lb-nav {
  display: none;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 0;
  background: none;
  -webkit-appearance: none;
  appearance: none;
  color: rgba(238, 238, 239, 0.55);
  pointer-events: auto;
  align-items: center;
  justify-content: center;
  -webkit-tap-highlight-color: transparent;
}
.lb-nav svg { width: 13px; height: 13px; display: block; }
.lb-nav:active { color: rgba(238, 238, 239, 0.9); }
.lb-nav:focus { outline: none; }
.lb-nav:focus-visible {
  outline: 1px solid rgba(238, 238, 239, 0.5);
  outline-offset: 2px;
}
/* Quarantaquattro pixel di lato: è la misura sotto la quale un bersaglio
   da toccare comincia a sbagliarsi. Il segno dentro è piccolo, la zona
   che risponde no. */
@media (hover: none), (max-width: 767px) {
  .lb-nav { display: flex; }
}
/* Da ingranditi si percorre una fotografia, non se ne cambia: i tasti si
   tolgono di mezzo invece di restare lì a offrire un salto che
   perderebbe il punto in cui si sta guardando. */
.lightbox.is-zoom .lb-nav { display: none; }

/* Invariato, tranne che adesso non intercetta il clic che chiude e sta
   dentro la barra invece di essere lui a stare fisso. */
.lightbox-counter {
  pointer-events: none;
  color: rgba(238,238,239,0.4);
  font-size: 10px;
  letter-spacing: 0.15em;
  font-family: 'PPNueMontreal', sans-serif;
}

/* Sul telefono il pallino cala di un altro 6%: 22,75 → 21,39 px.
   Con lui calano «WFPA | 2025» e «IT | EN», che devono restare della
   sua stessa misura (16,04pt = 21,39 px). Sul computer nessuno dei
   tre cambia. */
@media (max-width: 767px) {
  .hamburger-btn {
    width: 21.39px;
    height: 21.39px;
  }
  .vertical-text,
  .portrait-vertical-text { font-size: 16.04pt; }

  /* ── Il visualizzatore sul telefono ──
     Qui la larghezza è tutto. La fotografia a fuoco cede larghezza —
     72vw invece di 54 — e quello che avanza, 14vw per parte (54,6 px su
     un telefono da 390), è la vicina che spunta da dietro, tagliata
     dalla finestra.

     La composizione è la stessa del computer: le vicine sono ancora
     DIETRO, ancora infilate sotto il bordo. Cambia solo che qui il video
     le taglia. Non è un secondo disegno, è lo stesso ritagliato — ed è
     per questo che non servono selettori nuovi: cambiano sei numeri.

     Nota di cascata: `.lightbox.open { --lb-open: 1 }` vale (0,2,0) e
     batte il `.lightbox` (0,1,0) qui dentro. Le media query non
     aggiungono peso, quindi non va ripetuto. */
  .lightbox {
    /* 84vh e 94vw. Sul telefono la larghezza è tutto: una verticale 2:3
       a 94vw riempie lo schermo da bordo a bordo e ne occupa i due terzi
       in altezza, che è quanto di più vicino a «tutto lo schermo» si
       possa dare a una fotografia verticale senza tagliarla. Le vicine
       non hanno più bisogno dei 14vw per parte che si riservavano prima:
       ruotate, spuntano dagli angoli, e il video le taglia. */
    --lb-h: 84vh;
    --lb-w: 94vw;
    /* Il ventaglio si apre meno che sul computer: qui delle vicine si
       vede un angolo, non una fotografia, e 3,6° su un angolo sono un
       taglio storto. */
    --lb-fan: 2.4deg;
    --lb-raduna: 10vw;
    /* .94 e non .86: quello che si vede della vicina è una striscia, e
       arretrarla del 14% non è una profondità che si legga — è solo otto
       pixel di striscia in meno. Qui il lavoro lo fanno l'incastro, la
       sfocatura e il velo, che non dipendono da quanto ne spunta. */
    --lb-recess: .94;
    /* Su una striscia di 55 px una sfocatura da 4 px è una macchia, non
       una fotografia fuori fuoco. 2,5 px lasciano la grana. */
    --lb-blur: 2.5px;
    /* Più chiara del computer, e per lo stesso motivo: la striscia è
       corta, e su 55 px il velo al 62% la spegneva del tutto. */
    --lb-shade-in:  .46;
    --lb-shade-out: .34;
    --lb-open: .975;
  }
}
