/* components.css — componenti di sezione e chrome del verticale artisan_atelier.
   Tesi: atelier sartoriale. Il carattere lo danno i BLOCCHI PIENI di colore (Prussia/ottone) e il filo
   d'ottone, NON la fotografia: il materiale di questi clienti è murato a ~1000px e non regge un hero a
   piena larghezza. Le foto stanno in TESSERE misurate, sempre con gutter — mai a contatto tra loro.
   I colori arrivano da tokens.css: qui non si dichiarano valori. */

/* ============================ Chrome: header ============================ */
/* Header fisso "a vetro". ⚠ backdrop-filter crea un containing-block per il position:fixed → l'overlay
   del menu mobile va forzato a 100vh (vedi .is-menu-open in fondo), altrimenti si confina all'header. */
.site-header {
  position: sticky; top: 0; z-index: 50;
  background: color-mix(in srgb, var(--paper) 86%, transparent);
  backdrop-filter: saturate(1.4) blur(10px);
  border-bottom: var(--border);
}
/* Il wrapper WP del template-part limiterebbe lo sticky: display:contents lo toglie di mezzo. */
.wp-block-template-part { display: contents; }

/* Riga header CENTRATA verticalmente: align-items:center + azzeramento dei margini di blocco WP,
   che spingerebbero nav e CTA sotto il centro. */
.site-header__row {
  display: flex; align-items: center; gap: var(--space-5);
  min-height: 74px; padding-block: var(--space-3);
}
.site-header__row > * { align-self: center; margin-block: 0; }

.wordmark { font-family: var(--font-display); font-size: 1.5rem; line-height: 1; display: flex; align-items: center; gap: var(--space-3); }
.wordmark small { display: block; font-family: var(--font-body); font-size: var(--text-sm); letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--ink-muted); margin-top: .2rem; }
.wordmark--logo .wordmark__mark { flex: none; }
.wordmark__txt { display: block; }

.site-nav { margin-left: auto; }
.site-nav a { font-size: .95rem; }
.site-nav a:hover { color: var(--accent-text); }

/* Sotto-menu DESKTOP: il default WP è una card bianca squadrata, estranea al resto. Qui è un pannello
   Prussia col filo d'ottone in testa — lo stesso segno delle tessere e della foto d'intro.
   ⚠ SPECIFICITÀ: WP dichiara `.wp-block-navigation .wp-block-navigation__submenu-container{background-color:#fff;border:1px solid rgba(0,0,0,.15)}` — stesso peso (0,2,0) del selettore `.site-nav …`, ma il CSS dei
   blocchi è iniettato DOPO il tema, quindi a parità vince WP e il pannello resta BIANCO. Serve un livello
   in più (`.site-header .site-nav …`). Stessa trappola del bottone header e dell'overlay del menu. */
.site-header .site-nav .wp-block-navigation__submenu-container {
  background: var(--brand);
  border: none; border-top: 2px solid var(--accent-deco);
  border-radius: 0 0 var(--radius-lg) var(--radius-lg);
  box-shadow: var(--shadow-md);
  padding-block: var(--space-3);
  min-width: 14rem;
}
.site-header .site-nav .wp-block-navigation__submenu-container .wp-block-navigation-item__content {
  color: var(--on-dark); padding: var(--space-3) var(--space-5); width: 100%;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.site-header .site-nav .wp-block-navigation__submenu-container .wp-block-navigation-item__content:hover {
  background: color-mix(in srgb, var(--on-dark) 10%, transparent); color: var(--accent-lt);
}
.site-header__tel { font-weight: 600; white-space: nowrap; }
.site-header__cta { white-space: nowrap; }
/* Su mobile telefono e CTA escono dall'header (che ha già logo + hamburger) e lo fanno sbordare in
   orizzontale: li porta la .cta-bar fissa in basso, quindi qui sono ridondanti.
   ⚠ Selettore discendente NON per vezzo: `.site-header__cta` e `.btn` hanno la stessa specificità e
   `.btn{display:inline-flex}` è dichiarato DOPO — la media query non aggiunge specificità, quindi una
   regola piatta qui verrebbe sovrascritta e il bottone resterebbe visibile (sbordando). */
@media (max-width: 780px) {
  .site-header .site-header__tel, .site-header .site-header__cta { display: none; }
}

/* ============================ Bottoni ============================ */
/* ⚠ CONTRATTO a11y: il bottone in ottone porta testo --ink (5.2:1). MAI bianco su ottone (3.1:1). */
.btn {
  display: inline-flex; align-items: center; gap: var(--space-2);
  padding: var(--space-3) var(--space-5);
  font-family: var(--font-body); font-weight: 600; font-size: .95rem;
  border: 1px solid transparent; border-radius: var(--radius);
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease),
    border-color var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.btn:hover { transform: translateY(-2px); }
.btn--accent { background: var(--accent-deco); color: var(--ink); }
.btn--accent:hover { background: var(--accent-lt); }
.btn--ink { background: var(--brand); color: var(--on-dark); }
.btn--ink:hover { background: var(--night); }
.btn--ghost { border-color: currentColor; }
.btn--ghost:hover { background: var(--brand); color: var(--on-dark); border-color: var(--brand); }
/* Ghost su banda scura: il bordo eredita --on-dark, l'hover inverte. */
.band--dark .btn--ghost:hover { background: var(--on-dark); color: var(--brand); }

/* ============================ Hero: due campi ============================ */
/* Banda Prussia piena + tessera foto VERTICALE che la scavalca. Il testo NON sta sopra la foto:
   il contrasto non dipende dal fotogramma, e la foto (piccola, ~1000px) non deve reggere l'intera banda. */
.hero { position: relative; background: var(--brand); color: var(--on-dark); overflow: visible; isolation: isolate; }
.hero__inner { display: grid; grid-template-columns: 1.15fr .85fr; gap: var(--gutter); align-items: center; padding-block: clamp(3.5rem, 2rem + 6vw, 7rem); }
/* ⚠ NIENTE max-width sulla colonna: la misura di lettura (~46ch) vale per la LEAD, non per il display —
   strozzata a 34ch, l'h1 andava a 6 righe. La misura si mette sul paragrafo, mai sul contenitore del titolo. */
.hero__text { }
/* ⚠ Size PROPRIA, non --text-3xl: quel gradino è tarato su un titolo breve (il demo ne ha 47 caratteri), ma
   il titolo reale del cliente ne ha 60+ e qui sta in COLONNA, non su riga piena → a 77px faceva 6 righe. */
.hero h1 { color: var(--on-dark); font-size: clamp(2.1rem, 1.4rem + 2.4vw, 3.3rem); margin-block: var(--space-4) var(--space-5); }
.hero .lead { color: var(--on-dark); opacity: .92; max-width: 46ch; }
.hero__actions { display: flex; flex-wrap: wrap; gap: var(--space-3); margin-top: var(--space-6); }
/* La tessera scavalca la banda in basso: margine negativo + z-index. Ratio verticale = il formato che il
   materiale tipico ha davvero (tende fotografate in piedi). */
.hero__tile { position: relative; z-index: 1; aspect-ratio: 3 / 4; margin-bottom: calc(var(--section-y) * -0.5); border-radius: var(--radius-lg); overflow: hidden; box-shadow: var(--shadow-md); }
.hero__tile img { width: 100%; height: 100%; object-fit: cover; }
/* Filo d'ottone che accompagna la tessera (decoro, non testo). */
.hero__tile::after { content: ""; position: absolute; inset: auto 0 0 0; height: 3px; background: var(--accent-deco); }
@media (max-width: 860px) {
  .hero__inner { grid-template-columns: 1fr; }
  .hero__tile { display: none; }   /* su mobile la banda piena basta: la foto piccola non aggiunge nulla */
}

/* ============================ Manifesto (featured) ============================ */
.manifesto__grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--gutter) clamp(2rem, 6vw, 5rem); align-items: start; }
.manifesto__body { color: var(--ink); }
/* Attacco editoriale: il primo capoverso è la voce dell'artigiano. Nessun campo nuovo nell'IR:
   è il body che c'è già, trattato tipograficamente. */
.manifesto__body > p:first-child { font-family: var(--font-display); font-size: var(--text-md); color: var(--accent-text); border-left: 2px solid var(--accent-deco); padding-left: var(--space-5); margin-bottom: var(--space-5); }
@media (max-width: 860px) { .manifesto__grid { grid-template-columns: 1fr; } }

/* ============================ Lavorazioni (services) ============================ */
/* Mosaico di tessere CON GUTTER (mai a contatto: è il difetto tipico delle gallerie di questi clienti).
   Due tessere PIENE di colore danno il carattere senza chiedere nulla alla fotografia: stando in posizione
   alterna (2ª e 4ª) scendono in diagonale, ed è LÌ che sta il ritmo — non in un disallineamento delle celle.
   ⚠ Le celle si allungano tutte alla riga (stretch, il default della griglia): una tessera piena non ha la
   foto che le occupa la parte alta, quindi da sola verrebbe alta quasi la metà di una card con foto. Un
   offset sfalsato SOPRA altezze diverse non si legge come scala, si legge come disallineamento: perché una
   discesa sia leggibile le tessere devono prima essere alte uguali. */
.works { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--tile-gap); }
.work { position: relative; display: flex; flex-direction: column; background: var(--paper); border: var(--border); border-radius: var(--radius); overflow: hidden; transition: transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease); }
.work:hover { transform: translateY(-3px); box-shadow: var(--shadow-md); }
.work__media { aspect-ratio: 4 / 3; overflow: hidden; background: var(--surface); }
.work__media img { width: 100%; height: 100%; object-fit: cover; transition: transform var(--dur) var(--ease); }
.work:hover .work__media img { transform: scale(1.03); }
/* Il link copre il corpo della card: la tessera intera è cliccabile e porta DIRITTO alla pagina della
   lavorazione (mai a un hub intermedio). Gli URL sono di pagine solo-progetto → hardcodati nel pattern. */
.work__link { display: flex; flex-direction: column; flex: 1; color: inherit; }
.work__link:hover h3 { color: var(--accent-text); }
.work--filled-ink .work__link:hover h3, .work--filled-accent .work__link:hover h3 { color: inherit; text-decoration: underline; text-underline-offset: 3px; }
.work__body { padding: var(--space-5); display: flex; flex-direction: column; gap: var(--space-2); flex: 1; }
.work h3 { color: var(--ink); }
.work__text { color: var(--ink-muted); font-size: .95rem; }
/* Tessere piene: 2ª Prussia, 4ª ottone. Il testo segue il contratto (su ottone → --ink).
   Non avendo la foto che occupa la parte alta, il loro testo va CENTRATO nella cella: allineato in alto
   lascerebbe un vuoto sotto e la tessera sembrerebbe incompiuta accanto alle card con foto. */
/* Serve a COLONNA SINGOLA, dove ogni tessera è sola nella sua riga e lo stretch non ha nulla da pareggiare:
   senza la foto resterebbe mozza. Nelle griglie a più colonne l'altezza della riga la supera ed è inerte.
   ⚠ Non è una misura per pareggiare le card con foto: quella la fa lo stretch, che segue la copy reale —
   un minimo fisso resta tarato sulla lunghezza dei testi del giorno in cui lo si scrive. */
.work--filled-ink, .work--filled-accent { min-height: 15rem; }
.work--filled-ink .work__body, .work--filled-accent .work__body { justify-content: center; }
.work--filled-ink { background: var(--brand); border-color: var(--brand); }
.work--filled-ink h3, .work--filled-ink .work__text { color: var(--on-dark); }
.work--filled-ink .work__text { opacity: .9; }
.work--filled-accent { background: var(--accent-deco); border-color: var(--accent-deco); }
.work--filled-accent h3, .work--filled-accent .work__text { color: var(--ink); }
/* Cucitura: il filo tratteggiato che rifinisce il bordo, come il punto su un cuscino imbottito. È il segno
   del mestiere — sta SOLO sulle tessere piene (dove non c'è la foto), altrimenti diventa decorazione. */
.work--filled-ink::before, .work--filled-accent::before {
  content: ""; position: absolute; inset: 10px; border-radius: var(--radius); pointer-events: none;
  border: 1px dashed color-mix(in srgb, var(--on-dark) 42%, transparent);
}
.work--filled-accent::before { border-color: color-mix(in srgb, var(--ink) 34%, transparent); }
@media (max-width: 980px) { .works { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 620px) { .works { grid-template-columns: 1fr; } }

/* ============================ Movimento ============================ */
/* Il movimento è quello del mestiere: il filo si tende, la cucitura si posa a lavoro finito, le tessere
   entrano come punti dati uno dopo l'altro. Tutto si aggancia a .reveal/.is-visible (reveal.js), quindi
   resta fail-visible senza JS; gli stati di riposo sono gli stessi che il CSS dichiara sopra.
   ⚠ Le tessere si muovono in SOLO transform, MAI in opacity: un elemento trasparente non fa scaricare le
   immagini che contiene, e sono quelle delle lavorazioni. */
.js .work.reveal { opacity: 1; transform: translateY(22px);
  transition: transform .65s var(--ease), box-shadow var(--dur) var(--ease); }
.js .work.reveal.is-visible { transform: none; transition-delay: calc(var(--reveal-i, 0) * 80ms); }
.js .work.reveal.is-visible:hover { transform: translateY(-3px); transition-delay: 0s; }
/* La cucitura arriva DOPO la tessera e si stringe al bordo: è il punto dato a lavoro finito. */
.js .work.reveal::before { opacity: 0; inset: 3px;
  transition: opacity .5s var(--ease), inset .7s var(--ease); }
.js .work.reveal.is-visible::before { opacity: 1; inset: 10px;
  transition-delay: calc(var(--reveal-i, 0) * 80ms + 280ms); }

/* Il cartamodello: entrano i passaggi e il filo li rincorre da sinistra a destra. Il contenitore non
   sfuma, altrimenti il passaggio sfumerebbe due volte (una col gruppo, una per sé).
   ⚠ I passaggi si muovono in SOLO transform: il loro testo è --ink-muted, che sul tint sta a 4.64 e cioè
   appena sopra la soglia AA — un'opacità intermedia lo comporrebbe col fondo e lo porterebbe sotto (3.88
   misurato) per tutta la durata della dissolvenza. Un testo non deve mai attraversare la soglia. */
.js .pattern-steps.reveal { opacity: 1; transform: none; }
.js .pattern-steps.reveal .pstep { opacity: 1; transform: translateY(14px);
  transition: transform .5s var(--ease); }
.js .pattern-steps.reveal.is-visible .pstep { transform: none; }
.js .pattern-steps.reveal .pstep::before { transform: scaleX(0); transform-origin: left;
  transition: transform .55s var(--ease); }
.js .pattern-steps.reveal.is-visible .pstep::before { transform: scaleX(1); }
.js .pattern-steps.reveal.is-visible .pstep:nth-child(1) { transition-delay: 0ms; }
.js .pattern-steps.reveal.is-visible .pstep:nth-child(2) { transition-delay: 110ms; }
.js .pattern-steps.reveal.is-visible .pstep:nth-child(3) { transition-delay: 220ms; }
.js .pattern-steps.reveal.is-visible .pstep:nth-child(4) { transition-delay: 330ms; }
.js .pattern-steps.reveal.is-visible .pstep:nth-child(1)::before { transition-delay: 120ms; }
.js .pattern-steps.reveal.is-visible .pstep:nth-child(2)::before { transition-delay: 230ms; }
.js .pattern-steps.reveal.is-visible .pstep:nth-child(3)::before { transition-delay: 340ms; }
.js .pattern-steps.reveal.is-visible .pstep:nth-child(4)::before { transition-delay: 450ms; }

/* L'occhiello: il filo si tira prima della parola. */
.js .reveal .eyebrow::before { width: 0; transition: width .5s var(--ease) .15s; }
.js .reveal.is-visible .eyebrow::before { width: 1.6em; }

/* La tessera dell'hero si posa. Sta sopra la piega: solo transform, la foto deve scaricarsi subito. */
@keyframes fp-tile-settle { from { transform: translateY(26px); } to { transform: none; } }
.js .hero__tile { animation: fp-tile-settle .9s var(--ease) .1s both; }

/* Il filo sotto la voce di menu cresce da sinistra, come un punto che corre. */
.site-header .site-nav .wp-block-navigation-item__content { position: relative; }
.site-header .site-nav .wp-block-navigation-item__content::after { content: ""; position: absolute;
  left: 0; right: 100%; bottom: -3px; height: 1px; background: var(--accent-deco);
  transition: right .32s var(--ease); }
.site-header .site-nav .wp-block-navigation-item__content:hover::after { right: 0; }

/* Chi ha disattivato le animazioni vede gli stati finali, subito e senza transizioni. */
@media (prefers-reduced-motion: reduce) {
  .js .work.reveal, .js .pattern-steps.reveal .pstep, .js .hero__tile { transform: none; opacity: 1; animation: none; }
  .js .work.reveal::before { opacity: 1; inset: 10px; }
  .js .pattern-steps.reveal .pstep::before, .tcard::before { transform: none; }
  .js .reveal .eyebrow::before { width: 1.6em; }
  .js .work.reveal, .js .work.reveal::before, .js .pattern-steps.reveal .pstep,
  .js .pattern-steps.reveal .pstep::before, .tcard::before, .btn,
  .site-header .site-nav .wp-block-navigation-item__content::after { transition: none; }
}

/* ============================ Intro di pagina categoria ============================ */
/* Il testo introduttivo da solo in colonna stretta lascia mezza pagina vuota (difetto tipico: "spoglia").
   Regola: la foto sta ACCANTO alla descrizione, non relegata in una banda a fondo pagina. */
.cat-intro { display: grid; grid-template-columns: 1.05fr .95fr; gap: clamp(2rem, 5vw, 4rem); align-items: center; }
.cat-intro__text > p + p { margin-top: var(--space-4); }
.cat-intro__media { border-radius: var(--radius-lg); overflow: hidden; box-shadow: var(--shadow-md); position: relative; }
.cat-intro__media img { width: 100%; height: 100%; object-fit: cover; aspect-ratio: 4 / 3; }
/* filo d'ottone: lo stesso segno della tessera hero */
.cat-intro__media::after { content: ""; position: absolute; inset: auto 0 0 0; height: 3px; background: var(--accent-deco); }
@media (max-width: 860px) { .cat-intro { grid-template-columns: 1fr; } }

/* ============================ Metodo: il cartamodello ============================ */
/* Numerali serif grandi in colonna, legati da un filo d'ottone verticale — il segno del sarto,
   non i bolli in cerchio (che sono di un altro verticale). */
.pattern-steps { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--gutter); }
.pstep { position: relative; padding-top: var(--space-6); }
.pstep__n { font-family: var(--font-display); font-size: 3rem; line-height: 1; color: var(--accent-text); display: block; }
.pstep h3 { margin-block: var(--space-3) var(--space-2); color: var(--ink); }
.pstep__text { color: var(--ink-muted); font-size: .95rem; }
/* Filo orizzontale che cuce gli step (si spegne a una colonna). */
.pstep::before { content: ""; position: absolute; top: var(--space-6); left: 0; right: calc(var(--gutter) * -1); height: 1px; background: var(--accent-deco); opacity: .5; }
.pstep:last-child::before { right: 0; }
@media (max-width: 980px) { .pattern-steps { grid-template-columns: repeat(2, 1fr); } .pstep::before { display: none; } }
@media (max-width: 560px) { .pattern-steps { grid-template-columns: 1fr; } }

/* ============================ Fiducia (trust) ============================ */
.trust__grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--gutter); align-items: start; }
.trust__items { display: grid; gap: var(--space-5); }
.tcard { position: relative; overflow: hidden; padding: var(--space-5); background: var(--paper);
  border: var(--border); border-radius: var(--radius);
  transition: transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease); }
/* La cimosa: il filo d'ottone corre lungo il lato della scheda, come sul bordo del manifesto — senza
   chiedere nulla alla fotografia, che qui non c'è. Scende quando la sezione entra. */
.tcard::before { content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 2px;
  background: var(--accent-deco); transform: scaleY(0); transform-origin: top;
  transition: transform .6s var(--ease); }
.js .trust__grid.reveal.is-visible .tcard::before { transform: scaleY(1); }
.js .trust__grid.reveal.is-visible .tcard:nth-child(1)::before { transition-delay: 180ms; }
.js .trust__grid.reveal.is-visible .tcard:nth-child(2)::before { transition-delay: 320ms; }
.tcard:hover { transform: translateY(-2px); box-shadow: var(--shadow-sm); }
.tcard h3 { color: var(--ink); margin-bottom: var(--space-2); }
.tcard__text { color: var(--ink-muted); font-size: .95rem; }
@media (max-width: 860px) { .trust__grid { grid-template-columns: 1fr; } }

/* ============================ Banda contatti ============================ */
.band--dark { background: var(--brand); color: var(--on-dark); }
.band--dark h2 { color: var(--on-dark); }
.band--dark .lead { color: var(--on-dark); opacity: .92; }
.contact-band__inner { display: flex; flex-wrap: wrap; gap: var(--space-6); align-items: center; justify-content: space-between; }
.contact-band__text { max-width: 46ch; }

/* ============================ Testata di pagina ============================ */
/* ⚠ La page-head NON riusa la size dell'hero (--text-3xl): è una testata, non un hero. Un gradino sotto
   + padding contenuto, altrimenti "occupa mezza schermata". È CONDIVISA da tutte le pagine interne. */
.page-head { background: var(--surface); padding-block: clamp(2.5rem, 1.5rem + 3vw, 4rem); border-bottom: var(--border); }
.page-head h1 { font-size: var(--text-2xl); }
.page-head p { color: var(--ink-muted); }

/* Intro di sezione: colonna di misura leggibile, non riga piena. */
.section-intro { max-width: 48rem; margin-bottom: var(--space-7); }
/* ⚠ Il titolo di sezione sta in colonna, non su riga piena → resta a --text-xl (mai --text-2xl):
   una size da riga piena qui manda i titoli lunghi del cliente a due righe. */

/* ============================ Pagina Contatti (2 colonne) ============================ */
/* Form a SINISTRA + recapiti in scheda CHIARA a destra. ⚠ La scheda NON riusa gli stili da fondo scuro:
   sul fondo chiaro della pagina i colori si invertirebbero. */
.contact-cols { display: grid; grid-template-columns: 1.1fr .9fr; gap: clamp(2rem, 5vw, 4rem); align-items: start; }
.contact-cols h2 { margin-bottom: var(--space-5); }
.contact-form { display: grid; gap: var(--space-4); }
/* Coppie di campi affiancate (Nome | Telefono). */
.contact-form .row { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-4); }
/* Il campo è una colonna: label SOPRA il controllo, mai di fianco (il default inline è illeggibile). */
.field { display: grid; gap: var(--space-2); }
.field label { font-family: var(--font-body); font-size: var(--text-sm); font-weight: 600; letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--ink-muted); }
.field input, .field textarea {
  font: inherit; color: var(--ink); width: 100%;
  padding: var(--space-3) var(--space-4);
  background: var(--paper); border: 1px solid var(--line); border-radius: var(--radius);
}
.field textarea { resize: vertical; min-height: 8rem; }
.field input:focus-visible, .field textarea:focus-visible { outline: 2px solid var(--focus); outline-offset: 1px; border-color: var(--accent-deco); }
/* ⚠ .consent è un flex: il testo (link incluso) va TUTTO in uno <span>, altrimenti l'<a> diventa
   un flex-item a sé e la riga si spezza. */
.consent { display: flex; align-items: flex-start; gap: var(--space-3); font-size: .95rem; color: var(--ink-muted); }
.consent input { margin-top: .25rem; flex: none; }
.consent a { color: var(--accent-text); text-decoration: underline; }
.contact-form button { justify-self: start; }
.form-note { margin-top: var(--space-1); }
/* Aside dei recapiti: scheda chiara, non la banda scura dell'home. */
.contact-info { background: var(--surface); border: var(--border); border-radius: var(--radius); padding: var(--space-6); }
.contact-info dl { display: grid; gap: var(--space-4); margin: 0; }
.contact-info dt { font-family: var(--font-body); font-size: var(--text-sm); font-weight: 600; letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--accent-text); }
.contact-info dd { margin: var(--space-1) 0 0; line-height: 1.6; }
.contact-info a { text-decoration: underline; text-underline-offset: 2px; }
.contact-info .btn { margin-top: var(--space-5); text-decoration: none; }
@media (max-width: 860px) {
  .contact-cols { grid-template-columns: 1fr; }
  .contact-form .row { grid-template-columns: 1fr; }
}

/* ============================ Footer ============================ */
.site-footer { background: var(--night); color: var(--on-dark); padding-block: var(--space-8) var(--space-6); }
.site-footer a:hover { color: var(--accent-lt); }
.site-footer__grid { display: grid; grid-template-columns: 1.2fr 1fr 1fr; gap: var(--gutter); }
.site-footer h4 { font-family: var(--font-body); font-size: var(--text-sm); font-weight: 600; letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--accent-lt); margin-bottom: var(--space-4); }
/* Il wordmark è condiviso con l'header (fondo chiaro), dove il suo <small> è --ink-muted: sul fondo scuro
   del footer quel grigio scende a 2.4:1 → qui va il testo secondario da fondo scuro (contratto palette). */
.site-footer .wordmark small { color: var(--muted-on-dark); }
.site-footer p { color: var(--on-dark); opacity: .92; font-size: .95rem; }
.site-footer__tag { margin-top: var(--space-4); max-width: 34ch; }
.site-footer__demo { margin-top: var(--space-4); color: var(--muted-on-dark); font-size: var(--text-sm); }
.site-footer__legal { margin-top: var(--space-7); padding-top: var(--space-5); border-top: 1px solid color-mix(in srgb, var(--on-dark) 18%, transparent); display: flex; flex-wrap: wrap; gap: var(--space-4); justify-content: space-between; color: var(--muted-on-dark); font-size: var(--text-sm); }
/* Powered by Dgitaly (fence fp:real: solo progetti reali). */
.site-footer__dgitaly { display: inline-flex; align-items: center; gap: var(--space-2); }
.site-footer__dgitaly img { display: inline-block; }
@media (max-width: 860px) { .site-footer__grid { grid-template-columns: 1fr; } }

/* ============================ CTA bar mobile ============================ */
/* Barra fissa solo su mobile: il preventivo telefonico è l'obiettivo di conversione del verticale.
   ⚠ Il menu overlay ha padding-bottom generoso per non finire sotto questa barra. */
.cta-bar { display: none; }
@media (max-width: 780px) {
  .cta-bar {
    position: fixed; inset: auto 0 0 0; z-index: 40;
    display: grid; grid-template-columns: 1fr 1fr;
    background: var(--night); border-top: 1px solid color-mix(in srgb, var(--on-dark) 18%, transparent);
  }
  .cta-bar a { padding: var(--space-4); text-align: center; color: var(--on-dark); font-weight: 600; font-size: .95rem; }
  /* ⚠ SPECIFICITÀ: `.cta-bar a` pesa (0,1,1) e batte `.cta-bar__call` (0,1,0) QUALUNQUE sia l'ordine →
     il testo resterebbe écru sull'ottone (3.09:1). Serve un selettore di pari peso: `a.cta-bar__call`. */
  .cta-bar a.cta-bar__call { background: var(--accent-deco); color: var(--ink); }   /* contratto: su ottone, testo ink (5.16:1) */
  body { padding-bottom: 56px; }
}

/* ============================ Menu mobile (overlay wp:navigation) ============================ */
/* ⚠ L'header ha backdrop-filter → containing-block per il fixed: senza questo, l'overlay si confina
   all'altezza dell'header (~74px) e il menu risulta "rotto". */
/* ⚠ SPECIFICITÀ: WP dichiara `.wp-block-navigation:not(.has-background) .wp-block-navigation__responsive-container.is-menu-open:not(.disable-default-overlay){background-color:#fff}` (0,4,0). Una regola
   piatta sul container (0,2,0) NON vince e l'overlay resta BIANCO. Va ripreso lo stesso schema. */
.site-nav:not(.has-background) .wp-block-navigation__responsive-container.is-menu-open:not(.disable-default-overlay),
.wp-block-navigation__responsive-container.is-menu-open {
  height: 100vh; max-height: 100vh; overflow-y: auto; -webkit-overflow-scrolling: touch;
  background: var(--brand); color: var(--on-dark);
}
/* Le voci vanno a SINISTRA: `justifyContent:right` (desktop) in colonna diventa align-items:flex-end.
   ⚠ Va messo su TUTTA la catena, non solo sul `__container`: è il PADRE
   `__responsive-container-content` (largo quanto il viewport) che, restando flex-end, spinge a destra
   il blocco delle voci — correggere il solo figlio non sposta nulla. */
.site-nav .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-container-content,
.site-nav .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__container,
.site-nav .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation-item,
.site-nav .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__submenu-container {
  align-items: flex-start; justify-content: flex-start;
}
/* Aria a sinistra: le voci non devono toccare il bordo dello schermo. */
.site-nav .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-container-content { padding-left: var(--gutter); }
/* La X di chiusura: il default è sottile e incollata all'angolo. Più marcata (stroke sul path, che WP
   disegna in solo fill) e con aria sopra e di lato — l'area di tocco cresce con lei. */
.site-nav .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-container-close {
  top: var(--space-4); right: var(--space-4);
  padding: var(--space-3); color: var(--on-dark);
  border-radius: var(--radius);
}
.site-nav .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-container-close:hover { background: color-mix(in srgb, var(--on-dark) 12%, transparent); }
.site-nav .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-container-close svg {
  width: 28px; height: 28px;
  stroke: currentColor; stroke-width: 1.4;   /* l'icona WP è solo `fill`: lo stroke la ingrossa */
}
/* ⚠ La nav desktop ha `justifyContent:right`: nell'overlay (flex COLUMN) quel valore si traduce in
   `align-items:flex-end` → le voci si incolonnano a DESTRA e restano larghe quanto il testo (43px),
   col sotto-menu che sborda. Vanno rimessi allineamento e larghezza sul container E sull'item: agire
   solo sul `__content` non basta. */
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__container { align-items: flex-start; }
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation-item { width: 100%; }
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation-item__content { width: 100%; text-align: left; }
/* Il sotto-menu «Lavorazioni» va inline e indentato, non come card-dropdown desktop. */
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__submenu-container .wp-block-navigation-item { width: 100%; }
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__submenu-icon { margin-left: auto; }
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-container-content { padding-bottom: 96px; }
/* I sotto-menu su mobile stanno INLINE, non come card-dropdown desktop. */
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__submenu-container {
  position: static !important; border: none !important; box-shadow: none !important; background: none !important; padding-left: var(--space-5);
}

/* ============================ Scroll-reveal (micro-JS IntersectionObserver) ============================ */
/* Fail-visible: senza JS (.js assente) il contenuto è già visibile. reduced-motion rivela tutto.
   ⚠ MAI mettere `.reveal` su un contenitore di IMMAGINI (es. la griglia `.works`): con `opacity:0` il browser
   NON scarica le img che contiene — né lazy né eager — finché l'osservatore non lo rivela. Risultato: gallerie
   che restano vuote finché non si scrolla fin lì. Il reveal sta sui blocchi di TESTO (intro, step, card). */
.js .reveal { opacity: 0; transform: translateY(24px); }
/* Rete di sicurezza: una griglia foto non deve mai restare invisibile, nemmeno se qualcuno le rimette .reveal. */
.js .works, .js .works.reveal { opacity: 1; transform: none; }
.js .reveal.is-visible { opacity: 1; transform: none; transition: opacity 620ms var(--ease), transform 620ms var(--ease); transition-delay: calc(var(--reveal-i, 0) * 90ms); }
@media (prefers-reduced-motion: reduce) { .js .reveal { opacity: 1; transform: none; } }
