/* ==========================================================================
   PhotoGallery — foglio di stile
   Mobile-first. Fondo bianco, testo nero, filetti grigi da 1px, angoli
   morbidi: l'impianto è quello di un'applicazione di foto da telefono.
   Nessun gradiente, nessuna ombra pesante, nessun colore d'accento: il
   colore lo mettono le fotografie.
   ========================================================================== */

@font-face {
  font-family: 'Inter';
  src: url('/fonts/inter-latin.woff2') format('woff2');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Inter';
  src: url('/fonts/inter-latin-ext.woff2') format('woff2');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

:root {
  --bg: #ffffff;
  --ink: #000000;
  /* Grigio del testo secondario: abbastanza scuro da restare leggibile su
     bianco anche a 12px, dove il grigio chiaro di tante interfacce non lo è. */
  --ink-2: #6b6b6b;
  /* 4,6:1 su bianco: sopra la soglia AA per il testo piccolo. Il grigio
     precedente (#9a9a9a) stava a 2,6 ed era illeggibile in pieno sole, che e'
     esattamente la condizione in cui si usa questa applicazione. */
  --ink-3: #767676;
  --line: #dbdbdb;
  --line-soft: #efefef;
  --surface: #fafafa;
  --skeleton: #f0f0f0;

  --radius: 10px;
  --radius-sm: 8px;
  --radius-lg: 14px;

  --font: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;

  --header-h: 52px;
  /* 12px come il px-3 di officinebit.ch: margini, titolo, filtri e griglia
     partono tutti dalla stessa riga. */
  --gutter: 12px;
  /* Il margine laterale tiene conto della tacca: in orizzontale, su un
     telefono con il notch, il testo finirebbe sotto la fotocamera. */
  --gutter-l: calc(12px + var(--safe-left, 0px));
  --gutter-r: calc(12px + var(--safe-right, 0px));

  --safe-top: env(safe-area-inset-top, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
  --safe-left: env(safe-area-inset-left, 0px);
  --safe-right: env(safe-area-inset-right, 0px);

  /* Larghezza del contenuto: una colonna da telefono fino a 700px, poi tutta
     la finestra, come officinebit.ch su desktop. */
  --shell: 640px;
}

/* --------------------------------------------------------------------------
   Base
   -------------------------------------------------------------------------- */

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

html {
  -webkit-text-size-adjust: 100%;
  /* clip e non hidden: hidden crea un contenitore di scorrimento e
     spezzerebbe le intestazioni appiccicate in cima. clip taglia e basta. */
  overflow-x: clip;
}

body {
  margin: 0;
  /* Nessuno scorrimento orizzontale della pagina, mai.
     Un solo elemento un po' troppo largo — una pillola con un nome lungo, una
     riga che non va a capo — e tutta la pagina scivola di lato: le barre
     appiccicate in cima scorrono con lei e i pulsanti finiscono fuori dallo
     schermo. Chi lo subisce non vede un elemento largo: vede "Esci" sparire. */
  overflow-x: clip;
  max-width: 100%;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font);
  font-size: 16px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  /* Il grigio del tocco su Android fa sembrare rotta ogni interazione. */
  -webkit-tap-highlight-color: transparent;
  overscroll-behavior-y: none;
}

img,
video {
  max-width: 100%;
  display: block;
}

button {
  font: inherit;
  color: inherit;
  cursor: pointer;
}

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

[hidden] {
  display: none !important;
}

#app {
  max-width: var(--shell);
  margin: 0 auto;
  min-height: 100dvh;
  position: relative;
  overflow-x: clip;
}

.view {
  padding-bottom: calc(96px + var(--safe-bottom));
}

/* --------------------------------------------------------------------------
   Testo
   -------------------------------------------------------------------------- */

.brand {
  font-size: 20px;
  font-weight: 500;
  letter-spacing: normal;
  line-height: 1.2;
  margin: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.kicker {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin: 0 0 6px;
}

.lead {
  font-size: 15px;
  color: var(--ink-2);
  margin: 0 0 20px;
}

.info {
  font-size: 13px;
  color: var(--ink-2);
  margin: 12px 0 0;
}

.info a {
  color: var(--ink);
  font-weight: 600;
}

.link-inline {
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  font-weight: 600;
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* --------------------------------------------------------------------------
   Schede centrate: accesso, registrazione, ingresso, errori
   -------------------------------------------------------------------------- */

.view-gate,
.view-lock {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100dvh;
  padding: calc(var(--safe-top) + 24px) var(--gutter) calc(var(--safe-bottom) + 40px);
}

.sheet-block {
  width: 100%;
  max-width: 360px;
  text-align: center;
}

.sheet-block .brand {
  font-size: 26px;
  white-space: normal;
  margin-bottom: 8px;
}

/* Il nome dell'applicazione sulle schermate d'ingresso: è la prima cosa che
   si legge aprendo il sito, quindi è il titolo e non un'etichetta sopra al
   titolo.
   Helvetica e non Inter: è la grottesca del marchio Officine Bit, e qui
   l'applicazione si presenta. Dove Helvetica non c'è — Android, Windows —
   arriva Arial, che ha le stesse misure e a questo corpo non si distingue. */
/* Selettore con la stessa specificita' di .sheet-block .brand, che altrimenti
   vince con i suoi 26px. */
/* Il marchio: il disegno di photogallery.png, largo quanto lo era la scritta
   in Helvetica (5,45 volte il corpo), e mai piu' largo del foglio. Il PNG ha
   qualche pixel di margine attorno alle lettere, cosi' le code di p, g e y
   non vengono mai mozzate. */
.sheet-block .brand--grande {
  line-height: 0;
  overflow: visible;
}

.brand--grande .logo-img {
  display: block;
  margin: 0 auto;
  width: min(284px, calc(100vw - 48px));
  max-width: 100%;
  height: auto;
}

@media (min-width: 1000px) {
  .brand--grande .logo-img {
    width: 349px;
  }
}

/* Cosa fa l'applicazione, o cosa si sta facendo in questa schermata. Sta
   sotto al nome e prima della spiegazione. */
.claim {
  font-size: 17px;
  font-weight: 500;
  margin: 6px 0 14px;
}

.sheet-block form {
  margin-top: 20px;
  text-align: left;
}

.sheet-block .info {
  text-align: center;
}

/* --------------------------------------------------------------------------
   Campi
   -------------------------------------------------------------------------- */

.field-label {
  display: block;
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-2);
  margin: 14px 0 6px;
}

.text-input {
  width: 100%;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 12px 14px;
  font: inherit;
  font-size: 15px;
  color: var(--ink);
  outline: none;
}

.text-input::placeholder {
  color: var(--ink-3);
}

.text-input:focus {
  border-color: var(--ink);
  background: var(--bg);
}

.select-input {
  appearance: none;
  /* La freccia è disegnata qui perché quella di sistema cambia forma su ogni
     piattaforma e rompe l'allineamento con gli altri campi. */
  background-image: linear-gradient(45deg, transparent 50%, var(--ink) 50%),
    linear-gradient(135deg, var(--ink) 50%, transparent 50%);
  background-position: calc(100% - 18px) 50%, calc(100% - 13px) 50%;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
  padding-right: 38px;
}

.select-inline {
  width: auto;
  min-width: 150px;
}

.consent-row {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  margin: 16px 0 4px;
  font-size: 13px;
  color: var(--ink-2);
  line-height: 1.4;
}

.consent-row input[type='checkbox'] {
  flex: none;
  width: 18px;
  height: 18px;
  margin: 1px 0 0;
  accent-color: #000;
}

.form-message {
  font-size: 13px;
  line-height: 1.4;
  margin: 14px 0 0;
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  background: var(--surface);
  border: 1px solid var(--line);
}

.form-message--error {
  border-color: var(--ink);
  font-weight: 500;
}

.form-message--success {
  background: var(--ink);
  border-color: var(--ink);
  color: #fff;
}

/* --------------------------------------------------------------------------
   Pulsanti
   -------------------------------------------------------------------------- */

.btn,
.btn-outline,
.btn-delete {
  display: block;
  width: 100%;
  border-radius: var(--radius-sm);
  padding: 13px 18px;
  font-size: 15px;
  font-weight: 600;
  text-align: center;
  border: 1px solid transparent;
  transition: opacity 0.15s ease;
}

.btn {
  margin-top: 20px;
  background: var(--ink);
  color: #fff;
}

.btn:active {
  opacity: 0.75;
}

.btn:disabled {
  opacity: 0.3;
  cursor: default;
}

.btn-outline {
  margin-top: 12px;
  background: var(--bg);
  color: var(--ink);
  border-color: var(--line);
}

.btn-outline:active {
  background: var(--surface);
}

.btn-delete {
  margin-top: 12px;
  background: var(--bg);
  color: var(--ink);
  border-color: var(--ink);
}

/* Secondo tocco: il pulsante si riempie di nero, così è evidente che la
   prossima pressione fa sul serio. */
.btn-delete.confirming {
  background: var(--ink);
  color: #fff;
}

.btn-text {
  display: block;
  width: 100%;
  background: none;
  border: 0;
  padding: 14px;
  font-size: 15px;
  font-weight: 600;
  color: var(--ink-2);
}

.btn-scan {
  margin-top: 24px;
}

a.btn {
  text-decoration: none;
  color: #fff;
}

/* Quello che serve solo col dito o solo col mouse: sul telefono si scansiona
   il QR, su desktop si accede. */
.solo-mouse {
  display: none;
}

@media (hover: hover) and (pointer: fine) {
  .solo-tocco {
    display: none;
  }

  .solo-mouse {
    display: block;
  }
}

.icon-btn {
  flex: none;
  width: 36px;
  height: 36px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  font-size: 16px;
  line-height: 1;
  color: var(--ink);
}

.icon-btn:active {
  background: var(--surface);
}

/* --------------------------------------------------------------------------
   Barra dell'account e intestazione
   -------------------------------------------------------------------------- */

.account-bar {
  position: sticky;
  top: 0;
  z-index: 30;
  display: flex;
  align-items: center;
  gap: 14px;
  /* min-width: 0 sui figli e nessuna larghezza minima qui: il nome si accorcia
     con i puntini invece di spingere fuori il pulsante di uscita. */
  max-width: 100%;
  height: calc(var(--header-h) + var(--safe-top));
  padding: var(--safe-top) var(--gutter-r) 0 var(--gutter-l);
  background: rgba(255, 255, 255, 0.92);
  backdrop-filter: saturate(180%) blur(12px);
  border-bottom: 1px solid var(--line-soft);
  font-size: 13px;
}

.account-name {
  flex: 1;
  min-width: 0;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.feed-header {
  position: sticky;
  top: 0;
  z-index: 20;
  max-width: 100%;
  background: rgba(255, 255, 255, 0.92);
  backdrop-filter: saturate(180%) blur(12px);
  border-bottom: 1px solid var(--line-soft);
  padding: 12px var(--gutter-r) 12px var(--gutter-l);
}

/* Quando c'è la barra dell'account, l'intestazione si appoggia sotto di lei. */
.account-bar:not([hidden]) ~ .view .feed-header {
  top: calc(var(--header-h) + var(--safe-top));
}

.view-feed > .feed-header ~ *,
.view-admin > .feed-header ~ * {
  padding-left: var(--gutter);
  padding-right: var(--gutter);
}

.archived-notice {
  margin: 8px 0 0;
  padding: 8px 12px;
  border-radius: var(--radius-sm);
  background: var(--surface);
  border: 1px solid var(--line);
  font-size: 12px;
}

/* --------------------------------------------------------------------------
   Barre di voci: azioni e filtri
   -------------------------------------------------------------------------- */

.rulebar {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 10px;
  /* Senza questo, in un contenitore flex la riga prende la larghezza del suo
     contenuto invece di scorrere, e trascina fuori tutto il resto. */
  min-width: 0;
  max-width: 100%;
  /* Scorrimento orizzontale invece di andare a capo: con sei filtri, su un
     telefono stretto, l'intestazione diventerebbe alta mezzo schermo. */
  overflow-x: auto;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}

.rulebar::-webkit-scrollbar {
  display: none;
}

.rule-item {
  flex: none;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 6px 14px;
  font-size: 13px;
  font-weight: 500;
  color: var(--ink-2);
  white-space: nowrap;
}

.rule-item:active {
  background: var(--surface);
}

.rule-item.is-current {
  background: var(--ink);
  border-color: var(--ink);
  color: #fff;
  font-weight: 600;
}

.rulebar--secondary .rule-item {
  border-style: dashed;
}

/* --------------------------------------------------------------------------
   Griglia delle foto
   -------------------------------------------------------------------------- */

.photo-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 2px;
  padding-top: 4px;
}

.photo-card {
  position: relative;
  aspect-ratio: 1 / 1;
  overflow: hidden;
  background: var(--skeleton);
  cursor: pointer;
}

/* Il riquadro dell'immagine: sul telefono riempie la tessera quadrata, su
   desktop prende l'altezza della foto e le didascalie gli vanno sotto. */
.photo-card-media {
  position: absolute;
  inset: 0;
  overflow: hidden;
}

.thumb {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.4s ease-out;
  transform-origin: center;
}

/* Lo stesso hover:scale-105 delle schede di officinebit.ch, solo dove c'e'
   un mouse: su telefono resterebbe ingrandita dopo il tocco. */
@media (hover: hover) {
  .photo-card-media:hover .thumb {
    transform: scale(1.05);
  }
  .photo-card {
    cursor: zoom-in;
  }
}

.thumb.skeleton {
  background: linear-gradient(90deg, #f2f2f2 25%, #e8e8e8 37%, #f2f2f2 63%);
  background-size: 400% 100%;
  animation: scorrimento 1.2s ease infinite;
}

@keyframes scorrimento {
  from { background-position: 100% 0; }
  to { background-position: 0 0; }
}

/* Titolo, campi e autore non stanno sulla tessera: la griglia è fatta di
   sole immagini, e il resto si legge aprendo la foto. */
.photo-card-title,
.photo-card-meta,
.photo-card-author {
  display: none;
}

.play-badge {
  position: absolute;
  top: 6px;
  right: 6px;
  width: 22px;
  height: 22px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.55);
  color: #fff;
  font-size: 10px;
  padding-left: 2px;
}

.play-badge svg {
  display: block;
  width: 11px;
  height: 11px;
}

/* Sul telefono il video si riconosce dal solo triangolo del play, bianco e
   pieno, al centro della tessera: niente cerchio. Un'ombra morbida lo tiene
   leggibile anche sulle foto chiare. */
@media (max-width: 700px) {
  .play-badge {
    top: 50%;
    left: 50%;
    right: auto;
    width: auto;
    height: auto;
    padding: 0;
    transform: translate(-50%, -50%);
    border-radius: 0;
    background: none;
    color: #fff;
    filter: drop-shadow(0 1px 6px rgba(0, 0, 0, 0.45));
    pointer-events: none;
  }

  .play-badge svg {
    width: 38px;
    height: 38px;
    /* Il triangolo pesa a sinistra: spostato di poco sembra al centro. */
    margin-left: 4px;
  }
}

.photo-card-like {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  align-items: flex-end;
  justify-content: flex-start;
  gap: 4px;
  padding: 18px 8px 6px;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.45), transparent);
  border: 0;
  color: #fff;
  font-size: 12px;
  font-weight: 600;
  /* Il cuore vuoto è appena accennato: sulla griglia conta l'immagine. */
  opacity: 0.85;
}

.photo-card-like.liked {
  opacity: 1;
}

.empty-state {
  padding: 64px var(--gutter);
  text-align: center;
}

.empty-title {
  font-size: 24px;
  font-weight: 500;
  line-height: 1.25;
  margin: 0 0 6px;
}

.empty-sub {
  font-size: 14px;
  color: var(--ink);
  margin: 0;
}

.feed-footer {
  padding: 28px var(--gutter) 0;
  text-align: center;
}

.feed-footer .info {
  font-size: 12px;
  color: var(--ink-3);
}

/* --------------------------------------------------------------------------
   Pulsante di caricamento
   -------------------------------------------------------------------------- */

.fab {
  position: fixed;
  right: max(var(--gutter), calc(50vw - var(--shell) / 2 + var(--gutter)));
  bottom: calc(20px + var(--safe-bottom));
  z-index: 40;
  width: 56px;
  height: 56px;
  border: 0;
  border-radius: 50%;
  background: var(--ink);
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.25);
}

.fab:active {
  transform: scale(0.94);
}

.fab-cross,
.fab-cross::before {
  content: '';
  display: block;
  background: #fff;
  border-radius: 2px;
}

.fab-cross {
  width: 22px;
  height: 2px;
  position: relative;
}

.fab-cross::before {
  position: absolute;
  inset: 0;
  transform: rotate(90deg);
}

.pop {
  animation: battito 0.3s ease;
}

@keyframes battito {
  0% { transform: scale(1); }
  40% { transform: scale(1.25); }
  100% { transform: scale(1); }
}

/* --------------------------------------------------------------------------
   Foglio di caricamento (sale dal basso)
   -------------------------------------------------------------------------- */

.sheet {
  position: fixed;
  inset: 0;
  z-index: 70;
  display: flex;
  align-items: flex-end;
  justify-content: center;
}

.sheet-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.45);
}

.sheet-panel {
  position: relative;
  width: 100%;
  /* Il foglio resta largo come un telefono anche quando la pagina e' a tutta
     larghezza: un modulo di mille pixel si legge male. */
  max-width: 640px;
  max-height: 90dvh;
  overflow-y: auto;
  background: var(--bg);
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  padding: 8px var(--gutter) calc(16px + var(--safe-bottom));
  animation: salita 0.22s ease;
}

@keyframes salita {
  from { transform: translateY(16px); opacity: 0.6; }
  to { transform: translateY(0); opacity: 1; }
}

/* La maniglia: dice che il foglio si chiude tirandolo giù, senza scriverlo. */
.sheet-panel::before {
  content: '';
  display: block;
  width: 36px;
  height: 4px;
  margin: 0 auto 12px;
  border-radius: 2px;
  background: var(--line);
}

.sheet-title {
  font-size: 17px;
  font-weight: 500;
  margin: 0 0 16px;
  text-align: center;
}

.sheet-close-x {
  position: absolute;
  top: 10px;
  right: 10px;
  width: 32px;
  height: 32px;
  border: 0;
  border-radius: 50%;
  background: var(--surface);
  color: var(--ink);
  font-size: 18px;
  line-height: 1;
}

.upload-drop {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  padding: 32px 16px;
  border: 1px dashed var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  font-size: 14px;
  color: var(--ink-2);
  text-align: center;
  cursor: pointer;
}

.upload-drop:active {
  background: #f2f2f2;
}

/* Col mouse il riquadro accetta anche i file trascinati, e lo dice. */
.upload-drop-click {
  display: none;
}

@media (hover: hover) and (pointer: fine) {
  .upload-drop-tap {
    display: none;
  }

  .upload-drop-click {
    display: inline;
  }

  .upload-drop:hover {
    border-color: var(--ink-2);
  }
}

.upload-drop.is-over {
  border: 1px solid var(--ink);
  background: #f2f2f2;
  color: var(--ink);
}

.upload-drop-icon {
  width: 40px;
  height: 40px;
  color: var(--ink);
}

/* --------------------------------------------------------------------------
   Coda di caricamento
   -------------------------------------------------------------------------- */

.upload-queue {
  margin-top: 16px;
}

.upload-item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 0;
  border-top: 1px solid var(--line-soft);
}

.upload-item-thumb {
  flex: none;
  width: 44px;
  height: 44px;
  border-radius: var(--radius-sm);
  object-fit: cover;
  background: var(--skeleton);
}

.upload-item-thumb--video {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 16px;
  color: var(--ink-2);
}

.upload-item-name {
  flex: 1;
  min-width: 0;
  font-size: 13px;
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.upload-item-status {
  font-size: 12px;
  color: var(--ink-2);
  white-space: nowrap;
}

.upload-item.is-done .upload-item-status {
  color: var(--ink);
  font-weight: 600;
}

.upload-item.is-error .upload-item-status {
  color: var(--ink);
  font-weight: 600;
}

.upload-item-progress {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 2px;
  background: var(--line-soft);
}

.upload-item-progress-bar {
  height: 100%;
  background: var(--ink);
  transition: width 0.2s ease;
}

.upload-item {
  position: relative;
}

/* --------------------------------------------------------------------------
   Finestre: privacy e conferme
   -------------------------------------------------------------------------- */

.modal {
  position: fixed;
  inset: 0;
  z-index: 80;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--gutter);
}

.modal-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.5);
}

.modal-card {
  position: relative;
  width: 100%;
  max-width: 420px;
  max-height: 85dvh;
  overflow-y: auto;
  background: var(--bg);
  border-radius: var(--radius-lg);
  padding: 22px var(--gutter);
}

.modal-card h2 {
  font-size: 18px;
  font-weight: 500;
  margin: 0 0 14px;
}

.modal-close {
  position: absolute;
  top: 12px;
  right: 12px;
  width: 30px;
  height: 30px;
  border: 0;
  border-radius: 50%;
  background: var(--surface);
  font-size: 17px;
  line-height: 1;
}

.modal-body {
  font-size: 14px;
  color: var(--ink-2);
}

.modal-body h3 {
  font-size: 13px;
  font-weight: 700;
  color: var(--ink);
  margin: 18px 0 4px;
}

.modal-body p {
  margin: 0 0 8px;
}

/* Finestra di conferma, nello stile di un'applicazione e non del browser:
   titolo, testo, e i pulsanti separati da filetti. */
.dialog-card {
  width: 100%;
  max-width: 340px;
  background: var(--bg);
  border-radius: var(--radius-lg);
  overflow: hidden;
  text-align: center;
  position: relative;
}

.dialog-head {
  padding: 22px 20px 18px;
}

.dialog-title {
  font-size: 17px;
  font-weight: 500;
  margin: 0;
}

.dialog-text {
  font-size: 13px;
  color: var(--ink-2);
  margin: 8px 0 0;
  line-height: 1.45;
}

.dialog-fields {
  margin-top: 16px;
  text-align: left;
}

.dialog-fields .field-label:first-child {
  margin-top: 0;
}

.dialog-actions {
  display: flex;
  flex-direction: column;
  border-top: 1px solid var(--line);
}

.dialog-btn {
  background: none;
  border: 0;
  padding: 14px;
  font-size: 15px;
  color: var(--ink);
}

.dialog-btn + .dialog-btn {
  border-top: 1px solid var(--line);
}

.dialog-btn--confirm {
  font-weight: 700;
}

.dialog-btn--danger {
  font-weight: 700;
}

.dialog-btn:disabled {
  opacity: 0.35;
}

.dialog-btn:active {
  background: var(--surface);
}

/* --------------------------------------------------------------------------
   Avvisi
   -------------------------------------------------------------------------- */

.toast-container {
  position: fixed;
  left: 50%;
  transform: translateX(-50%);
  bottom: calc(88px + var(--safe-bottom));
  z-index: 90;
  display: flex;
  flex-direction: column;
  gap: 8px;
  width: calc(100% - 32px);
  max-width: 380px;
  pointer-events: none;
}

.toast {
  background: rgba(0, 0, 0, 0.9);
  color: #fff;
  border-radius: var(--radius);
  padding: 12px 16px;
  font-size: 14px;
  text-align: center;
  animation: comparsa 0.2s ease;
}

@keyframes comparsa {
  from { transform: translateY(8px); opacity: 0; }
  to { transform: translateY(0); opacity: 1; }
}

/* --------------------------------------------------------------------------
   Scanner QR
   -------------------------------------------------------------------------- */

.scanner {
  position: fixed;
  inset: 0;
  z-index: 85;
  background: #000;
}

.scanner video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.scanner-frame {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: min(70vw, 280px);
  aspect-ratio: 1;
  border: 2px solid rgba(255, 255, 255, 0.9);
  border-radius: var(--radius-lg);
}

.scanner-hint {
  position: absolute;
  left: 0;
  right: 0;
  bottom: calc(60px + var(--safe-bottom));
  text-align: center;
  color: #fff;
  font-size: 14px;
}

.scanner-close {
  position: absolute;
  top: calc(var(--safe-top) + 10px);
  right: 10px;
  width: 40px;
  height: 40px;
  border: 0;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.15);
  color: #fff;
  font-size: 22px;
  line-height: 1;
}

/* --------------------------------------------------------------------------
   Pannelli di amministrazione
   -------------------------------------------------------------------------- */

.view-admin .lead {
  padding: 16px var(--gutter) 0;
  font-size: 13px;
}

#fields-editor,
#events-list,
#event-detail {
  padding: 8px var(--gutter) 0;
}

.field-card {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 14px;
  margin-top: 12px;
}

.field-card-head {
  display: flex;
  gap: 8px;
  align-items: center;
}

.option-list {
  margin-top: 8px;
}

.option-row {
  display: flex;
  gap: 8px;
  align-items: center;
  margin-top: 8px;
}

.option-row .text-input {
  flex: 1;
  min-width: 0;
}

.admin-actions {
  display: flex;
  gap: 10px;
  padding: 20px var(--gutter) 0;
}

.admin-actions .btn,
.admin-actions .btn-outline {
  margin-top: 0;
  flex: 1;
}

/* --- elenco eventi --- */

.event-card {
  border-bottom: 1px solid var(--line-soft);
  padding: 16px 0;
}

.event-card.is-archived {
  opacity: 0.55;
}

.event-card-title {
  display: block;
  width: 100%;
  text-align: left;
  background: none;
  border: 0;
  padding: 0;
  font-size: 16px;
  font-weight: 500;
}

.event-card-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 10px;
  margin-top: 4px;
  font-size: 12px;
  color: var(--ink-2);
}

.event-code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 1px 6px;
  color: var(--ink);
}

.badge {
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 0 8px;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.event-card-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 10px;
}

.event-card-actions .rule-item {
  font-size: 12px;
  padding: 5px 12px;
}

/* --- dettaglio evento --- */

.admin-field {
  border-top: 1px solid var(--line-soft);
  padding: 18px 0;
}

.admin-field:first-child {
  border-top: 0;
}

.admin-field--danger {
  border-top: 1px solid var(--line);
  margin-top: 12px;
}

.qr-preview {
  width: 180px;
  height: 180px;
  margin: 12px 0;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: #fff;
}

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

/* L'azione principale di una schermata e' piena, non contornata: in una fila
   di voci tutte uguali non si capirebbe qual e' quella che si cerca. */
#btn-new-event {
  background: var(--ink);
  border-color: var(--ink);
  color: #fff;
  font-weight: 600;
}

/* Le azioni dell'amministratore sull'evento: tratteggiate per distinguerle dai
   filtri, che sono la fila subito sotto e si usano molto piu' spesso. */
.rulebar--secondary {
  margin-top: 8px;
}

.feed-footer {
  border-top: 1px solid var(--line-soft);
  margin-top: 28px;
  padding-top: 20px;
}

.feed-footer .btn-text {
  font-size: 13px;
  padding: 8px;
}

/* Un pulsante dentro una riga in linea non e' a tutta larghezza: altrimenti si
   prende lo spazio del campo che sta accanto, che e' esattamente la parte che
   serve vedere mentre si scrive. */
.option-row .btn,
.option-row .btn-outline,
.option-row .btn-delete {
  width: auto;
  flex: none;
  margin-top: 0;
  padding: 12px 16px;
  font-size: 14px;
}

.admin-field .option-row {
  margin-top: 0;
}

/* Il campo del codice e' un indirizzo: si legge meglio a spaziatura fissa, e
   si vede subito se c'e' uno spazio di troppo. */
#event-detail .option-row .text-input {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 14px;
}

#event-detail .admin-field:nth-of-type(1) .text-input {
  font-family: var(--font);
  font-size: 15px;
}

/* Le pillole possono scorrere fino al bordo dello schermo: senza questo, in
   fondo alla riga restava un margine vuoto e l'ultima sembrava tagliata a
   caso invece che continuare. */
.rulebar {
  padding-right: var(--gutter);
  margin-right: calc(-1 * var(--gutter));
  scroll-padding-right: var(--gutter);
}

/* --------------------------------------------------------------------------
   Campi del caricamento
   -------------------------------------------------------------------------- */

.upload-field + .upload-field {
  margin-top: 4px;
}

/* Scelta multipla: pillole da accendere invece di caselle di spunta. Una
   casella da 18px è un bersaglio scomodo per un pollice; una pillola alta 34
   no, e si vede da lontano quali sono accese. */
.choice-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 4px;
}

.choice-chip {
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 8px 14px;
  font-size: 14px;
  color: var(--ink-2);
}

.choice-chip.is-on {
  background: var(--ink);
  border-color: var(--ink);
  color: #fff;
  font-weight: 600;
}

.choice-chip:active {
  transform: scale(0.97);
}

/* --------------------------------------------------------------------------
   Editor dei campi: righe delle voci più compatte
   -------------------------------------------------------------------------- */

.field-card .select-input {
  margin-top: 10px;
}

.option-row .icon-btn {
  width: 34px;
  height: 34px;
  font-size: 14px;
}

.option-row {
  gap: 6px;
}

/* La colonna dei moduli non segue la larghezza della pagina: un campo email
   largo mille pixel è scomodo da leggere quanto uno largo cento. */
@media (min-width: 1000px) {
  .sheet-block {
    max-width: 400px;
  }

  #event-detail,
  #fields-editor,
  #events-list {
    max-width: 720px;
  }
}

/* --------------------------------------------------------------------------
   Intestazione dell'evento con avatar e menu
   -------------------------------------------------------------------------- */

.feed-header {
  position: sticky;
  /* Serve al menu dell'account, che si appende qui sotto. */
  z-index: 25;
}

.topbar {
  display: flex;
  align-items: center;
  gap: 12px;
}

.topbar .brand {
  flex: 1;
  min-width: 0;
}

/* L'iniziale al posto di una fotografia del profilo: non la chiediamo a
   nessuno, e una sagoma grigia uguale per tutti non direbbe niente. */
.avatar {
  flex: none;
  width: 34px;
  height: 34px;
  border: 0;
  border-radius: 50%;
  background: var(--ink);
  color: #fff;
  font-size: 14px;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
}

/* L'ospite senza account e' contornato e non pieno: una differenza piccola,
   ma dice che quell'identita' vive solo in questo evento. */
.avatar--ospite {
  background: var(--bg);
  color: var(--ink);
  border: 1px solid var(--line);
}

.menu {
  position: absolute;
  right: var(--gutter);
  top: calc(100% - 6px);
  z-index: 50;
  min-width: 210px;
  max-width: calc(100vw - 32px);
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.14);
}

.menu-name {
  margin: 0;
  padding: 12px 14px;
  font-size: 12px;
  color: var(--ink-3);
  border-bottom: 1px solid var(--line-soft);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.menu-item {
  display: block;
  width: 100%;
  text-align: left;
  background: none;
  border: 0;
  padding: 13px 14px;
  font-size: 14px;
  font-weight: 500;
}

.menu-item + .menu-item {
  border-top: 1px solid var(--line-soft);
}

.menu-item:active {
  background: var(--surface);
}

/* --------------------------------------------------------------------------
   Scheletri della griglia
   -------------------------------------------------------------------------- */

.photo-card--scheletro {
  background: linear-gradient(90deg, #f2f2f2 25%, #e8e8e8 37%, #f2f2f2 63%);
  background-size: 400% 100%;
  animation: scorrimento 1.2s ease infinite;
  cursor: default;
}

/* Il cuore che sboccia al doppio tocco. Dura meno di un secondo e non aspetta
   la risposta del server: il segnale deve arrivare nell'istante del gesto. */
.cuore-volante {
  position: absolute;
  transform: translate(-50%, -50%) scale(0);
  color: #fff;
  font-size: 90px;
  line-height: 1;
  pointer-events: none;
  text-shadow: 0 2px 16px rgba(0, 0, 0, 0.5);
  animation: sboccia 0.8s cubic-bezier(0.17, 0.89, 0.32, 1.28) forwards;
}

@keyframes sboccia {
  0% { transform: translate(-50%, -50%) scale(0); opacity: 0; }
  25% { transform: translate(-50%, -50%) scale(1.15); opacity: 1; }
  45% { transform: translate(-50%, -50%) scale(0.95); opacity: 1; }
  70% { transform: translate(-50%, -50%) scale(1); opacity: 1; }
  100% { transform: translate(-50%, -55%) scale(1); opacity: 0; }
}

/* Con il movimento ridotto il cuore compare e sparisce, senza rimbalzi. */
@media (prefers-reduced-motion: reduce) {
  .cuore-volante {
    animation: comparsa 0.4s ease forwards;
  }
}

/* I file scelti, in attesa che si tocchi "Carica". */
.upload-chosen {
  margin: 12px 0 0;
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  background: var(--surface);
  border: 1px solid var(--line);
  font-size: 13px;
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

#upload-start {
  margin-top: 16px;
}

/* L'area di modifica dell'informativa: testo lungo, quindi a spaziatura
   normale ma con le righe conservate, perche' la struttura del documento
   (titoletti e paragrafi) si legge dagli a capo. */
.privacy-editor {
  min-height: 55vh;
  line-height: 1.5;
  font-size: 14px;
  resize: vertical;
  white-space: pre-wrap;
}

/* Il testo mostrato agli invitati conserva gli a capo dentro il paragrafo. */
.modal-body p {
  white-space: pre-line;
}

/* --------------------------------------------------------------------------
   Firma in fondo alle schermate d'ingresso
   -------------------------------------------------------------------------- */

.firma {
  /* Agganciata al fondo della pagina e non dello schermo: fissata, sulle
     schermate piu' lunghe dello schermo (la registrazione con la conferma
     della password) finiva sopra al modulo. #app e' alto almeno quanto lo
     schermo, quindi sulle schermate corte resta comunque in basso. */
  position: absolute;
  left: 0;
  right: 0;
  bottom: calc(18px + var(--safe-bottom));
  z-index: 10;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  /* Non deve rubare il tocco a quello che ha sopra: la parte cliccabile e'
     solo il marchio, non la striscia larga quanto lo schermo. */
  pointer-events: none;
}

.firma-testo {
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.firma-logo {
  width: 110px;
  height: auto;
  pointer-events: auto;
  opacity: 0.85;
  transition: opacity 0.15s ease;
}

.firma-logo:active {
  opacity: 1;
}

/* In fondo alla galleria: lo spazio per la firma dopo l'ultima foto. */
#view-feed {
  padding-bottom: calc(var(--safe-bottom) + 120px);
}

/* Su schermi bassi la firma andrebbe a finire sopra al modulo: li' torna a
   scorrere con la pagina invece di restare incollata in fondo. */


/* --------------------------------------------------------------------------
   Elenco dei partecipanti
   -------------------------------------------------------------------------- */

#participants-list {
  padding: 8px var(--gutter) 0;
}

.participant-card {
  border-bottom: 1px solid var(--line-soft);
  padding: 14px 0;
}

.participant-head {
  display: flex;
  align-items: center;
  gap: 8px;
}

.participant-name {
  font-size: 15px;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.participant-email {
  margin: 2px 0 0;
  font-size: 13px;
  color: var(--ink-2);
  /* Un indirizzo lungo va a capo invece di allargare la riga. */
  overflow-wrap: anywhere;
}

.participant-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 2px 12px;
  margin-top: 4px;
  font-size: 12px;
  color: var(--ink-3);
}

/* --------------------------------------------------------------------------
   Compositore del caricamento: una scheda per foto
   -------------------------------------------------------------------------- */

.composer-conto {
  margin: 14px 0 0;
  font-size: 12px;
  color: var(--ink-2);
}

.composer-card {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 12px;
  margin-top: 12px;
}

.composer-head {
  display: flex;
  align-items: center;
  gap: 10px;
}

.composer-thumb {
  flex: none;
  width: 48px;
  height: 48px;
  border-radius: var(--radius-sm);
  object-fit: cover;
  background: var(--skeleton);
}

.composer-thumb--video {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 16px;
  color: var(--ink-2);
}

.composer-name {
  flex: 1;
  min-width: 0;
  font-size: 13px;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.composer-card .field-label:first-of-type {
  margin-top: 12px;
}

/* ==========================================================================
   Aspetto di officinebit.ch
   Le misure vengono da artistwall-react (Header.jsx, ArtGallery.jsx,
   photoswipe-custom.css): la stessa intestazione, lo stesso titolo con il
   conteggio fra quadre, le stesse pillole dei filtri e la stessa galleria.
   La griglia invece resta quella quadrata a tre colonne: e' un'app di foto.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Intestazione: marchio a sinistra, riquadro dell'account a destra
   -------------------------------------------------------------------------- */

.site-header {
  background: var(--bg);
  backdrop-filter: none;
  border-bottom: 0;
  padding: calc(var(--safe-top) + 8px) var(--gutter-r) 8px var(--gutter-l);
}

.site-header .topbar {
  justify-content: space-between;
}

/* Il marchio come il logo di artistwall (artistwall_logo.svg): Helvetica
   normale, in minuscolo. Le misure sono quelle dell'intestazione di
   artistwall — logo alto 40px, 84 da 640px, 96 da 1024 — convertite in corpo
   del carattere: il disegno e' alto 1/1,302 del corpo. "photogallery" e' piu'
   lungo di "artistwall", quindi dove non ci starebbe si stringe con lo
   schermo invece di andare sotto il riquadro dell'account. */
.site-logo {
  flex: 1;
  min-width: 0;
  line-height: 0;
}

/* Largo quanto la scritta di prima (5,6 volte il corpo); dove non ci sta si
   stringe con lo schermo invece di andare sotto il riquadro dell'account. */
.site-logo .logo-img {
  display: block;
  width: min(291px, calc(100vw - 96px));
  max-width: 100%;
  height: auto;
}

/* Il riquadro della lingua di officinebit, qui con l'iniziale di chi guarda. */
.avatar {
  width: 32px;
  height: 32px;
  border: 2px solid var(--ink);
  border-radius: 0;
  background: var(--bg);
  color: var(--ink);
  font-size: 16px;
  font-weight: 500;
}

.avatar:hover span,
.avatar:hover {
  color: rgba(0, 0, 0, 0.5);
}

.avatar--ospite {
  border: 2px solid var(--ink);
}

.avatar[hidden] {
  display: none;
}

/* "Log in" e "Sign up" per chi guarda senza account: riquadri come quello
   dell'iniziale, alti uguali, con il testo dentro. */
.visitor-links {
  flex: none;
  display: flex;
  gap: 8px;
}

.visitor-links[hidden] {
  display: none;
}

.box-link {
  display: flex;
  align-items: center;
  height: 32px;
  padding: 0 10px;
  border: 2px solid var(--ink);
  background: var(--bg);
  color: var(--ink);
  font-size: 15px;
  font-weight: 500;
  line-height: 1;
  text-decoration: none;
  white-space: nowrap;
}

.box-link:hover {
  background: var(--ink);
  color: var(--bg);
}

@media (min-width: 640px) {
  .box-link {
    height: 40px;
    padding: 0 14px;
    font-size: 18px;
  }
}

@media (min-width: 1024px) {
  .box-link {
    height: 48px;
    padding: 0 16px;
    font-size: 20px;
  }
}

.site-header .menu {
  top: calc(100% - 4px);
  width: max-content;
  max-width: min(340px, calc(100vw - 24px));
  right: var(--gutter-r);
  border: 2px solid var(--ink);
  border-radius: 0;
  box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1);
}

.site-header .menu-name {
  color: var(--ink-2);
  border-bottom: 1px solid var(--ink);
}

.site-header .menu-item {
  font-weight: 500;
  color: var(--ink);
}

.site-header .menu-item + .menu-item {
  border-top: 1px solid var(--ink);
}

.site-header .menu-item:hover {
  background: #f3f4f6;
}

/* --------------------------------------------------------------------------
   Titolo della sezione, con il conteggio fra quadre
   -------------------------------------------------------------------------- */

.section-head {
  padding-top: 12px;
  margin-bottom: 16px;
}

.section-title {
  margin: 0;
  font-size: 24px;
  font-weight: 500;
  line-height: 1.25;
  overflow-wrap: anywhere;
}

.section-count {
  position: relative;
  top: -8px;
  font-size: 12px;
  font-weight: 500;
  vertical-align: super;
  line-height: 0;
}

.section-head .archived-notice,
.section-head .rulebar {
  margin-top: 12px;
}

/* --------------------------------------------------------------------------
   Filtri: una fila di pillole che scorre, appiccicata sotto l'intestazione
   -------------------------------------------------------------------------- */

.filter-bar {
  position: sticky;
  top: var(--feed-header-h, 56px);
  z-index: 18;
  background: var(--bg);
  padding-top: 8px;
  padding-bottom: 8px;
}

.filter-row {
  display: flex;
  flex-wrap: nowrap;
  gap: 8px;
  margin: 8px calc(-1 * var(--gutter));
  padding: 0 var(--gutter);
  overflow-x: auto;
  scrollbar-width: none;
  -ms-overflow-style: none;
  -webkit-overflow-scrolling: touch;
  scroll-snap-type: x proximity;
  scroll-padding: 0 var(--gutter);
}

.filter-row::-webkit-scrollbar {
  display: none;
}

.filter-pill {
  flex-shrink: 0;
  white-space: nowrap;
  scroll-snap-align: start;
  padding: 6px 12px;
  font-size: 12px;
  font-weight: 400;
  line-height: 16px;
  color: #000;
  background: #fff;
  border: 1px solid #d1d5db;
  border-radius: 999px;
  transition: color 0.15s, background-color 0.15s, border-color 0.15s;
}

.filter-pill:hover {
  border-color: #000;
}

.filter-pill.is-on {
  background: #000;
  color: #fff;
  border-color: #000;
}

.filter-pill-count {
  margin-left: 4px;
}

.filter-pill-x {
  display: inline;
  margin-left: 4px;
  vertical-align: -1px;
}

@media (min-width: 640px) {
  .site-header {
    padding-top: calc(var(--safe-top) + 12px);
    padding-bottom: 12px;
  }

  .site-logo .logo-img {
    width: min(610px, calc(100vw - 120px));
  }

  .avatar {
    width: 40px;
    height: 40px;
    font-size: 24px;
    line-height: 1;
  }

  .section-head {
    margin-bottom: 24px;
  }

  .section-title {
    font-size: 30px;
  }

  .section-count {
    top: -12px;
    font-size: 14px;
  }

  .filter-bar {
    padding-top: 12px;
    padding-bottom: 12px;
  }

  .filter-row {
    gap: 12px;
    margin-top: 12px;
    margin-bottom: 12px;
  }

  .filter-pill {
    padding: 8px 16px;
    font-size: 16px;
    line-height: 24px;
  }

  .filter-pill-count,
  .filter-pill-x {
    margin-left: 8px;
  }
}

@media (min-width: 768px) {
  .section-title {
    font-size: 36px;
  }
}

@media (min-width: 1024px) {
  .site-logo .logo-img {
    width: min(700px, calc(100vw - 130px));
  }

  .avatar {
    width: 48px;
    height: 48px;
    font-size: 30px;
  }
}

/* --------------------------------------------------------------------------
   Galleria: PhotoSwipe come su officinebit.ch
   -------------------------------------------------------------------------- */

/* Bottone "Caption" sotto l'immagine. L'immagine NON viene ridotta:
   il bottone sta nello spazio in basso della galleria. */
.pswp__caption-toggle {
  position: absolute;
  left: 50%;
  bottom: calc(24px + var(--safe-bottom));
  transform: translateX(-50%);
  z-index: 20;
  display: none; /* mostrato via JS solo se la slide ha una didascalia */
  border: 1px solid rgba(0, 0, 0, 0.4);
  background: transparent;
  color: #000;
  font-size: 13px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 8px 18px;
  border-radius: 20px;
  cursor: pointer;
  transition: background 0.2s, color 0.2s;
}

.pswp__caption-toggle:hover {
  background: rgba(0, 0, 0, 0.08);
}

.pswp__caption-toggle--active {
  background: #000;
  color: #fff;
  border-color: #000;
}

/* Foto ingrandita, con la lente, con le dita o con un doppio tocco: le icone
   si tolgono di mezzo e resta solo la foto. Tornano quando la foto e' di
   nuovo alla grandezza di partenza. La classe la mette PhotoSwipe stessa,
   ogni volta che l'ingrandimento cambia. */
.pswp__top-bar,
.pswp__button--arrow,
.pswp__caption-toggle,
.pswp__caption-overlay {
  transition: opacity 0.2s, visibility 0.2s;
}

.pswp--zoomed-in .pswp__top-bar,
.pswp--zoomed-in .pswp__button--arrow,
.pswp--zoomed-in .pswp__caption-toggle,
.pswp--zoomed-in .pswp__caption-overlay {
  opacity: 0 !important;
  visibility: hidden;
  pointer-events: none;
}

/* La didascalia SOPRA l'immagine, nascosta finche' non si tocca "Caption".
   Fondo semitrasparente: la foto resta intravista sotto. */
.pswp__caption-overlay {
  position: absolute;
  inset: 0;
  z-index: 15;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 80px 24px 110px;
  box-sizing: border-box;
  background: rgba(255, 255, 255, 0.78);
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.25s ease, visibility 0.25s ease;
  cursor: pointer;
}

.pswp__caption-overlay--visible {
  opacity: 1;
  visibility: visible;
}

.pswp__caption-overlay__inner {
  color: #000;
  text-align: center;
  font-size: 16px;
  line-height: 1;
  max-width: 640px;
  max-height: 100%;
  overflow-y: auto;
  overflow-wrap: anywhere;
}

.pswp__caption-overlay__inner p {
  margin: 0 0 0.6em;
}

/* Una didascalia lunga, con gli a capo di chi l'ha scritta: a interlinea 1 le
   righe si toccavano. */
.pswp__caption-overlay__inner p:first-child {
  line-height: 1.35;
  white-space: pre-line;
}

.pswp__caption-overlay__inner p:last-child {
  margin-bottom: 0;
}

/* Pulsanti senza cerchi, icone nere sul bianco. */
.pswp__button {
  background-color: transparent !important;
  background: none !important;
  transition: opacity 0.2s;
  opacity: 0.85;
}

.pswp__button:hover {
  opacity: 1;
  background-color: transparent !important;
}

.pswp__button--arrow--prev,
.pswp__button--arrow--next {
  width: 60px;
  height: 60px;
}

.pswp__button--close {
  width: 44px;
  height: 44px;
}

.pswp__button--zoom {
  display: none !important;
}

.pswp__icn {
  fill: #000 !important;
  color: #000 !important;
  filter: none;
}

.pswp__counter {
  color: #000 !important;
  text-shadow: none;
  opacity: 0.85;
}

.pswp__bg {
  background: #fff !important;
  opacity: 1 !important;
}

.pswp {
  background: #fff !important;
}

/* Lo spazio sotto la tacca e sopra la barra di iOS: senza, il contatore e la
   X finirebbero sotto l'orologio quando l'app e' installata. */
.pswp__top-bar {
  top: var(--safe-top);
}

/* Il cuore e il cestino stanno nella barra, fra il contatore e la X: gli
   stessi tratti neri delle altre icone. */
.pswp__button--like,
.pswp__button--delete {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  width: auto;
  min-width: 44px;
  /* 60px come la barra: il cuore resta in riga con il contatore e la X. */
  height: 60px;
  padding: 0 8px;
  color: #000;
}

.pswp-like__icn {
  fill: none;
  stroke: #000;
  stroke-width: 2;
  stroke-linejoin: round;
  transition: fill 0.15s ease;
}

.pswp__button--like.liked .pswp-like__icn {
  fill: #000;
}

.pswp-like__count {
  font-size: 14px;
  font-variant-numeric: tabular-nums;
}

/* Il video al posto dell'immagine, alle stesse misure. */
.pswp-video {
  display: flex;
  align-items: center;
  justify-content: center;
}

.pswp-video video {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.pswp .cuore-volante {
  z-index: 30;
}

/* Le conferme e gli avvisi si aprono anche con la galleria aperta: devono
   starle sopra, e PhotoSwipe sta a 100000. */
.modal {
  z-index: 100010;
}

.toast-container {
  z-index: 100020;
}

/* --------------------------------------------------------------------------
   Desktop: la pagina di officinebit.ch
   Da 701px in su niente colonna centrale: la pagina prende tutta la
   finestra, e le foto stanno in colonne nelle loro proporzioni, con le
   didascalie sotto. Le colonne sono quelle di ArtGallery.jsx (react-masonry-
   css): 4 fino a 900px, 5 fino a 1200, poi 6. Le distribuisce feed.js.
   -------------------------------------------------------------------------- */

@media (min-width: 701px) {
  :root {
    --shell: 100vw;
  }

  #app {
    max-width: none;
  }

  .photo-grid {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: 0 16px;
    padding-top: 0;
  }

  .masonry-col {
    flex: 1 1 0;
    min-width: 0;
  }

  /* I rettangoli d'attesa, prima che feed.js metta le colonne. */
  .photo-grid > .photo-card--scheletro {
    flex: 0 0 calc((100% - 5 * 16px) / 6);
    aspect-ratio: 3 / 4;
    margin-bottom: 24px;
  }

  .masonry-col .photo-card {
    aspect-ratio: auto;
    overflow: visible;
    background: none;
    margin-bottom: 24px;
    cursor: pointer;
  }

  .masonry-col .photo-card-media {
    position: relative;
    inset: auto;
    min-height: 2rem;
    margin-bottom: 12px;
    background: var(--skeleton);
  }

  .masonry-col .thumb {
    height: auto;
    object-fit: contain;
  }

  /* Le righe sotto la foto, come le schede del sito: 14px, interlinea piena,
     nere. */
  .masonry-col .photo-card-title,
  .masonry-col .photo-card-meta,
  .masonry-col .photo-card-author {
    display: block;
    font-size: 14px;
    line-height: 1;
    color: #000;
    overflow-wrap: anywhere;
  }

  /* La didascalia sotto la miniatura si ferma a due righe: intera si legge
     aprendo la foto e toccando "Caption". */
  .masonry-col .photo-card-title {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    overflow: hidden;
    line-height: 1.15;
  }

  .masonry-col .photo-card-title[hidden],
  .masonry-col .photo-card-meta[hidden] {
    display: none;
  }

  .masonry-col .photo-card-title + *,
  .masonry-col .photo-card-meta + * {
    margin-top: 4px;
  }

  /* Il cuore compare al passaggio del mouse: su desktop il pollice non c'e',
     e la griglia resta pulita finche' non serve. */
  .photo-card-like {
    opacity: 0;
    transition: opacity 0.15s ease;
  }

  .photo-card-media:hover .photo-card-like,
  .photo-card-like.liked {
    opacity: 1;
  }

  /* La propria foto non si vota: il cuore resta a contare, e il clic passa
     alla tessera, che apre la foto. */
  .photo-card-like.is-own {
    pointer-events: none;
  }

  /* La matita, in basso a destra sulla fascia del cuore. */
  .photo-card-edit {
    position: absolute;
    right: 4px;
    bottom: 2px;
    z-index: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    padding: 0;
    border: 0;
    background: none;
    color: #fff;
    cursor: pointer;
    opacity: 0;
    transition: opacity 0.15s ease;
  }

  .photo-card-edit[hidden] {
    display: none;
  }

  .photo-card-media:hover .photo-card-edit,
  .photo-card-edit:focus-visible {
    opacity: 1;
  }

  .photo-card-edit:hover {
    opacity: 0.7 !important;
  }
}

/* Sul telefono, e su ogni schermo a tocco, niente matita sulla tessera: la
   si trova aprendo la foto. */
@media (max-width: 700px), (hover: none), (pointer: coarse) {
  .photo-card-edit {
    display: none;
  }
}

/* --------------------------------------------------------------------------
   Logo dell'evento, sopra il titolo
   -------------------------------------------------------------------------- */

.event-logo {
  display: block;
  width: auto;
  height: auto;
  max-width: min(100%, 360px);
  max-height: 96px;
  object-fit: contain;
  margin: 0 0 12px;
}

.event-logo--gate {
  margin: 0 auto 20px;
  max-height: 120px;
}

@media (min-width: 701px) {
  .section-head .event-logo {
    max-width: min(100%, 480px);
    max-height: 140px;
  }
}

.logo-preview {
  display: block;
  max-width: 240px;
  max-height: 120px;
  margin: 8px 0 12px;
  padding: 8px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: #fff;
}

/* --------------------------------------------------------------------------
   Menu del profilo: la nota sulla cancellazione
   -------------------------------------------------------------------------- */

.menu-note {
  padding: 12px 14px;
  border-top: 1px solid var(--ink);
  font-size: 12px;
  line-height: 1.4;
  color: var(--ink-2);
}

.menu-note p {
  margin: 0 0 10px;
}

.menu-note a {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 2px;
  overflow-wrap: anywhere;
}

.menu-note-btn {
  background: var(--bg);
  border: 1px solid #d1d5db;
  border-radius: 999px;
  padding: 6px 12px;
  font-size: 12px;
  line-height: 16px;
  color: var(--ink);
}

.menu-note-btn:hover {
  border-color: var(--ink);
}

/* Il pulsante che copia i dati della prima foto su tutte le altre. */
.composer-copy {
  margin-top: 8px;
  padding: 8px 0 0;
  text-align: left;
  font-size: 13px;
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* --------------------------------------------------------------------------
   Partecipanti bloccati
   -------------------------------------------------------------------------- */

.rule-item--danger {
  border-color: var(--ink);
  color: var(--ink);
}

.bans-section {
  margin-top: 32px;
  padding-top: 8px;
  border-top: 1px solid var(--ink);
}

.bans-title {
  margin: 12px 0 0;
  font-size: 20px;
  font-weight: 500;
}

/* --------------------------------------------------------------------------
   iOS: niente zoom sui campi
   Safari su iPhone ingrandisce la pagina quando si tocca un campo con il
   testo sotto i 16px, e non la rimette a posto dopo: si entrava nell'evento
   con la pagina ingrandita, i margini fuori dallo schermo, il riquadro
   dell'account e la X della galleria tagliati. A 16px lo zoom non scatta.
   -------------------------------------------------------------------------- */

input,
select,
textarea,
.text-input,
.privacy-editor,
#event-detail .option-row .text-input,
#event-detail .admin-field:nth-of-type(1) .text-input {
  font-size: 16px;
}

/* --------------------------------------------------------------------------
   Galleria su telefono, dentro al browser
   La barra di Safari su iPhone galleggia sopra il fondo della pagina e
   copriva il pulsante "Caption". Sui dispositivi a tocco il pulsante sale
   sopra la barra; nell'app installata la barra non c'e' e torna in basso.
   -------------------------------------------------------------------------- */

@media (hover: none) and (pointer: coarse) {
  .pswp__caption-toggle {
    bottom: calc(96px + var(--safe-bottom));
  }
}

@media (hover: none) and (pointer: coarse) and (display-mode: standalone) {
  .pswp__caption-toggle {
    bottom: calc(24px + var(--safe-bottom));
  }
}

/* --------------------------------------------------------------------------
   I tuoi eventi
   -------------------------------------------------------------------------- */

.my-event {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 16px 0;
  border-top: 1px solid var(--line-soft);
  color: var(--ink);
}

.my-event:last-child {
  border-bottom: 1px solid var(--line-soft);
}

.my-event.is-archived {
  opacity: 0.6;
}

.my-event-logo {
  flex: none;
  width: 56px;
  height: 56px;
  object-fit: contain;
}

.my-event-text {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.my-event-title {
  font-size: 24px;
  font-weight: 500;
  line-height: 1.25;
  overflow-wrap: anywhere;
}

.my-event-meta {
  font-size: 14px;
  line-height: 1;
  color: var(--ink-2);
}

/* La freccia del sito, in forma di pillola: dice che la riga si tocca. */
.my-event-go {
  flex: none;
  padding: 6px 12px;
  font-size: 12px;
  line-height: 16px;
  border: 1px solid #d1d5db;
  border-radius: 999px;
}

.my-event:hover .my-event-go,
.my-event:active .my-event-go {
  background: #000;
  border-color: #000;
  color: #fff;
}

.my-events .empty-title {
  margin: 24px 0 6px;
}

.my-events-foot {
  padding-top: 32px;
  max-width: 400px;
}

@media (min-width: 640px) {
  .my-event-title {
    font-size: 30px;
  }
  .my-event-go {
    padding: 8px 16px;
    font-size: 16px;
    line-height: 24px;
  }
}

/* --------------------------------------------------------------------------
   Campi password: l'occhio per vederla, e la conferma
   -------------------------------------------------------------------------- */

.password-field {
  position: relative;
}

.password-field .text-input {
  padding-right: 52px;
}

/* 44px di bersaglio, dentro al campo sul bordo destro. */
.password-eye {
  position: absolute;
  top: 50%;
  right: 4px;
  transform: translateY(-50%);
  width: 44px;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 0;
  background: none;
  color: var(--ink-2);
}

.password-eye:hover,
.password-eye[aria-pressed='true'] {
  color: var(--ink);
}

/* Safari e Edge disegnano un loro occhio o una chiave dentro al campo: con il
   nostro accanto sarebbero due. */
.password-field input::-ms-reveal,
.password-field input::-ms-clear {
  display: none;
}

.text-input.is-invalid {
  border-color: var(--ink);
  background: var(--bg);
}

.field-hint {
  margin-top: 6px;
  color: var(--ink);
  font-weight: 500;
}

/* Lo spazio per la firma sotto al modulo: la firma e' alta circa 60px e sta
   a 18px dal fondo, qui ne restano altri per respirare. */
.view-gate,
.view-lock {
  padding-bottom: calc(var(--safe-bottom) + 130px);
}

/* --------------------------------------------------------------------------
   Cuore piu' grande, e la propria foto: matita al posto del voto
   -------------------------------------------------------------------------- */

.photo-card-like {
  font-size: 14px;
  gap: 5px;
}

.photo-card-heart {
  font-size: 20px;
  line-height: 1;
}

.pswp-like__count {
  font-size: 16px;
}

/* Sulla propria foto il cuore resta a contare, ma non e' un pulsante. */
.pswp__button--like.is-static {
  cursor: default;
  opacity: 0.85;
}

.pswp__button--like.is-static .pswp-like__icn {
  fill: #000;
  opacity: 0.25;
}

.pswp__button--edit {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 60px;
  color: #000;
}

/* Il foglio di modifica si apre sopra la galleria, che sta a 100000. */
.sheet--sopra {
  z-index: 100015;
}

.edit-card {
  margin-top: 0;
}

.edit-card .field-label:first-child {
  margin-top: 0;
}

/* --------------------------------------------------------------------------
   Autore: @nome in corsivo, che filtra le sue foto
   -------------------------------------------------------------------------- */

.author-link {
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  font-style: italic;
  font-weight: 400;
  color: inherit;
  text-align: left;
  cursor: pointer;
}

.author-link:hover {
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* Su desktop sotto la foto, come le altre righe ma in corsivo. */
@media (min-width: 701px) {
  .masonry-col .photo-card-author {
    font-style: italic;
    font-weight: 400;
  }
}

/* Nella didascalia della galleria il nome e' un pulsante: si vede che si
   tocca, senza diventare un bottone a tutti gli effetti. */
.author-link--caption {
  font-size: 16px;
  line-height: 1.2;
  padding: 6px 2px;
  text-decoration: underline;
  text-underline-offset: 3px;
  text-align: center;
}

#feed-title {
  cursor: pointer;
}

/* --------------------------------------------------------------------------
   Errori in rosso
   L'unico colore dell'interfaccia oltre al nero: un errore deve saltare
   all'occhio anche in pieno sole. #c8102e sta a 5,9:1 sul bianco, sopra la
   soglia AA anche per il testo piccolo.
   -------------------------------------------------------------------------- */

:root {
  --danger: #c8102e;
  --danger-bg: #fdecee;
}

/* Il messaggio sotto un modulo: accesso, registrazione, password. */
.form-message--error {
  color: var(--danger);
  background: var(--danger-bg);
  border-color: var(--danger);
}

/* L'avviso a comparsa in basso. */
.toast--error {
  background: var(--danger);
  color: #fff;
}

/* "Le due password non coincidono" e il campo che lo causa. */
.field-hint {
  color: var(--danger);
}

.text-input.is-invalid {
  border-color: var(--danger);
}

/* Il file che non si e' caricato, nella coda. */
.upload-item.is-error .upload-item-status {
  color: var(--danger);
}

.upload-item.is-error .upload-item-progress-bar {
  background: var(--danger);
}


/* --------------------------------------------------------------------------
   Fino a quando si carica: la riga sotto il titolo dell'evento
   Grigia finche' manca tanto, nera negli ultimi due giorni, con il puntino
   che pulsa nell'ultimo.
   -------------------------------------------------------------------------- */

.upload-deadline {
  margin: 8px 0 0;
  font-size: 14px;
  line-height: 1.3;
  color: var(--ink-2);
}

.upload-deadline--vicino,
.upload-deadline--urgente {
  color: var(--ink);
  font-weight: 500;
}

.upload-deadline--urgente::before {
  content: '';
  display: inline-block;
  width: 8px;
  height: 8px;
  margin-right: 8px;
  border-radius: 50%;
  background: var(--ink);
  vertical-align: 1px;
  animation: pulsa-scadenza 1.4s ease-in-out infinite;
}

@keyframes pulsa-scadenza {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.2; }
}

@media (prefers-reduced-motion: reduce) {
  .upload-deadline--urgente::before {
    animation: none;
  }
}

@media (min-width: 701px) {
  .upload-deadline {
    font-size: 16px;
  }
}

/* La stessa data dentro al foglio di caricamento, sotto il titolo. */
.upload-deadline-sheet {
  margin: -4px 0 12px;
  font-size: 13px;
  color: var(--ink-2);
  text-align: center;
}

/* Il file che non si e' caricato, nel compositore: la scheda resta aperta
   con il motivo sotto il nome, perche' si possa decidere se riprovare. */
.composer-card.is-error {
  border-color: var(--danger);
}

.composer-error {
  margin: 10px 0 0;
  padding: 8px 10px;
  font-size: 13px;
  line-height: 1.4;
  color: var(--danger);
  background: var(--danger-bg);
  border-radius: var(--radius-sm);
}

/* La didascalia si scrive su piu' righe: cresce solo in altezza, per non
   uscire dalla scheda. */
.caption-input {
  display: block;
  resize: vertical;
  min-height: 72px;
  line-height: 1.35;
}

/* La sentinella in fondo alla griglia: quando si avvicina allo schermo
   arrivano le schede successive. Ha un'altezza perche' l'osservatore la veda. */
.photo-more {
  height: 1px;
}
