/* Tema "mono" — ispirato al riferimento indicato dal cliente.
   Carattere monospace, nessuna decorazione, il lavoro parla da solo.

   Tutte le parti variabili sono variabili CSS: è ciò che permetterà di rendere
   il tema configurabile senza riscrivere il foglio di stile (vedi D13). */

/* La tavolozza chiara vive su :root nudo, così esiste sempre.
   Le due varianti scure ridefiniscono solo i colori:
   - la media query per chi non ha scelto (preferenza di sistema)
   - l'attributo data-theme per chi ha scelto esplicitamente, che vince */
:root {
  color-scheme: light;

  --fg: #111111;
  --bg: #ffffff;
  --muted: #8a8a8a;
  --accent: #111111;
  --placeholder: #f0f0f0;

  --font: ui-monospace, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
  --size: 12px;
  --line: 1.45;

  --columns: 3;
  --gap: 2.5rem;
  --page-pad: 1.5rem;
  --max-width: 1600px;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --fg: #ededed;
    --bg: #0c0c0c;
    --muted: #7d7d7d;
    --accent: #ededed;
    --placeholder: #1a1a1a;
  }
}

:root[data-theme="dark"] {
  color-scheme: dark;
  --fg: #ededed;
  --bg: #0c0c0c;
  --muted: #7d7d7d;
  --accent: #ededed;
  --placeholder: #1a1a1a;
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  padding: var(--page-pad);
  max-width: var(--max-width);
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font);
  font-size: var(--size);
  line-height: var(--line);
  -webkit-font-smoothing: antialiased;
}

a {
  color: inherit;
  text-decoration: none;
}

a:hover {
  text-decoration: underline;
}

/* ---------- Intestazione ---------- */

.masthead {
  margin-bottom: 3.5rem;
}

.topbar {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 2rem;
}

/* Stesso idioma dei filtri: testo, attivo sottolineato. */
.appearance {
  display: flex;
  gap: 0 0.9rem;
  flex-shrink: 0;
}

.appearance button {
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: var(--muted);
  cursor: pointer;
}

.appearance button:hover {
  color: var(--fg);
}

.appearance button[aria-pressed="true"] {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.identity {
  margin: 0 0 0.2rem;
  font-size: var(--size);
  font-weight: 400;
}

.identity .role::before {
  content: " [";
}

.identity .role::after {
  content: "]";
}

.meta {
  margin: 0 0 1.4rem;
  color: var(--muted);
}

.meta .bio {
  white-space: pre-line;
  margin: 0 0 0.4rem;
  max-width: 42em;
}

/* ---------- Filtri di categoria ---------- */

.filters {
  display: flex;
  flex-wrap: wrap;
  gap: 0 1.6rem;
}

.filters button {
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: var(--muted);
  cursor: pointer;
}

.filters button:hover {
  color: var(--fg);
}

.filters button[aria-current="true"] {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* ---------- Griglia sfalsata ---------- */

/* ⚠️ Griglia e non colonne CSS.
   `column-count` riempie **una colonna alla volta dall'alto in basso**: il
   secondo lavoro finisce sotto il primo, non accanto. Per la lettura naturale
   — da sinistra a destra, poi a capo — serve CSS Grid, che dispone per righe.

   Il prezzo è che le righe si allineano invece di sfalsarsi: gli elementi più
   bassi lasciano spazio sotto di sé. Con le descrizioni spente le altezze sono
   quasi uguali e non si nota; con quelle accese è comunque più ordinato di una
   colonna che scorre per conto suo. */
.works {
  display: grid;
  grid-template-columns: repeat(var(--columns), minmax(0, 1fr));
  gap: var(--gap);
  /* Ogni scheda parte dall'alto della propria riga, invece di stirarsi. */
  align-items: start;
}

.work {
  margin: 0;
  min-width: 0;
}

.work[hidden] {
  display: none;
}

.work-title {
  margin: 0 0 0.4rem;
  font-weight: 400;
}

.work-client,
.work-year {
  color: var(--muted);
}

.work-media {
  position: relative;
  margin: 0;
  background: var(--placeholder);
  cursor: pointer;
}

.work-media img,
.work-media iframe {
  display: block;
  width: 100%;
  height: auto;
  border: 0;
}

/* Rete di sicurezza per l'istante prima che il player dipinga: la tela che il
   browser assegna agli iframe è bianca, e in tema scuro si nota. Il parametro
   `transparent=0` risolve il caso normale, questo copre il frammento iniziale. */
.work-media iframe,
.cinema-frame iframe {
  background: #000;
}

/* L'anteprima sta SOTTO la miniatura, non al posto suo.
   Il player ci mette qualche decimo di secondo ad avviarsi: scoprirlo subito
   mostrerebbe il suo sfondo vuoto: un lampo grigio a ogni passaggio del mouse.
   L'immagine resta quindi in copertura e svanisce solo quando il video parte
   davvero (evento `play` del player), rivelando ciò che c'è già sotto. */
.work-media .work-preview {
  position: absolute;
  inset: 0;
  height: 100%;
  z-index: 0;
  /* ⚠️ Senza questo, appena la miniatura svanisce l'iframe diventa l'elemento
     in cima e si mangia i click: finirebbero dentro il player di Vimeo invece
     di arrivare alla pagina, e il video non si aprirebbe più. In modalità
     background non ha comandi, quindi non gli serve ricevere nulla. */
  pointer-events: none;
}

.work-media img {
  position: relative;
  z-index: 1;
  transition: opacity 220ms ease;
}

.work-media.preview-playing img {
  opacity: 0;
  pointer-events: none;
}

/* Chi ha chiesto meno movimento non deve nemmeno subire la dissolvenza. */
@media (prefers-reduced-motion: reduce) {
  .work-media img {
    transition: none;
  }
}

/* L'aspect ratio è noto prima che l'immagine carichi: niente sobbalzi. */
.work-media img {
  aspect-ratio: var(--ratio, 16 / 9);
  object-fit: cover;
}

.work-media iframe {
  aspect-ratio: var(--ratio, 16 / 9);
}

/* La descrizione è limitata a un numero di righe deciso dal creator.
   Il troncamento produce da solo i puntini di sospensione, che fanno da
   invito: il testo completo si apre al click. */
.work-desc {
  margin: 0.4rem 0 0;
  color: var(--muted);
  white-space: pre-line;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: var(--desc-lines, 3);
  line-clamp: var(--desc-lines, 3);
  overflow: hidden;
}

.work-desc.is-open {
  display: block;
  overflow: visible;
}

/* Aggiunta dal JavaScript solo quando il testo eccede davvero le righe:
   senza troncamento non c'è nulla da aprire. */
.work-desc.is-clamped {
  cursor: pointer;
}

.work-desc-toggle {
  display: block;
  margin-top: 0.2rem;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: var(--muted);
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}

.work-desc-toggle:hover {
  color: var(--fg);
}

/* ---------- Vista cinema ---------- */

.cinema {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 3rem 1.5rem;
  /* Fondo quasi nero a prescindere dal tema: davanti a un video si guarda il
     video, e un fondo chiaro ne falserebbe i colori. */
  background: rgba(0, 0, 0, 0.94);
}

.cinema[hidden] {
  display: none;
}

.cinema-stage {
  margin: 0;
  width: 100%;
  /* Il riquadro rispetta le proporzioni native del video e resta dentro lo
     schermo in entrambe le direzioni, senza bande né ritagli. */
  max-width: min(100%, calc((100vh - 8rem) * var(--ratio, 1.7778)));
}

.cinema-frame {
  position: relative;
  aspect-ratio: var(--ratio, 16 / 9);
  background: #000;
}

.cinema-frame iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

/* Copre il player finché i fotogrammi non arrivano: senza, su iOS si vede la
   tela bianca dell'iframe prima che il player dipinga. Mostra la stessa
   miniatura della griglia, così l'apertura è una continuazione e non uno
   stacco. Nero pieno anche se la miniatura mancasse. */
.cinema-cover {
  position: absolute;
  inset: 0;
  z-index: 1;
  background-color: #000;
  background-size: cover;
  background-position: center;
  transition: opacity 220ms ease;
  pointer-events: none;
}

.cinema-cover.is-gone {
  opacity: 0;
}

/* Velo scuro sopra la miniatura: dà contrasto all'indicatore qualunque sia il
   fotogramma sotto, e segnala che quella non è ancora la riproduzione. */
.cinema-cover::before {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.45);
}

/* Indicatore di caricamento. Compare dopo 250 ms: se il video parte subito,
   un lampo di rotella sarebbe fastidioso quanto il fermo immagine. */
.cinema-cover::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 32px;
  height: 32px;
  margin: -16px 0 0 -16px;
  border: 2px solid rgba(237, 237, 237, 0.25);
  border-top-color: rgba(237, 237, 237, 0.9);
  border-radius: 50%;
  opacity: 0;
  animation: vimolio-spin 800ms linear infinite,
    vimolio-appear 200ms ease 250ms forwards;
}

@keyframes vimolio-spin {
  to {
    transform: rotate(360deg);
  }
}

@keyframes vimolio-appear {
  to {
    opacity: 1;
  }
}

@media (prefers-reduced-motion: reduce) {
  .cinema-cover {
    transition: none;
  }

  /* Niente rotazione per chi ha chiesto meno movimento: resta una pulsazione
     lenta, che comunica "sto lavorando" senza girare. */
  .cinema-cover::after {
    animation: vimolio-pulse 1.4s ease-in-out 250ms infinite;
  }
}

@keyframes vimolio-pulse {
  0%,
  100% {
    opacity: 0.25;
  }
  50% {
    opacity: 0.9;
  }
}

/* Comandi nostri, nello stesso linguaggio del resto del tema: testo
   monospazio, nessuna decorazione. Il player sotto è senza interfaccia. */
.cinema-controls {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  margin-top: 0.6rem;
  color: #ededed;
}

.cinema-controls[hidden] {
  display: none;
}

.cinema-controls button {
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: inherit;
  cursor: pointer;
  white-space: nowrap;
}

.cinema-controls button:hover {
  opacity: 0.7;
}

.cinema-controls button {
  font-size: 1.05em;
  line-height: 1;
}

/* Larghezza fissa: play e pausa hanno glifi di larghezza diversa, e senza
   questo la barra sotto sobbalzerebbe a ogni pausa. */
.cc-play {
  min-width: 1.6em;
  text-align: center;
}

/* Audio spento: lo stesso glifo, sbarrato. Più leggibile di un secondo
   simbolo da imparare. */
.cc-mute.is-muted {
  text-decoration: line-through;
  opacity: 0.55;
}

/* La linea resta sottile ma l'area sensibile è alta: `content-box` fa sì che
   lo sfondo dipinga solo i 2px del contenuto, mentre l'imbottitura sopra e
   sotto raccoglie i tocchi. Una barra alta 2px sarebbe impossibile da
   centrare con un dito. */
.cc-track {
  flex: 1;
  box-sizing: content-box;
  height: 2px;
  padding: 9px 0;
  background: rgba(237, 237, 237, 0.3);
  background-clip: content-box;
  cursor: pointer;
}

.cc-track:focus-visible {
  outline: 1px solid #ededed;
  outline-offset: 4px;
}

.cc-fill {
  height: 100%;
  width: 0;
  background: #ededed;
}

.cc-time {
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.cinema-title {
  margin-top: 0.7rem;
  color: #ededed;
}

/* Con le icone tutti i comandi entrano anche su telefono: nulla da nascondere.
   Sugli schermi più stretti si stringono soltanto le spaziature, e il tempo
   passa a un carattere più piccolo invece di sparire. */
@media (max-width: 420px) {
  .cinema-controls {
    gap: 0.4rem;
  }

  .cc-time {
    font-size: 0.9em;
  }
}

/* ⚠️ Con un dito non si centra un glifo da 13 pixel. Dove si tocca invece di
   puntare, i comandi diventano bersagli di 44px — la misura minima indicata
   dalle linee guida Apple — con l'icona ingrandita di conseguenza.
   L'area cresce con l'imbottitura, quindi la barra resta della stessa
   altezza e la grafica non cambia. */
@media (pointer: coarse) {
  .cinema-controls button {
    min-width: 44px;
    min-height: 44px;
    font-size: 1.5em;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }

  .cc-play {
    min-width: 44px;
  }

  .cc-track {
    padding: 20px 0;
  }

  .cinema-close {
    min-width: 44px;
    min-height: 44px;
    font-size: 2rem;
    top: 0.4rem;
    right: 0.6rem;
  }

  .cinema-controls {
    gap: 0.2rem;
  }

  .cc-time {
    margin: 0 0.3rem;
  }
}

/* Su telefono i bersagli da 44px lascerebbero alla barra un centinaio di
   pixel: troppo pochi per cercare un punto nel video. Va quindi su una riga
   propria, a tutta larghezza, e i pulsanti scendono sotto. */
@media (pointer: coarse) and (max-width: 520px) {
  .cinema-controls {
    flex-wrap: wrap;
    gap: 0.2rem 0.4rem;
  }

  .cc-track {
    order: -1;
    flex-basis: 100%;
  }

  /* Spinge audio e schermo intero a destra, lasciando play e tempo a sinistra. */
  .cc-mute {
    margin-left: auto;
  }
}

/* Nella vista cinema i comandi sono tutti nostri, quindi il player non ha
   bisogno di ricevere clic — e senza questo si mangerebbe il doppio tocco
   per lo schermo intero, come già faceva con l'anteprima. */
.cinema-frame .cinema-player {
  pointer-events: none;
}

.cinema-close {
  position: absolute;
  top: 0.8rem;
  right: 1.2rem;
  padding: 0.2rem 0.5rem;
  border: 0;
  background: none;
  color: #ededed;
  font: inherit;
  font-size: 1.6rem;
  line-height: 1;
  cursor: pointer;
}

.cinema-close:hover {
  opacity: 0.7;
}

/* Con il sipario aperto la pagina sotto non deve scorrere. */
body.cinema-open {
  overflow: hidden;
}

/* ---------- Piè di pagina ---------- */

.colophon {
  margin-top: 4rem;
  color: var(--muted);
}

.colophon ul {
  margin: 0;
  padding: 0;
  list-style: none;
}

.empty {
  color: var(--muted);
}

/* ---------- Adattamento ---------- */

@media (max-width: 900px) {
  :root {
    --columns: 2;
    --gap: 1.8rem;
  }
}

@media (max-width: 600px) {
  :root {
    --columns: 1;
  }
}

