/* components.css — building_metalwork. Componenti di sezione e cromo.
   Regola di composizione del verticale: sul terreno NERO la separazione la fanno i FILETTI e lo spazio
   (un pannello --surface contro --paper fa 1,14: invisibile). È anche il dispositivo del riferimento di
   categoria BeArchitect6, quindi vincolo di contrasto e forma dicono la stessa cosa. */

/* ============ LAYOUT ============ */
.container { max-width: var(--container); margin-inline: auto; padding-inline: var(--gutter); }
/* ⭐ LA LUCE SULLE BANDE. Il terreno resta #000, ma ogni banda scura riceve una lieve salita — la stessa
   idea della testata («dal nero si schiarisce»), portata dentro la pagina. È volutamente al limite del
   percepibile (il punto più chiaro è #0B0B0B, +4%): serve a dare PROFONDITÀ, non a disegnare una striscia.
   ⚠ Il bianco su #0B0B0B tiene comunque 18,9:1, quindi nessun testo cambia di leggibilità. */
.section { padding-block: var(--section-y);
  background-image: linear-gradient(168deg, #0B0B0B 0%, #000 42%, #000 100%); }
/* Le bande che portano il catalogo prendono la luce dall'altro lato, così due sezioni scure di fila non
   si leggono come una sola lastra: è lo stesso alternarsi dei blocchi affiancati. */
.section.catalogo { background-image: linear-gradient(-168deg, #0B0B0B 0%, #000 42%, #000 100%); }
.section--alt { background: var(--brand); }
/* Banda di LETTURA: la prosa lunga delle pagine categoria non si legge su nero. */
/* La carta non è un rettangolo uniforme: scende dal bianco pieno alla carta calda. Il testo scuro
   (#131313) tiene 17,6:1 in cima e 16,0:1 in fondo — la leggibilità non dipende dal punto. */
.section--light { background-color: var(--sage); color: var(--ink-on-light);
  background-image: linear-gradient(180deg, var(--sage-light) 0%, var(--sage) 46%); }
.section--tight { padding-block: calc(var(--section-y) * .55); }
.section-intro { margin-bottom: var(--space-7); }
.section-intro > p { color: var(--ink-muted); }
.section--light .section-intro > p, .section--light .lead { color: var(--ink-muted-on-light); }

.eyebrow { font: 500 var(--text-sm)/1.4 var(--font-mono); letter-spacing: var(--tracking-label);
  text-transform: uppercase; color: var(--accent); margin-bottom: var(--space-4); }
.section--light .eyebrow { color: var(--accent-ink); }
.lead { color: var(--ink-muted); font-size: var(--text-md); }
.prose > p + p { margin-top: 1.1em; }
.prose strong { font-weight: 600; }

/* Elenco tecnico: due colonne quando le voci sono molte (regola 5: contenuti ricchi, mai una colonna
   sola lunghissima accanto a mezza pagina bianca). */
.spec-list { display: grid; grid-template-columns: repeat(2, minmax(0,1fr)); gap: var(--space-2) var(--space-6);
  margin-top: var(--space-5); }
.spec-list li { position: relative; padding-left: var(--space-5); font-size: var(--text-base); }
.spec-list li::before { content: ""; position: absolute; left: 0; top: .62em; width: 10px; height: 2px;
  background: var(--accent); }
.spec-list--wide { grid-template-columns: repeat(3, minmax(0,1fr)); margin-top: var(--space-6); }
/* ⚠ Dentro una sezione AFFIANCATA la colonna è larga la metà: tre tracce ci stanno solo spezzando le
   voci una parola per riga, e con voci di altezza diversa le righe della griglia si sfalsano. Lì
   l'elenco resta a UNA colonna, che è anche l'unico modo di leggerlo. */
.split .spec-list, .split .spec-list--wide { grid-template-columns: 1fr; gap: var(--space-2); }
.spec-list { align-items: start; }
.section--light .spec-list li::before { background: var(--accent-ink); }
@media (max-width: 900px) { .spec-list--wide { grid-template-columns: repeat(2, minmax(0,1fr)); } }
@media (max-width: 640px) { .spec-list, .spec-list--wide { grid-template-columns: 1fr; } }

/* ============ BOTTONI ============
   ⚠⚠ Il rosso NON porta il bianco (4,39). Il bottone d'accento porta TESTO NERO (4,79). */
.btn { display: inline-block; font: 600 var(--text-base)/1 var(--font-body);
  padding: 1.05em 1.9em; border: var(--border) solid transparent; border-radius: var(--radius);
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease), border-color var(--dur) var(--ease); }
.btn--accent { background: var(--accent); color: #000; }
.btn--accent:hover { background: #EF5346; }
.btn--ghost { border-color: currentColor; background: none; color: inherit; }
.btn--ghost:hover { background: var(--ink); color: var(--paper); }
.section--light .btn--ghost:hover { background: var(--ink-on-light); color: var(--sage); }
/* Il link in uscita si dichiara: lo shop del cliente vive su un altro dominio. */
.btn--ext::after, .link-ext::after { content: " \2197"; }

/* ============ TESTATA ============ */
.site-header { position: sticky; top: 0; z-index: 50; background: var(--brand-dark);
  border-bottom: var(--border) solid var(--line); }
/* ⚠ Regola 16: nav e CTA hanno un margine di blocco WP che li spinge sotto il centro. */
.site-header__row { padding-block: var(--space-3); gap: clamp(1rem, 2.5vw, 2.5rem); }
.site-header__row > * { align-self: center; margin-block: 0; }
.wordmark { display: inline-flex; align-items: center; }
.wordmark__mark { height: 46px; width: auto; }
.wordmark__name { font: 800 var(--text-lg)/1 var(--font-display); color: var(--ink); letter-spacing: -.02em; }
.site-header__cta { margin-left: var(--space-4); padding: .62em 1.2em; font-size: var(--text-sm); }
.site-header__tel { font: 500 var(--text-sm)/1 var(--font-mono); color: var(--ink-muted); white-space: nowrap; }
.site-header__tel:hover { color: var(--ink); }
@media (max-width: 1180px) { .site-header__tel { display: none; } }
/* ⚠ Sotto il breakpoint dell'overlay la testata porta SOLO marchio e hamburger: i recapiti vivono già
   nella barra CTA fissa in fondo (Chiama · WhatsApp · Preventivo), e ripeterli in alto toglie spazio
   all'unica cosa che deve restare raggiungibile con il pollice. L'hamburger va TUTTO a destra. */
@media (max-width: 1080px) {
  .site-header__cta { display: none; }
  .site-nav .wp-block-navigation__responsive-container-open { margin-left: auto; }
}

/* Nav: blocco wp:navigation con overlayMenu:mobile.
   ⚠⚠ Il colore delle voci si dichiara sul BLOCCO (`.wp-block-navigation`), non solo su `.site-nav a`:
   il CSS di WP-core colora le voci a PARI specificità e, dichiarato dopo, vince — è il difetto
   «menu grafite su grafite» già pagato, e su un terreno nero sarebbe nero-su-nero. */
.site-nav, .site-nav.wp-block-navigation { color: var(--ink); font: 600 var(--text-sm)/1 var(--font-body); }
.site-nav .wp-block-navigation-item__content { color: var(--ink); padding-block: var(--space-2);
  border-bottom: 2px solid transparent; }
.site-nav .wp-block-navigation-item__content:hover,
.site-nav .wp-block-navigation-item.current-menu-item > .wp-block-navigation-item__content {
  color: var(--ink); border-bottom-color: var(--accent); }

/* Overlay mobile.
   ⚠⚠ MISURATO SUL SITO SERVITO, non dedotto: WordPress veste l'overlay con
     `.wp-block-navigation:not(.has-background) .wp-block-navigation__responsive-container.is-menu-open:not(.disable-default-overlay)`
   che pesa (0,5,0) e impone `background-color:#fff` + `color:#000`. Una regola scritta come
   `.site-nav .wp-block-navigation__responsive-container.is-menu-open` pesa (0,3,0) e PERDE: su un sito dal
   terreno nero il menu si apriva BIANCO, leggibile ma di un altro sito. Si pareggia il peso ricalcando la
   forma di WP e aggiungendo la nostra classe — (0,6,0). Il gate del verticale presidia questo numero.
   ⚠ L'altezza si dichiara comunque: con una testata filtrata (backdrop-filter) il `fixed` si ancora alla
   testata e l'overlay resterebbe alto quanto lei. */
.wp-block-navigation.site-nav:not(.has-background) .wp-block-navigation__responsive-container.is-menu-open:not(.disable-default-overlay),
.site-nav .wp-block-navigation__responsive-container.is-menu-open {
  background-color: var(--paper); color: var(--ink);
  height: 100vh; max-height: 100vh; overflow-y: auto; -webkit-overflow-scrolling: touch;
  /* ⚠ Il padding orizzontale è lo STESSO gutter del resto del sito: con un valore diverso le voci
     partivano da un margine che non esiste altrove e il menu sembrava disallineato. In alto lascia
     posto alla X, in basso alla cta-bar fissa. */
  padding: 5rem var(--gutter) 7rem;
  justify-content: flex-start;
}
/* Le voci ereditano il colore del contenitore (`color:inherit` di WP): basta che il contenitore sia giusto. */
.wp-block-navigation.site-nav:not(.has-text-color) .wp-block-navigation__responsive-container.is-menu-open:not(.disable-default-overlay) .wp-block-navigation-item__content { color: var(--ink); }
.site-nav .is-menu-open .wp-block-navigation__responsive-container-content { width: 100%; }
.site-nav .is-menu-open .wp-block-navigation-item { width: 100%; }
.site-nav .is-menu-open .wp-block-navigation-item__content {
  width: 100%; text-align: left; font: 800 var(--text-lg)/1.25 var(--font-display);
  padding-block: var(--space-4); border-bottom: var(--border) solid var(--line); }
/* La X sta sulla stessa colonna delle voci: allineata al gutter, non al bordo dello schermo. */
.site-nav .wp-block-navigation__responsive-container-close { top: var(--space-5); right: var(--gutter); }
.site-nav .is-menu-open .wp-block-navigation__container { gap: 0; width: 100%; }
/* I sotto-menu vanno INLINE: il default WP li rende come tendine desktop, illeggibili su telefono. */
.site-nav .is-menu-open .wp-block-navigation__submenu-container {
  position: static !important; background: none !important; border: 0 !important; box-shadow: none !important;
  padding-left: var(--space-5); width: 100%; }
/* ⚠ I due bottoni dell'overlay nascono da WP SENZA misura: la X esce minuscola e incollata all'angolo,
   sotto il bersaglio di tocco minimo. Misura e area si dichiarano qui, non si ereditano. */
/* ⚠⚠ NIENTE `display` qui: la VISIBILITÀ del pulsante la governa WordPress (lo mostra sotto il breakpoint
   dell'overlay e lo nasconde sopra). Dichiarando `display:grid` lo si rende visibile a OGNI larghezza, e a
   1440px comparivano insieme l'hamburger E la nav, su due righe. Qui si dà solo la MISURA (il bersaglio di
   tocco, che WP non dichiara); il centraggio del glifo lo fa il margine automatico. */
.site-nav .wp-block-navigation__responsive-container-open,
.site-nav .wp-block-navigation__responsive-container-close {
  color: var(--ink); width: 48px; height: 48px; padding: var(--space-3);
}
.site-nav .wp-block-navigation__responsive-container-close { top: var(--space-4); right: var(--gutter); }
.site-nav .wp-block-navigation__responsive-container-open svg,
.site-nav .wp-block-navigation__responsive-container-close svg { width: 24px; height: 24px; fill: currentColor; margin: auto; }

/* ============ HERO ============ */
.hero { position: relative; isolation: isolate; min-height: min(86vh, 760px);
  display: flex; align-items: flex-end; overflow: hidden; background: var(--paper); }
.hero__inner { padding-block: clamp(3rem, 7vw, 6rem); }
.hero h1 { margin-bottom: var(--space-4); max-width: 20ch; }
.hero .lead { color: #E6E6E6; font-size: var(--text-lg); max-width: 46ch; }
.hero__cta { display: flex; flex-wrap: wrap; gap: var(--space-3); margin-top: var(--space-6); }
.hero__sub { font: 500 var(--text-sm)/1.5 var(--font-mono); letter-spacing: .13em; text-transform: uppercase;
  color: var(--ink-muted); margin-top: var(--space-6); max-width: 52ch; }
/* ⚠⚠ L'occhiello dell'hero è una TARGA OPACA, non testo colorato: misurato dal pixel, l'accento come
   testo sopra la foto scendeva a 2,40 anche con lo scrim. Opaco fa 4,79 qualunque sia la foto dietro. */
.hero .eyebrow { display: inline-block; background: var(--accent); color: #000;
  padding: .5em .9em; margin-bottom: var(--space-5); }
/* Variante DESIGN (nessuna foto hero-grade): campitura piena, nessun velo da misurare. */
.hero--design { background: var(--brand-dark); }
.hero--design::before { content: ""; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(140deg, #000 0%, #131313 100%); }
/* Variante FOTO: slideshow in dissolvenza dietro uno scrim direzionale. */
.hero__media { position: absolute; inset: 0; z-index: -2; }
/* ⚠ Le slide sono <img>, non background-image: solo un `src` con il path relativo COMPLETO
   `../assets/img/works/<id>.jpg` diventa un handle media. Un fondo CSS resterebbe non risolto. */
.hero__slide { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; opacity: 0; }
.hero__slide:first-child { opacity: 1; }
/* ⚠⚠ Lo scrim è tarato sulla COLONNA DI TESTO, non sul bordo sinistro: il contenitore è centrato, quindi
   il buio deve arrivare oltre metà campo. Con la sfumatura precedente (buio solo a sinistra) il testo
   cadeva sopra le fiamme e il peggiore misurato era rgb(63,63,63); ora è rgb(36,36,36). */
.hero::after { content: ""; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(100deg, rgba(0,0,0,.96) 0%, rgba(0,0,0,.95) 52%, rgba(0,0,0,.86) 66%,
    rgba(0,0,0,.5) 86%, rgba(0,0,0,.34) 100%); }
@media (prefers-reduced-motion: no-preference) {
  .hero__slide { animation: fp-hero-fade 27s infinite; }
  .hero__slide:nth-child(1) { animation-delay: 0s; }
  .hero__slide:nth-child(2) { animation-delay: 9s; }
  .hero__slide:nth-child(3) { animation-delay: 18s; }
  @keyframes fp-hero-fade { 0%{opacity:0} 3%{opacity:1} 30%{opacity:1} 36%{opacity:0} 100%{opacity:0} }
}

/* ============ CATEGORIE (device: riga numerata del riferimento) ============ */
.cats { display: grid; grid-template-columns: repeat(4, 1fr); border-top: var(--border) solid var(--line);
  background: var(--paper); }
.cat { padding: var(--space-7) clamp(1rem,2vw,2rem) var(--space-8);
  border-right: var(--border) solid var(--line); border-bottom: var(--border) solid var(--line);
  display: block; transition: background var(--dur) var(--ease); }
.cat:first-child { border-left: var(--border) solid var(--line); }
.cat:hover { background: var(--surface); }
.cat__n { font: 500 var(--text-sm)/1 var(--font-mono); color: var(--accent); letter-spacing: .1em; }
/* ⚠ Le icone del cliente sono raster dentro un guscio SVG (120×120) e non erediterebbero currentColor.
   Si usano come MASCHERA: la maschera prende il canale alfa, quindi il colore lo dà il background e
   l'icona diventa ricolorabile davvero. L'URL è relativo a QUESTO foglio (theme/css/ → theme/assets/).
   ⚠ Un `data-icon` senza la sua regola qui, o senza il file su disco, è un quadrato vuoto che nessun
   gate di link vedrebbe: il gate del verticale controlla la catena per intero. */
.cat__icon { width: 54px; height: 54px; margin: var(--space-5) 0; display: block;
  background-color: var(--accent);
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
  -webkit-mask-position: center; mask-position: center;
  -webkit-mask-size: contain; mask-size: contain; }
.cat__icon[data-icon="griglie"]   { -webkit-mask-image: url("../assets/img/icons/cat-griglie.svg");   mask-image: url("../assets/img/icons/cat-griglie.svg"); }
.cat__icon[data-icon="sigilli"]   { -webkit-mask-image: url("../assets/img/icons/cat-sigilli.svg");   mask-image: url("../assets/img/icons/cat-sigilli.svg"); }
.cat__icon[data-icon="porte"]     { -webkit-mask-image: url("../assets/img/icons/cat-porte.svg");     mask-image: url("../assets/img/icons/cat-porte.svg"); }
.cat__icon[data-icon="sportelli"] { -webkit-mask-image: url("../assets/img/icons/cat-sportelli.svg"); mask-image: url("../assets/img/icons/cat-sportelli.svg"); }
.cat h3 { margin-bottom: var(--space-3); }
.cat p { color: var(--ink-muted); font-size: var(--text-base); }
.cat__go { display: inline-block; margin-top: var(--space-5); font: 600 var(--text-sm)/1 var(--font-body);
  color: var(--accent); }
.cat:hover .cat__go { color: #EF5346; }
@media (max-width: 900px) { .cats { grid-template-columns: repeat(2, 1fr); }
  .cat:nth-child(odd) { border-left: var(--border) solid var(--line); } }
@media (max-width: 560px) { .cats { grid-template-columns: 1fr; }
  .cat { border-left: var(--border) solid var(--line); } }

/* ============ CATALOGO SU NERO ============
   Le foto si fondono col terreno: nessuna cornice, nessun fondo di tessera.
   ⭐ La cella è uniforme e l'immagine sta in `contain`: sul nero pieno il riempimento è INVISIBILE,
   quindi uno scatto verticale e uno panoramico stanno nella stessa griglia senza tagliare nulla. */
/* ⭐ DUE colonne, non tre: a 1280px di contenitore la cella passa da 382x287 a 591x443 px — il pezzo si
   legge davvero invece di essere una miniatura. Gli scatti sono stati ricomposti a monte su tela 4:3 con
   lo stesso margine, quindi `contain` non deve piu' compensare nulla: tutti rendono alla STESSA scala. */
.catalogo__grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--grid-gap); margin-top: var(--space-7); }
.catalogo__grid figure { margin: 0; }
.catalogo__grid img { width: 100%; aspect-ratio: var(--tile-ratio); object-fit: contain; background: var(--paper); }
.catalogo__grid figcaption { font: 500 var(--text-sm)/1.5 var(--font-mono); color: var(--ink-muted);
  letter-spacing: .06em; margin-top: var(--space-3); border-top: var(--border) solid var(--line);
  padding-top: var(--space-3); }
@media (max-width: 520px) { .catalogo__grid { grid-template-columns: 1fr; } }

/* Foto apribile: il gancio e' `a.zoom`, che reveal.js riconosce da solo. L'ancora deve diventare un
   blocco, sennó la riga di testo che la contiene le lascia sotto lo spazio del discendente. */
a.zoom { display: block; cursor: zoom-in; }
a.zoom:focus-visible { outline: 2px solid var(--focus); outline-offset: 3px; }

/* ============ SPLIT EDITORIALE (azienda) ============ */
.split { display: grid; grid-template-columns: 1.05fr .95fr; gap: clamp(2rem, 5vw, 5rem); align-items: center; }
/* ⚠⚠ SOVRASCANSIONE per la parallasse. reveal.js sposta l'immagine di `data-parallax`% della PROPRIA
   altezza, e il fattore arriva a |1,15| (non a 1: difetto già pagato dalla flotta). Con ampiezza 5 lo
   spostamento massimo è 5,75% dell'immagine; l'immagine è alta il 118% del riquadro e parte da -9%,
   quindi resta sempre almeno il 3% di margine su entrambi i lati e il fondo non si scopre mai.
   `clip` e non `hidden`: hidden creerebbe un contenitore di scorrimento. */
.split__media { overflow: clip; height: clamp(280px, 34vw, 440px); }
/* ⚠⚠ Lo scarto si dà con `top`, MAI con `margin-top`: un margine in percentuale si risolve sulla
   LARGHEZZA del blocco contenitore, non sull'altezza. Con `margin-top:-9%` lo scarto valeva 9% di 584px
   mentre l'eccedenza era il 18% di 440px: misurato dal vivo, la parallasse scopriva il fondo di 4-9px.
   Con `top` la percentuale è sull'altezza e i due margini sono davvero il 9% per lato. */
.split__media a.zoom { display: block; position: relative; height: 100%; overflow: clip; }
.split__media img { position: absolute; left: 0; top: -9%; width: 100%; height: 118%; object-fit: cover; }
/* Sul nero il `contain` non si taglia e non si muove: il pezzo deve restare intero e centrato. */
.split__media--contain { height: auto; }
.split__media--contain a.zoom { height: auto; }
.split__media--contain img { position: static; height: clamp(280px, 34vw, 440px); object-fit: contain; background: var(--paper); }
.split .btn { margin-top: var(--space-5); }
/* Colonne invertite: la foto a SINISTRA. Si alterna di sezione in sezione, sennò la pagina ha un solo
   bordo vivo e l'occhio scende sempre dallo stesso lato. ⚠ Si inverte l'ORDINE, non la direzione della
   griglia: con `direction:rtl` si ribalterebbe anche il testo. */
.split--flip .prose { order: 2; }
.split--flip .split__media { order: 1; }
@media (max-width: 900px) {
  .split { grid-template-columns: 1fr; }
  /* Su una colonna la foto torna SOTTO il testo in entrambe le varianti: impilata sopra, l'utente
     scorrerebbe un'immagine prima di sapere di che sezione si tratta. */
  .split--flip .prose { order: 1; }
  .split--flip .split__media { order: 2; }
}

/* ============ IN EVIDENZA ============
   ⚠ Gli scatti dei più venduti sono SCONTORNATI SU BIANCO: stanno sulla carta chiara, in `contain`.
   Sul terreno nero disegnerebbero un riquadro bianco; `cover` li decapiterebbe. */
.evidenza__grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--border);
  background: var(--sage-tint); border: var(--border) solid var(--sage-tint); margin-top: var(--space-7); }
.evidenza__it { background: var(--sage-light); padding: var(--space-6) var(--space-5) var(--space-6); text-align: center; }
.evidenza__it img { height: clamp(200px, 18vw, 280px); width: 100%; object-fit: contain; margin-bottom: var(--space-4); }
.evidenza__it h3 { font-size: var(--text-base); color: var(--ink-on-light); }
.evidenza__meta { font: 500 var(--text-sm)/1 var(--font-mono); color: var(--ink-muted-on-light);
  letter-spacing: .1em; display: block; margin-top: var(--space-2); }
@media (max-width: 820px) { .evidenza__grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 520px) { .evidenza__grid { grid-template-columns: 1fr; } }

/* ============ SERVIZI ============ */
.servizi__grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(1.5rem,3vw,3rem); margin-top: var(--space-7); }
.servizi__it { border-top: 2px solid var(--accent); padding-top: var(--space-5); }
.servizi__it h3 { margin-bottom: var(--space-3); }
.servizi__it p { color: var(--ink-muted); font-size: var(--text-base); }
@media (max-width: 820px) { .servizi__grid { grid-template-columns: 1fr; } }

/* ============ FASCIA SHOP (link in uscita) ============
   ⚠ Il paragrafo è NERO, non un near-black caldo: #1a0f0d sul rosso faceva 4,28. */
/* ⚠⚠ Il testo qui è NERO su accento (4,79). La sfumatura può solo SCHIARIRE: `--accent-dark` è tarato
   per portare il BIANCO, e il nero sopra fa 3,40 — una banda che scivolasse verso lo scuro romperebbe
   il testo pur restando "in palette". Un velo bianco alza il fondo, e il nero sopra guadagna contrasto. */
.shopband { background-color: var(--accent); color: #000;
  background-image: linear-gradient(102deg, rgba(255,255,255,0) 0%, rgba(255,255,255,.12) 100%); }
.shopband .container { display: flex; flex-wrap: wrap; gap: var(--space-6); align-items: center;
  justify-content: space-between; padding-block: clamp(2.6rem, 5vw, 4rem); }
.shopband h2 { max-width: 22ch; }
.shopband p { margin-top: var(--space-3); max-width: 48ch; font-size: var(--text-base); color: #000; }
.shopband .btn { background: #000; color: var(--accent); border-color: #000; }
.shopband .btn:hover { background: #1a1a1a; }

/* ============ RECENSIONI ============ */
.recensioni__grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(1.2rem,2.5vw,2.2rem);
  margin-top: var(--space-7); }
.rev { border: var(--border) solid var(--line); padding: var(--space-6) var(--space-5); }
.rev__stars { color: var(--accent); letter-spacing: .14em; }
.rev__q { font-size: var(--text-md); margin: var(--space-3) 0 var(--space-4); }
.rev__by { font: 500 var(--text-sm)/1.4 var(--font-mono); color: var(--ink-muted);
  letter-spacing: .06em; text-transform: uppercase; }
@media (max-width: 820px) { .recensioni__grid { grid-template-columns: 1fr; } }

/* ============ FAQ ============
   Tendina NATIVA (<details>): la CSP vieta il JS inline sui progetti reali. Funziona a JS spento. */
.faq__list { margin-top: var(--space-6); border-top: var(--border) solid var(--sage-tint); }
.faq__item { border-bottom: var(--border) solid var(--sage-tint); }
.faq__item > summary { cursor: pointer; list-style: none; position: relative;
  padding: var(--space-5) var(--space-8) var(--space-5) 0;
  font: 600 var(--text-md)/1.45 var(--font-body); color: var(--ink-on-light); }
.faq__item > summary::-webkit-details-marker { display: none; }
.faq__item > summary::after { content: "+"; position: absolute; right: var(--space-2); top: var(--space-4);
  font: 400 1.7rem/1 var(--font-display); color: var(--accent-ink); }
.faq__item[open] > summary::after { content: "\2013"; }
.faq__item > p { margin-bottom: var(--space-5); color: var(--ink-muted-on-light); max-width: 78ch; }

/* ============ BANDA CONTATTI ============ */
.contact-band { border-top: var(--border) solid var(--line); border-bottom: var(--border) solid var(--line);
  background-color: var(--paper);
  /* Un alone d'accento sul fianco destro: è la banda che chiede di essere chiamata, e l'occhio ci finisce
     sopra. Al 12% resta un'ombra calda, non una campitura colorata. */
  background-image: radial-gradient(70% 200% at 100% 50%, rgba(221,61,49,.12), transparent 62%); }
.contact-band .container { display: flex; flex-wrap: wrap; gap: var(--space-6); align-items: center;
  justify-content: space-between; padding-block: clamp(2.4rem,4.5vw,3.6rem); }
.contact-band p { margin: 0; max-width: 60ch; font-size: var(--text-md); }

/* ============ TESTATA DI PAGINA ============
   ⚠ Regola 6: la page-head NON riusa la size dell'hero, sennò occupa mezza schermata.

   ⭐ IL SEGNO: la luce che filtra da un grigliato. Il fianco destro non resta vuoto e NON chiede una
   fotografia — il materiale è finito, e riusare uno scatto del corpo lo toglierebbe da dove serve.
   Al suo posto due strati, entrambi di puro CSS: un'ALBA che dal nero si schiarisce verso destra (rosso
   di marca che si spegne, più un velo freddo), e le FERITOIE, filetti di 1px in diagonale che la
   tagliano. È lo stesso dispositivo su cui è costruito tutto il verticale — sul nero separano i FILETTI,
   non i fondi — ed è letteralmente ciò che il cliente produce: un pezzo forato che lascia passare la luce.
   ⚠ È DECORO: sta dietro il testo e si spegne PRIMA della colonna di testo, che resta sul nero pieno.
   Misurato dai pixel: il punto più chiaro sotto il titolo tiene il bianco a oltre 19:1. */
.page-head { position: relative; isolation: isolate; overflow: clip;
  background-color: var(--paper); border-bottom: var(--border) solid var(--line);
  padding-block: clamp(2.5rem, 5vw, 4.5rem);
  /* Le tre variabili sono l'ALFABETO: la LUCE che sale dal nero, la TRAMA di filetti, e il VELO che
     decide dove la trama nasce. Ogni pagina ne cambia i valori, non la struttura — così le testate sono
     riconoscibilmente parenti e nessuna è la fotocopia dell'altra. */
  --lift: radial-gradient(80% 190% at 104% 50%, rgba(221,61,49,.32), rgba(221,61,49,.07) 44%, transparent 70%),
          linear-gradient(100deg, transparent 46%, rgba(255,255,255,.032) 82%, rgba(255,255,255,.07) 100%);
  --trama: repeating-linear-gradient(101deg, rgba(255,255,255,.10) 0 1px, transparent 1px 22px);
  --velo: linear-gradient(97deg, transparent 40%, #000 96%);
  background-image: var(--lift); }
.page-head > * { position: relative; z-index: 1; }
.page-head h1 { font-size: var(--text-2xl); }
.page-head p { color: var(--ink-muted); margin-top: var(--space-4); }
/* ⭐ La colonna della testata si LIMITA. Non è una misura di lettura di comodo: è ciò che rende la
   promessa «la trama non tocca mai il testo» strutturale invece che fortunata. Con il testo a tutta
   larghezza la garanzia dipendeva dalla lunghezza della frase — una frase più lunga, su una pagina
   futura, sarebbe finita sopra i filetti senza che nessuno se ne accorgesse. Qui c'è qualcosa di fianco
   (la trama), quindi la colonna è giusto che sia incolonnata: è la stessa regola delle sezioni affiancate. */
.page-head h1, .page-head p { max-width: 58%; }
@media (max-width: 760px) { .page-head h1, .page-head p { max-width: none; } }
/* ⚠ Il velo spegne SEMPRE la trama prima della colonna di testo: il titolo resta su nero pieno, qualunque
   sia la variante. È il vincolo che rende la decorazione gratuita in termini di leggibilità. */
.page-head::after { content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background: var(--trama); -webkit-mask: var(--velo); mask: var(--velo); }

/* ── LE SEI VARIANTI ─────────────────────────────────────────────────────────────────────────────
   Ognuna è il DISEGNO di ciò che la pagina vende, ridotto a filetti: feritoie, maglia, raggiera,
   cordolo. Non è ornamento generico — è il pezzo, ridotto a segno. */

/* GRIGLIE (base, nessun modificatore): l'alba calda a destra e le FERITOIE in diagonale. */

/* SIGILLI PORTA PAVIMENTO: la MAGLIA ortogonale, cioè un chiusino visto dall'alto. Il velo è radiale,
   così la maglia esiste solo nell'angolo e sfuma in ogni direzione. */
.page-head--maglia {
  --lift: radial-gradient(70% 160% at 100% 30%, rgba(221,61,49,.24), transparent 62%),
          linear-gradient(255deg, rgba(255,255,255,.075) 0%, transparent 55%);
  --trama: repeating-linear-gradient(0deg, rgba(255,255,255,.115) 0 1px, transparent 1px 26px),
           repeating-linear-gradient(90deg, rgba(255,255,255,.115) 0 1px, transparent 1px 26px);
  /* ⚠ Il velo radiale era largo l'86% e la maglia arrivava sotto la riga di sommario: misurato dai
     pixel, il grigio di servizio scendeva a 3,71. Ristretto al 44%, la maglia nasce oltre il 62% della
     banda — cioè dopo dove il testo finisce — e il sommario risale a oltre 5. */
  --velo: radial-gradient(40% 160% at 108% 50%, #000 20%, transparent 96%);
}
/* PORTE, SPORTELLI E CASSETTE: la RAGGIERA, il ventaglio di razze del chiusino a raggi, aperto dal
   fianco destro. Il conico ripetuto disegna le razze senza un solo file. */
.page-head--raggiera {
  --lift: radial-gradient(60% 200% at 96% 100%, rgba(221,61,49,.28), transparent 66%),
          linear-gradient(80deg, transparent 50%, rgba(255,255,255,.055) 100%);
  --trama: repeating-conic-gradient(from -20deg at 108% 50%, rgba(255,255,255,.11) 0 .55deg, transparent .55deg 5deg);
  --velo: linear-gradient(92deg, transparent 44%, #000 100%);
}
/* CONTATTI: il CORDOLO, le fasce orizzontali di una sezione di canale, con il calore in basso a destra
   — dove sta il pulsante che si vuole far premere. */
.page-head--cordolo {
  --lift: linear-gradient(180deg, rgba(255,255,255,.05) 0%, transparent 58%),
          radial-gradient(90% 130% at 100% 100%, rgba(221,61,49,.26), transparent 64%);
  --trama: repeating-linear-gradient(180deg, rgba(255,255,255,.115) 0 2px, transparent 2px 14px);
  --velo: linear-gradient(102deg, transparent 47%, #000 97%);
}
/* PRIVACY: il FOGLIO. La più silenziosa di tutte — un testo di legge non chiede di essere guardato. */
.page-head--foglio {
  --lift: linear-gradient(115deg, transparent 40%, rgba(255,255,255,.05) 100%);
  --trama: repeating-linear-gradient(101deg, rgba(255,255,255,.075) 0 1px, transparent 1px 40px);
  --velo: linear-gradient(97deg, transparent 46%, #000 100%);
}
/* CATALOGHI: la SCALA del disegno tecnico, tacche fitte e tacche lunghe. ⚠ Si aggancia al TAG e non a un
   modificatore: quella pagina la genera `apply/build-downloads.mjs`, che è di flotta e serve tutti i
   verticali — l'unica cosa che la distingue senza toccarlo è che la sua testata è un <header>, mentre
   tutte le altre sono <section>. */
header.page-head {
  --lift: radial-gradient(75% 170% at 102% 40%, rgba(221,61,49,.22), transparent 68%),
          linear-gradient(90deg, transparent 55%, rgba(255,255,255,.055) 100%);
  --trama: repeating-linear-gradient(90deg, rgba(255,255,255,.13) 0 1px, transparent 1px 12px,
           rgba(255,255,255,.07) 12px 13px, transparent 13px 36px);
  --velo: linear-gradient(97deg, transparent 42%, #000 96%);
}

/* Sotto i 760px la colonna di testo occupa tutto: qualunque trama finirebbe DIETRO il titolo invece che
   di fianco. Il velo si stringe all'angolo per TUTTE le varianti insieme, e la trama si attenua. */
@media (max-width: 760px) {
  .page-head { --velo: radial-gradient(70% 90% at 100% 100%, #000 0%, transparent 78%); }
  .page-head::after { opacity: .55; }
}

/* ============ PIÈ ============ */
.site-footer { background-color: var(--sage); color: var(--ink-on-light); padding-top: clamp(3rem,6vw,4.5rem);
  background-image: linear-gradient(180deg, var(--sage-tint) 0%, var(--sage) 14%); }
.site-footer__grid { display: grid; grid-template-columns: 1.1fr 1fr 1fr 1fr; gap: clamp(1.5rem,3vw,3rem); }
/* ⚠ Un titoletto che segue un blocco deve STACCARE: senza margine superiore «PAGINE» si incollava
   all'ultima riga dei pagamenti e sembrava parte di quell'elenco. */
.site-footer h4 { font: 600 var(--text-sm)/1.4 var(--font-mono); letter-spacing: var(--tracking-label);
  text-transform: uppercase; color: var(--ink-muted-on-light); margin-bottom: var(--space-4); }
.site-footer__col > * + h4 { margin-top: var(--space-6); }
.site-footer__logo { height: 64px; width: auto; margin-bottom: var(--space-4); }
/* ⚠ Il telefono a --text-xl (fino a 2,15rem) andava a capo dentro la colonna del piè: la misura si prende
   nel contenitore REALE, non a schermo pieno. Sceso di un gradino e tenuto su una riga. */
.site-footer__tel { font: 800 clamp(1.15rem, 1rem + .5vw, 1.45rem)/1.15 var(--font-display);
  color: var(--ink-on-light); display: block; white-space: nowrap;
  padding-block: .25rem;   /* bersaglio di tocco: col corpo ridotto la riga scendeva a 21px */ }
.site-footer__tel:hover { color: var(--accent-ink); }
.site-footer p, .site-footer li { font-size: var(--text-base); color: var(--ink-muted-on-light); }
.site-footer li { margin-bottom: var(--space-2); }
/* ⚠ Regola 23: `.site-footer__links a` (0,1,1) pareggia con `.site-footer a` dichiarata DOPO e perde.
   Si qualifica con il contenitore. */
/* ⚠ Bersaglio di tocco: i link del piè sono righe di elenco alte ~20px, sotto i 24 minimi di WCAG 2.2
   (l'esenzione vale per i link IN LINEA nel testo, non per una lista di link). Il padding verticale li
   porta a 28px senza cambiare la spaziatura percepita. */
.site-footer .site-footer__links a { color: var(--ink-muted-on-light); display: inline-block; padding-block: .25rem; }
/* ⚠ Qui si dà SOLO il padding del bersaglio di tocco: cambiare anche il `display` scavalcherebbe il
   flex di `.dgitaly` (0,2,0 batte 0,1,0) e «Powered by» andrebbe a capo separandosi dal marchio.
   È successo: la correzione dei bersagli aveva rotto il piè. */
.site-footer .badges a, .site-footer__legal > a:not(.dgitaly) { display: inline-block; padding-block: .25rem; }
.site-footer .dgitaly { padding-block: .25rem; }
.site-footer .site-footer__links a:hover { color: var(--accent-ink); text-decoration: underline; }
.hours-list li { display: flex; gap: var(--space-4); justify-content: space-between; max-width: 22rem; }
/* Social a PULSANTE PIENO: sul sito precedente erano quattro icone a filo, grigie e minute. */
.socials { display: flex; gap: var(--space-2); margin-top: var(--space-5); }
.socials a { width: 42px; height: 42px; display: grid; place-items: center; background: var(--ink-on-light);
  color: var(--sage); border-radius: 50%; transition: background var(--dur) var(--ease), transform var(--dur) var(--ease); }
.socials a:hover { background: var(--accent-ink); color: #fff; }
@media (prefers-reduced-motion: no-preference) { .socials a:hover { transform: translateY(-2px); } }
.socials svg { width: 19px; height: 19px; fill: currentColor; }
.badges { display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: center; }
.badges { gap: var(--space-3); margin-bottom: var(--space-2); }
.badges img { height: 24px; width: auto; object-fit: contain; }
.badges a { display: inline-flex; padding-block: .25rem; }
.badges a:hover img { opacity: .7; }
.paylist { display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: center; }
.paylist img { height: 22px; width: auto; object-fit: contain; background: #fff;
  padding: 4px 6px; border: var(--border) solid var(--sage-tint); }
/* ⚠ `space-between` con TRE elementi NON centra il mediano: lo mette dove capita, in funzione della
   larghezza dei laterali. Il centraggio vero vuole tre tracce, con quelle esterne uguali. */
.site-footer__legal { border-top: var(--border) solid var(--sage-tint); margin-top: clamp(2rem,4vw,3rem);
  padding-block: var(--space-4); display: grid; grid-template-columns: 1fr auto 1fr; gap: var(--space-4);
  align-items: center; font-size: var(--text-sm); color: var(--ink-muted-on-light); }
.site-footer__legal > :last-child { justify-self: end; text-align: right; }
@media (max-width: 720px) { .site-footer__legal { grid-template-columns: 1fr; text-align: center; }
  .site-footer__legal > :last-child { justify-self: center; text-align: center; } }
/* ⚠ «Powered by» e il marchio devono restare sulla stessa riga: in una traccia `auto` della griglia il
   flex andava a capo e il logo finiva sotto la scritta. */
/* ⚠ `flex`, non `inline-flex`: è figlio DIRETTO di una griglia, e un grid item viene comunque
   blockificato — `inline-flex` diventerebbe `flex` e `inline-block` diventa `block`. */
.dgitaly { display: flex; align-items: center; justify-content: center; gap: var(--space-2);
  white-space: nowrap; flex-wrap: nowrap; }
.dgitaly img { height: 20px; width: auto; }
@media (max-width: 900px) { .site-footer__grid { grid-template-columns: 1fr 1fr; } }
@media (max-width: 560px) { .site-footer__grid { grid-template-columns: 1fr; } }

/* ============ CTA-BAR MOBILE + WHATSAPP ============ */
.cta-bar { display: none; position: fixed; left: 0; right: 0; bottom: 0; z-index: 55;
  background: var(--surface); border-top: var(--border) solid var(--line); padding: var(--space-2); gap: var(--space-2); }
.cta-bar a { flex: 1; text-align: center; padding: .85em .4em; font: 600 var(--text-sm)/1 var(--font-body);
  border: var(--border) solid var(--line); color: var(--ink); }
.cta-bar a.is-accent { background: var(--accent); color: #000; border-color: var(--accent); }
.cta-bar a.is-wa { background: #0B8043; color: #fff; border-color: #0B8043; }   /* bianco su verde 5,0 */
@media (max-width: 820px) { .cta-bar { display: flex; } body { padding-bottom: 64px; } }

.wa-float { position: fixed; right: 18px; bottom: 18px; z-index: 60; width: 56px; height: 56px;
  border-radius: 50%; background: #0B8043; color: #fff; display: grid; place-items: center;
  box-shadow: var(--shadow-md); }
.wa-float svg { width: 30px; height: 30px; fill: currentColor; }
@media (max-width: 820px) { .wa-float { bottom: 76px; } }   /* non copre la cta-bar */
/* ⚠ La guardia prefers-reduced-motion NON si toglie: l'anello che pulsa è un'animazione infinita. */
@media (prefers-reduced-motion: no-preference) {
  .wa-float::before { content: ""; position: absolute; inset: 0; border-radius: 50%;
    border: 2px solid #0B8043; animation: fp-wa-pulse 2.4s ease-out infinite; }
  @keyframes fp-wa-pulse { 0%{transform:scale(1);opacity:.85} 70%{transform:scale(1.55);opacity:0} 100%{opacity:0} }
}

/* ============ MODULO CONTATTI ============ */
.contact-cols { display: grid; grid-template-columns: 1.1fr .9fr; gap: clamp(2rem,4vw,4rem); align-items: start; }
@media (max-width: 900px) { .contact-cols { grid-template-columns: 1fr; } }
.contact-form .field { display: block; margin-bottom: var(--space-4); }
.contact-form .field > span { display: block; font: 600 var(--text-sm)/1.4 var(--font-mono);
  letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--ink-muted); margin-bottom: var(--space-2); }
.contact-form input, .contact-form textarea { width: 100%; background: var(--surface-2); color: var(--ink);
  border: var(--border) solid var(--line); border-radius: var(--field-radius); padding: .85em 1em; font: inherit; }
.contact-form .row { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-4); }
@media (max-width: 640px) { .contact-form .row { grid-template-columns: 1fr; } }
/* ⚠ `.consent` è un flex: il testo va tutto in UN figlio, sennò il link interno si stacca in un flex-item. */
.consent { display: flex; gap: var(--space-3); align-items: flex-start; margin-block: var(--space-4); }
/* ⚠ La casella di consenso nasce 13×13: sotto il bersaglio minimo, e su un modulo è l'elemento che
   DEVE essere spuntato perché l'invio funzioni. */
.consent input { width: 24px; height: 24px; flex: none; margin-top: .1em; accent-color: var(--accent); }
.form-note { font-size: var(--text-sm); color: var(--ink-muted); margin-top: var(--space-3); }
.contact-info { background: var(--surface); border: var(--border) solid var(--line); padding: var(--space-6); }
.contact-info dt { font: 600 var(--text-sm)/1.4 var(--font-mono); letter-spacing: var(--tracking-label);
  text-transform: uppercase; color: var(--ink-muted); margin-top: var(--space-5); }
.contact-info dt:first-child { margin-top: 0; }
.contact-info dd { margin: var(--space-2) 0 0; }
/* Telefono ed email della scheda contatti sono bersagli di tocco, non link in linea. */
.contact-info dd > a { display: inline-block; padding-block: .25rem; }

/* ============ 404 ============ */
.notfound { padding-block: clamp(5rem,12vw,9rem); text-align: center; background: var(--paper); }
.notfound p { color: var(--ink-muted); margin-block: var(--space-4) var(--space-6); }

/* ============ MOVIMENTO ============
   Additivo e sobrio: nessuna struttura cambia, e tutto è dentro `prefers-reduced-motion: no-preference`.
   ⚠ `.reveal.is-image` non sfuma mai (un elemento trasparente può non far scaricare le immagini che
   contiene, e la dissolvenza porta il testo sotto AA mentre è in corso): lì si muove solo il transform. */
@media (prefers-reduced-motion: no-preference) {
  /* ⚠ Lo sfalsamento NON si scrive più a `nth-child`: quei selettori erano tarati su TRE colonne e sono
     diventati sbagliati appena la griglia è passata a due — una regola di movimento non deve conoscere il
     numero di colonne. L'indice lo assegna reveal.js a ogni figlio di un contenitore `.fp-stagger`
     (`--reveal-i`), e qui si legge soltanto. Vale per qualunque griglia, a qualunque larghezza. */
  .js .reveal { transition-delay: calc(var(--reveal-i, 0) * .07s); }

  /* Rivelazioni DIREZIONALI: la colonna di testo entra da sinistra, la foto affiancata da destra.
     Sul contenitore-immagine è solo transform, mai opacità. */
  .js .split .prose.reveal { transform: translateX(-18px); }
  .js .split .split__media.reveal { transform: translateX(18px); }
  .js .split .prose.reveal.is-visible, .js .split .split__media.reveal.is-visible { transform: none; }

  /* La testata respira: uno zoom lentissimo sulla slide attiva, impercettibile ma non fermo. */
  .hero__slide { animation: fp-hero-fade 27s infinite, fp-hero-zoom 27s infinite; }
  @keyframes fp-hero-zoom { 0% { transform: scale(1.06) } 36% { transform: scale(1.01) } 100% { transform: scale(1.01) } }

  /* Il pezzo si stacca dal fondo quando ci passi sopra: su fondo nero è l'unico modo di dare rilievo,
     perché un'ombra non si vedrebbe. */
  .catalogo__grid figure img, .evidenza__it img { transition: transform .45s var(--ease); }
  .catalogo__grid figure:hover img { transform: scale(1.06); }
  .evidenza__it:hover img { transform: scale(1.05); }
  .catalogo__grid figcaption { transition: color .25s var(--ease), border-color .25s var(--ease); }
  .catalogo__grid figure:hover figcaption { color: var(--ink); border-color: var(--accent); }

  /* La tessera di categoria alza il filetto d'accento e sposta la freccia. */
  .cat { transition: background var(--dur) var(--ease), box-shadow var(--dur) var(--ease); }
  .cat__go { transition: transform var(--dur) var(--ease), color var(--dur) var(--ease); display: inline-block; }
  .cat:hover .cat__go { transform: translateX(4px); }
  .cat__icon { transition: transform .35s var(--ease); }
  .cat:hover .cat__icon { transform: translateY(-3px); }

  .servizi__it { transition: border-color var(--dur) var(--ease); }
  .servizi__it:hover { border-top-color: var(--ink); }
  .btn { 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); }
  .rev { transition: border-color var(--dur) var(--ease); }
  .rev:hover { border-color: var(--accent); }
}

/* ============ LIGHTBOX ============
   ⚠⚠ Lo stato NASCOSTO non e' facoltativo: reveal.js costruisce `.fp-lb` al caricamento e la apre
   aggiungendo `.is-open`. Senza `display:none` l'overlay resta steso sopra la pagina a z-index 200 e
   INTERCETTA OGNI CLICK — il sito sembra funzionante in uno screenshot e non risponde a un dito.
   (Difetto trovato dal cliente su TONIONI: un crawl verde non lo vede, solo un click vero.) */
.fp-lb { display: none; position: fixed; inset: 0; z-index: 200; background: rgba(0, 0, 0, .93);
  align-items: center; justify-content: center; padding: clamp(1rem, 4vw, 3rem); }
.fp-lb.is-open { display: flex; }
.fp-lb__img { max-width: 92vw; max-height: 88vh; object-fit: contain;
  border: var(--border) solid var(--line); background: var(--paper); }
.fp-lb__x, .fp-lb__nav { position: absolute; width: 48px; height: 48px; border: var(--border) solid var(--line);
  background: var(--surface); color: var(--ink); display: grid; place-items: center; cursor: pointer;
  font-size: 0; padding: 0; }
.fp-lb__x { top: clamp(.75rem, 3vw, 2rem); right: clamp(.75rem, 3vw, 2rem); }
.fp-lb__x::before, .fp-lb__x::after { content: ""; position: absolute; width: 18px; height: 2px; background: currentColor; }
.fp-lb__x::before { transform: rotate(45deg); }
.fp-lb__x::after { transform: rotate(-45deg); }
.fp-lb__nav { top: 50%; transform: translateY(-50%); }
.fp-lb__nav svg { width: 24px; height: 24px; }
.fp-lb__prev { left: clamp(.5rem, 2.5vw, 2rem); }
.fp-lb__next { right: clamp(.5rem, 2.5vw, 2rem); }
@media (max-width: 560px) {
  /* Su schermo stretto le frecce laterali coprirebbero il pezzo: scendono a fondo schermo, affiancate. */
  .fp-lb__nav { top: auto; bottom: clamp(.75rem, 3vw, 2rem); transform: none; }
  .fp-lb__prev { left: calc(50% - 56px); }
  .fp-lb__next { right: calc(50% - 56px); }
}
@media (prefers-reduced-motion: no-preference) {
  .fp-lb__x, .fp-lb__nav { transition: background-color var(--dur) var(--ease), border-color var(--dur) var(--ease); }
  .fp-lb__x:hover, .fp-lb__nav:hover { background: var(--accent); border-color: var(--accent); color: #000; }
}

/* ============ PAGINA CATALOGHI ============
   ⚠ La genera `apply/build-downloads.mjs`, che è di flotta: qui si può solo VESTIRE il markup che
   produce. Due link su terreno nero erano una pagina spoglia; la carta chiara e le copertine vere dei
   PDF la rendono una vetrina. `:has()` è l'unico aggancio possibile senza toccare un file condiviso. */
.section:has(.cat-row) { background-color: var(--sage); color: var(--ink-on-light);
  background-image: linear-gradient(180deg, var(--sage-light) 0%, var(--sage) 52%); }
.section:has(.cat-row) h2 { color: var(--ink-on-light); margin-top: var(--space-7); }
.section:has(.cat-row) h2:first-child { margin-top: 0; }
.cat-row { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(400px, 100%), 1fr));
  gap: var(--grid-gap); margin-top: var(--space-5); }
/* ⚠ `.cat` è la stessa classe delle tessere di categoria, che vivono sul nero: qui va rivestita per
   intero, sennò eredita fondo e filetti sbagliati.
   La scheda è ORIZZONTALE: i PDF sono A4 in verticale, e una collezione qui porta un solo documento —
   una tessera verticale isolata resterebbe una figurina persa in mezzo alla carta. Con la copertina di
   fianco la scheda ha la proporzione di un documento appoggiato sul tavolo. */
/* ⚠ Le AREE si dichiarano: i tre figli (copertina, titolo, scarica) in una griglia a due colonne
   finivano per collocamento automatico in caselle sbagliate — la copertina non arrivava a fondo scheda e
   il «Scarica» scivolava sotto l'immagine invece che sotto il titolo. */
.cat-row .cat { display: grid; grid-template-columns: 152px 1fr; grid-template-rows: 1fr auto auto 1fr;
  /* ⚠ `padding: 0`: la tessera di categoria (stessa classe, altro mestiere) porta un'imbottitura di 30px
     che qui staccava la copertina dai bordi e la lasciava sospesa in mezzo al bianco. */
  padding: 0; min-height: 196px; background: var(--sage-light); border: var(--border) solid var(--sage-tint);
  color: var(--ink-on-light); text-decoration: none; }
.cat-row .cat__media { grid-area: 1 / 1 / 5 / 2; overflow: clip;
  border-right: var(--border) solid var(--sage-tint); background: var(--sage-light); }
.cat-row .cat__media img { display: block; width: 100%; height: 100%; object-fit: cover; object-position: top center; }
.cat-row .cat__name { grid-area: 2 / 2 / 3 / 3; font: 700 var(--text-md)/1.25 var(--font-display);
  letter-spacing: var(--tracking-display); padding: 0 var(--space-5); }
.cat-row .cat__dl { grid-area: 3 / 2 / 4 / 3; font: 600 var(--text-sm)/1 var(--font-body);
  color: var(--accent-ink); padding: var(--space-3) var(--space-5) 0; }
@media (max-width: 420px) { .cat-row .cat { grid-template-columns: 108px 1fr; } }
@media (prefers-reduced-motion: no-preference) {
  .cat-row .cat { transition: border-color var(--dur) var(--ease), transform var(--dur) var(--ease); }
  .cat-row .cat:hover { border-color: var(--accent-ink); transform: translateY(-3px); }
}

/* ============ SCHEDA CONTATTI SU CARTA ============
   ⚠⚠ Era `background: var(--surface)`: su terreno nero fa 1,14 di rapporto, cioè NON SI VEDE — è la
   prima proibizione scritta nei token («un pannello non si separa per campitura»), che questo pannello
   violava. Sulla carta chiara si stacca davvero, e i recapiti diventano la cosa che non puoi mancare. */
.contact-info { background: var(--sage-light); border: var(--border) solid var(--sage-tint);
  color: var(--ink-on-light); padding: var(--space-6); }
.contact-info dt { color: var(--ink-muted-on-light); }
.contact-info dd, .contact-info dd > a { color: var(--ink-on-light); }
.contact-info dd > a { text-decoration: underline; text-underline-offset: 3px; }
@media (prefers-reduced-motion: no-preference) { .contact-info dd > a { transition: color var(--dur) var(--ease); } }
.contact-info dd > a:hover { color: var(--accent-ink); }
