/* ============================================================================
   BASE — il pavimento tecnico
   ----------------------------------------------------------------------------
   Qui c'è solo quello che deve valere identico in OGNI bozza: reset,
   accessibilità, tipografia di partenza, due contenitori. Nessuna decisione
   di design: niente stili di card, di hero, di sezione.

   Il CSS del sito si scrive in `site.css`, non qui. Questo file si estende
   solo se si scopre che manca un pezzo di pavimento a tutte le bozze.
   ========================================================================= */

/* ——— Reset —————————————————————————————————————————————————————————————— */

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

* {
  margin: 0;
}

html {
  -webkit-text-size-adjust: 100%;
  /* Lo scroll fluido lo gestisce Lenis (app.js): senza questo si accavallano. */
  scroll-behavior: auto;
}

body {
  background: var(--fondo);
  color: var(--testo);
  font-family: var(--font-testo);
  font-size: var(--t-corpo);
  line-height: var(--interlinea);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

img,
picture,
video,
canvas,
svg {
  display: block;
  max-width: 100%;
  height: auto;
}

input,
button,
textarea,
select {
  font: inherit;
  color: inherit;
}

button {
  background: none;
  border: 0;
  cursor: pointer;
}

/* ——— Tipografia di partenza ————————————————————————————————————————————— */

/* Un blocco solo per i titoli: erano due, identici nel selettore, separati
   solo perché il commento sul margine è arrivato dopo.

   `margin-bottom`: `* { margin: 0 }` sopra azzera anche i titoli, e senza
   questo un h2 seguito da un paragrafo li rende visivamente incollati —
   scoperto a schermo, non è un dettaglio. In un contenitore flex/grid con
   `gap` proprio, sovrascrivi punto per punto (`h3 { margin-bottom: 0 }`), non
   è la norma.

   `font-optical-sizing`: le famiglie con asse ottico (Fraunces, Bodoni Moda,
   DM Sans, Nunito Sans) assottigliano le aste man mano che il corpo cresce —
   è il taglio da display, giusto sulla carta e spesso sbagliato a schermo,
   dove il filetto scende sotto il pixel e il titolo si legge scolorito.
   Misurato: 44 bozze su 132 usano una famiglia con questo asse, **42 non lo
   governavano affatto**, e su Nonna Tetti il claim da 88px in Bodoni 400 era
   illeggibile. `none` blocca l'asse sul taglio da testo, che ha meno
   contrasto di tratto. Sulle famiglie senza asse ottico non fa nulla.
   Se per QUESTA bozza il taglio da display è quello giusto, si rimette
   `auto` in site.css: è una decisione da prendere guardando la pagina, non
   un default da subire. */
h1,
h2,
h3,
h4 {
  font-family: var(--font-titoli);
  line-height: var(--interlinea-titoli);
  letter-spacing: var(--spaziatura-titoli);
  text-wrap: balance;
  font-weight: 600;
  font-optical-sizing: none;
  margin-bottom: var(--spazio-blocco);
}

h1 { font-size: var(--t-h1); }
h2 { font-size: var(--t-h2); }
h3 { font-size: var(--t-h3); }
h4 { font-size: var(--t-h4); }

p,
li {
  text-wrap: pretty;
}

a {
  color: inherit;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.2em;
}

/* Ogni <ul>/<ol> di navigazione o struttura porta `role="list"` (i browser
   tolgono la semantica di lista quando si toglie list-style, role="list" la
   restituisce agli screen reader). Senza questo reset i pallini di default
   del browser spuntano ovunque — nell'header, nel menu mobile, in ogni
   elenco — anche dove nel design non c'è nessun elenco puntato. */
ul[role='list'],
ol[role='list'] {
  list-style: none;
  padding: 0;
}

/* ——— Accessibilità ——————————————————————————————————————————————————————
   Non negoziabile: il focus da tastiera deve restare visibile ovunque, e il
   salto al contenuto deve funzionare. Si può cambiare l'aspetto, non
   togliere. */

:focus-visible {
  outline: 2px solid var(--accento);
  outline-offset: 3px;
  border-radius: 2px;
}

.salta-al-contenuto {
  position: absolute;
  left: var(--gronda);
  top: 0;
  z-index: 999;
  padding: 0.75rem 1.25rem;
  background: var(--accento);
  color: var(--su-accento);
  transform: translateY(-120%);
  transition: transform var(--durata-breve) var(--curva);
}

.salta-al-contenuto:focus-visible {
  transform: translateY(0);
}

/* ——— Superficie scura ————————————————————————————————————————————————————
   Da mettere sulla sezione (o sul <footer>) che ha un fondo scuro. Il fondo
   lo scegli tu in site.css; questa classe si occupa di tutto ciò che ci va
   sopra, in un colpo solo.

   Perché è nel pavimento e non in ogni bozza: la sezione scura ce l'hanno
   quasi tutte, e senza un posto dove dichiararla ognuna se la reinventa. Le
   conseguenze misurate su 132 bozze:
     · 61 hanno inventato un token per l'inchiostro chiaro, con 20 nomi diversi
     · 30 hanno dovuto ripatchare `outline-color` a mano, perché l'anello di
       focus resta `--accento` — che nelle palette chiare è scuro quanto il
       fondo della sezione, cioè invisibile proprio dove serve

   `--testo-tenue` viene ri-legato qui dentro: qualunque discendente lo usi
   prende da solo la versione da fondo scuro, senza che nessuno debba
   ricordarsene. È il motivo per cui 21 bozze avevano un
   `--testo-tenue-su-scuro` scritto a mano.

   L'anello di focus NON diventa `currentColor`: su un pulsante pieno
   currentColor è `--su-accento`, e l'anello si disegna fuori dal pulsante,
   sul fondo della pagina — misurato, sarebbe cieco su 36 terne di palette su
   36. Qui si sposta solo dentro la superficie scura, dove è giusto. */
.su-scuro {
  color: var(--su-scuro);
  --testo-tenue: var(--su-scuro-tenue);
}

.su-scuro :focus-visible,
.su-scuro:focus-visible {
  outline-color: var(--su-scuro);
}

/* ——— Impianti di sezione ————————————————————————————————————————————————
   Otto strutture, nessuna estetica. Sono le primitive di layout che il BRIEF
   chiama "forme": si applicano al contenitore di una sezione e decidono **come
   sta il contenuto**, non che aspetto ha — colori, spaziature e tipografia
   restano dei token.

   Perché stanno nel pavimento e non in ogni bozza: misurato su bozze vere, un
   piano che dichiarava nove forme diverse ha prodotto `site.css` con otto
   varianti di due colonne affiancate — 60/40, 50/50, 55/45, 58/42, 1fr 1fr.
   Non per pigrizia: chi scrive una sezione apre la pagina, vede la griglia di
   quella sopra e la ricopia cambiando le percentuali, perché è l'unica
   struttura che ha sotto gli occhi. Un divieto («non fare due colonne») senza
   alternative concrete produce due colonne: quello che serve è un menu di cose
   che esistono già e hanno un nome.

   Le proporzioni sono di partenza: si sovrascrivono in `site.css` con le
   custom property, non riscrivendo la regola. */

/* Impilato con respiro costante: il default onesto. */
.u-stack > * + * {
  margin-block-start: var(--stack, var(--spazio-blocco));
}

/* Contenuto principale + spalla stretta. Sotto la soglia si impilano da soli,
   senza media query: è la larghezza a decidere, non il dispositivo. */
.u-sidebar {
  display: flex;
  flex-wrap: wrap;
  gap: var(--gap, var(--spazio-blocco));
}
.u-sidebar > :first-child {
  flex-basis: var(--spalla, 20rem);
  flex-grow: 1;
}
.u-sidebar > :last-child {
  flex-basis: 0;
  flex-grow: 999;
  min-inline-size: var(--soglia, 50%);
}

/* N elementi paritari che restano in riga finché ci stanno, poi vanno in
   colonna tutti insieme. Diverso dalla griglia: non ha colonne fisse. */
.u-switcher {
  display: flex;
  flex-wrap: wrap;
  gap: var(--gap, var(--spazio-blocco));
}
.u-switcher > * {
  flex-grow: 1;
  flex-basis: calc((var(--soglia-switcher, 30rem) - 100%) * 999);
}

/* Uno schermo intero con un elemento centrato e gli altri spinti ai bordi.
   È l'impianto delle aperture: nessuna colonna, nessuna griglia. */
.u-cover {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  min-block-size: var(--altezza, 100svh);
  padding: var(--spazio-blocco);
}
.u-cover > :where(.u-cover__centro) {
  margin-block: auto;
}

/* Un elemento sopra un altro, nello stesso spazio: testo su immagine, logo su
   fotografia, didascalia dentro la figura. */
.u-imposter {
  position: relative;
  isolation: isolate;
}
.u-imposter > :where(.u-imposter__sopra) {
  position: absolute;
  inset-block-end: var(--sotto, 0);
  inset-inline-start: var(--lato, 0);
  z-index: 1;
}

/* Proporzione fissa che ritaglia il contenuto: fotografie che devono stare
   tutte uguali senza deformarsi. */
.u-frame {
  aspect-ratio: var(--rapporto, 16 / 9);
  overflow: hidden;
}
.u-frame > img,
.u-frame > video {
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
}

/* Scorrimento orizzontale con aggancio: una galleria lunga che non allunga la
   pagina. Sotto il puntatore resta trascinabile, da tastiera resta navigabile. */
.u-reel {
  display: flex;
  gap: var(--gap, var(--spazio-blocco));
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  overscroll-behavior-inline: contain;
}
.u-reel > * {
  flex: 0 0 var(--larghezza-elemento, min(22rem, 80vw));
  scroll-snap-align: start;
}

/* Elementi di peso diverso: uno grande e gli altri piccoli, senza colonne
   fisse. Il grande dichiara `--grande` sulle sue righe e colonne. */
.u-bento {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(var(--minimo, 14rem), 1fr));
  grid-auto-rows: minmax(var(--riga, 12rem), auto);
  gap: var(--gap, var(--spazio-blocco));
}
.u-bento > .u-bento__grande {
  grid-column: span 2;
  grid-row: span 2;
}

@media (max-width: 40rem) {
  .u-bento > .u-bento__grande {
    grid-column: span 1;
    grid-row: span 1;
  }
}

/* ——— Intestazione ————————————————————————————————————————————————————————
   Il pavimento dava `<header data-sito-header>` con logo, navigazione e
   bottone del menu, e **nessuna regola per impaginarlo**. Ogni bozza doveva
   riscrivere da zero sticky, sfondo, altezza, allineamento del logo e nav
   orizzontale — e misurato su 20 bozze, **12 non l'hanno fatto**: header senza
   fondo che si confonde con la pagina scorrendo, logo a dimensione naturale
   alto mezzo schermo, voci di menu una sotto l'altra.

   Questi valori sono neutri come quelli di `tokens.css`: non decidono il
   design, garantiscono che l'intestazione non esca rotta. Si sovrascrivono in
   `site.css` — la specificità è di proposito la più bassa possibile. */
/* Sovrapposto alla prima sezione, non appoggiato sopra: `sticky` lascia il
   posto nel flusso, quindi l'apertura comincia sotto l'header e il primo
   schermo si apre con una fascia di fondo alta 4rem — la stessa "fascia vuota
   sotto l'header" che il BRIEF vieta all'apertura. `fixed` toglie l'header dal
   flusso: l'apertura parte dal bordo del viewport e l'intestazione ci galleggia
   sopra.

   Trasparente finché la pagina è in cima, con fondo e bordo appena si scorre
   (`data-scorso`, messo da app.js): sopra l'apertura l'header si fonde con
   quello che c'è dietro, sopra il resto della pagina resta leggibile. Il colore
   del testo lo decide `site.css` — su un'apertura scura serve chiaro, e qui non
   si può sapere. */
[data-sito-header] {
  position: fixed;
  inset-inline: 0;
  top: 0;
  z-index: 100;
  background: transparent;
  border-bottom: var(--bordo-spessore) solid transparent;
  transition: background-color 250ms ease, border-color 250ms ease;
}

[data-sito-header][data-scorso] {
  background: var(--fondo);
  border-bottom-color: var(--bordo);
}

/* L'header non occupa più spazio: senza questo, la prima sezione gli finisce
   sotto. Con `box-sizing: border-box` un'apertura `min-block-size: 100svh`
   resta alta uno schermo, il contenuto scende e basta. */
main > :first-child {
  padding-block-start: var(--altezza-header, 4rem);
}

[data-sito-header] > * {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--spazio-blocco);
  min-height: 4rem;
}

/* Il logo arriva a dimensione naturale: senza un tetto, un PNG da 800px alto
   occupa la prima schermata. `width:auto` tiene le proporzioni. */
[data-sito-header] img {
  height: clamp(2rem, 4vw, 3rem);
  width: auto;
}

[data-sito-header] nav ul {
  display: flex;
  align-items: center;
  gap: clamp(0.75rem, 2vw, 2rem);
}

[data-sito-header] a {
  text-decoration: none;
}

/* Il bottone del menu porta solo un testo per screen reader: senza queste tre
   righe è un pulsante invisibile, e su telefono la navigazione non esiste. */
[data-menu-toggle] {
  display: none;
  width: 2.75rem;
  height: 2.75rem;
  padding: 0;
  border: 0;
  color: inherit;
  cursor: pointer;
  /* Tre tratti disegnati dal fondo: nessun pseudo-elemento da coordinare, e il
     colore segue il testo dell'intestazione qualunque palette abbia. */
  background:
    linear-gradient(currentColor 0 0) 50% 0.9rem / 1.5rem 2px no-repeat,
    linear-gradient(currentColor 0 0) 50% 1.375rem / 1.5rem 2px no-repeat,
    linear-gradient(currentColor 0 0) 50% 1.85rem / 1.5rem 2px no-repeat;
}

@media (max-width: 48rem) {
  [data-sito-header] nav {
    display: none;
  }
  [data-menu-toggle] {
    display: block;
  }
}

/* ——— Menu mobile: chiuso finché non lo si apre ———————————————————————————
   `inert` e `aria-hidden="true"` tolgono il focus e la lettura, **non il
   rendering**: senza questa riga il pannello resta in pagina, sotto l'header,
   con i suoi link uno sotto l'altro — e su desktop si legge come un secondo
   menu attaccato al primo. È esattamente com'è uscita la bozza di La Torre di
   Merlino, ed è un difetto che non si vede nel pavimento perché lì la lista è
   vuota: compare solo quando l'agente la riempie, cioè sempre.

   Misurato: 17 bozze su 18 non hanno nessuna regola che nasconda `[data-menu]`.
   `app.js` commuta `aria-hidden` insieme a `inert`, quindi aprire il menu
   basta a mostrarlo.

   **`!important` qui è giustificato**, ed è costato una bozza per impararlo. La
   regola era a specificità 20 col commento «sovrascrivila pure se vuoi animare
   l'apertura»; una bozza ha scritto `#menu-mobile { position: fixed; inset: 0;
   display: flex }` per dare *stile allo stato aperto* — specificità 100 — e ha
   riaperto il pannello anche da chiuso: pagina intera coperta di bianco, sette
   controlli verdi, tre sessioni che avevano guardato lo screenshot senza
   vederlo (§`verificaPrimoSchermo`).

   Non è una regola di stile ma **di stato**, e vale solo mentre
   `aria-hidden="true"`: appena `app.js` apre il pannello il selettore smette di
   applicarsi, quindi non impedisce nessuna animazione d'apertura. Uno stato che
   dipende dal fatto che nessuno lo contraddica non è uno stato. */
[data-menu][aria-hidden='true'] {
  display: none !important;
}

/* ——— Icone ———————————————————————————————————————————————————————————————
   Un'icona è quasi sempre dentro un flex, accanto a un testo — un orario, un
   indirizzo, una voce di servizio — e lì un SVG senza `flex-shrink: 0` viene
   **schiacciato** dal testo che gli sta accanto: esce ovale, tagliato, o alto
   metà. È il modo più comune in cui un'icona corretta si vede sbagliata, e le
   77 icone di una bozza vera erano tutte così.

   `aspect-ratio` e la larghezza fissa reggono anche quando il contenitore
   stringe; `vertical-align` mette la linea di base dove sta il testo, invece
   che sotto. */
.icona {
  flex-shrink: 0;
  inline-size: var(--icona, 1.25em);
  block-size: var(--icona, 1.25em);
  aspect-ratio: 1;
  vertical-align: -0.15em;
}

/* L'accento come inchiostro, dalla parte giusta del contrasto (§tokens.css).
   `color: var(--accento)` su un testo è il modo in cui una palette corretta
   produce una pagina illeggibile: qui il colore c'è, ma nella variante che
   regge 4,5:1. */
.accento-testo {
  color: var(--accento-inchiostro);
}

/* Nasconde all'occhio ma non allo screen reader. */
.solo-lettori {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ——— Contenitori ————————————————————————————————————————————————————————
   Due soli, di proposito. Il resto delle griglie si scrive per questo sito. */

.u-contenitore {
  width: 100%;
  max-width: var(--larghezza-max);
  margin-inline: auto;
  padding-inline: var(--gronda);
}

.u-lettura {
  max-width: var(--larghezza-lettura);
}

/* Per una frase isolata che è metadato, non corpo del testo — "prezzi su
   richiesta", "check-in dalle 15", un disclaimer breve. Un pallino sospeso
   davanti a una frase qualunque, senza contenitore né tipografia diversa dal
   corpo, si legge come un elenco puntato lasciato a metà: scoperto a
   schermo, non è un dettaglio. Un vero chip — sfondo, raggio coerente con la
   forma assegnata, corpo più piccolo — si legge come nota di design apposta,
   non come markup dimenticato. Il pallino resta `aria-hidden`: la nota deve
   avere senso anche senza.

   Sfondo su `currentColor`, non su `--fondo-alt`: `--fondo-alt` in questo
   sistema può essere la sezione scura dell'alternanza (vedi RESPIRO in
   tokens.css), quindi non è garantito chiaro. Un colore fisso qui poteva
   uscire testo scuro su fondo scuro — successo davvero, 2,2:1 di contrasto
   invece del 4,5:1 minimo. `currentColor` eredita il colore già corretto
   della sezione che lo ospita, chiara o scura che sia: zero rischio. */
.u-nota {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.4rem 0.9rem;
  border-radius: var(--raggio-interattivo);
  background: color-mix(in srgb, currentColor 12%, transparent);
  font-size: var(--t-piccolo);
}

/* Il pallino seguiva `--accento` mentre il contenitore sopra seguiva
   `currentColor`, e la ragione scritta lì valeva identica per tutti e due:
   su una sezione scura `--accento` (scuro nelle palette chiare) sparisce nel
   fondo. Metà della regola era stata corretta, metà no. */
.u-nota::before {
  content: '';
  width: 0.4rem;
  height: 0.4rem;
  flex-shrink: 0;
  border-radius: 50%;
  background: currentColor;
}

.u-sezione {
  padding-block: var(--spazio-sezione);
}

.u-sezione--fitta {
  padding-block: calc(var(--spazio-sezione) * 0.45);
}

/* Qualunque sezione con un id (le ancore del menu) non deve atterrare sotto
   l'header sticky: --altezza-header la scrive app.js a runtime, letta
   dall'header vero di QUESTO sito. Vale sia per il click sull'ancora sia per
   un salto nativo del browser (focus da tastiera, link diretto con #hash). */
[id] {
  scroll-margin-top: var(--altezza-header, 0px);
}

/* ——— Movimento ——————————————————————————————————————————————————————————
   Stato di partenza dei reveal: nascosto SOLO se il JS è vivo e il movimento
   è consentito (`html.js-movimento`, messa da app.js). Senza questa guardia,
   un errore di sintassi nel JS lascerebbe la pagina bianca invece che
   semplicemente senza animazioni. */

.js-movimento [data-reveal]:not(.e-rivelato) {
  opacity: 0;
  transform: translateY(1.5rem);
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }

  /* Il contenuto resta visibile: senza questa riga, chi ha il movimento
     ridotto vedrebbe una pagina vuota. */
  [data-reveal] {
    opacity: 1 !important;
    transform: none !important;
  }
}

/* Lenis: obbligatorio finché app.js lo inizializza. */
html.lenis,
html.lenis body {
  height: auto;
}

.lenis.lenis-smooth {
  scroll-behavior: auto !important;
}

.lenis.lenis-stopped {
  overflow: hidden;
}
