/* ==========================================================================
   Foto Fabbiani — regole di base
   Qui sta solo ciò che theme.json non sa esprimere: il token dell'accento,
   le compensazioni tipografiche di Mrs Eaves, il focus visibile, le utility
   per didascalie e provini.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Accento — token unico.
   Cambiare questo blocco (o l'attributo data-accent su <html>) commuta
   l'intero sito. Serve per la scelta finale terracotta / salvia.
   -------------------------------------------------------------------------- */
:root {
	/* terracotta — 5.19:1 su avorio */
	--ff-accent: #A64F32;
	/* Sul nero del logo la terracotta piena scende a 3.04:1: sotto il minimo AA.
	   Il footer e le sezioni scure usano quindi questa variante schiarita, 5.16:1. */
	--ff-accent-on-dark: #C97A5C;
}

:root[data-accent="sage"] {
	--ff-accent: #5A6B52; /* verde salvia — 5.37:1 su avorio */
	--ff-accent-on-dark: #8FA383; /* 6.22:1 sul nero del logo */
}

/* --------------------------------------------------------------------------
   Compensazione Mrs Eaves.
   Mrs Eaves ha una x-height molto bassa (~0.375 em): alla stessa dimensione
   nominale appare circa il 25% più piccola di un carattere da testo normale.
   Il corpo base in theme.json è già alzato a 19-21px; qui si aggiungono
   interlinea e misura di riga, che sono l'altra metà della leggibilità.
   -------------------------------------------------------------------------- */
/* width:100vw sugli sfondamenti a piena larghezza (.ff-process__bg e
   .ff-process__scrim) misura la larghezza della finestra INCLUSA la
   scrollbar, mentre il layout è largo quanto il viewport ESCLUSA la
   scrollbar: la differenza (in genere pochi px) crea uno scroll orizzontale
   fantasma. overflow-x:hidden va su entrambi html e body — lo scrollWidth
   del documento si misura sull'elemento html, non su body — senza toccare
   nessun overflow verticale o gli overflow-x locali già in uso altrove. */
/* scrollbar-gutter:stable riserva sempre lo spazio della barra di
   scorrimento. Serve all'apertura del menu: WordPress mette overflow:hidden
   sul body (classe .has-modal-open), la barra sparisce e senza il gutter
   l'intera pagina — hamburger compreso — scivolerebbe di una quindicina di
   pixel proprio mentre la X ci si deve sovrapporre. */
html {
	overflow-x: hidden;
	scrollbar-gutter: stable;
}

body {
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
	text-rendering: optimizeLegibility;
	font-kerning: normal;
	font-variant-ligatures: common-ligatures;
	overflow-x: hidden;
}

/* Mrs Eaves ha cifre oldstyle di default: nei metadati (date, prezzi, orari)
   servono cifre allineate, altrimenti i numeri "ballano" sulla riga. */
.ff-lining-numerals,
time,
.wp-block-table td,
.wp-block-table th {
	font-family: mrs-eaves-roman-lining, mrs-eaves, Baskerville, Garamond, serif;
	font-variant-numeric: lining-nums tabular-nums;
}

p {
	max-width: 66ch;
	text-wrap: pretty;
}

/* L'interlinea 1.68 serve alle righe lunghe del desktop. Su mobile la colonna
   scende a 5-6 parole per riga e la stessa interlinea sfilaccia il paragrafo:
   l'occhio perde l'attacco della riga successiva. Sotto i 600px si stringe. */
@media (max-width: 600px) {
	html body {
		line-height: 1.52;
	}

	html body h1,
	html body h2,
	html body h3 {
		line-height: 1.1;
	}
}

/* I titoli restano liberi di occupare tutta la colonna, ma senza orfane. */
h1, h2, h3, h4 {
	text-wrap: balance;
	max-width: 22ch;
}

h1 { max-width: 18ch; }

/* Il corsivo di Mrs Eaves è marcatamente calligrafico: ottimo per una parola,
   pessimo per un paragrafo. Consentito solo per enfasi semantica breve. */
em, i {
	font-style: italic;
}

blockquote em,
blockquote i {
	font-style: normal;
}

/* --------------------------------------------------------------------------
   Occhiello / etichette in small caps.
   Sostituiscono il corsivo dove serve stacco gerarchico: Mrs Eaves Small Caps
   è la variante in cui questo carattere dà il meglio, e non porta con sé
   il tono "wedding template" del corsivo.
   -------------------------------------------------------------------------- */
.ff-eyebrow {
	font-family: mrs-eaves-roman-small-caps, mrs-eaves, Baskerville, serif;
	font-size: var(--wp--preset--font-size--small);
	letter-spacing: 0.09em;
	color: var(--wp--preset--color--ink-soft);
	display: block;
	margin-block-end: var(--wp--preset--spacing--20);
}

/* --------------------------------------------------------------------------
   Didascalie e metadati — unico territorio di Nitti Typewriter.
   Nitti nel kit ha un solo peso (400) e nessun corsivo: qualsiasi uso oltre
   questo non è supportato dai file disponibili.
   -------------------------------------------------------------------------- */
.ff-meta {
	font-family: nitti-typewriter-normal, ui-monospace, "SF Mono", Menlo, monospace;
	font-size: var(--wp--preset--font-size--caption);
	letter-spacing: 0.04em;
	line-height: 1.5;
	color: var(--wp--preset--color--ink-soft);
}

/* Riga "Formigine, Settembre 2025" nelle card delle Storie. */
.ff-meta--place {
	text-transform: none;
}

/* --------------------------------------------------------------------------
   Provino fotografico — bordo carta discreto attorno alle immagini
   che lo richiedono esplicitamente. Mai applicato di default.
   -------------------------------------------------------------------------- */
.ff-contact-print img {
	background: var(--wp--preset--color--paper);
	padding: var(--wp--preset--spacing--20);
	box-shadow: 0 1px 2px rgb(42 36 34 / 0.08), 0 8px 24px rgb(42 36 34 / 0.06);
}

/* --------------------------------------------------------------------------
   Immagini — il contenuto vero del sito.
   -------------------------------------------------------------------------- */
img {
	max-width: 100%;
	height: auto;
}

figure {
	margin: 0;
}

figcaption {
	margin-block-start: var(--wp--preset--spacing--20);
}

/* --------------------------------------------------------------------------
   Accessibilità — focus visibile su tutto ciò che è interattivo.
   Requisito esplicito del brief: l'anello non va mai rimosso.
   -------------------------------------------------------------------------- */
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
	outline: 2px solid var(--ff-accent);
	outline-offset: 3px;
	border-radius: 1px;
}

/* Salto al contenuto, visibile solo da tastiera. */
.ff-skip-link {
	position: absolute;
	left: -9999px;
	top: 0;
	z-index: 999;
	padding: var(--wp--preset--spacing--20) var(--wp--preset--spacing--30);
	background: var(--wp--preset--color--ink);
	color: var(--wp--preset--color--paper);
	font-family: mrs-eaves-roman-small-caps, mrs-eaves, serif;
	letter-spacing: 0.07em;
	text-decoration: none;
}

.ff-skip-link:focus {
	left: var(--wp--preset--spacing--30);
	top: var(--wp--preset--spacing--20);
}

/* --------------------------------------------------------------------------
   Rispetto delle preferenze di movimento.
   Il brief esclude slider automatici e parallax: qui si chiude comunque
   la porta a qualsiasi animazione residua del tema genitore.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
	*,
	*::before,
	*::after {
		animation-duration: 0.01ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.01ms !important;
		scroll-behavior: auto !important;
	}
}

/* ==========================================================================
   COMPONENTI — testata, sezioni, moduli
   ========================================================================== */

/* --------------------------------------------------------------------------
   Logo e testata
   Il lockup completo (marchio + wordmark) è 926.44x277.6. L'altezza è fissata
   qui, la larghezza segue il rapporto. Il marchio non compare mai da solo e
   mai più grande del wordmark: nel lockup è il wordmark a dominare.
   -------------------------------------------------------------------------- */
.ff-logo {
	display: inline-flex;
	flex: 0 0 auto;
	text-decoration: none;
	line-height: 0;
}

.ff-logo__img {
	display: block;
	width: auto;
	height: clamp(2.25rem, 1.9rem + 1.6vw, 3.25rem); /* 36px → 52px */
}

/* La variante chiara serve solo dove il fondo è scuro. */
.ff-logo__img--light { display: none; }

.ff-header {
	position: relative;
	z-index: 2;
}

/* Su richiesta del cliente: Nitti Typewriter 12px per il menu, non più Mrs
   Eaves small caps impostato in theme.json sul blocco core/navigation.
   !important per la stessa ragione del footer: le global styles di
   WordPress hanno la meglio sulla specificità semplice. */
.ff-nav,
.ff-nav a {
	font-family: nitti-typewriter-normal, ui-monospace, "SF Mono", Menlo, monospace !important;
	font-size: 12px !important;
	letter-spacing: 0.02em !important;
	text-decoration: none;
}

.ff-nav a:hover,
.ff-nav a:focus-visible {
	color: var(--ff-accent);
}

/* --------------------------------------------------------------------------
   MENU A SCHERMO INTERO
   Ispirato a danieleandmarilia.com: hamburger sempre visibile (overlayMenu
   "always" nel pattern header, non solo "mobile") e overlay a piena pagina
   in ink invece del bianco del tema genitore. Le voci restano in Nitti
   Typewriter su richiesta esplicita del cliente, a 17px e allineate a destra
   sotto alla X — non più la scala gigante di prima.

   L'overlay è SEMPRE renderizzato, non più display:none quando è chiuso.
   WordPress lo nasconde con "display:none" (classe .hidden-by-default e stato
   :not(.is-menu-open)), ma da display:none non parte nessuna transizione:
   l'apertura e — soprattutto — la chiusura risultavano due tagli netti.
   Qui resta invece in pagina con opacity:0 + visibility:hidden +
   pointer-events:none, così l'una e l'altra sono animabili in entrambi i
   versi. visibility è la garanzia che conta: toglie le voci anche dal
   percorso di tabulazione e dall'albero di accessibilità, cosa che la sola
   opacità non farebbe. Nella transizione ha ritardo pari alla durata in
   chiusura (resta visibile mentre sfuma) e zero in apertura.
   -------------------------------------------------------------------------- */
.wp-block-navigation__responsive-container,
.wp-block-navigation__responsive-container.hidden-by-default {
	display: flex !important;
	/* Fondo e colore stanno qui, NON sullo stato aperto: .is-menu-open viene
	   tolta nell'istante del click, e se il fondo dipendesse da quella classe
	   sparirebbe di colpo lasciando le voci a sfumare sul nulla. */
	background-color: var(--wp--preset--color--ink) !important;
	color: var(--wp--preset--color--paper) !important;
	opacity: 0;
	visibility: hidden;
	pointer-events: none;
	transition: opacity 0.5s ease, visibility 0s linear 0.5s;
	/* Il padding del contenitore va a zero e lo spazio lo prende il contenuto
	   (regole più sotto, sulle stesse --ff-burger-*). Non è estetica: questo
	   elemento porta una transform identità, che basta a farne il blocco
	   contenitore dei discendenti posizionati — i quali si ancorano quindi al
	   suo box di padding, non al viewport. Con il padding a zero i due
	   riferimenti tornano a coincidere e la X può usare le coordinate di
	   viewport misurate sull'hamburger senza doverne sottrarre nulla. */
	padding: 0 !important;
}

.wp-block-navigation__responsive-container.is-menu-open {
	opacity: 1;
	visibility: visible;
	pointer-events: auto;
	transition: opacity 0.5s ease, visibility 0s linear 0s;
}

/* position:static sui due involucri intermedi: WordPress rende il dialogo
   position:relative, e finché lo è tocca a lui — non al contenitore a piena
   pagina — fare da riferimento alla X posizionata. Il suo bordo superiore
   cade qualche pixel più in basso di quello del contenitore, e la X ereditava
   quello scarto restando disallineata rispetto all'hamburger che deve
   sostituire. Sono involucri di puro raggruppamento: renderli statici non
   toglie nulla. */
.wp-block-navigation__responsive-container .wp-block-navigation__responsive-close,
.wp-block-navigation__responsive-container .wp-block-navigation__responsive-dialog {
	width: 100%;
	position: static;
}

/* Le voci partono subito sotto la X e sono allineate al suo stesso bordo
   destro: --ff-burger-* sono misurate da site.js sull'hamburger reale
   (initMenuGeometry), perché la sua posizione dipende dall'altezza del logo e
   dal momento in cui Adobe Fonts finisce di caricare. I valori di riserva
   qui sotto tengono il menu allineato anche prima che il JS misuri. */
/* !important sul padding-top: il core di WordPress porta una propria regola
   ".is-menu-open:not(.disable-default-overlay) .wp-block-navigation__
   responsive-container-content { padding-top: calc(24px + 2rem) }" con
   specificità più alta di questa qui (stessa lotta già documentata per il
   footer), che a menu aperto sovrascriveva il calcolo corretto con un valore
   fisso di WordPress — il primo link ("Matrimoni") finiva dietro alla X di
   chiusura invece che sotto. */
.wp-block-navigation__responsive-container .wp-block-navigation__responsive-container-content {
	display: flex;
	flex-direction: column;
	align-items: flex-end;
	justify-content: flex-start;
	gap: 0;
	padding-top: calc(var(--ff-burger-top, 2rem) + var(--ff-burger-size, 2rem) + var(--wp--preset--spacing--30)) !important;
	padding-inline-end: var(--ff-burger-right, 1.5rem);
}

.wp-block-navigation__responsive-container .wp-block-navigation__container {
	align-items: flex-end;
	gap: 0;
}

.wp-block-navigation__responsive-container .wp-block-navigation-item {
	overflow: hidden;
	text-align: right;
}

/* 17px fisso su richiesta del cliente. !important obbligatorio due volte: la
   <ul> dell'overlay porta essa stessa la classe .ff-nav (WordPress la eredita
   dal blocco), quindi la regola della testata — ".ff-nav a { font-size:12px
   !important }" — colpisce anche queste voci e va pareggiata.

   Le due dichiarazioni di transizione (colore da un lato, comparsa in
   ingresso dall'altro) stanno volutamente in un'unica regola: erano separate
   in due blocchi con lo stesso identico selettore, quindi la seconda
   sovrascriveva sempre la prima per intero — la "transition: color 0.3s ease"
   qui sotto non aveva mai effetto reale, era morta. Il ritardo di comparsa
   (--ff-nav-item-delay, impostato più sotto per ogni voce) sta SOLO su
   transform e opacity: se stesse sul colore, ogni hover — non solo l'ingresso
   — aspetterebbe fino a 0.33s prima di rispondere, perché transition-delay è
   una proprietà statica dell'elemento e vale per qualunque cambio di quel
   valore, non solo per il primo. Era esattamente il ritardo percepito
   all'hover, segnalato dal cliente. */
.wp-block-navigation__responsive-container .wp-block-navigation-item__content {
	font-family: nitti-typewriter-normal, ui-monospace, "SF Mono", Menlo, monospace !important;
	font-size: 17px !important;
	letter-spacing: 0.02em !important;
	color: var(--wp--preset--color--paper) !important;
	text-align: right;
	padding: 0.35em 0 !important;
	transform: translateY(0.6em);
	opacity: 0;
	transition:
		color 0.3s ease,
		transform 0.5s cubic-bezier(0.16, 1, 0.3, 1) var(--ff-nav-item-delay, 0s),
		opacity 0.4s ease var(--ff-nav-item-delay, 0s);
}

.wp-block-navigation__responsive-container .wp-block-navigation-item__content:hover,
.wp-block-navigation__responsive-container .wp-block-navigation-item__content:focus-visible {
	color: var(--ff-accent-on-dark) !important;
}

/* La sottolineatura a comparsa della testata non ha senso qui: le voci sono
   già l'unico contenuto della schermata. Il selettore include .ff-nav perché
   la regola da battere è ".ff-nav .wp-block-navigation-item__content::after",
   che sta più in basso nel foglio: a parità di specificità avrebbe vinto lei
   per ordine di sorgente, e la sottolineatura ricompariva. Il fuoco resta
   comunque segnalato dal cambio di colore e dall'anello di :focus-visible. */
.wp-block-navigation__responsive-container .ff-nav .wp-block-navigation-item__content::after {
	content: none;
}

/* Ogni voce entra con un lieve slide-up in sequenza. Ora che il contenitore
   resta in pagina anche da chiuso, la stessa transizione lavora in entrambi i
   versi: in uscita le voci ridiscendono mentre l'overlay sfuma. */
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation-item__content {
	transform: translateY(0);
	opacity: 1;
}

.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation-item:nth-child(1) .wp-block-navigation-item__content { --ff-nav-item-delay: 0.08s; }
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation-item:nth-child(2) .wp-block-navigation-item__content { --ff-nav-item-delay: 0.13s; }
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation-item:nth-child(3) .wp-block-navigation-item__content { --ff-nav-item-delay: 0.18s; }
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation-item:nth-child(4) .wp-block-navigation-item__content { --ff-nav-item-delay: 0.23s; }
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation-item:nth-child(5) .wp-block-navigation-item__content { --ff-nav-item-delay: 0.28s; }
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation-item:nth-child(6) .wp-block-navigation-item__content { --ff-nav-item-delay: 0.33s; }

/* --------------------------------------------------------------------------
   HAMBURGER CHE DIVENTA X
   Due bottoni distinti — quello di apertura sta nella testata, quello di
   chiusura dentro l'overlay — e non è possibile fonderli in uno solo senza
   riscrivere il markup del blocco core. Si disegnano quindi le stesse due
   lineette su entrambi, nella stessa identica posizione a schermo (la
   geometria arriva dalle --ff-burger-* misurate da site.js), e si fanno
   ruotare in X insieme: mentre l'overlay sfuma in ingresso i due bottoni
   mostrano già la stessa figura sovrapposta, quindi la sostituzione non si
   percepisce e si legge come un unico segno che si trasforma.
   Le due lineette sono pseudo-elementi, non l'SVG di WordPress: un <path>
   non è ruotabile in modo indipendente senza toccarne il markup.
   -------------------------------------------------------------------------- */
.wp-block-navigation__responsive-container-open svg,
.wp-block-navigation__responsive-container-close svg {
	display: none;
}

.wp-block-navigation__responsive-container-open,
.wp-block-navigation__responsive-container-close {
	position: relative;
	width: 2rem;
	height: 2rem;
	padding: 0;
	background: none;
	border: 0;
	cursor: pointer;
	color: var(--wp--preset--color--ink);
}

.wp-block-navigation__responsive-container-open::before,
.wp-block-navigation__responsive-container-open::after,
.wp-block-navigation__responsive-container-close::before,
.wp-block-navigation__responsive-container-close::after {
	content: "";
	position: absolute;
	top: 50%;
	left: 50%;
	width: 1.5rem;
	height: 1.5px;
	margin-left: -0.75rem;
	background: currentColor;
	transition: transform 0.45s cubic-bezier(0.16, 1, 0.3, 1);
}

.wp-block-navigation__responsive-container-open::before,
.wp-block-navigation__responsive-container-close::before {
	transform: translateY(-4px);
}

.wp-block-navigation__responsive-container-open::after,
.wp-block-navigation__responsive-container-close::after {
	transform: translateY(4px);
}

/* Stato aperto. Per il bottone di chiusura basta l'antenato .is-menu-open;
   per quello di apertura, che gli è fratello, serve :has() sul blocco
   navigazione che li contiene entrambi. */
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-container-close::before,
.wp-block-navigation:has(.wp-block-navigation__responsive-container.is-menu-open) .wp-block-navigation__responsive-container-open::before {
	transform: translateY(0) rotate(45deg);
}

.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-container-close::after,
.wp-block-navigation:has(.wp-block-navigation__responsive-container.is-menu-open) .wp-block-navigation__responsive-container-open::after {
	transform: translateY(0) rotate(-45deg);
}

/* A menu aperto il segno sta sul fondo ink dell'overlay: entrambi i bottoni
   passano all'avorio, così durante la dissolvenza non si vede una X scura
   sotto a una chiara. */
.wp-block-navigation__responsive-container-close,
.wp-block-navigation:has(.wp-block-navigation__responsive-container.is-menu-open) .wp-block-navigation__responsive-container-open {
	color: var(--wp--preset--color--paper) !important;
}

/* Con la testata scura (scroll) l'hamburger va in avorio come le voci: il
   colore esplicito qui sopra non eredita più da .js-ff-header.is-scrolled. */
.js-ff-header.is-scrolled .wp-block-navigation__responsive-container-open {
	color: var(--wp--preset--color--paper);
}

/* La X si sovrappone esattamente all'hamburger della testata. L'ancoraggio è
   al contenitore dell'overlay, che copre il viewport e ha padding azzerato
   (vedi sopra): le --ff-burger-*, che sono coordinate di viewport misurate
   sull'hamburger, valgono quindi tali e quali. Inutile provare con fixed —
   la transform identità sul contenitore intercetta anche quello. */
.wp-block-navigation__responsive-container-close {
	position: absolute;
	top: var(--ff-burger-top, 2rem);
	right: var(--ff-burger-right, 1.5rem);
	z-index: 1;
}

@media (prefers-reduced-motion: reduce) {
	.wp-block-navigation__responsive-container .wp-block-navigation-item__content {
		transition: color 0.3s ease;
		transform: none;
		opacity: 1;
	}

	.wp-block-navigation__responsive-container {
		transition: none;
	}
}

/* --------------------------------------------------------------------------
   Hero
   -------------------------------------------------------------------------- */
.ff-hero__media img {
	width: 100%;
	height: clamp(20rem, 14rem + 34vw, 42rem);
	object-fit: cover;
	display: block;
}

.ff-hero__title {
	max-width: 20ch;
}

/* --------------------------------------------------------------------------
   Sezioni ricorrenti
   -------------------------------------------------------------------------- */
.ff-section-head {
	gap: var(--wp--preset--spacing--20);
	border-block-end: 1px solid var(--wp--preset--color--rule);
	padding-block-end: var(--wp--preset--spacing--20);
}

.ff-section-head h2 { margin: 0; }

/* Su richiesta del cliente: Nitti Typewriter 12px per tutti i link "di
   servizio" della pagina (door-link e simili), non più Mrs Eaves small caps. */
.ff-section-head__link,
.ff-door__link {
	margin: 0;
	font-family: nitti-typewriter-normal, ui-monospace, "SF Mono", Menlo, monospace;
	letter-spacing: 0.02em;
	font-size: 12px;
}

.ff-door__link a,
.ff-section-head__link a {
	text-decoration: none;
	border-block-end: 1px solid var(--wp--preset--color--rule);
	padding-block-end: 0.15em;
}

.ff-door__link a:hover,
.ff-door__link a:focus-visible,
.ff-section-head__link a:hover,
.ff-section-head__link a:focus-visible {
	color: var(--ff-accent);
	border-block-end-color: currentColor;
}

/* Tre ingressi e card storie: l'immagine è il contenuto, il testo la accompagna */
.ff-door__media img,
.ff-story-card__media img,
.ff-people__media img {
	width: 100%;
	display: block;
}

.ff-door__media img { aspect-ratio: 2 / 3; object-fit: cover; }
.ff-story-card__media img { aspect-ratio: 3 / 2; object-fit: cover; }

/* Marcella e Marco: la foto reale è verticale (960x1113), lasciata alla sua
   proporzione naturale invece di forzarla in un riquadro landscape. */
.ff-people__media--portrait img {
	max-height: 34rem;
	margin-inline: auto;
	object-fit: cover;
}

.ff-door h2,
.ff-story-card h3 {
	margin-block: var(--wp--preset--spacing--20) var(--wp--preset--spacing--10);
}

.ff-door p,
.ff-story-card p {
	margin-block: 0 var(--wp--preset--spacing--20);
}

/* --------------------------------------------------------------------------
   Gallerie progetti (Matrimoni, Ritratti e famiglie) — griglia con filtri e
   paginazione, tutta gestita da site.js (initProjectFilters). Le tile sono
   le stesse .ff-recent-tile della home (vedi più sotto): stesso comporta-
   mento hover, stessa forma quadrata, un solo posto dove tenerli aggiornati.
   -------------------------------------------------------------------------- */
.ff-projects-app {
	margin-top: var(--wp--preset--spacing--40);
}

.ff-projects__filters {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--wp--preset--spacing--20);
	margin-bottom: var(--wp--preset--spacing--40);
}

.ff-filter-chip {
	font-family: nitti-typewriter-normal, ui-monospace, "SF Mono", Menlo, monospace;
	font-size: 12px;
	letter-spacing: 0.04em;
	padding: 0.5em 1.1em;
	border: 1px solid var(--wp--preset--color--rule);
	background: transparent;
	color: var(--wp--preset--color--ink-soft);
	cursor: pointer;
	transition: background-color 0.25s ease, color 0.25s ease, border-color 0.25s ease;
}

.ff-filter-chip:hover,
.ff-filter-chip:focus-visible {
	border-color: var(--ff-accent);
	color: var(--ff-accent);
}

.ff-filter-chip.is-active {
	background: var(--wp--preset--color--ink);
	border-color: var(--wp--preset--color--ink);
	color: var(--wp--preset--color--paper);
}

.ff-filter-clear {
	font-family: nitti-typewriter-normal, ui-monospace, "SF Mono", Menlo, monospace;
	font-size: 12px;
	letter-spacing: 0.04em;
	padding: 0.5em 0;
	border: none;
	background: none;
	color: var(--ff-accent);
	text-decoration: underline;
	text-underline-offset: 0.2em;
	cursor: pointer;
}

/* Sotto i 700px: uno slider, una scheda alla volta con la successiva che fa
   capolino a destra (flex-basis 82%, non 100%) — scorrimento nativo, niente
   libreria, coerente con .ff-reviews__strip e .ff-recent-strip qui sotto. */
.ff-projects__grid {
	display: flex;
	overflow-x: auto;
	overflow-y: hidden;
	scroll-snap-type: x mandatory;
	gap: var(--wp--preset--spacing--30);
	padding-bottom: var(--wp--preset--spacing--10);
	scrollbar-width: thin;
	scrollbar-color: var(--wp--preset--color--ink-soft) transparent;
}

.ff-projects__grid > * {
	flex: 0 0 82%;
	scroll-snap-align: center;
}

@media (min-width: 700px) {
	.ff-projects__grid {
		display: grid;
		grid-template-columns: repeat(3, 1fr);
		gap: var(--wp--preset--spacing--30);
		overflow: visible;
		scroll-snap-type: none;
		padding-bottom: 0;
	}

	.ff-projects__grid > * {
		flex: initial;
		scroll-snap-align: none;
	}
}

@media (min-width: 1000px) {
	.ff-projects__grid {
		grid-template-columns: repeat(4, 1fr);
	}
}

/* Prima pagina di default: senza JS (o prima che giri) restano visibili solo
   le prime 16 tile invece di scaricare in un colpo solo l'intera galleria —
   site.js prende poi il controllo esatto di cosa mostrare secondo filtri e
   pagina corrente. */
.ff-projects__grid > :nth-child(n+17) {
	display: none;
}

.ff-projects__pager {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: var(--wp--preset--spacing--20);
	margin-top: var(--wp--preset--spacing--50);
}

.ff-projects__pager-item {
	font-family: nitti-typewriter-normal, ui-monospace, "SF Mono", Menlo, monospace;
	font-size: 12px;
	width: 2.4em;
	height: 2.4em;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	border: 1px solid var(--wp--preset--color--rule);
	background: transparent;
	color: var(--wp--preset--color--ink-soft);
	cursor: pointer;
	transition: background-color 0.25s ease, color 0.25s ease, border-color 0.25s ease;
}

.ff-projects__pager-item:hover,
.ff-projects__pager-item:focus-visible {
	border-color: var(--ff-accent);
	color: var(--ff-accent);
}

.ff-projects__pager-item.is-active {
	background: var(--wp--preset--color--ink);
	border-color: var(--wp--preset--color--ink);
	color: var(--wp--preset--color--paper);
}

/* --------------------------------------------------------------------------
   Processo — numerazione in Nitti, l'unico posto dove i numeri sono protagonisti
   -------------------------------------------------------------------------- */
.ff-step__num {
	margin: 0 0 var(--wp--preset--spacing--20);
	padding-block-end: var(--wp--preset--spacing--10);
	border-block-end: 1px solid rgb(250 247 242 / 0.25);
}

.ff-step h3 { margin-block: 0 var(--wp--preset--spacing--20); }

/* Foto di sfondo a piena luminosità con una velatura scura sopra — non la
   foto stessa abbassata di opacità: un'immagine chiara al 20% su un fondo
   quasi nero sparisce otticamente (verificato: il codice era corretto,
   semplicemente 0.2*chiaro + 0.8*quasi-nero resta troppo scuro per essere
   percepito). Qui la foto resta a piena intensità, e un velo ink al 60%
   sopra di lei — sotto al testo — dà il contrasto necessario per la
   leggibilità, come nel riferimento fornito dal cliente. Doppio z-index
   negativo (-2 la foto, -1 il velo), nessun riordino dell'HTML necessario. */
/* z-index:0, non solo position:relative: un elemento position:relative con
   z-index:auto (il default) NON crea un contesto di stacking isolato — i
   figli con z-index negativo finiscono per competere con l'INTERA pagina
   invece che restare contenuti qui dentro. Era esattamente questo il motivo
   per cui la foto sotto risultava invisibile: non stava dietro al testo di
   questa sezione, stava chissà dove nello stacking dell'intera pagina. */
.ff-process {
	position: relative;
	z-index: 0;
}

/* Sfondamento a piena larghezza di schermo: .ff-process è un contenitore
   "constrained" (max-width 88rem, centrato) come il resto del sito, quindi
   inset:0 fermava la foto ai bordi del contenuto, non del viewport.
   left:50% + width:100vw + translateX(-50%) centra un riquadro largo quanto
   lo schermo indipendentemente da quanto è stretto il genitore — ma le
   global styles di WordPress impongono comunque, su ogni figlio diretto di
   un contenitore .is-layout-constrained privo della classe "alignfull",
   max-width:var(--wp--style--global--content-size) e
   margin-left/right:auto !important, che scavalcano width:100vw non appena
   il viewport supera quella max-width (~88rem): da lì in poi i bordi neri.
   Aggiungere la classe "alignfull" NON è la soluzione: quella classe porta
   con sé anche la regola ".has-global-padding > .alignfull" (due classi,
   quindi più specifica del semplice margin:0 qui sotto), pensata per
   elementi nel flusso normale — su un elemento position:absolute introduce
   un margin-left negativo asimmetrico che sposta l'immagine fuori centro.
   Si neutralizza quindi solo il vincolo che serve, senza la classe. */
/* height:100% esplicito, non solo top:0 + bottom:0. Su un <img> la coppia
   top/bottom non basta: la regola generale "img { height: auto }" (poche righe
   più su, specificità di tipo ma unica dichiarazione di height presente)
   risolve l'altezza dalla proporzione intrinseca del file invece che dai due
   ancoraggi. Con hero-matrimonio.jpg, che è quadrato, l'altezza diventava pari
   alla larghezza del viewport — 1000px di foto dentro una sezione alta 740 —
   e i 260px in eccesso sfondavano sotto, comparendo come sfondo della sezione
   "Chi siamo" che segue (su schermi larghi l'eccedenza superava i 700px e la
   copriva quasi tutta). Il velo .ff-process__scrim invece era già corretto,
   ed è per questo che la foto sbordata appariva anche senza velatura. */
.ff-process__bg {
	position: absolute;
	top: 0;
	bottom: 0;
	left: 50%;
	width: 100vw;
	height: 100%;
	max-width: none !important;
	transform: translateX(-50%);
	z-index: -2;
	object-fit: cover;
	margin: 0 !important;
}

/* Elemento a sé, non uno pseudo-elemento: <img> è un elemento sostituito e
   non renderizza in modo affidabile ::before/::after in tutti i browser. */
.ff-process__scrim {
	position: absolute;
	top: 0;
	bottom: 0;
	left: 50%;
	width: 100vw;
	max-width: none !important;
	transform: translateX(-50%);
	z-index: -1;
	background: rgb(29 29 27 / 0.6);
	margin: 0 !important;
}

/* Sezioni a fondo scuro: link e accenti passano alla variante chiara. */
.ff-process a,
.ff-availability a,
.ff-footer a {
	color: var(--wp--preset--color--paper);
	text-underline-offset: 0.2em;
}

.ff-process a:hover,
.ff-availability a:hover,
.ff-footer a:hover,
.ff-process a:focus-visible,
.ff-availability a:focus-visible,
.ff-footer a:focus-visible {
	color: var(--ff-accent-on-dark);
}

.ff-process .ff-eyebrow,
.ff-availability .ff-eyebrow,
.ff-footer .ff-eyebrow,
.ff-process .ff-meta,
.ff-availability .ff-meta,
.ff-footer .ff-meta {
	color: rgb(250 247 242 / 0.72);
}

/* --------------------------------------------------------------------------
   Recensioni — striscia scorrevole orizzontalmente (Matrimonio.com).
   Scroll-snap così ogni card si "aggancia" invece di fermarsi a metà;
   scrollbar visibile perché qui è essa stessa l'invito a scorrere.
   -------------------------------------------------------------------------- */
.ff-reviews__strip {
	display: flex;
	gap: var(--wp--preset--spacing--40);
	overflow-x: auto;
	overflow-y: hidden;
	scroll-snap-type: x proximity;
	padding-block-end: var(--wp--preset--spacing--20);
	padding-inline: var(--wp--preset--spacing--30);
	margin-inline: calc(var(--wp--preset--spacing--30) * -1);
	scrollbar-width: thin;
	scrollbar-color: var(--wp--preset--color--ink-soft) transparent;
}

.ff-review {
	flex: 0 0 auto;
	width: min(85vw, 26rem);
	scroll-snap-align: start;
	border-inline-start: 1px solid var(--wp--preset--color--rule);
	padding-inline-start: var(--wp--preset--spacing--30);
}

.ff-review p:first-child { margin-block-start: 0; }

/* L'ultima card della striscia è un invito esplicito a proseguire fuori dal
   sito, non solo una recensione: si distingue con un fondo pieno. */
.ff-review--more {
	display: flex;
	flex-direction: column;
	justify-content: center;
	border-inline-start: none;
	background: var(--wp--preset--color--paper-alt);
	padding: var(--wp--preset--spacing--30);
	text-decoration: none;
	color: var(--wp--preset--color--ink);
	transition: background-color 0.25s ease;
}

.ff-review--more:hover,
.ff-review--more:focus-visible {
	background: var(--wp--preset--color--rule);
}

.ff-review--more p { margin-block-start: var(--wp--preset--spacing--10); }

/* --------------------------------------------------------------------------
   Lavori recenti — tile quadrate "attaccate" (gap:0, si toccano) disposte
   su due righe (grid-auto-flow:column con due righe fisse, invece di
   un'unica fila): con almeno 8 tile restano visibili quattro progetti per
   riga senza dover scorrere sugli schermi larghi, e la griglia continua ad
   aggiungere colonne — restando scorrevole verso destra — quando in futuro
   se ne aggiungeranno altre. Volutamente diverse dalle colonne di testo
   delle sezioni servizio: qui la forma stessa segnala "sono progetti da
   sfogliare", non "leggi cosa offriamo". L'anteprima a scorrimento
   sull'hover è gestita da .ff-hover-preview (site.js + regole più sopra).
   Su desktop con mouse reale la didascalia resta nascosta finché non si
   passa sopra la tile — solo immagini, come richiesto: comparsa in fade-in
   insieme al velo, in coppia con il carosello che parte nello stesso
   momento. Su touch (niente hover vero) resta sempre visibile: senza
   quell'indizio visivo il progetto non si riconoscerebbe prima del tocco.
   -------------------------------------------------------------------------- */
/* Sotto i 900px: stesso slider a scheda singola di .ff-projects__grid — una
   foto alla volta, la successiva che fa capolino a destra. Da 900px in su
   torna alla griglia a due righe "attaccate" originaria. */
.ff-recent-strip {
	display: flex;
	overflow-x: auto;
	overflow-y: hidden;
	scroll-snap-type: x mandatory;
	gap: var(--wp--preset--spacing--30);
	margin-top: var(--wp--preset--spacing--40);
	scrollbar-width: thin;
	scrollbar-color: var(--wp--preset--color--ink-soft) transparent;
}

.ff-recent-strip > * {
	flex: 0 0 82%;
	scroll-snap-align: center;
}

/* Da 900px in su le prime quattro colonne (le otto tile attuali, due righe
   da quattro) si allargano a riempire tutta la larghezza del contenitore,
   invece di restare ancorate a sinistra con vuoto a destra — segnalato dal
   cliente con uno screenshot dei due margini tracciati in rosso. Solo le
   prime 4 colonne: eventuali tile aggiuntive in futuro (una quinta colonna
   e oltre) continuano a usare grid-auto-columns qui sopra, così la riga
   trabocca e scorre invece di schiacciare tutte le colonne per farcele
   stare — quello sì che romperebbe il quadrato delle tile. */
@media (min-width: 900px) {
	.ff-recent-strip {
		display: grid;
		grid-auto-flow: column;
		grid-auto-columns: min(45vw, 16rem);
		grid-template-columns: repeat(4, minmax(0, 1fr));
		grid-template-rows: repeat(2, auto);
		gap: 0;
		scroll-snap-type: x proximity;
	}

	.ff-recent-strip > * {
		flex: initial;
		scroll-snap-align: none;
	}
}

/* Sotto ai due breakpoint qui sotto (700px nelle pagine progetto, 900px in
   home): tile "da slider", foto in alto con proporzione fissa e didascalia
   sotto, sempre leggibile — non più il quadrato con testo sovrapposto in
   velatura, pensato per l'hover che su touch non esiste. Da lì in su le
   regole dentro i due blocchi min-width restituiscono il quadrato con la
   didascalia in overlay-su-hover originaria. */
.ff-recent-tile {
	position: relative;
	width: 100%;
	scroll-snap-align: center;
	display: flex;
	flex-direction: column;
	text-decoration: none;
	color: inherit;
}

.ff-recent-tile .ff-hover-preview {
	width: 100%;
	aspect-ratio: 4 / 5;
	flex-shrink: 0;
}

.ff-recent-tile__caption {
	padding: var(--wp--preset--spacing--20) 0 0;
	color: var(--wp--preset--color--ink);
}

@media (min-width: 700px) {
	.ff-projects__grid .ff-recent-tile {
		aspect-ratio: 1;
		display: block;
	}

	.ff-projects__grid .ff-recent-tile .ff-hover-preview {
		aspect-ratio: auto;
		height: 100%;
	}

	/* Leggibilità del testo sovrapposto: velo più coprente e più esteso
	   verso l'alto (arrivava solo al 60% dell'altezza, lasciando la parte
	   centrale della tile priva di scurimento se la foto lì era chiara),
	   più un'ombra diretta sul testo stesso — doppia garanzia indipendente
	   dalla luminosità della foto sotto, non solo dal gradiente. */
	.ff-projects__grid .ff-recent-tile__caption {
		position: absolute;
		inset-inline: 0;
		bottom: 0;
		padding: var(--wp--preset--spacing--30);
		background: linear-gradient(to top, rgb(29 29 27 / 0.88), rgb(29 29 27 / 0.35) 55%, rgb(29 29 27 / 0) 100%);
		color: var(--wp--preset--color--paper);
		text-shadow: 0 1px 6px rgb(0 0 0 / 0.45);
		pointer-events: none;
	}

	@media (hover: hover) and (pointer: fine) {
		.ff-projects__grid .ff-recent-tile__caption {
			opacity: 0;
			transition: opacity 0.35s ease;
		}

		.ff-projects__grid .ff-recent-tile:hover .ff-recent-tile__caption,
		.ff-projects__grid .ff-recent-tile:focus-visible .ff-recent-tile__caption {
			opacity: 1;
		}

		@media (prefers-reduced-motion: reduce) {
			.ff-projects__grid .ff-recent-tile__caption {
				transition: none;
			}
		}
	}
}

@media (min-width: 900px) {
	.ff-recent-strip .ff-recent-tile {
		aspect-ratio: 1;
		display: block;
	}

	.ff-recent-strip .ff-recent-tile .ff-hover-preview {
		aspect-ratio: auto;
		height: 100%;
	}

	.ff-recent-strip .ff-recent-tile__caption {
		position: absolute;
		inset-inline: 0;
		bottom: 0;
		padding: var(--wp--preset--spacing--30);
		background: linear-gradient(to top, rgb(29 29 27 / 0.88), rgb(29 29 27 / 0.35) 55%, rgb(29 29 27 / 0) 100%);
		color: var(--wp--preset--color--paper);
		text-shadow: 0 1px 6px rgb(0 0 0 / 0.45);
		pointer-events: none;
	}

	@media (hover: hover) and (pointer: fine) {
		.ff-recent-strip .ff-recent-tile__caption {
			opacity: 0;
			transition: opacity 0.35s ease;
		}

		.ff-recent-strip .ff-recent-tile:hover .ff-recent-tile__caption,
		.ff-recent-strip .ff-recent-tile:focus-visible .ff-recent-tile__caption {
			opacity: 1;
		}

		@media (prefers-reduced-motion: reduce) {
			.ff-recent-strip .ff-recent-tile__caption {
				transition: none;
			}
		}
	}
}

/* Titolo più contenuto (era font-size--medium, troppo grande accanto alla
   didascalia) e interlinea stretta: a piena misura Mrs Eaves porta con sé
   l'interlinea larga impostata per il testo lungo, qui invece il titolo è
   corto e su una riga sola — l'interlinea da paragrafo lo staccava troppo
   dalla riga di didascalia sotto. */
.ff-recent-tile__title {
	display: block;
	font-family: mrs-eaves-roman-small-caps, mrs-eaves, Baskerville, serif;
	font-size: var(--wp--preset--font-size--small);
	line-height: 1.15;
	margin-block-end: 0.15em;
}

/* Nitti fissato a 12px (non la clamp fluida di --caption, su richiesta del
   cliente) e interlinea più stretta di quella usata nei blocchi di testo
   lunghi (.ff-prose-nitti ha line-height:1.7, pensata per paragrafi — qui è
   una riga sola di metadato, quella stessa interlinea sembrava un vuoto
   ingiustificato sotto il titolo).
   !important sul font-size: il markup porta anche la classe utility
   "has-caption-font-size" e le global styles di WP la emettono come
   ".has-caption-font-size{font-size:var(...) !important}" — senza pareggiare
   con !important qui, quella regola vince nonostante la specificità più
   bassa. */
.ff-recent-tile .ff-meta {
	font-size: 12px !important;
	line-height: 1.3;
	color: var(--wp--preset--color--ink-soft);
	opacity: 1;
}

@media (min-width: 700px) {
	.ff-projects__grid .ff-recent-tile .ff-meta {
		color: var(--wp--preset--color--paper);
		opacity: 0.9;
	}
}

@media (min-width: 900px) {
	.ff-recent-strip .ff-recent-tile .ff-meta {
		color: var(--wp--preset--color--paper);
		opacity: 0.9;
	}
}

/* --------------------------------------------------------------------------
   CTA segmentata
   -------------------------------------------------------------------------- */
.ff-cta__card {
	background: var(--wp--preset--color--paper-alt);
	padding: var(--wp--preset--spacing--40);
	display: flex;
	flex-direction: column;
}

.ff-cta__card h3 { margin-block: 0 var(--wp--preset--spacing--20); }
.ff-cta__card p { margin-block: 0 var(--wp--preset--spacing--30); flex: 1 1 auto; }
.ff-cta__card .wp-block-buttons { margin-block-start: auto; }

/* --------------------------------------------------------------------------
   Nota di prezzo e segnaposto redazionali
   -------------------------------------------------------------------------- */
.ff-price-note {
	max-width: 46rem;
	color: var(--wp--preset--color--ink-soft);
}

/* Marcatore visibile dei contenuti ancora da fornire: deve saltare all'occhio
   in fase di revisione e sparire quando il testo reale prende il suo posto. */
/* Niente white-space: nowrap — su mobile un marcatore lungo sfonda la colonna
   e trascina l'intera pagina in scroll orizzontale. */
.ff-note {
	font-family: nitti-typewriter-normal, ui-monospace, Menlo, monospace;
	font-size: 0.72em;
	letter-spacing: 0.04em;
	color: var(--ff-accent);
	overflow-wrap: anywhere;
}

/* Anche le didascalie in Nitti: è monospaziato, quindi non si comprime da solo. */
.ff-meta {
	overflow-wrap: anywhere;
}

/* --------------------------------------------------------------------------
   Moduli
   -------------------------------------------------------------------------- */
.ff-form-wrap { margin-block-start: var(--wp--preset--spacing--40); }

.ff-form__grid {
	display: grid;
	grid-template-columns: 1fr;
	gap: var(--wp--preset--spacing--30);
}

@media (min-width: 700px) {
	.ff-form__grid { grid-template-columns: 1fr 1fr; }
	.ff-field--full { grid-column: 1 / -1; }
}

.ff-field { margin: 0; }

.ff-field label {
	display: block;
	font-family: mrs-eaves-roman-small-caps, mrs-eaves, Baskerville, serif;
	font-size: var(--wp--preset--font-size--small);
	letter-spacing: 0.07em;
	margin-block-end: 0.4em;
}

.ff-field input,
.ff-field select,
.ff-field textarea {
	/* I controlli di modulo non ereditano il box-sizing del tema: senza questo,
	   width:100% più il padding li fa sporgere oltre la colonna. */
	box-sizing: border-box;
	width: 100%;
	max-width: 100%;
	font-family: inherit;
	font-size: var(--wp--preset--font-size--small);
	color: var(--wp--preset--color--ink);
	background: var(--wp--preset--color--paper);
	border: 1px solid var(--wp--preset--color--rule);
	border-radius: 0;
	padding: 0.75em 0.9em;
	line-height: 1.4;
}

.ff-field textarea { resize: vertical; }

.ff-field input:focus-visible,
.ff-field textarea:focus-visible {
	outline: 2px solid var(--ff-accent-on-dark);
	outline-offset: 2px;
	border-color: transparent;
}

/* --------------------------------------------------------------------------
   Select personalizzata — il <select> nativo (nascosto da site.js, che
   costruisce qui accanto pulsante + listbox) porta con sé un pannello di
   opzioni che nessun CSS può restilizzare in modo affidabile fra i browser:
   segnalato dal cliente con screenshot del popup ancora di sistema. Pulsante
   e lista qui sotto replicano esattamente lo stesso trattamento di
   input/textarea (bordo, padding, hover), font Nitti compreso, anche a
   pannello aperto. Se JS non gira, il <select> nativo resta visibile e
   funzionante (site.js lo nasconde solo dopo averlo potenziato). */
.ff-select {
	position: relative;
}

.ff-select__button {
	display: block;
	width: 100%;
	box-sizing: border-box;
	text-align: left;
	font-family: inherit;
	font-size: var(--wp--preset--font-size--small);
	color: var(--wp--preset--color--ink);
	background: var(--wp--preset--color--paper);
	border: 1px solid var(--wp--preset--color--rule);
	border-radius: 0;
	padding: 0.75em 2.4em 0.75em 0.9em;
	line-height: 1.4;
	cursor: pointer;
	transition: border-color 0.2s ease;
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5 11 1.5' fill='none' stroke='%231D1D1B' stroke-width='1.3' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
	background-repeat: no-repeat;
	background-position: right 0.9em center;
	background-size: 0.7em auto;
}

.ff-select__button:hover {
	border-color: var(--wp--preset--color--ink);
}

/* Freccia capovolta a pannello aperto, stesso tratto e colore. */
.ff-select.is-open .ff-select__button {
	border-color: var(--wp--preset--color--ink);
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 6.5 6 1.5 11 6.5' fill='none' stroke='%231D1D1B' stroke-width='1.3' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

.ff-select__button:focus-visible {
	outline: 2px solid var(--ff-accent-on-dark);
	outline-offset: 2px;
	border-color: transparent;
}

.ff-select__list {
	position: absolute;
	z-index: 20;
	inset-inline: 0;
	top: calc(100% + 0.3em);
	max-height: 16rem;
	overflow-y: auto;
	margin: 0;
	padding: 0.3em 0;
	list-style: none;
	background: var(--wp--preset--color--paper);
	border: 1px solid var(--wp--preset--color--ink);
	box-shadow: 0 12px 24px rgb(29 29 27 / 0.12);
}

.ff-select__option {
	padding: 0.6em 0.9em;
	font-family: inherit;
	font-size: var(--wp--preset--font-size--small);
	color: var(--wp--preset--color--ink);
	cursor: pointer;
}

.ff-select__option.is-highlighted,
.ff-select__option:hover {
	background: var(--wp--preset--color--paper-alt);
}

.ff-select__option[aria-selected="true"] {
	color: var(--ff-accent);
}

/* --------------------------------------------------------------------------
   Calendario personalizzato — stesso principio della select: il pannello
   nativo di <input type="date"> è disegnato dal sistema operativo e non
   restilizzabile in nessun browser, segnalato dal cliente sullo stesso
   modulo. Numeri (giorni, mese, anno) in Nitti Typewriter su richiesta
   esplicita: è l'unico punto del calendario dove i numeri sono protagonisti,
   stessa logica già applicata altrove nel sito (.ff-step__num). */
.ff-date {
	position: relative;
}

.ff-date__button {
	display: block;
	width: 100%;
	box-sizing: border-box;
	text-align: left;
	font-family: inherit;
	font-size: var(--wp--preset--font-size--small);
	color: var(--wp--preset--color--ink);
	background: var(--wp--preset--color--paper);
	border: 1px solid var(--wp--preset--color--rule);
	border-radius: 0;
	padding: 0.75em 0.9em;
	line-height: 1.4;
	cursor: pointer;
	transition: border-color 0.2s ease;
}

.ff-date__button:hover,
.ff-date.is-open .ff-date__button {
	border-color: var(--wp--preset--color--ink);
}

.ff-date__button:focus-visible {
	outline: 2px solid var(--ff-accent-on-dark);
	outline-offset: 2px;
	border-color: transparent;
}

.ff-date__panel {
	position: absolute;
	z-index: 20;
	top: calc(100% + 0.3em);
	left: 0;
	width: 18rem;
	max-width: 90vw;
	padding: var(--wp--preset--spacing--20);
	box-sizing: border-box;
	background: var(--wp--preset--color--paper);
	color: var(--wp--preset--color--ink);
	border: 1px solid var(--wp--preset--color--ink);
	box-shadow: 0 12px 24px rgb(29 29 27 / 0.12);
}

.ff-date__header {
	display: flex;
	align-items: center;
	justify-content: space-between;
	margin-block-end: var(--wp--preset--spacing--20);
}

.ff-date__month {
	font-family: nitti-typewriter-normal, ui-monospace, "SF Mono", Menlo, monospace;
	font-size: var(--wp--preset--font-size--small);
	letter-spacing: 0.02em;
	color: var(--wp--preset--color--ink);
}

.ff-date__nav {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 1.8rem;
	height: 1.8rem;
	font-size: 1rem;
	line-height: 1;
	color: var(--wp--preset--color--ink);
	background: none;
	border: 1px solid var(--wp--preset--color--rule);
	cursor: pointer;
}

.ff-date__nav:hover {
	border-color: var(--wp--preset--color--ink);
	color: var(--ff-accent);
}

.ff-date__weekdays,
.ff-date__days {
	display: grid;
	grid-template-columns: repeat(7, 1fr);
	gap: 0.15rem;
}

.ff-date__weekdays span {
	text-align: center;
	font-family: nitti-typewriter-normal, ui-monospace, "SF Mono", Menlo, monospace;
	font-size: 0.7rem;
	letter-spacing: 0.02em;
	color: var(--wp--preset--color--ink-soft);
	padding-block-end: 0.4em;
}

.ff-date__day {
	aspect-ratio: 1;
	display: flex;
	align-items: center;
	justify-content: center;
	font-family: nitti-typewriter-normal, ui-monospace, "SF Mono", Menlo, monospace;
	font-size: 0.75rem;
	color: var(--wp--preset--color--ink);
	background: none;
	border: 1px solid transparent;
	cursor: pointer;
}

.ff-date__day--empty {
	cursor: default;
}

.ff-date__day:not(.ff-date__day--empty):hover {
	background: var(--wp--preset--color--paper-alt);
}

.ff-date__day.is-today {
	border-color: var(--wp--preset--color--rule);
}

.ff-date__day.is-selected {
	background: var(--wp--preset--color--ink);
	color: var(--wp--preset--color--paper);
}

.ff-date__footer {
	display: flex;
	justify-content: space-between;
	margin-block-start: var(--wp--preset--spacing--20);
	padding-block-start: var(--wp--preset--spacing--20);
	border-block-start: 1px solid var(--wp--preset--color--rule);
}

.ff-date__action {
	font-family: nitti-typewriter-normal, ui-monospace, "SF Mono", Menlo, monospace;
	font-size: 0.72rem;
	letter-spacing: 0.02em;
	color: var(--ff-accent);
	background: none;
	border: none;
	padding: 0;
	cursor: pointer;
}

.ff-date__action:hover {
	text-decoration: underline;
}

/* "obbligatorio" resta leggibile dagli screen reader ma in pagina è un asterisco:
   ripetere la parola in ogni etichetta appesantirebbe il modulo. */
.ff-req {
	font-size: 0;
	letter-spacing: 0;
}

.ff-req::before {
	content: "*";
	font-size: 1rem;
	color: var(--ff-accent-on-dark);
	margin-inline-start: 0.2em;
}

.ff-form__hp {
	position: absolute;
	left: -9999px;
	width: 1px;
	height: 1px;
	overflow: hidden;
}

.ff-form__submit { margin-block-start: var(--wp--preset--spacing--40); }

.ff-form__submit button {
	font-family: mrs-eaves-roman-small-caps, mrs-eaves, Baskerville, serif;
	font-size: var(--wp--preset--font-size--small);
	letter-spacing: 0.06em;
	background: var(--wp--preset--color--paper);
	color: var(--wp--preset--color--ink);
	border: 1px solid var(--wp--preset--color--paper);
	border-radius: 0;
	padding: 0.9em 1.6em;
	cursor: pointer;
	/* Stessa animazione dei bottoni CTA (.wp-block-button__link): un
	   pulsante "Accedi" fermo, in mezzo a un modulo, altrimenti sembrava
	   meno interattivo dei pulsanti hero pur avendo lo stesso ruolo. */
	transition: transform 0.35s cubic-bezier(0.16, 1, 0.3, 1),
		box-shadow 0.35s cubic-bezier(0.16, 1, 0.3, 1),
		background-color 0.35s ease, border-color 0.35s ease, color 0.35s ease;
	will-change: transform;
}

.ff-form__submit button:hover,
.ff-form__submit button:focus-visible {
	background: var(--ff-accent-on-dark);
	border-color: var(--ff-accent-on-dark);
	color: var(--wp--preset--color--ink);
	transform: translateY(-3px);
	box-shadow: 0 14px 28px -12px rgb(29 29 27 / 0.35);
}

.ff-form__submit button:active {
	transform: translateY(-1px);
	box-shadow: 0 6px 14px -8px rgb(29 29 27 / 0.3);
	transition-duration: 0.12s;
}

@media (prefers-reduced-motion: reduce) {
	.ff-form__submit button {
		transition-property: background-color, border-color, color;
	}

	.ff-form__submit button:hover,
	.ff-form__submit button:focus-visible,
	.ff-form__submit button:active {
		transform: none;
		box-shadow: none;
	}
}

/* Bottoni-blocco (.wp-block-button__link) dentro una sezione a fondo scuro
   (.ff-availability): di default un bottone eredita ink/paper dal tema, cioè
   quasi invisibile sul fondo ink di questa sezione. Stessa coppia
   paper/ink→accento usata sopra per il bottone dei moduli, così "Vai ai tuoi
   file" ed "Esci" nell'area privata restano leggibili e coerenti con il resto
   del sito, mantenendo l'animazione già propria di .wp-block-button__link. */
.ff-availability .wp-block-button__link {
	background-color: var(--wp--preset--color--paper);
	color: var(--wp--preset--color--ink);
	border-color: var(--wp--preset--color--paper);
}

.ff-availability .wp-block-button__link:hover,
.ff-availability .wp-block-button__link:focus-visible {
	background-color: var(--ff-accent-on-dark);
	border-color: var(--ff-accent-on-dark);
	color: var(--wp--preset--color--ink);
}

.ff-form__privacy { margin-block-start: var(--wp--preset--spacing--20); }

.ff-notice {
	border-inline-start: 3px solid currentColor;
	padding: var(--wp--preset--spacing--20) var(--wp--preset--spacing--30);
	margin-block-end: var(--wp--preset--spacing--30);
	font-size: var(--wp--preset--font-size--small);
}

.ff-notice--ok { color: var(--ff-accent-on-dark); }
.ff-notice--ko { color: #F0A090; }

/* --------------------------------------------------------------------------
   Piè di pagina
   -------------------------------------------------------------------------- */
.ff-footer__logo {
	display: block;
	width: auto;
	height: clamp(2.5rem, 2.2rem + 1.2vw, 3.25rem);
}

/* Icone social sotto il payoff: linee sottili in currentColor, non loghi a
   colori pieni — restano coerenti con il tratto fine del monogramma e non
   introducono i colori di brand di terzi (rosa Instagram, blu Facebook...)
   in una pagina altrimenti solo ink/paper. */
.ff-social {
	display: flex;
	gap: var(--wp--preset--spacing--20);
	margin-top: var(--wp--preset--spacing--30);
}

/* L'opacità 0/1 di ".ff-reveal" (vedi sistema di reveal più sotto) governa
   già l'elemento <a>: l'attenuazione a riposo e l'hover vanno quindi sull'
   <svg> interno, non sull'<a> stesso, altrimenti questa regola (due classi,
   più specifica di ".ff-reveal") vincerebbe sempre e l'icona non sparirebbe
   mai prima dell'animazione d'ingresso. */
.ff-social a {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 2rem;
	height: 2rem;
	color: var(--wp--preset--color--paper);
}

.ff-social svg {
	width: 1.35rem;
	height: 1.35rem;
	opacity: 0.7;
	transition: opacity 0.2s ease;
}

.ff-social a:hover svg,
.ff-social a:focus-visible svg {
	opacity: 1;
}

.ff-footer__list { list-style: none; padding: 0; margin: 0; }
.ff-footer__list li { margin-block-end: 0.35em; font-size: var(--wp--preset--font-size--small); }

/* Area di tocco: i link in colonna vanno portati sopra i 24px di altezza,
   altrimenti su mobile si sbaglia bersaglio. */
.ff-footer__list a {
	text-decoration: none;
	display: inline-block;
	padding-block: 0.3em;
}
.ff-footer__list a:hover { text-decoration: underline; }

.ff-footer__rule {
	border: 0;
	border-block-start: 1px solid rgb(250 247 242 / 0.2);
	margin-block: var(--wp--preset--spacing--50);
}

.ff-footer__bottom { gap: var(--wp--preset--spacing--30); }

/* Il monogramma nel footer resta un timbro, non un protagonista. */
.ff-footer__mark {
	display: block;
	width: auto;
	height: 2rem;
	opacity: 0.75;
}

.ff-footer__bottom p { margin: 0; }

/* Orari di apertura: <dl> con giorno e fascia oraria affiancati invece di un
   'p' unico, per allineare in colonna anche a lunghezze di testo diverse
   ("Chiuso" contro "09–12:30, 16–19:30") senza dover indovinare a mano gli
   spazi — cosa che un monospace come Nitti tollererebbe ma non garantirebbe
   su ogni dimensione di schermo. */
.ff-hours {
	margin: 0;
	display: grid;
	grid-template-columns: auto 1fr;
	column-gap: 0.75em;
}

.ff-hours__row {
	display: contents;
}

.ff-hours dt,
.ff-hours dd {
	margin: 0;
	font: inherit;
	letter-spacing: inherit;
	color: inherit;
}

/* ==========================================================================
   TESTATA — sempre visibile, nessun nascondimento allo scroll.

   position: fixed, non sticky. Il wrapper <header> generato dal
   template-part di WordPress avvolge l'header con un'altezza identica alla
   sua (nessun margine extra): per come funziona position:sticky, l'elemento
   "si sblocca" non appena si supera l'altezza del proprio contenitore
   diretto, quindi con sticky la testata restava ancorata solo per i primi
   ~100px di scroll e poi scorreva via normalmente con il resto della pagina
   — verificato misurando bounding rect a diverse profondità di scroll.
   Fixed non dipende dal contenitore ed è sempre ancorata al viewport.
   Il main-tag riceve un padding-top pari all'altezza reale della testata,
   impostato da site.js (measureHeaderHeight) perché l'altezza cambia in
   base a viewport e al momento in cui Adobe Fonts carica il menu.
   ========================================================================== */
.js-ff-header {
	position: fixed;
	top: 0;
	left: 0;
	right: 0;
	z-index: 60;
	background: var(--wp--preset--color--paper);
	transition: background-color 0.3s ease, color 0.3s ease;
}

.wp-site-blocks > main {
	padding-top: var(--ff-header-h, 6rem);
}

/* --------------------------------------------------------------------------
   Testata durante lo scroll: fondo scuro pieno, logo e menu bianchi. La
   classe .is-scrolled è aggiunta da site.js appena si supera una soglia
   minima di scroll.

   NOTA: qui era stato provato mix-blend-mode:multiply per un effetto di
   trasfusione col contenuto sotto, ma un elemento position:fixed viene quasi
   sempre promosso dal browser a un livello di compositing separato (per le
   prestazioni dello scroll), e mix-blend-mode non riesce ad attraversare
   quel confine — risultato verificato: un rettangolo nero piatto, nessuna
   trasfusione. Non è un problema risolvibile con altro CSS sull'elemento
   stesso; qui resta il fondo pieno.
   -------------------------------------------------------------------------- */
.js-ff-header.is-scrolled {
	background-color: #1d1d1c;
}

.js-ff-header.is-scrolled .ff-nav,
.js-ff-header.is-scrolled .ff-nav a,
.js-ff-header.is-scrolled .wp-block-site-title a {
	color: var(--wp--preset--color--paper);
}

.js-ff-header.is-scrolled .ff-logo__img--dark { display: none; }
.js-ff-header.is-scrolled .ff-logo__img--light { display: block; }

/* ==========================================================================
   PRELOADER — schermata ink con conteggio 0→100%, ispirata a
   danieleandmarilia.com. Markup iniettato via wp_body_open (functions.php),
   qui solo l'aspetto. site.js anima il numero e aggiunge .is-done a fine
   conteggio per lo scomparire in dissolvenza.

   Solo alla prima pagina della sessione: se lo script inline in
   functions.php trova già il flag in sessionStorage, aggiunge
   .ff-preloader-skip su <html> PRIMA che questo elemento venga dipinto —
   quella regola lo nasconde con un secco "display:none", niente
   transizione, per evitare il lampo di un loader che compare e sparisce
   in un frame. Stesso discorso per prefers-reduced-motion: chi ha
   disattivato le animazioni non deve aspettare un conteggio comunque
   inutile per lui. */
.ff-preloader {
	position: fixed;
	inset: 0;
	z-index: 9999;
	display: flex;
	align-items: flex-end;
	background: var(--wp--preset--color--ink);
	padding: var(--wp--preset--spacing--40);
	transition: opacity 0.6s ease;
}

.ff-preloader__count {
	font-family: nitti-typewriter-normal, ui-monospace, "SF Mono", Menlo, monospace;
	font-size: clamp(1.75rem, 1.3rem + 2vw, 2.75rem);
	letter-spacing: 0.02em;
	color: var(--wp--preset--color--paper);
	font-variant-numeric: tabular-nums;
}

.ff-preloader.is-done {
	opacity: 0;
	pointer-events: none;
}

html.ff-preloader-skip .ff-preloader {
	display: none;
}

@media (prefers-reduced-motion: reduce) {
	.ff-preloader {
		display: none;
	}
}

/* ==========================================================================
   FRECCIA "TORNA SU" — iniettata via wp_footer, presente su tutto il sito.
   Nascosta di default: site.js aggiunge .is-visible dopo un po' di scroll.
   Senza JS resta invisibile — non è un link "#" che romperebbe la tastiera.
   ========================================================================== */
.ff-back-to-top {
	position: fixed;
	right: var(--wp--preset--spacing--30);
	bottom: var(--wp--preset--spacing--30);
	z-index: 55;
	width: 3rem;
	height: 3rem;
	display: flex;
	align-items: center;
	justify-content: center;
	background: var(--wp--preset--color--ink);
	color: var(--wp--preset--color--paper);
	border: none;
	border-radius: 0;
	font-size: 1.25rem;
	line-height: 1;
	cursor: pointer;
	opacity: 0;
	transform: translateY(12px);
	pointer-events: none;
	transition: opacity 0.3s ease, transform 0.3s ease, background-color 0.2s ease;
}

.ff-back-to-top.is-visible {
	opacity: 1;
	transform: translateY(0);
	pointer-events: auto;
}

.ff-back-to-top:hover,
.ff-back-to-top:focus-visible {
	background: var(--ff-accent);
}

/* ==========================================================================
   REVEAL IN INGRESSO
   Ispirato al trattamento di for-living.it, ma in CSS/JS puro: niente GSAP,
   niente ScrollTrigger, niente Lenis — il brief esclude parallax vistoso e
   il sito deve restare leggero su mobile. La classe .js-anim è aggiunta da
   site.js solo se esistono elementi .ff-reveal: senza JavaScript la regola
   sottostante non si applica mai, quindi il contenuto resta visibile di
   default (nessun rischio di pagina bloccata invisibile).
   ========================================================================== */
html.js-anim .ff-reveal {
	opacity: 0;
	transform: translateY(38px);
	transition: opacity 0.9s cubic-bezier(0.16, 1, 0.3, 1), transform 0.9s cubic-bezier(0.16, 1, 0.3, 1);
}

html.js-anim .ff-reveal.is-visible {
	opacity: 1;
	transform: translateY(0);
}

/* Scaglionamento dentro le griglie, così le card non appaiono tutte nello
   stesso istante. */
html.js-anim .ff-doors__grid .ff-reveal:nth-child(2) { transition-delay: 0.1s; }
html.js-anim .ff-doors__grid .ff-reveal:nth-child(3) { transition-delay: 0.2s; }
html.js-anim .ff-stories__grid .ff-reveal:nth-child(2),
html.js-anim .ff-cta__grid .ff-reveal:nth-child(2) { transition-delay: 0.1s; }
html.js-anim .ff-stories__grid .ff-reveal:nth-child(3),
html.js-anim .ff-cta__grid .ff-reveal:nth-child(3) { transition-delay: 0.2s; }
html.js-anim .ff-steps .ff-reveal:nth-child(2) { transition-delay: 0.08s; }
html.js-anim .ff-steps .ff-reveal:nth-child(3) { transition-delay: 0.16s; }
html.js-anim .ff-steps .ff-reveal:nth-child(4) { transition-delay: 0.24s; }
html.js-anim .ff-review.ff-reveal:nth-child(2) { transition-delay: 0.06s; }
html.js-anim .ff-review.ff-reveal:nth-child(3) { transition-delay: 0.12s; }
html.js-anim .ff-review.ff-reveal:nth-child(4) { transition-delay: 0.18s; }
html.js-anim .ff-review.ff-reveal:nth-child(5) { transition-delay: 0.24s; }
html.js-anim .ff-review.ff-reveal:nth-child(6) { transition-delay: 0.3s; }
html.js-anim .ff-review.ff-reveal:nth-child(7) { transition-delay: 0.36s; }
html.js-anim .ff-social .ff-reveal:nth-child(2) { transition-delay: 0.06s; }
html.js-anim .ff-social .ff-reveal:nth-child(3) { transition-delay: 0.12s; }
html.js-anim .ff-social .ff-reveal:nth-child(4) { transition-delay: 0.18s; }

/* --------------------------------------------------------------------------
   Transizione tra pagine — la pagina si smonta a pezzi prima di navigare
   davvero (site.js, initPageTransitions). Il transition-delay incrementale
   che dà l'effetto "uno dopo l'altro" è impostato inline da JS, elemento per
   elemento: qui solo la proprietà animata e lo stato finale.
   -------------------------------------------------------------------------- */
.wp-site-blocks > header,
.wp-site-blocks > main > *,
.wp-site-blocks > footer {
	transition: opacity 0.35s ease, transform 0.35s ease;
}

html.ff-page-leaving .wp-site-blocks > header,
html.ff-page-leaving .wp-site-blocks > main > *,
html.ff-page-leaving .wp-site-blocks > footer {
	opacity: 0;
	transform: translateY(-10px);
}

/* --------------------------------------------------------------------------
   Tenda fotografica: l'immagine si "apre" verticalmente mentre la foto dentro
   si assesta da un leggero zoom.

   Né clip-path né overflow:hidden possono stare sull'elemento osservato
   dall'IntersectionObserver: in Chromium un elemento che clippa se stesso
   in uno dei due modi smette di essere rilevabile come "in vista"
   (intersectionRatio resta 0 per sempre, anche a piena vista) — verificato
   con un observer di prova su entrambe le proprietà separatamente. Qui il
   clip-path e lo zoom stanno entrambi sull'<img>, mai sul contenitore con
   data-reveal="image", che resta "misurabile" (solo opacity/transform via
   .ff-reveal) e viene osservato correttamente. Il piccolo sconfino del bordo
   durante lo zoom iniziale (1.12 → 1) non è visibile comunque, perché in
   quella fase il clip-path stesso è già a inset(0 0 100% 0).
   -------------------------------------------------------------------------- */
html.js-anim [data-reveal="image"] img {
	clip-path: inset(0 0 100% 0);
	transform: scale(1.12);
	transition: clip-path 1.1s cubic-bezier(0.16, 1, 0.3, 1), transform 1.4s cubic-bezier(0.16, 1, 0.3, 1);
	transition-delay: inherit;
}

html.js-anim [data-reveal="image"].is-visible img {
	clip-path: inset(0 0 0% 0);
	transform: scale(1);
}

/* --------------------------------------------------------------------------
   Titoli a parole: ciascuna parola nasce dentro una maschera (overflow
   nascosto) e sale in fila con un piccolo sfalsamento impostato da site.js
   via transition-delay inline su .ff-word.
   -------------------------------------------------------------------------- */
/* padding-bottom + margin-bottom uguali e opposti: danno alla maschera lo
   spazio verticale per i discendenti (g, y, j) senza spostare il testo
   circostante — altrimenti overflow:hidden li taglia via. */
.ff-word-mask {
	display: inline-block;
	overflow: hidden;
	vertical-align: top;
	line-height: 1.2;
	padding-bottom: 0.28em;
	margin-bottom: -0.28em;
}

.ff-word {
	display: inline-block;
}

html.js-anim [data-reveal="lines"] .ff-word {
	transform: translateY(112%);
	transition: transform 0.9s cubic-bezier(0.16, 1, 0.3, 1);
}

html.js-anim [data-reveal="lines"].is-visible .ff-word {
	transform: translateY(0);
}

/* Su richiesta del cliente: niente più spostamento "magnetico" dei bottoni
   verso il cursore — trovato poco elegante. Il cambio secco di colore
   previsto da theme.json però risultava "troppo statico" (feedback
   successivo del cliente): qui aggiungiamo solo un lieve sollevamento +
   ombra morbida con transizione, per un hover elegante e dinamico senza
   che il bottone insegua il puntatore. */
.wp-block-button__link {
	transition: transform 0.35s cubic-bezier(0.16, 1, 0.3, 1),
		box-shadow 0.35s cubic-bezier(0.16, 1, 0.3, 1),
		background-color 0.35s ease, border-color 0.35s ease, color 0.35s ease;
	will-change: transform;
}

.wp-block-button__link:hover,
.wp-block-button__link:focus-visible {
	transform: translateY(-3px);
	box-shadow: 0 14px 28px -12px rgb(29 29 27 / 0.35);
}

.wp-block-button__link:active {
	transform: translateY(-1px);
	box-shadow: 0 6px 14px -8px rgb(29 29 27 / 0.3);
	transition-duration: 0.12s;
}

@media (prefers-reduced-motion: reduce) {
	.wp-block-button__link {
		transition-property: background-color, border-color, color;
	}

	.wp-block-button__link:hover,
	.wp-block-button__link:focus-visible,
	.wp-block-button__link:active {
		transform: none;
		box-shadow: none;
	}
}

/* --------------------------------------------------------------------------
   Pagina di progetto singolo (Matrimoni e Ritratti e famiglie) — struttura
   ridotta all'osso su indicazione del cliente (con wireframe di riferimento):
   header hero, UN sottotitolo, UN testo descrittivo, poi tutte le foto in
   un'unica galleria a mosaico, senza didascalie. Niente più blocchi ripetuti
   per ogni foto: chi dovrà pubblicare i prossimi progetti deve solo
   incollare un elenco di immagini, non replicare sottotitoli e testi per
   ciascuna.
   -------------------------------------------------------------------------- */
.ff-simple-story__intro h2 {
	margin-block-end: var(--wp--preset--spacing--20);
}

/* .ff-prose-nitti porta il proprio max-width:44ch, pensato per stare in
   contesti larghi. Qui il contenitore è già stretto (contentSize 46rem):
   quel secondo max-width, più stretto del sottotitolo sopra, veniva preso
   in carico dalla regola globale di WordPress che centra con margin:auto
   ogni figlio diretto di un blocco "constrained" — risultato, il paragrafo
   appariva rientrato a destra rispetto al sottotitolo invece che allineato
   con lui. Annullato qui: la larghezza la decide già il contenitore. */
.ff-simple-story__intro p {
	margin: 0;
	max-width: none;
}

/* Mosaico stile Pinterest: column-count invece di una griglia a righe, così
   ogni foto mantiene la propria proporzione naturale e le colonne si
   sfalsano da sole in base all'altezza di ciascuna — esattamente l'effetto
   "mattoncini" del wireframe, senza bisogno di JavaScript. */
.ff-simple-story__gallery {
	column-count: 2;
	column-gap: var(--wp--preset--spacing--20);
	margin-block-start: var(--wp--preset--spacing--50);
}

.ff-simple-story__gallery figure {
	margin: 0 0 var(--wp--preset--spacing--20);
	break-inside: avoid;
}

.ff-simple-story__gallery img {
	width: 100%;
	height: auto;
	display: block;
}

/* --------------------------------------------------------------------------
   Anteprima a scorrimento sull'hover — la track è impostata da site.js
   (initHoverPreview): qui solo la struttura (overflow nascosto, foto in
   fila a piena larghezza) e la transizione del movimento.
   -------------------------------------------------------------------------- */
.ff-hover-preview {
	position: relative;
	overflow: hidden;
}

.ff-hover-preview__track {
	display: flex;
	width: 100%;
	height: 100%;
	transition: transform 0.6s cubic-bezier(0.65, 0, 0.35, 1);
	will-change: transform;
}

.ff-hover-preview__track img {
	flex: 0 0 100%;
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}

/* --------------------------------------------------------------------------
   Sottolineatura a comparsa sui link di navigazione.
   -------------------------------------------------------------------------- */
.ff-nav .wp-block-navigation-item__content {
	position: relative;
}

/* transform: scaleX(), non l'animazione di "right" usata prima: "right" è una
   proprietà di layout, ricalcolata dal browser a ogni fotogramma della
   transizione — su una voce di menu è un costo minimo, ma è comunque uno
   scatto evitabile del tutto animando solo il compositor. */
.ff-nav .wp-block-navigation-item__content::after {
	content: "";
	position: absolute;
	left: 0;
	right: 0;
	bottom: -0.2em;
	height: 1px;
	background: currentColor;
	transform: scaleX(0);
	transform-origin: left;
	transition: transform 0.3s cubic-bezier(0.16, 1, 0.3, 1);
}

.ff-nav .wp-block-navigation-item__content:hover::after,
.ff-nav .wp-block-navigation-item__content:focus-visible::after {
	transform: scaleX(1);
}

/* --------------------------------------------------------------------------
   Scorrimento morbido verso le ancore (CTA → modulo disponibilità). Già
   neutralizzato per chi preferisce meno movimento dalla regola globale
   prefers-reduced-motion più sotto.
   -------------------------------------------------------------------------- */
html {
	scroll-behavior: smooth;
}

/* ==========================================================================
   FOOTER — tutto in Nitti Typewriter 10.08px, tranne la frase sotto il logo
   ========================================================================== */
/* !important: le classi utility "has-x-font-size" di WordPress (generate da
   global styles, innestate in media query proprie) hanno la meglio su
   qualunque selettore per specificità qui provato — verificato svuotando le
   regole candidate una a una in devtools. Per un override deliberato e
   circoscritto al footer, forzare qui è la via più robusta. */
.ff-footer,
.ff-footer a,
.ff-footer p,
.ff-footer li,
.ff-footer .ff-eyebrow,
.ff-footer .ff-meta {
	font-family: nitti-typewriter-normal, ui-monospace, "SF Mono", Menlo, monospace !important;
	font-size: 10.08px !important;
	letter-spacing: 0.02em;
	line-height: 1.6;
}

.ff-footer .ff-eyebrow {
	letter-spacing: 0.08em;
}

/* La tagline sotto il logo resta l'unica voce in Mrs Eaves: è la firma di
   marca del footer, non un metadato. Selettore rinforzato (.ff-footer p.ff-footer__claim,
   non solo .ff-footer__claim): la regola generale qui sopra è ".ff-footer p",
   che ha specificità maggiore di una singola classe e altrimenti vincerebbe
   anche lei essendo !important. */
.ff-footer p.ff-footer__claim {
	font-family: mrs-eaves, Baskerville, serif !important;
	font-size: var(--wp--preset--font-size--small) !important;
	letter-spacing: normal !important;
	line-height: 1.5 !important;
}

/* ==========================================================================
   NITTI TYPEWRITER SUI TESTI DISCORSIVI
   Applicato su richiesta esplicita del cliente ai paragrafi di apertura,
   tre-ingressi, perché-sceglierci e cta-segmentata. Bilanciamento: un
   monospazio alla stessa dimensione nominale di un serif proporzionale legge
   più "pesante" e le righe diventano molto più larghe (ch in monospace è la
   larghezza di ogni carattere, non una media) — quindi corpo ridotto,
   interlinea più aperta e misura di riga più corta rispetto al paragrafo
   di base in Mrs Eaves.
   ========================================================================== */
/* Il corpo del paragrafo è Nitti Typewriter NORMAL. Cameo non è un secondo
   peso della stessa famiglia: è la variante "in negativo", ogni glifo è
   disegnato come lettera chiara dentro un rettangolo pieno (verificato a
   schermo affiancando le due famiglie). Usato per un paragrafo intero
   produceva le barre nere continue segnalate dal cliente. */
.ff-prose-nitti {
	font-family: nitti-typewriter-normal, ui-monospace, "SF Mono", Menlo, monospace;
	font-size: 12px;
	line-height: 1.7;
	letter-spacing: 0.01em;
	max-width: 44ch;
}

/* Parole chiave dentro i paragrafi discorsivi: qui Cameo è al suo posto,
   perché il rettangolo pieno dei suoi glifi funziona esattamente come il
   tratto di un evidenziatore. Il colore non va forzato — il "blocco" è parte
   del disegno del carattere e viene dipinto in currentColor, quindi su fondo
   avorio dà blocco scuro/lettera chiara e sulle sezioni scure blocco chiaro/
   lettera scura, restando leggibile in entrambi i casi senza regole extra.
   Lo spazio in Cameo è anch'esso un blocco pieno: marcare più parole di
   seguito produce una barra continua, non una fila di rettangoli staccati —
   per questo va tenuto a una breve locuzione per paragrafo, non di più. */
.ff-key {
	font-family: nitti-typewriter-cameo, nitti-typewriter-normal, ui-monospace, "SF Mono", Menlo, monospace;
	font-style: normal;
}

/* I link dentro un paragrafo evidenziato non devono aggiungere una
   sottolineatura sopra il blocco pieno: sarebbe illeggibile. */
.ff-key a {
	text-decoration: none;
}

/* Il testo è tornato in Mrs Eaves su richiesta del cliente: qui solo la
   misura di riga per il centrato. */
.ff-promise__text {
	max-width: 48ch;
	margin-inline: auto;
}

/* ==========================================================================
   APERTURA PAGINE SERVIZIO (Matrimoni, Ritratti e famiglie, Stampa e ricordi)
   Le tre foto di apertura arrivavano con proporzioni completamente diverse
   (2048x1365, 1080x1440, 2048x2048): stessa larghezza pieno-schermo ma
   altezze molto diverse da una pagina all'altra, quindi "casuali" come
   segnalato dal cliente. Qui l'altezza è fissa e uguale per tutte e tre
   (clamp, non un valore rigido, per restare fluida tra mobile e desktop);
   l'immagine la riempie con object-fit:cover, tagliando in proporzione
   invece di deformarla.

   Il testo sovrapposto (in basso, su una velatura scura) funziona solo
   finché c'è abbastanza foto sotto per contenerlo: su schermi stretti il
   titolo va a 2 righe e il paragrafo a 4-5, il blocco di testo diventa più
   alto della foto stessa e — essendo in position:absolute — sborda sopra
   l'header invece di allargare la sezione (verificato: 590px di testo
   contro 250px di foto a 375px di larghezza). Stessa soluzione già in uso
   per l'hero della home: mobile-first in flusso normale (foto sopra, testo
   sotto, colori standard ink/paper), overlay assoluto solo da 700px in su,
   dove il testo ha lo spazio orizzontale per restare corto — con altezza
   fissa a 980px (non più fluida) perché il cliente vuole lo stesso valore
   esatto sulle tre pagine, non solo "la stessa formula".

   !important necessario: le global styles di WordPress impongono
   ".wp-block-image.alignfull img { height: auto }" con due classi, più
   specifica della singola classe qui sotto — senza !important quella
   regola vince e l'immagine torna alla sua proporzione naturale (verificato:
   è esattamente quello che succedeva, le tre foto sembravano "diverse"
   perché ognuna aveva altezza diversa in base al proprio aspect-ratio).

   Velatura: non un gradiente solo sul fondo ma un velo ink piatto sull'
   intera foto, stessa tecnica già usata in "Come lavoriamo" — lì il
   problema era identico (testo su foto di luminosità imprevedibile) ed è
   già la soluzione approvata dal cliente per quel caso. */
.ff-service-hero__media {
	overflow: hidden;
}

/* transform impostato via JS (initServiceHeroParallax in site.js): scale(1.12)
   di base per avere margine di manovra, altrimenti lo spostamento in
   translateY scoprirebbe il bordo dell'immagine dentro al contenitore a
   scroll lungo. will-change per evitare scatti sui browser che altrimenti
   ricreano il layer di compositing a ogni frame invece di riusarlo. */
.ff-service-hero__media img {
	width: 100% !important;
	height: clamp(16rem, 6rem + 34vw, 22rem) !important;
	object-fit: cover;
	display: block;
	will-change: transform;
}

.ff-service-hero__scrim {
	display: none;
}

.ff-service-hero__content {
	padding: var(--wp--preset--spacing--50) var(--wp--preset--spacing--30);
}

.ff-service-hero__content p {
	max-width: 46rem;
}

@media (min-width: 700px) {
	.ff-service-hero {
		position: relative;
	}

	/* min(980px, 82vh): il cliente vuole 980px fissi su desktop, ma un
	   valore fisso da solo rompe i tablet in verticale (iPad e simili),
	   dove l'altezza dello schermo è molto minore di quella di un monitor
	   — segnalato dal cliente con uno screenshot in cui la foto occupava
	   tutto lo schermo e il testo sovrapposto restava fuori dalla vista,
	   sotto la piega. Il tetto in vh lascia 980px intatti sugli schermi
	   alti (desktop) e li riduce automaticamente dove serve, così il testo
	   resta sempre visibile senza scroll. */
	.ff-service-hero__media img {
		height: min(980px, 82vh) !important;
	}

	.ff-service-hero__scrim {
		display: block;
		position: absolute;
		inset: 0;
		background: rgb(29 29 27 / 0.6);
		pointer-events: none;
	}

	.ff-service-hero__content {
		position: absolute;
		inset-inline: 0;
		bottom: 0;
		padding: var(--wp--preset--spacing--60) var(--wp--preset--spacing--50);
		color: var(--wp--preset--color--paper);
	}

	.ff-service-hero__content .ff-eyebrow {
		color: var(--wp--preset--color--paper);
		opacity: 0.85;
	}
}

/* "I servizi" (Stampa e ricordi): le tre foto mockup hanno inquadrature e
   proporzioni diverse fra loro (scena da tavolo con spazio vuoto intorno,
   collage a piena pagina, foto appese a parete) — senza un riquadro fisso
   l'immagine col più spazio negativo (l'album) sembrava "non riempire" la
   colonna. Riquadro comune con object-fit:cover: ogni immagine viene
   ritagliata per riempire lo stesso box, e object-position sull'<img>
   (impostato inline nel pattern) sposta l'inquadratura sul soggetto quando
   serve, senza toccare i file sorgente.
   !important: stessa collisione di specificità di .ff-service-hero__media
   sopra — ".wp-block-image.alignfull img { height:auto }" delle global
   styles WP vince altrimenti sulla singola classe. */
.ff-service-shot img {
	width: 100% !important;
	height: 100% !important;
	aspect-ratio: 4 / 3 !important;
	object-fit: cover;
	object-position: center;
	display: block;
}

/* ==========================================================================
   HERO — divisa a metà, testo a cavallo della giunzione (solo desktop)
   Mobile: immagine intera in alto, il cartiglio di testo segue sotto in
   flusso normale — niente testo minuscolo sovrapposto a una foto su 375px.
   ========================================================================== */
.ff-hero {
	position: relative;
}

.ff-hero__split {
	display: flex;
	flex-direction: column;
}

.ff-hero__panel--paper {
	display: none;
}

.ff-hero__panel--media {
	order: 1;
	position: relative;
	overflow: hidden;
	height: clamp(20rem, 60vw, 30rem);
}

/* Slider vero, non un crossfade: le foto stanno una accanto all'altra in
   fila (come un nastro), e site.js sposta l'intera fila di un fotogramma
   ogni 3 secondi. Mai due immagini semi-trasparenti in sovrapposizione —
   ognuna è sempre a piena opacità, cambia solo quale sta nella finestra
   visibile. Il parallax si applica alla stessa fila (translateY/scale in
   più rispetto al translateX dello slide, sulla stessa proprietà transform). */
.ff-hero__track {
	display: flex;
	width: 100%;
	height: 100%;
	transition: transform 0.9s cubic-bezier(0.65, 0, 0.35, 1);
	/* Il transform cambia a ogni frame di scroll (parallax) più ogni 3s
	   (avanzamento slide, site.js): will-change evita che il browser
	   ricrei il layer di compositing ogni volta invece di riusarlo, la
	   stessa causa di scatti già risolta per .ff-service-hero__media img. */
	will-change: transform;
}

.ff-hero__media-img {
	flex: 0 0 100%;
	display: block;
	width: 100%;
	/* +60px di riserva verticale: il parallax di site.js sposta la fila
	   dentro questo margine senza mai scoprire un vuoto ai bordi. */
	height: calc(100% + 60px);
	margin-block: -30px;
	object-fit: cover;
}

/* Animazione d'ingresso: il riquadro (non le singole foto) arriva con un
   leggero zoom-out — lo slide a tempo parte subito dopo, gestito da site.js.

   .ff-page-open__media è lo stesso identico trattamento esteso all'header di
   ogni altra pagina del sito (Matrimoni, Ritratti e famiglie, Stampa e
   ricordi, le due pagine progetto — e Chi siamo e Contatti, che riusano la
   stessa classe): prima restava solo sulla home, quindi cambiando pagina da
   menu l'header successivo compariva di scatto, senza alcuna transizione,
   segnalato dal cliente. Nessun conflitto con il parallax di
   initServiceHeroParallax in site.js: quello scrive il transform in linea
   sull'<img>, questo anima invece il <figure> che lo contiene — due elementi
   diversi, le due trasformazioni si compongono senza scavalcarsi (stessa
   separazione già in uso in home fra .js-ff-hero-media e .ff-hero__track). */
.js-ff-hero-media,
.ff-page-open__media {
	animation: ff-hero-entrance 1.2s cubic-bezier(0.16, 1, 0.3, 1);
}

@keyframes ff-hero-entrance {
	from {
		opacity: 0;
		transform: scale(1.06);
	}
	to {
		opacity: 1;
		transform: scale(1);
	}
}

/* Nessun cartiglio, nessun fondo bianco: il titolo sta direttamente sulla
   giunzione, e a renderlo leggibile su entrambe le metà è la fusione a
   differenza qui sotto — niente alone, niente riquadro. */
.ff-hero__overlay {
	order: 2;
	display: flex;
	justify-content: center;
	padding: var(--wp--preset--spacing--50) var(--wp--preset--spacing--30);
	background: var(--wp--preset--color--paper);
}

.ff-hero__title {
	max-width: 16ch;
	margin-inline: auto;
	text-align: left;
}

/* --------------------------------------------------------------------------
   FUSIONE A DIFFERENZA fra titolo e foto (richiesta del cliente, con anteprima
   InDesign a riferimento: pannello Effetti, metodo "Differenza").
   È il modo di fusione omonimo di InDesign/Photoshop: il risultato è il valore
   assoluto della differenza fra il colore del testo e quello che ha sotto.
   Con il testo BIANCO — bianco puro, non l'avorio della palette — la
   differenza vale esattamente l'inverso dello sfondo:
     · sull'avorio #FAF7F2 dà (5, 8, 13), un quasi-nero a un soffio dall'ink;
     · sulla foto restituisce il negativo dello scatto, la resa rosata sul
       verde scuro che si vede nell'anteprima allegata.
   Il vantaggio pratico oltre all'effetto: essendo calcolata sul colore reale
   che sta sotto, la leggibilità non dipende da quale delle quattro foto dello
   slider è in quel momento nel riquadro, e non serve alcun alone.

   Va sull'h1 e non sulle singole parole: l'elemento compone prima tutto il
   proprio contenuto — comprese le parole dentro le maschere dell'animazione
   d'ingresso — e poi fonde il risultato con lo sfondo, quindi lo split in
   parole non interferisce (a differenza di background-clip:text, che invece
   non attraversa le maschere).

   Nessun antenato deve dichiarare isolation:isolate né creare un contesto di
   impilamento che escluda la foto: .ff-hero__overlay e .ff-hero sono
   posizionati ma senza z-index proprio, quindi il pannello fotografico —
   fratello dipinto prima — resta parte dello sfondo con cui si fonde.
   -------------------------------------------------------------------------- */
.ff-hero__title {
	color: #fff;
	mix-blend-mode: difference;
}

@media (min-width: 900px) {
	.ff-hero__split {
		display: grid;
		grid-template-columns: 1fr 1fr;
		min-height: min(88vh, 46rem);
		position: relative;
	}

	.ff-hero__panel--paper {
		display: block;
		background: var(--wp--preset--color--paper);
	}

	.ff-hero__panel--media {
		order: initial;
		height: min(88vh, 46rem);
	}

	/* Centrato sull'intera area split: cade esattamente sulla linea che
	   divide le due metà, come richiesto — ma senza alcun fondo dietro. */
	.ff-hero__overlay {
		order: initial;
		position: absolute;
		inset: 0;
		align-items: center;
		background: none;
		padding: var(--wp--preset--spacing--30);
	}

	/* Nessun alone dietro al titolo: con la fusione a differenza il contrasto
	   è garantito dalla fusione stessa, e un'ombra verrebbe fusa anche lei,
	   sporcando la foto attorno alle lettere. */
}

/* ==========================================================================
   CHI SIAMO — colonna di testo fissa + galleria a scorrimento
   Ispirata a danieleandmarilia.com/about: mentre si scorre, il racconto resta
   fermo sullo schermo e la galleria di foto scorre accanto. Lì è ottenuto con
   uno scroll-pin via libreria (GSAP/ScrollTrigger); qui basta position:sticky
   nativo — niente libreria, coerente con il resto del sito, e per definizione
   già a prova di prefers-reduced-motion (non è un'animazione, è solo un
   ancoraggio: nulla da disattivare).
   ========================================================================== */
.ff-story-pin {
	display: grid;
	gap: var(--wp--preset--spacing--50);
}

.ff-story-pin__text .ff-door__link {
	margin-block-start: var(--wp--preset--spacing--40);
}

/* Masonry a due colonne: stessa tecnica di .ff-simple-story__gallery (colonne
   CSS, non griglia a righe), duplicata invece di riusata perché quella classe
   porta con sé un margin-block-start pensato per stare sotto un paragrafo,
   qui fuori posto dentro una colonna di griglia. */
.ff-story-pin__gallery {
	column-count: 2;
	column-gap: var(--wp--preset--spacing--20);
}

.ff-story-pin__gallery figure {
	margin: 0 0 var(--wp--preset--spacing--20);
	break-inside: avoid;
}

.ff-story-pin__gallery img {
	width: 100%;
	height: auto;
	display: block;
}

/* La seconda colonna parte più in basso della prima: alternando lo scarto
   file per file, la galleria si sfalsa come nel riferimento invece di
   allinearsi su una griglia rigida. */
.ff-story-pin__gallery figure:nth-child(2n) {
	margin-top: var(--wp--preset--spacing--50);
}

@media (min-width: 900px) {
	.ff-story-pin {
		grid-template-columns: minmax(0, 1fr) minmax(0, 1.3fr);
		align-items: start;
		gap: var(--wp--preset--spacing--60);
	}

	/* --ff-header-h è già misurata da site.js (measureHeaderHeight) per il
	   padding-top del main: la si riusa qui così l'ancoraggio si ferma
	   esattamente sotto la testata fissa, mai sotto di lei. */
	.ff-story-pin__text {
		position: sticky;
		top: calc(var(--ff-header-h, 6rem) + var(--wp--preset--spacing--40));
		align-self: start;
	}
}

/* ==========================================================================
   CONTATTI — mappa personalizzata
   -------------------------------------------------------------------------- */
/* L'ancora attorno all'header-mappa: stessa dimensione del blocco che
   racchiude, altrimenti l'area cliccabile resterebbe alta quanto il solo
   testo del link (comportamento di default di un <a> attorno a un blocco). */
.ff-map-link {
	display: block;
	text-decoration: none;
}
