/* components.css — contract_textile. Vetrina di prodotti di pregio: bianco dominante, BANDE PIENE di
   marca che incorniciano la pagina, fotografia grande a colori pieni, spazi ariosi.
   I colori arrivano SOLO dai token (tokens.css): qui non si dichiarano hex.
   ⚠ Contratto a11y: --azure è SUPERFICIE (mai testo, non regge nemmeno il bianco); il testo azzurro è
   --azure-ink. La CTA piena è --deep + bianco. Vedi l'intestazione di tokens.css. */

:root { --dur: 200ms; --ease: cubic-bezier(.2,.6,.2,1); }

/* ============================ Bottoni ============================
   Il cliente ha chiesto di "valorizzare i CTA con delle ombreggiature": la CTA piena porta un'ombra
   di marca (blu, non grigia) che si alza all'hover. Pill, come il lettering tondo del logo. */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2);
  padding: var(--space-3) var(--space-6);
  font-family: var(--font-body); font-weight: 700; font-size: .95rem;
  border-radius: var(--radius-pill); border: 2px solid transparent;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease),
              border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease),
              transform var(--dur) var(--ease);
}
/* ⚠ Fondo --deep, MAI --azure: bianco su azzurro fa 4.49 (sotto AA). Su --deep fa 15.26. */
.btn--accent { background: var(--deep); color: var(--on-dark); box-shadow: var(--shadow-cta); }
.btn--accent:hover { background: var(--navy); box-shadow: var(--shadow-cta-hover); transform: translateY(-2px); }
.btn--ghost { border-color: var(--azure); color: var(--azure-ink); background: transparent; }
.btn--ghost:hover { background: var(--azure); color: var(--on-dark); border-color: var(--azure); }
/* Su fondo scuro il contorno è bianco: --azure-ink su navy sarebbe 3.19. */
.btn--ghost-on-dark { border-color: var(--on-dark); color: var(--on-dark); background: transparent; }
.btn--ghost-on-dark:hover { background: var(--on-dark); color: var(--deep); }
@media (prefers-reduced-motion: reduce) { .btn:hover { transform: none; } }

/* ============================ Header: BARRA BIANCA, UNA RIGA ============================
   Il cliente vuole il logo "fuori la foto oppure su barra bianca" e le voci di menu "in blu, che diventano
   azzurre". Su banda navy l'azzurro del logo scende a 3.69 ⇒ barra BIANCA (la banda di marca vive nel
   footer e negli scrim). ⚠ Header a UNA RIGA (come gli altri siti), centrato verticalmente: logo + 8 voci
   + CTA ci stanno perché il TELEFONO NON è in header (ridondante: footer, Contatti, e il CTA dice già
   "Contattaci"). La nav inline sta in riga fino a ~1150px; sotto, hamburger (WP collassa solo a 600px →
   la soglia la alziamo noi). */
/* ⚠ La testata resta in vista mentre si scorre: su un sito a nove pagine il menu e' il modo con cui si
   passa da una all'altra, e riportarlo in cima a ogni salto e' il difetto che il cliente ha segnalato.
   `top: 0` con `position: sticky` esige che NESSUN antenato abbia overflow diverso da visible: il
   wrapper `.wp-block-template-part` non ne dichiara, ma se un giorno lo facesse lo sticky morirebbe in
   silenzio — e' la ragione della riga qui sotto. */
.site-header { background: var(--paper); border-bottom: 1px solid var(--line); position: sticky; top: 0; z-index: 20; }
.wp-block-template-part:has(> .site-header) { overflow: visible; }
/* Un'ancora sotto una testata fissa atterra COPERTA: si lascia lo spazio della testata. */
html { scroll-padding-top: 5.5rem; }
.site-header__row {
  display: flex; align-items: center; gap: clamp(0.75rem, 0.1rem + 1vw, 1.5rem);
  padding-block: var(--space-3); flex-wrap: nowrap; max-width: 1500px;
}
/* Un margine di blocco su un figlio lo spinge fuori dal centro della riga. */
.site-header__row > * { align-self: center; margin-block: 0; }
.site-nav { flex: 1 1 auto; }   /* la nav prende lo spazio in mezzo e allinea le voci a destra */

/* Logo: GRANDE (era il reclamo). Il lockup è un'immagine sola, non ridotta a un mark quadrato.
   max-width alto: il wordmark è largo per natura e non va strozzato. */
.wordmark { display: inline-flex; align-items: center; gap: var(--space-3); flex: none; }
.wordmark__logo { height: 32px; width: auto; max-width: min(50vw, 400px); object-fit: contain; }
.wordmark__txt {
  font-family: var(--font-display); font-weight: 700; font-size: 1.5rem; color: var(--deep);
  letter-spacing: -0.01em; line-height: 1.05; display: inline-flex; flex-direction: column;
}
.wordmark__txt small { font-family: var(--font-body); font-weight: 600; font-size: .62rem;
  letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--ink-muted); }
.site-footer .wordmark__logo { height: 32px; }

/* Nav: Sentence case (richiesta esplicita), voci in --deep, ATTIVA/hover in --azure-ink col filetto
   --azure sotto. ⚠ Niente text-transform:uppercase: il maiuscolo è largo ed è metà del motivo per cui
   il menu del sito bocciato andava a capo. */
.site-nav .wp-block-navigation__container { gap: clamp(.4rem, .05rem + .7vw, 1.05rem); flex-wrap: nowrap; }
.site-nav .wp-block-navigation-item__content {
  font-family: var(--font-display); font-weight: 600; font-size: .95rem;
  color: var(--deep); text-transform: none; white-space: nowrap;
  padding-block: 0.5rem; position: relative;
  transition: color var(--dur) var(--ease);
}
.site-nav .wp-block-navigation-item__content::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 2px;
  background: var(--azure); border-radius: 2px; transform: scaleX(0);
  transform-origin: left; transition: transform var(--dur) var(--ease);
}
.site-nav .wp-block-navigation-item__content:hover { color: var(--azure-ink); }
.site-nav .wp-block-navigation-item__content:hover::after { transform: scaleX(1); }
/* Stato ATTIVO: la pagina in cui ci si trova. WP marca la voce con .current-menu-item. */
.site-nav .wp-block-navigation-item.current-menu-item > .wp-block-navigation-item__content,
.site-nav .wp-block-navigation-item.current_page_item > .wp-block-navigation-item__content {
  color: var(--azure-ink);
}
.site-nav .wp-block-navigation-item.current-menu-item > .wp-block-navigation-item__content::after,
.site-nav .wp-block-navigation-item.current_page_item > .wp-block-navigation-item__content::after {
  transform: scaleX(1);
}

.site-header__cta { flex: none; padding-block: var(--space-2); font-size: .9rem; }

/* ⚠ La nav inline con 8 voci sta in riga solo ≳1200px. WP collassa a hamburger solo a 600px, lasciando
   un buco 600–1200px dove la nav sborda. Alzo la soglia a 1200px: sotto, forzo l'hamburger (mostro il
   bottone di WP, nascondo la lista inline). L'overlay è lo stesso (già a prova di regola 23). */
@media (max-width: 1200px) {
  .wp-block-navigation__responsive-container-open { display: flex !important; }
  .wp-block-navigation__responsive-container:not(.is-menu-open) .wp-block-navigation__container { display: none; }
  /* L'hamburger va a DESTRA, staccato dal logo: margin-left:auto lo spinge al bordo destro della riga. */
  .site-nav { flex: 0 0 auto; margin-left: auto; }
  /* Hamburger a 3 barrette (l'icona di WP ne ha solo 2): la nascondo e la ridisegno. */
  .wp-block-navigation__responsive-container-open {
    width: 34px; height: 34px; padding: 0; border: 0; background: transparent; cursor: pointer; position: relative;
  }
  .wp-block-navigation__responsive-container-open svg { display: none; }
  .wp-block-navigation__responsive-container-open::before {
    content: ""; position: absolute; left: 6px; right: 6px; top: 9px; height: 2.5px;
    background: var(--deep); border-radius: 2px;
    box-shadow: 0 7px 0 var(--deep), 0 14px 0 var(--deep);   /* + linea centrale + linea inferiore = 3 */
  }
}
/* Sotto i 900px: CTA fuori (è nella cta-bar fissa) e logo un filo più piccolo. */
@media (max-width: 900px) {
  .wordmark__logo { height: 30px; }
  .site-header__cta { display: none; }
}

/* Overlay mobile di wp:navigation: FISSO a tutto schermo, fondo --deep.
   ⚠⚠ REGOLA 23: il fondo BIANCO dell'overlay viene da WP con selettore a specificità 0,4,0
   (`.wp-block-navigation:not(.has-background) …:not(.disable-default-overlay)`) e le VOCI sono bianche →
   bianco-su-bianco, l'overlay sembra vuoto. Un `.is-menu-open{background}` (0,2,0) PERDE. Si vince solo
   RICOPIANDO il suo schema di specificità. Idem per la posizione/altezza. */
.wp-block-navigation:not(.has-background) .wp-block-navigation__responsive-container.is-menu-open:not(.disable-default-overlay),
.wp-block-navigation__responsive-container.is-menu-open {
  position: fixed; inset: 0; z-index: 99999;
  height: 100vh; width: 100vw; overflow-y: auto; background: var(--deep);
  /* ⚠ Le voci stanno IN ALTO, non centrate: con otto voci il centro le spinge sotto la piega e lascia
     sopra una fascia vuota alta quanto mezzo schermo. Il rientro in alto lo da' gia' il contenuto
     (che deve scavalcare il tasto di chiusura), quindi qui basta il minimo. */
  padding: 0.5rem var(--gutter) 6rem; display: flex; flex-direction: column; justify-content: flex-start;
}
/* ⚠⚠ Le voci si allineano a SINISTRA. L'allineamento a destra arriva dalla nav DESKTOP, e WP lo porta
   nel pannello con due VARIABILI (`.wp-block-navigation__container { align-items: var(--navigation-layout-align) }`):
   una regola nostra, anche piu' specifica, perde contro il valore che la variabile continua a fornire.
   Si sovrascrivono le VARIABILI sull'overlay — ereditano — invece di combattere la cascata.
   ⚠ Correggere il solo contenuto non basta: l'allineamento e' dichiarato su DUE antenati. */
.wp-block-navigation__responsive-container.is-menu-open {
  --navigation-layout-align: stretch;
  --navigation-layout-justification-setting: flex-start;
  --navigation-layout-justify: flex-start;
}
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-container-content {
  align-items: stretch; text-align: left; width: 100%;
}
/* ⚠⚠ SPECIFICITA': la regola di WP sul contenitore e' (0,4,0) — passa per `…-content .wp-block-navigation__container` —
   e batte una (0,3,0) anche se scritta dopo. Si RICOPIA il suo schema, come gia' si fa sopra per il fondo. */
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-container-content .wp-block-navigation__container,
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-container-content .wp-block-navigation-item {
  align-items: stretch; text-align: left; width: 100%;
}
/* ⚠ Bersaglio tattile: misurato a 34px, sotto il minimo di 44. Il testo resta a sinistra. */
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation-item__content {
  color: var(--on-dark); font-size: 1.25rem; width: 100%; padding-block: var(--space-3);
  min-height: 48px; display: flex; align-items: center; justify-content: flex-start; text-align: left;
}
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation-item__content::after { display: none; }
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__container { gap: 0; flex-wrap: wrap; }
.wp-block-navigation__responsive-container-close, .wp-block-navigation__responsive-container-open { color: var(--deep); }
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-container-close { color: var(--on-dark); }

/* Tasto WhatsApp flottante: lo INIETTA `cli/build.mjs` (withFloatingWhatsapp) quando il progetto
   dichiara `chrome.whatsapp_floating`. Senza queste regole l'ancora resta in FLUSSO dopo il pie' e
   l'SVG si dilata a tutta larghezza: un bollo verde gigante sotto il footer (difetto visto sul campo).
   ⚠ Additiva: un progetto che non dichiara la bandiera non ha mai `.wa-flot` nel markup, quindi i siti
   gia' consegnati di questo verticale restano identici. */
.wa-flot { position: fixed; right: clamp(1rem, 3vw, 2rem); bottom: clamp(1rem, 3vw, 2rem); z-index: 45;
  display: inline-flex; align-items: center; justify-content: center; width: 56px; height: 56px;
  border-radius: 50%; background: #25d366; box-shadow: 0 6px 20px rgba(0,0,0,.28); }
.wa-flot svg { width: 30px; height: 30px; }   /* il riempimento e' dichiarato nel marchio */
.wa-flot:focus-visible { outline: 3px solid var(--focus); outline-offset: 3px; }
@media (prefers-reduced-motion: no-preference) { .wa-flot { transition: transform var(--dur) var(--ease); } .wa-flot:hover { transform: scale(1.08); } }
/* ⚠ Sotto i 760px la barra fissa in fondo offre GIA' «Chiama | WhatsApp»: il tasto flottante sarebbe un
   secondo WhatsApp nella stessa schermata, e per giunta ci finisce SOPRA. Resta solo dove la barra non c'e'. */
@media (max-width: 760px) { .wa-flot { display: none; } }
/* Col lightbox aperto il tasto trasparirebbe sotto il velo (che e' al 94%): un puntino verde in un angolo
   della galleria. Il lightbox e' appeso al body DOPO il pie', quindi un selettore di fratellanza non lo
   raggiunge: si guarda l'antenato. */
body:has(.fp-lb.is-open) .wa-flot,
/* ⚠ Stessa ragione per la barra fissa del telefono: traspariva dal velo e le frecce le finivano SOPRA.
   Dietro un modale il cromo di pagina non ci va. */
body:has(.fp-lb.is-open) .cta-bar { display: none; }

/* ============================ Hero: foto grande, testo centrato ============================
   Il cliente si lamenta che l'header foto è "sgranato": qui la foto è full-bleed e va scelta hero-grade
   (>=1600x900) o presa dai RENDER. Senza foto (demo) resta una banda navy piena: mai una foto finta. */
.hero {
  position: relative; background: var(--navy); color: var(--on-dark);
  min-height: min(80vh, 680px); display: flex; align-items: center;
  overflow: hidden; isolation: isolate; text-align: center;
}
.hero-media { position: absolute; inset: 0; z-index: -2; overflow: hidden; background: var(--navy); }
.hero-slide { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; opacity: 0; }
.hero-slide:nth-child(1) { opacity: 1; }
/* ⚠ Uno scrim NON basta a garantire il contrasto: queste foto (camere d'albergo, barche, dehors) hanno
   finestre e soffitti BIANCHI PURI. Misurato: col solo scrim il bianco sul pixel peggiore fa 2,96 — sotto
   perfino la soglia 3:1 del testo grande — e axe NON lo vede (non valuta il testo sopra un'immagine).
   Quindi il testo sta su una TARGA piena: targa .55 + scrim .25 = alpha efficace .66 -> bianco 5,55 sul
   pixel peggiore possibile. Il contrasto non dipende più dal fotogramma, e lo scrim leggero lascia viva la
   foto (sono prodotti di pregio: la foto è il prodotto). */
.hero::after {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(180deg, rgba(var(--navy-rgb),.30) 0%, rgba(var(--navy-rgb),.22) 45%, rgba(var(--navy-rgb),.38) 100%);
}
.hero__inner { position: relative; padding-block: var(--space-9); width: 100%; }
.hero__text {
  max-width: 48rem; margin-inline: auto; display: flex; flex-direction: column;
  gap: var(--space-5); align-items: center;
  background: rgba(var(--navy-rgb), .55);
  padding: clamp(2rem, 1.4rem + 2.4vw, 3.25rem) clamp(1.5rem, 1rem + 2vw, 3rem);
  border-radius: var(--radius-lg);
}
.hero__text h1 { color: var(--on-dark); }
/* ⚠ Sulla TARGA il testo è SOLO bianco. I token "on dark" (--azure-lt 6,42 · --muted-on-dark 10,24) sono
   tarati sulla banda navy PIENA: sulla targa semitrasparente il fondo è più chiaro (misurato 102,98,137)
   e lì scendono a 2,22 e 3,54. axe non lo coglie (sopra un'immagine non valuta), quindi la regola è esplicita. */
.hero__text .eyebrow--light { color: var(--on-dark); }
.hero__text .eyebrow--light::before { background: var(--on-dark); }
/* La misura di lettura sta sul PARAGRAFO, mai sul contenitore del display: un max-width sul wrapper
   strozzerebbe anche il titolo (errore ripetuto 4 volte in questo repo). */
.hero__text .lead { color: var(--on-dark); max-width: 42rem; }
.hero__actions { display: flex; flex-wrap: wrap; gap: var(--space-4); justify-content: center; }

@media (prefers-reduced-motion: no-preference) {
  .hero-slide { animation: fp-hero-fade 32s linear infinite; }
  .hero-slide:nth-child(2) { animation-delay: 8s; }
  .hero-slide:nth-child(3) { animation-delay: 16s; }
  .hero-slide:nth-child(4) { animation-delay: 24s; }
}
@keyframes fp-hero-fade {
  0%   { opacity: 0; transform: scale(1.0); }
  3%   { opacity: 1; }
  22%  { opacity: 1; }
  27%  { opacity: 0; }
  100% { opacity: 0; transform: scale(1.06); }
}

/* ============================ Intro di sezione ============================ */
.section-intro { max-width: 52rem; }
.section-intro--center { margin-inline: auto; text-align: center; align-items: center; }
.section-intro--center .lead { margin-inline: auto; max-width: 44rem; }

/* ============================ Manifesto (Chi siamo) ============================ */
.manifesto__grid { display: grid; grid-template-columns: 1fr; gap: var(--space-6); align-items: start; }
@media (min-width: 900px) { .manifesto__grid { grid-template-columns: 0.85fr 1fr 0.8fr; gap: var(--space-7); align-items: center; } }
/* La tessera chiude la riga: senza, «Chi siamo» è una colonna di prosa e basta — il "spoglio" del cliente. */
.manifesto__fig { margin: 0; border-radius: var(--radius-lg); overflow: hidden; box-shadow: var(--shadow-card-hover); }
.manifesto__fig img { width: 100%; aspect-ratio: 3/4; object-fit: cover; display: block; }
@media (max-width: 899px) { .manifesto__fig { display: none; } }
.manifesto__body { display: flex; flex-direction: column; gap: var(--space-4); max-width: 62ch; }
/* Size PROPRIA e non --text-2xl: la copy reale del cliente supera i 100 caratteri, dove una size da
   titolo breve frantuma la colonna (lezione DeMartini: 123 char su una size tarata su 67). */
.statement { font-family: var(--font-display); font-weight: 600; color: var(--deep);
  font-size: clamp(1.6rem, 1.1rem + 1.9vw, 2.3rem); line-height: var(--lh-snug); }

/* Striscia credenziali: dà autorità subito dopo il "Chi siamo", chiude la sezione con ritmo.
   Filetto azzurro in cima a ogni voce, numerali nel display. */
.creds { display: grid; grid-template-columns: 1fr; gap: var(--frame-gap); margin-top: var(--space-8); }
@media (min-width: 560px) { .creds { grid-template-columns: 1fr 1fr; } }
@media (min-width: 900px) { .creds { grid-template-columns: repeat(4, 1fr); } }
.creds__item { border-top: 3px solid var(--azure); padding-top: var(--space-4); display: flex; flex-direction: column; gap: var(--space-2); }
.creds__n { font-family: var(--font-display); font-weight: 700; font-size: 1.35rem; color: var(--deep); }
.creds__l { color: var(--ink-muted); font-size: .9rem; line-height: 1.4; }

/* ============================ Offerta: card = foto + BANDA di caption ============================
   È il dispositivo del template: la foto non è mai nuda, porta una banda piena di marca col titolo.
   Il cliente vuole le foto "staccate da una cornice o bordatura", MAI appiccicate: gutter netto +
   cornice bianca + filetto azzurro. */
/* Flex e non grid: le categorie sono CINQUE e in una griglia a 3 colonne le ultime due restano appese a
   sinistra come un avanzo. Col flex la riga orfana si centra da sola, qualunque sia il numero di voci. */
.ocards { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--frame-gap); margin-top: var(--space-7); }
.ocard { flex: 0 1 100%; }
@media (min-width: 640px) { .ocard { flex-basis: calc(50% - var(--frame-gap) / 2); } }
@media (min-width: 1000px) { .ocard { flex-basis: calc(33.333% - var(--frame-gap) * 2 / 3); } }
.ocard {
  display: flex; flex-direction: column; background: var(--paper);
  border: 1px solid var(--line); border-radius: var(--radius-lg); overflow: hidden;
  box-shadow: var(--shadow-card); transition: box-shadow var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.ocard:hover { box-shadow: var(--shadow-card-hover); transform: translateY(-3px); }
.ocard:focus-within { outline: 2px solid var(--focus); outline-offset: 3px; }
.ocard__media { display: block; aspect-ratio: 4 / 3; background: var(--surface); overflow: hidden; }
.ocard__media img { width: 100%; height: 100%; object-fit: cover; transition: transform 600ms var(--ease); }
.ocard:hover .ocard__media img { transform: scale(1.04); }
/* La banda: piena, testo bianco su --navy (16.5:1). */
.ocard__band {
  display: block; background: var(--navy); color: var(--on-dark);
  font-family: var(--font-display); font-weight: 600; font-size: 1.1rem;
  padding: var(--space-3) var(--space-5);
}
.ocard__text { display: block; padding: var(--space-5); color: var(--ink-muted); font-size: .95rem; }
@media (prefers-reduced-motion: reduce) {
  .ocard:hover { transform: none; }
  .ocard:hover .ocard__media img { transform: none; }
}


/* Chip dei settori (Gallery): pastiglie a filetto, non bottoni. */
.chips { display: flex; flex-wrap: wrap; gap: var(--space-3); justify-content: center; margin-top: var(--space-6); }
.chip { font-family: var(--font-display); font-weight: 600; font-size: .95rem; color: var(--deep);
  padding: var(--space-2) var(--space-5); border: 1px solid var(--azure); border-radius: var(--radius-pill); }

/* Card offerta: affordance "Scopri" che appare all'hover (2026, senza rumore). */
.ocard__go { display: inline-flex; align-items: center; gap: var(--space-2); color: var(--azure-ink);
  font-weight: 700; font-size: .9rem; padding: 0 var(--space-5) var(--space-5); opacity: 0;
  transform: translateX(-4px); transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease); }
.ocard:hover .ocard__go, .ocard:focus-within .ocard__go { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) { .ocard__go { opacity: 1; transform: none; } }

/* ============================ Metodo: quattro passi ============================ */
.pattern-steps { display: grid; gap: var(--space-6); grid-template-columns: 1fr; margin-top: var(--space-7); }
@media (min-width: 700px) { .pattern-steps { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1000px) { .pattern-steps { grid-template-columns: repeat(4, 1fr); } }
.pstep { padding: var(--space-5); border-top: 3px solid var(--azure); background: var(--paper);
  border-radius: 0 0 var(--radius-lg) var(--radius-lg); }
.pstep__n { font-family: var(--font-display); font-weight: 700; font-size: 1.05rem; color: var(--azure-ink);
  letter-spacing: var(--tracking-label); display: block; margin-bottom: var(--space-2); }
.pstep h3 { margin-bottom: var(--space-2); }
.pstep__text { color: var(--ink-muted); font-size: .95rem; }

/* ============================ Settori: banda navy piena + tessere foto ============================ */
.settori__head { display: grid; grid-template-columns: 1fr; gap: var(--space-5); align-items: end; }
@media (min-width: 900px) { .settori__head { grid-template-columns: 1fr 1fr; gap: var(--space-8); } }
.settori__body { max-width: 60ch; }
.stiles { display: grid; gap: var(--frame-gap); grid-template-columns: 1fr; margin-top: var(--space-7); }
@media (min-width: 640px) { .stiles { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1000px) { .stiles { grid-template-columns: repeat(4, 1fr); } }
/* Cornice chiara attorno alla foto: staccata dalla banda navy, mai a filo. */
.stile { background: rgba(255,255,255,.06); border: 1px solid rgba(255,255,255,.16);
  border-radius: var(--radius-lg); overflow: hidden; display: flex; flex-direction: column; }
.stile__media { display: block; aspect-ratio: 3 / 4; background: rgba(255,255,255,.08); overflow: hidden; }
.stile__media img { width: 100%; height: 100%; object-fit: cover; }
.stile__cap { display: block; padding: var(--space-4) var(--space-5) var(--space-5); }
.stile__title { display: block; font-family: var(--font-display); font-weight: 600; font-size: 1.15rem;
  color: var(--on-dark); margin-bottom: var(--space-2); }
.stile__text { display: block; color: var(--muted-on-dark); font-size: .9rem; line-height: 1.55; }

/* ============================ Banda contatti (CTA finale) ============================ */
.cband__box { max-width: 46rem; margin-inline: auto; text-align: center;
  display: flex; flex-direction: column; gap: var(--space-4); align-items: center; }
.cband__actions { display: flex; flex-wrap: wrap; gap: var(--space-4); justify-content: center; margin-top: var(--space-3); }

/* ============================ Page-head (pagine interne) ============================
   Compatta: l'h1 NON usa la size dell'hero. Vale per tutte le pagine interne, si sistema una volta sola. */
.page-head { background: var(--surface); border-bottom: 1px solid var(--line); text-align: center;
  padding-block: clamp(2.5rem, 1.8rem + 3vw, 4rem); }
.page-head h1 { font-size: var(--text-2xl); color: var(--deep); }
.page-head .container { display: flex; flex-direction: column; gap: var(--space-4); align-items: center; }
.page-head .lead { max-width: 48rem; }

/* ============================ Pagina categoria ============================ */
.cat-split { display: grid; grid-template-columns: 1fr; gap: var(--space-6); align-items: start; }
@media (min-width: 900px) { .cat-split { grid-template-columns: 1.05fr .95fr; gap: var(--space-8); } }
.cat-split__text { max-width: 62ch; display: flex; flex-direction: column; gap: var(--space-4); }
.cat-split__fig { margin: 0; border-radius: var(--radius-lg); overflow: hidden; background: var(--surface);
  border: 1px solid var(--line); box-shadow: var(--shadow-card); min-height: 260px; }
.cat-split__fig img { width: 100%; height: 100%; object-fit: cover; }
.prose > * + * { margin-top: var(--space-4); }

/* ============================ Gallery: foto INCORNICIATE e STACCATE ============================
   Reclamo esplicito del cliente sui caroselli: mai foto a filo. Cornice bianca + filetto + gutter. */
.gal-grid { display: grid; gap: var(--frame-gap); grid-template-columns: 1fr; }
@media (min-width: 640px) { .gal-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1000px) { .gal-grid { grid-template-columns: repeat(3, 1fr); } }
.gframe {
  margin: 0; background: var(--paper); padding: var(--frame-pad);
  border: 1px solid var(--line); border-radius: var(--radius-lg);
  box-shadow: var(--shadow-card); overflow: hidden;
  aspect-ratio: 4 / 3; min-height: 200px;
  transition: box-shadow var(--dur) var(--ease);
}
.gframe:hover { box-shadow: var(--shadow-card-hover); }
.gframe img { width: 100%; height: 100%; object-fit: cover; border-radius: 2px; }

/* ============================ Banda «I nostri brand» ============================
   Il docx la vuole «a fondo pagina HOME» coi marchi «che devono girare a catena»: nastro infinito.
   ⚠ I marchi VERI non ci sono ancora (lo dice il cliente: «dobbiamo richiedere a casa madre») e qui
   stanno dei SEGNAPOSTO NEUTRI, dichiarati tali: non si disegnano imitazioni di marchi altrui.
   Il nastro è duplicato e scorre di -50%: l'anello è continuo senza salti. La copia duplicata è
   aria-hidden e il viewport ha un aria-label unico (uno screen reader non legge 30 etichette). */
.brands { background: var(--paper); overflow: hidden; padding-block: var(--space-7);
  border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
.brands .eyebrow { justify-content: center; margin-bottom: var(--space-6); }
.brands__viewport { overflow: hidden; -webkit-mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent); }
.brands__track { display: flex; gap: clamp(2rem, 1rem + 3vw, 4.5rem); width: max-content; align-items: center; }
.brandmark {
  font-family: var(--font-display); font-weight: 600; font-size: 1.15rem; white-space: nowrap;
  color: var(--deep); opacity: .72; letter-spacing: .04em;
  padding: var(--space-3) var(--space-5); border: 1px solid var(--line); border-radius: var(--radius);
  transition: opacity var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.brands__viewport:hover .brandmark { opacity: 1; border-color: var(--azure); }
.brands__note { color: var(--ink-muted); font-size: .8rem; text-align: center; margin-top: var(--space-5); }
@media (prefers-reduced-motion: no-preference) {
  .brands__track { animation: fp-marquee 42s linear infinite; }
  /* Il nastro si ferma al passaggio del mouse: si legge il marchio invece di inseguirlo. */
  .brands__viewport:hover .brands__track { animation-play-state: paused; }
}
@keyframes fp-marquee { from { transform: translateX(0); } to { transform: translateX(-50%); } }

/* ============================ Pagina categoria: banda hero fotografica ============================
   Le pagine interne non vivono di una page-head tinta e basta: sono la VETRINA di un mestiere. La banda
   porta la foto grande (le foto sono del cliente) e il titolo su TARGA — stesso contratto dell'hero:
   il contrasto non dipende dal fotogramma. */
.page-hero { position: relative; min-height: clamp(320px, 34vw, 460px); display: flex; align-items: center;
  overflow: hidden; isolation: isolate; background: var(--navy); text-align: center; }
.page-hero__img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; z-index: -2; }
.page-hero::after { content: ""; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(180deg, rgba(var(--navy-rgb),.32) 0%, rgba(var(--navy-rgb),.26) 50%, rgba(var(--navy-rgb),.42) 100%); }
.page-hero__plate { max-width: 46rem; margin-inline: auto; background: rgba(var(--navy-rgb), .55);
  padding: clamp(1.75rem, 1.2rem + 2vw, 2.75rem) clamp(1.25rem, 1rem + 1.6vw, 2.5rem);
  border-radius: var(--radius-lg); display: flex; flex-direction: column; gap: var(--space-4); align-items: center; }
.page-hero__plate h1 { color: var(--on-dark); font-size: var(--text-2xl); }
/* Sulla targa il testo è SOLO bianco: i token "on dark" sono tarati sulla banda PIENA (vedi hero). */
.page-hero__plate .eyebrow--light { color: var(--on-dark); }
.page-hero__plate .eyebrow--light::before { background: var(--on-dark); }
.page-hero__plate .lead { color: var(--on-dark); max-width: 40rem; }

/* Intro della categoria: statement + prosa, con una TESSERA che SCAVALCA la banda sopra (dispositivo
   Pafundi: dà profondità e lega le due sezioni invece di impilarle). */
.cat-intro { position: relative; }
.cat-intro__grid { display: grid; grid-template-columns: 1fr; gap: var(--space-6); align-items: start; }
@media (min-width: 900px) { .cat-intro__grid { grid-template-columns: 0.95fr 1.05fr; gap: var(--space-8); } }
.cat-intro__body { max-width: 62ch; display: flex; flex-direction: column; gap: var(--space-4); }
.cat-intro__tile { margin: 0; border-radius: var(--radius-lg); overflow: hidden; box-shadow: var(--shadow-card-hover);
  border: 6px solid var(--paper); }
@media (min-width: 900px) { .cat-intro__tile { margin-top: -6rem; } }   /* scavalca la banda */
.cat-intro__tile img { width: 100%; aspect-ratio: 4/3; object-fit: cover; display: block; }
/* Variante "piatta": stessa grafica delle foto in pagina (ombra leggera, niente cornice
   né scavalcamento della banda). */
.cat-intro__tile--flat { box-shadow: var(--shadow-card); border: 0; }
@media (min-width: 900px) { .cat-intro__tile--flat { margin-top: 0; } }

/* Blocchi alternati testo/foto: è ciò che toglie il "muro di prosa" alle pagine del cliente, che sono
   testi LUNGHI. Le foto si alternano di lato (mai una colonna sola di testo che scorre). */
.cat-block { display: grid; grid-template-columns: 1fr; gap: var(--space-6); align-items: center; }
/* Il margine sta TRA i blocchi, mai sul primo (col padding della banda collasserebbe e il titolo toccherebbe il bordo). */
.cat-block + .cat-block { margin-top: var(--space-8); }
@media (min-width: 900px) {
  .cat-block { grid-template-columns: 1fr 1fr; gap: var(--space-8); }
  .cat-block--flip .cat-block__fig { order: -1; }   /* sfalsate: la foto cambia lato a ogni blocco */
}
.cat-block__text { max-width: 60ch; display: flex; flex-direction: column; gap: var(--space-4); }
.cat-block__text h2 { margin-bottom: var(--space-2); }
.cat-block__fig { margin: 0; border-radius: var(--radius-lg); overflow: hidden; box-shadow: var(--shadow-card); }
.cat-block__fig img { width: 100%; aspect-ratio: 4/3; object-fit: cover; display: block;
  transition: transform 700ms var(--ease); }
.cat-block__fig:hover img { transform: scale(1.03); }
@media (prefers-reduced-motion: reduce) { .cat-block__fig:hover img { transform: none; } }

/* Elenchi dei mestieri: pastiglie col filetto azzurro, non pallini di sistema. */
.checks { display: grid; grid-template-columns: 1fr; gap: var(--space-3); }
@media (min-width: 560px) { .checks { grid-template-columns: 1fr 1fr; } }
.checks li { display: flex; gap: var(--space-3); align-items: flex-start; color: var(--ink);
  padding: var(--space-3) var(--space-4); background: var(--surface); border-radius: var(--radius);
  border-left: 3px solid var(--azure); font-size: .95rem; }

/* ============================ Mosaico fotografico ============================
   Griglia ASIMMETRICA (alcune tessere scavalcano due colonne/righe): una griglia piatta di quadrati è
   quello che il cliente chiama "disordinato e spoglio". Cornice + gutter: il cliente vuole le foto
   STACCATE, mai appiccicate. */
/* Griglia UNIFORME: tutte le tessere 4/3, stessa dimensione → allineata, nessun buco (gli span
   sfalsati creavano vuoti brutti). Gutter + cornice: le foto restano staccate. */
.mosaic { display: grid; gap: var(--frame-gap); grid-template-columns: repeat(2, 1fr); }
@media (min-width: 700px) { .mosaic { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 1100px) { .mosaic { grid-template-columns: repeat(4, 1fr); } }
.mosaic figure { margin: 0; position: relative; overflow: hidden; border-radius: var(--radius-lg);
  background: var(--surface); border: 1px solid var(--line); box-shadow: var(--shadow-card);
  aspect-ratio: 4/3; transition: box-shadow var(--dur) var(--ease), transform var(--dur) var(--ease); }
.mosaic figure:hover { box-shadow: 0 16px 40px rgba(var(--deep-rgb),.20); transform: translateY(-4px); z-index: 2; }
.mosaic img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform 800ms var(--ease); }
.mosaic figure:hover img { transform: scale(1.06); }
@media (prefers-reduced-motion: reduce) {
  .mosaic figure:hover { transform: none; }
  .mosaic figure:hover img { transform: none; }
}


/* «Perché noi»: tre tessere a numerali, riempiono il respiro sotto la scheda recapiti. */
.why { display: grid; grid-template-columns: 1fr; gap: var(--frame-gap); margin-top: var(--space-7); }
@media (min-width: 760px) { .why { grid-template-columns: repeat(3, 1fr); } }
.why__card { background: var(--paper); border: 1px solid var(--line); border-radius: var(--radius-lg);
  padding: var(--space-6); box-shadow: var(--shadow-card); }
.why__n { font-family: var(--font-display); font-weight: 700; color: var(--azure-ink); font-size: 1.1rem;
  letter-spacing: var(--tracking-label); display: block; margin-bottom: var(--space-3); }
.why__card h3 { margin-bottom: var(--space-2); }
.why__card p { color: var(--ink-muted); font-size: .95rem; }

/* ============================ Pagina Contatti ============================
   Due colonne: a sinistra la foto della sede, a destra i recapiti in una scheda CHIARA (mai la banda
   scura dell'home-band: qui il fondo è bianco). Il markup è per-progetto (pages.json), ma le classi
   vivono QUI — un cliente non deve scrivere CSS. */
.contact-cols { display: grid; grid-template-columns: 1fr; gap: var(--space-6); align-items: start; }
@media (min-width: 900px) { .contact-cols { grid-template-columns: 1.15fr .85fr; gap: var(--space-8); } }
.contact-main h2, .contact-info h2 { margin-bottom: var(--space-4); }
.contact-hero { margin: 0; border-radius: var(--radius-lg); overflow: hidden; border: 1px solid var(--line);
  box-shadow: var(--shadow-card); }
.contact-hero img { width: 100%; height: 100%; object-fit: cover; }
/* La didascalia dice COSA si sta guardando: senza, una foto di un loro lavoro sotto un titolo di sezione
   si legge come se fosse la loro sede. */
.contact-hero figcaption { padding: var(--space-3) var(--space-4); background: var(--surface);
  color: var(--ink-muted); font-size: .88rem; }
.contact-main > p { margin-bottom: var(--space-5); }
.contact-info { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-lg);
  padding: var(--space-6); }
.contact-info h3 { margin: var(--space-6) 0 var(--space-3); }
.contact-info .btn { margin-top: var(--space-5); }
.map-link { color: var(--azure-ink); text-decoration: underline; text-underline-offset: 3px;
  display: inline-block; margin-top: var(--space-4); }

/* Tabella orari: una TABELLA vera, non uno screenshot (nel materiale di questi clienti gli orari
   arrivano come immagini di tabelle Word: illeggibili per uno screen reader e invisibili a Google). */
.hours { border-collapse: collapse; width: 100%; }
.hours th, .hours td { text-align: left; padding: var(--space-2) 0; border-bottom: 1px solid var(--line);
  font-weight: 400; }
.hours th { color: var(--deep); font-weight: 700; padding-right: var(--space-4); white-space: nowrap; }
.hours td { color: var(--ink-muted); }
.hours .is-closed { color: var(--ink-muted); font-style: italic; }


/* Form di contatto first-party ([fp_contact_form]): campi puliti, moderni. */
.contact-form { display: flex; flex-direction: column; gap: var(--space-4); }
.contact-form .row { display: grid; grid-template-columns: 1fr; gap: var(--space-4); }
@media (min-width: 560px) { .contact-form .row { grid-template-columns: 1fr 1fr; } }
.contact-form .field { display: flex; flex-direction: column; gap: var(--space-2); }
.contact-form label { font-weight: 700; font-size: .9rem; color: var(--deep); }
.contact-form input, .contact-form textarea {
  font: inherit; color: var(--ink); background: var(--paper);
  border: 1px solid var(--line); border-radius: var(--radius); padding: var(--space-3) var(--space-4);
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.contact-form input:focus, .contact-form textarea:focus {
  outline: none; border-color: var(--azure); box-shadow: 0 0 0 3px rgba(var(--azure-rgb),.18);
}
.contact-form textarea { resize: vertical; min-height: 8rem; }
.contact-form .consent { display: flex; gap: var(--space-3); align-items: flex-start; font-size: .9rem; color: var(--ink-muted); font-weight: 400; }
.contact-form .consent input { width: 1.1rem; height: 1.1rem; flex: none; margin-top: .15rem; }
.contact-form .btn { align-self: flex-start; margin-top: var(--space-2); }
.fp-form-notice { padding: var(--space-3) var(--space-4); border-radius: var(--radius); font-size: .95rem; }
.fp-form-notice.is-error { background: #fdecec; color: #8a1f1f; border: 1px solid #f0b8b8; }
.fp-form-notice.is-ok { background: var(--surface); color: var(--deep); border: 1px solid var(--azure); }

/* ============================ Footer ============================
   Il cliente vuole il logo "fuori la foto oppure su barra bianca", "non andare a capo" e un uso migliore
   del bold. Barra bianca col logo + banda navy a 3 colonne con etichette in bold e valori regular. */
.site-footer__logobar { background: var(--paper); border-top: 1px solid var(--line); padding-block: var(--space-5); }
.site-footer__main { background: var(--navy); color: var(--on-dark); }
.site-footer__inner { padding-block: var(--space-8) var(--space-5); }
.site-footer__grid { display: grid; grid-template-columns: 1fr; gap: var(--space-7); }
@media (min-width: 760px) { .site-footer__grid { grid-template-columns: 1.5fr 1.1fr 0.9fr; gap: var(--space-7); } }
.site-footer__col h4 { font-family: var(--font-display); font-weight: 600; font-size: 1.1rem;
  color: var(--on-dark); margin-bottom: var(--space-4); }
.site-footer__col a { color: var(--on-dark); text-decoration: underline; text-underline-offset: 3px;
  text-decoration-color: rgba(255,255,255,.4); }
.site-footer__col a:hover { text-decoration-color: var(--on-dark); }
.site-footer__col .muted, .site-footer__tag { color: var(--muted-on-dark); }
.site-footer__tag { font-size: .9rem; margin-top: var(--space-4); max-width: 34ch; }
.site-footer__demo { color: var(--muted-on-dark); font-size: .82rem; margin-top: var(--space-4); }

/* Il bold porta l'etichetta, il regular il valore: è la gerarchia che il cliente ha chiesto.
   ⚠ Niente a capo: l'etichetta non si spezza e il valore resta sulla sua riga.
   ⚠⚠ `.finfo` è un componente CONDIVISO chiaro/scuro: nasce SCURO-SU-CHIARO (il caso generale — la
   pagina Contatti) ed è il FOOTER a ridipingerlo per la sua banda navy. Il contrario — colori "on dark"
   di default — rende le etichette BIANCHE SU BIANCO fuori dal footer: invisibili, e axe non le segnala
   nemmeno (segnala solo i valori). Verificato dal vivo, non dedotto. */
.finfo { display: grid; grid-template-columns: auto 1fr; gap: var(--space-2) var(--space-3); align-items: baseline; }
.finfo dt { font-weight: 700; color: var(--deep); white-space: nowrap; }
.finfo dd { margin: 0; color: var(--ink-muted); text-wrap: pretty; }
.finfo dd a { color: var(--azure-ink); }
.site-footer .finfo dt { color: var(--on-dark); }
.site-footer .finfo dd, .site-footer .finfo dd a { color: var(--muted-on-dark); }
@media (max-width: 420px) { .finfo { grid-template-columns: 1fr; gap: 0 0; } .finfo dd { margin-bottom: var(--space-3); } }

.flinks { display: flex; flex-direction: column; gap: var(--space-3); }
.flinks a { display: inline-flex; align-items: center; gap: var(--space-3); }
.flinks a::before { content: ""; width: 6px; height: 6px; border-radius: 50%;
  border: 1.5px solid var(--azure-lt); flex: none; }

.site-footer__legal {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--space-4);
  margin-top: var(--space-7); padding-top: var(--space-5);
  border-top: 1px solid rgba(255,255,255,.18); color: var(--muted-on-dark); font-size: .85rem;
}
.site-footer__dgitaly { display: inline-flex; align-items: center; gap: var(--space-2); color: var(--muted-on-dark); }
.site-footer__dgitaly img { width: 20px; height: 20px; }

/* ============================ Barra CTA mobile ============================ */
.cta-bar { display: none; }
@media (max-width: 760px) {
  .cta-bar {
    display: grid; grid-template-columns: 1fr 1fr; gap: 1px; position: fixed; left: 0; right: 0; bottom: 0;
    z-index: 40; background: var(--line); box-shadow: 0 -4px 18px rgba(28,34,51,.18);
  }
  .cta-bar a { background: var(--paper); color: var(--deep); text-align: center;
    padding: var(--space-4); font-weight: 700; font-family: var(--font-display); }
  /* ⚠ Specificità: `.cta-bar a` (0,1,1) batterebbe `.cta-bar__call` (0,1,0) — il selettore va qualificato. */
  a.cta-bar__call { background: var(--deep); color: var(--on-dark); }
  /* ⚠ Fondo --azure-ink e non --azure: bianco su --azure fa 4.49 (sotto AA). Si legge azzurro lo stesso. */
  a.cta-bar__wa { background: var(--azure-ink); color: var(--on-dark); }
  body { padding-bottom: 4rem; }
}

/* ============================ Foto apribili (lightbox) ============================
   Le foto dei lavori sono `a.zoom`: cursore d'ingrandimento + un'icona che appare all'hover. Il lightbox
   (JS bundlato, guardato) mostra l'immagine a PIENA risoluzione (1200×900): a schermo intero ci sta senza
   upscale, quindi non si sgrana. */
a.zoom { display: block; position: relative; cursor: zoom-in; }
a.zoom::after {
  content: ""; position: absolute; right: var(--space-3); bottom: var(--space-3); width: 30px; height: 30px;
  border-radius: 50%; background: rgba(var(--navy-rgb),.72);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='M21 21l-4.3-4.3M11 8v6M8 11h6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: center; background-size: 16px;
  opacity: 0; transform: translateY(4px); transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease);
}
a.zoom:hover::after, a.zoom:focus-visible::after { opacity: 1; transform: none; }

.fp-lb {
  position: fixed; inset: 0; z-index: 100000; display: none;
  align-items: center; justify-content: center; padding: 5vh 4vw;
  background: rgba(var(--navy-rgb),.94); cursor: zoom-out;
}
.fp-lb.is-open { display: flex; animation: fp-lb-in 200ms var(--ease); }
@keyframes fp-lb-in { from { opacity: 0; } to { opacity: 1; } }
.fp-lb__img { max-width: 92vw; max-height: 88vh; object-fit: contain; border-radius: var(--radius);
  box-shadow: 0 20px 60px rgba(0,0,0,.5); cursor: default; }
.fp-lb__x { position: absolute; top: max(1rem, 3vh); right: max(1rem, 3vw); width: 44px; height: 44px;
  border: 0; border-radius: 50%; background: rgba(255,255,255,.14); color: #fff; font-size: 1.8rem; line-height: 1;
  cursor: pointer; transition: background var(--dur) var(--ease); }
.fp-lb__x:hover { background: rgba(255,255,255,.28); }

/* Frecce ← → per scorrere la galleria senza chiudere e riaprire. Le crea `reveal.js` insieme alla X, ma
   questo verticale non le vestiva: restavano <button> di sistema alti 6px con l'SVG collassato a 0x0 —
   un trattino grigio sul bordo (misurato: 16x6, position static, svg 0x0). Stessa pastiglia della X.
   ⚠ Con UNA sola foto lo script mette `display:none` INLINE, che vince su questa regola: le frecce
   restano nascoste dove non servono, senza che il foglio debba saperlo. */
.fp-lb__nav { position: absolute; top: 50%; transform: translateY(-50%); width: 52px; height: 52px;
  border: 0; border-radius: 50%; background: rgba(255,255,255,.14); color: #fff;
  display: grid; place-items: center; cursor: pointer; z-index: 1;
  transition: background var(--dur) var(--ease); }
.fp-lb__nav:hover { background: rgba(255,255,255,.28); }
.fp-lb__nav:focus-visible { outline: 3px solid #fff; outline-offset: 3px; }
.fp-lb__nav svg { width: 26px; height: 26px; }   /* l'SVG non porta misure proprie: senza queste e' 0x0 */
.fp-lb__prev { left: max(0.6rem, 2vw); }
.fp-lb__next { right: max(0.6rem, 2vw); }
/* Sul telefono le frecce starebbero SOPRA la foto: scendono in basso, affiancate al centro. */
@media (max-width: 600px) {
  .fp-lb__nav { top: auto; bottom: max(1rem, 2vh); transform: none; width: 48px; height: 48px; }
  .fp-lb__prev { left: calc(50% - 60px); }
  .fp-lb__next { right: calc(50% - 60px); }
}
@media (prefers-reduced-motion: reduce) { .fp-lb.is-open { animation: none; } }

/* ============================ Pulsante WhatsApp con glow ============================
   Come su K Edilizia: il WhatsApp "vive" con un anello che pulsa (richiama l'attenzione senza rumore).
   ⚠ Palette del cliente = solo blu/azzurro: il bottone resta --deep (non verde WhatsApp) e l'anello pulsa
   in azzurro. Fail-safe: reduced-motion → niente pulsazione. */
.btn--wa { position: relative; }
.btn--wa svg { width: 1.15em; height: 1.15em; fill: currentColor; }
@media (prefers-reduced-motion: no-preference) {
  .btn--wa { animation: fp-wa-pulse 2.6s ease-in-out infinite; }
}
@keyframes fp-wa-pulse {
  0%, 70%, 100% { box-shadow: var(--shadow-cta), 0 0 0 0 rgba(var(--azure-rgb),.55); }
  35% { box-shadow: var(--shadow-cta), 0 0 0 12px rgba(var(--azure-rgb),0); }
}
/* Anche il tasto WhatsApp della cta-bar mobile pulsa. */
@media (max-width: 760px) and (prefers-reduced-motion: no-preference) {
  a.cta-bar__wa { position: relative; animation: fp-wa-pulse-bar 2.6s ease-in-out infinite; }
}
@keyframes fp-wa-pulse-bar {
  0%, 70%, 100% { box-shadow: inset 0 0 0 0 rgba(255,255,255,.0); }
  35% { box-shadow: inset 0 0 22px 0 rgba(255,255,255,.22); }
}

/* ============================ 404 ============================ */
.nf { text-align: center; padding-block: var(--space-9); }
/* --azure-ink anche qui: la regola "l'azzurro non è testo" resta assoluta, senza eccezioni da ricordare. */
.nf__code { font-family: var(--font-display); font-weight: 700; font-size: clamp(3.5rem, 2rem + 7vw, 7rem);
  color: var(--azure-ink); line-height: 1; }
.nf__actions { display: flex; gap: var(--space-4); justify-content: center; flex-wrap: wrap; margin-top: var(--space-6); }

/* ============================ Scroll-reveal (micro-JS IntersectionObserver) ============================
   ⚠⚠ Il reveal MUOVE, non sfuma. Due motivi, entrambi pagati altrove: un'opacità intermedia COMPONE il
   testo col fondo e un --ink-muted (5.75 sul tint) scende sotto AA a metà transizione; e un contenitore
   trasparente non fa scaricare le immagini che contiene. Fail-visible: senza JS resta tutto visibile. */
.js .reveal { opacity: 1; transform: translateY(24px); }
.js .reveal.is-visible { transform: none; transition: transform 620ms var(--ease);
  transition-delay: calc(var(--reveal-i, 0) * 90ms); }
@media (prefers-reduced-motion: reduce) { .js .reveal { transform: none; } }

/* --- Stagger: i figli di una griglia entrano a scalare, non tutti insieme. In SOLO transform (le foto
   dentro devono scaricarsi comunque) e senza toccare l'opacità del testo. --- */
.js .stagger > * { transform: translateY(20px); transition: transform 640ms var(--ease); }
.js .stagger.is-visible > * { transform: none; }
.js .stagger.is-visible > *:nth-child(1) { transition-delay: 0ms; }
.js .stagger.is-visible > *:nth-child(2) { transition-delay: 70ms; }
.js .stagger.is-visible > *:nth-child(3) { transition-delay: 140ms; }
.js .stagger.is-visible > *:nth-child(4) { transition-delay: 210ms; }
.js .stagger.is-visible > *:nth-child(5) { transition-delay: 280ms; }
.js .stagger.is-visible > *:nth-child(6) { transition-delay: 350ms; }
.js .stagger.is-visible > *:nth-child(7) { transition-delay: 420ms; }
.js .stagger.is-visible > *:nth-child(8) { transition-delay: 490ms; }
.js .stagger.is-visible > *:nth-child(n+9) { transition-delay: 560ms; }
@media (prefers-reduced-motion: reduce) { .js .stagger > * { transform: none; } }

/* --- Wipe: la foto si SCOPRE da sinistra invece di comparire. È il gesto che fa "2026" senza chiedere
   nulla al contenuto. ⚠ clip-path e non opacity: un'immagine trasparente non si scarica, e il wipe
   lascia il testo accanto sempre pieno (mai un testo che attraversa la soglia AA sfumando). --- */
.js .wipe img, .js img.wipe { clip-path: inset(0 100% 0 0); transform: scale(1.04); }
.js .wipe.is-visible img, .js img.wipe.is-visible {
  clip-path: inset(0 0 0 0); transform: none;
  transition: clip-path 900ms cubic-bezier(.22,.8,.24,1), transform 1200ms cubic-bezier(.22,.8,.24,1);
}
@media (prefers-reduced-motion: reduce) {
  .js .wipe img, .js img.wipe { clip-path: none; transform: none; }
}

/* --- LA PIEGA: le foto delle schede si scoprono con un taglio INCLINATO, non con un bordo dritto -----
   Perche' esiste: sulla home le fotografie delle schede COMPARIVANO e basta — era l'unica pagina del sito
   dove non si usava il gesto del verticale (misurato: 0 `wipe` e 0 `stagger` sulla home, contro 4 e 2 su
   /servizi/). Qui il gesto c'e', e porta l'angolo del MARCHIO invece di un bordo verticale qualunque.

   ⚠ L'ANGOLO NON E' ARBITRARIO: il rombo azzurro del logo ha una pendenza misurata di dx/dy = 0,1298
   (7,4 gradi dalla verticale, regressione lineare su 63 campioni del bordo sinistro del rombo). Con
   `--piega-dx: 34px` su riquadri alti 221-459px il taglio resta fra 4,2 e 7,3 gradi: la stessa famiglia
   di inclinazione del marchio, e la lettura e' quella di un taglio di fustella.

   ⚠⚠ PERCHE' NON `animation-timeline: view()`: ci ho provato ed e' inservibile QUI. `view()` misura
   l'elemento dentro il suo scrollport piu' vicino, e sia `.ocard` sia `.ocard__media` portano
   `overflow: hidden` — sono quindi contenitori di scorrimento. Misurato: il timeline restava congelato
   (64,94% a ogni posizione) e il gesto finiva prima di cominciare. Farlo funzionare vorrebbe dire
   togliere l'overflow dalle schede, cioe' riprogettare il markup anche del primo cliente. Si usa invece
   il rivelatore del verticale, che e' provato e vale su ogni browser.

   ⚠ DEFAULT INERTI: con `--piega-da: 100%` e `--piega-dx: 0px` i due stati sono entrambi il rettangolo
   pieno, quindi un sito che non accende i token non vede alcuna differenza. */
.js .ocards .ocard__media img,
.js .stiles .stile__media img {
  clip-path: polygon(0 0, calc(var(--piega-da) + var(--piega-dx)) 0, var(--piega-da) 100%, 0 100%);
}
.js .ocards.is-visible .ocard__media img,
.js .stiles.is-visible .stile__media img {
  clip-path: polygon(0 0, calc(100% + var(--piega-dx)) 0, 100% 100%, 0 100%);
  transition: clip-path 900ms cubic-bezier(.22,.8,.24,1);
}
/* La cascata: ogni scheda apre poco dopo la precedente. Stessi passi dello `stagger` del verticale. */
.js .ocards.is-visible > *:nth-child(2) .ocard__media img, .js .stiles.is-visible > *:nth-child(2) .stile__media img { transition-delay: 90ms; }
.js .ocards.is-visible > *:nth-child(3) .ocard__media img, .js .stiles.is-visible > *:nth-child(3) .stile__media img { transition-delay: 180ms; }
.js .ocards.is-visible > *:nth-child(4) .ocard__media img, .js .stiles.is-visible > *:nth-child(4) .stile__media img { transition-delay: 270ms; }
.js .ocards.is-visible > *:nth-child(5) .ocard__media img { transition-delay: 360ms; }
/* ⚠ Senza JavaScript e con movimento ridotto le foto sono PIENE: il gesto non puo' nascondere contenuto. */
/* ⚠ La specificita' deve pareggiare quella dello stato aperto (0,4,1), altrimenti con `is-visible`
   presente la regola del movimento ridotto perde e il taglio resta dichiarato. */
@media (prefers-reduced-motion: reduce) {
  .js .ocards .ocard__media img, .js .stiles .stile__media img,
  .js .ocards.is-visible .ocard__media img, .js .stiles.is-visible .stile__media img {
    clip-path: none; transition: none;
  }
}

/* --- Il titolo di sezione porta un filetto che si tira da sinistra: piccolo, sobrio, percepibile. --- */
.js .section-intro h2 { position: relative; }
.js .section-intro.is-visible h2::after {
  content: ""; position: absolute; left: 50%; transform: translateX(-50%); bottom: -14px;
  width: 0; height: 3px; background: var(--azure); border-radius: 3px;
  animation: fp-rule 700ms 240ms var(--ease) forwards;
}
@keyframes fp-rule { to { width: 64px; } }
@media (prefers-reduced-motion: reduce) { .js .section-intro.is-visible h2::after { width: 64px; animation: none; } }

/* Bottone hamburger di wp:navigation: WP lo mostra solo sotto il breakpoint (overlayMenu:"mobile").
   Sta sulla barra BIANCA dell'header, quindi porta --deep. */
.wp-block-navigation__responsive-container-open { background: none; border: 0; font-size: 1.6rem; line-height: 1; color: var(--deep); padding: var(--space-2); }
@media (min-width: 901px) { .wp-block-navigation__responsive-container-open { display: none; } }
@media (max-width: 900px) { .site-nav > .wp-block-navigation__container { display: none; } }
