/*
 * Stili base ConSergio — CSS a mano (nessun build step, Propshaft).
 * Palette azzurro/blu, card arrotondate, look pulito. Mobile-first.
 * Le componenti reali (Guest::/Manage::/Admin::) arriveranno nelle epiche successive.
 */

:root {
  --c-blue-900: #0b3a66;
  --c-blue-700: #145ea8;
  --c-blue-500: #1f7ae0;
  --c-blue-300: #7ec1ff;
  --c-azure-100: #e8f3ff;
  --c-azure-50: #f4f9ff;
  --c-white: #ffffff;
  --c-ink: #1a2733;
  --c-ink-soft: #4a5b6b;
  --c-ok: #46b450;

  --radius: 20px;
  --radius-sm: 999px;
  --shadow: 0 10px 30px rgba(20, 94, 168, 0.15);
  --font: system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}

* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  padding: 0;
}

body {
  font-family: var(--font);
  color: var(--c-ink);
  background: linear-gradient(160deg, var(--c-azure-50) 0%, var(--c-azure-100) 100%);
  -webkit-font-smoothing: antialiased;
  min-height: 100vh;
}

/* --- Hero / landing ------------------------------------------------------- */
.hero {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
}

.hero__card {
  background: var(--c-white);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 32px 28px;
  max-width: 520px;
  width: 100%;
  border: 1px solid var(--c-azure-100);
  /* La testata è a tutta larghezza: senza ritaglio sborderebbe dagli angoli. */
  overflow: hidden;
}

.hero__brand {
  display: inline-block;
  margin: 0 0 16px;
  padding: 6px 14px;
  font-weight: 700;
  letter-spacing: 0.3px;
  color: var(--c-blue-700);
  background: var(--c-azure-100);
  border-radius: var(--radius-sm);
  font-size: 0.85rem;
}

.hero__title {
  margin: 0 0 12px;
  font-size: 1.9rem;
  line-height: 1.15;
  color: var(--c-blue-900);
}

.hero__subtitle {
  margin: 0 0 24px;
  font-size: 1.05rem;
  line-height: 1.5;
  color: var(--c-ink-soft);
}

.hero__status {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin: 0 0 24px;
  padding: 8px 14px;
  border-radius: var(--radius-sm);
  background: rgba(70, 180, 80, 0.1);
  color: var(--c-ok);
  font-weight: 600;
  font-size: 0.95rem;
}

.hero__dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--c-ok);
  box-shadow: 0 0 0 4px rgba(70, 180, 80, 0.18);
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin: 0 0 24px;
}

.hero__langs {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  border-top: 1px solid var(--c-azure-100);
  padding-top: 20px;
}

.hero__langs-label {
  color: var(--c-ink-soft);
  font-size: 0.9rem;
  margin-right: 4px;
}

.lang-chip {
  display: inline-block;
  padding: 4px 10px;
  border-radius: var(--radius-sm);
  background: var(--c-azure-50);
  border: 1px solid var(--c-azure-100);
  color: var(--c-blue-700);
  font-size: 0.8rem;
  font-weight: 600;
}

.lang-chip--active {
  background: var(--c-blue-500);
  border-color: var(--c-blue-500);
  color: var(--c-white);
}

/* --- Flash messages ------------------------------------------------------- */
.flash {
  margin: 0;
  padding: 12px 20px;
  text-align: center;
  font-weight: 600;
  font-size: 0.95rem;
}

.flash--notice {
  background: rgba(70, 180, 80, 0.12);
  color: var(--c-ok);
}

.flash--alert {
  background: #fdecec;
  color: var(--sb-danger, #C62828);
}

/* --- Bottoni --------------------------------------------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 10px 18px;
  border-radius: 12px;
  border: 1px solid transparent;
  font-family: inherit;
  font-size: 0.95rem;
  font-weight: 600;
  cursor: pointer;
  text-decoration: none;
  line-height: 1;
  transition: filter 0.15s ease, background 0.15s ease;
}

.btn--sm {
  padding: 7px 12px;
  font-size: 0.85rem;
}

.btn--primary {
  background: var(--c-blue-500);
  border-color: var(--c-blue-500);
  color: var(--c-white);
}

.btn--primary:hover {
  filter: brightness(0.95);
}

.btn--ghost {
  background: var(--c-white);
  border-color: var(--c-azure-100);
  color: var(--c-blue-700);
}

.btn--ghost:hover {
  background: var(--c-azure-50);
}

.btn--danger {
  background: var(--c-white);
  border-color: #f3c9c9;
  color: var(--sb-danger, #C62828);
}

.btn--danger:hover {
  background: #fdecec;
}

.chip {
  display: inline-block;
  padding: 5px 12px;
  border-radius: var(--radius-sm);
  background: var(--c-azure-50);
  border: 1px solid var(--c-azure-100);
  color: var(--c-blue-700);
  font-size: 0.8rem;
  font-weight: 600;
  text-decoration: none;
}

.chip:hover {
  background: var(--c-azure-100);
}

/* --- Badge ----------------------------------------------------------------- */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 5px 12px;
  border-radius: var(--radius-sm);
  font-size: 0.82rem;
  font-weight: 700;
}

.badge--ok {
  background: rgba(70, 180, 80, 0.12);
  color: var(--c-ok);
}

.badge__dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--c-ok);
  box-shadow: 0 0 0 4px rgba(70, 180, 80, 0.18);
}

/* --- Form generico --------------------------------------------------------- */
.form__section {
  border: 1px solid var(--c-azure-100);
  border-radius: var(--radius);
  padding: 20px;
  margin: 0 0 20px;
}

.form__legend {
  padding: 0 8px;
  font-weight: 700;
  color: var(--c-blue-700);
  font-size: 0.95rem;
}

.form__row {
  margin: 0 0 14px;
}

.form__row:last-child {
  margin-bottom: 0;
}

.form__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 14px;
}

.form__label {
  display: block;
  margin: 0 0 6px;
  font-size: 0.88rem;
  font-weight: 600;
  color: var(--c-ink-soft);
}

.form__input {
  width: 100%;
  padding: 11px 14px;
  border-radius: 12px;
  border: 1px solid var(--c-azure-100);
  background: var(--c-white);
  font-family: inherit;
  font-size: 1rem;
  color: var(--c-ink);
}

.form__input:focus {
  outline: none;
  border-color: var(--c-blue-300);
  box-shadow: 0 0 0 3px rgba(126, 193, 255, 0.35);
}

.form__input--sm {
  max-width: 120px;
}

.form__hint {
  margin: 6px 0 0;
  font-size: 0.8rem;
  color: var(--c-ink-soft);
}

.form__actions {
  display: flex;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
}

/* Separatore tra blocchi di un form. */
.form__sep {
  margin: 18px 0;
  border: 0;
  border-top: 1px solid var(--c-azure-100);
}

/* Sezione facoltativa richiudibile (<details>): chiusa di default, si apre solo
   quando serve davvero. Marker nativo nascosto, chevron ruotato all'apertura. */
.form__collapse {
  margin-bottom: 14px;
}

.form__collapse-summary {
  display: flex;
  align-items: center;
  gap: 8px;
  list-style: none;
  cursor: pointer;
  font-size: 0.88rem;
  font-weight: 600;
  color: var(--c-ink-soft);
}

.form__collapse-summary::-webkit-details-marker {
  display: none;
}

.form__collapse-label {
  flex: 1;
}

.form__collapse-chevron {
  transition: transform 0.15s ease;
}

.form__collapse[open] .form__collapse-chevron {
  transform: rotate(180deg);
}

.form__collapse-body {
  margin-top: 14px;
}

.form__link {
  color: var(--c-blue-700);
  font-weight: 600;
  font-size: 0.9rem;
  text-decoration: none;
}

.form__errors {
  background: #fdecec;
  border: 1px solid #f3c9c9;
  border-radius: 12px;
  padding: 14px 16px;
  margin: 0 0 20px;
  color: var(--sb-danger, #C62828);
}

.form__errors-title {
  margin: 0 0 8px;
  font-weight: 700;
}

.form__errors ul {
  margin: 0;
  padding-left: 18px;
}

/* --- Registrazione self-service ------------------------------------------- */
.signup {
  min-height: 100vh;
  display: flex;
  justify-content: center;
  padding: 32px 20px;
}

/* `margin: auto` e non `align-items: center` sul contenitore: centra la card
   nella pagina ma, quando il form è più alto della finestra (registrazione),
   non ne taglia la testa fuori dallo scroll. Serve anche a spegnere lo stretch
   di default del flex, che allungava la card per tutta l'altezza dello schermo. */
.signup__card {
  background: var(--c-white);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 32px 26px;
  max-width: 640px;
  width: 100%;
  margin: auto;
  border: 1px solid var(--c-azure-100);
  /* La testata è a tutta larghezza: senza ritaglio sborderebbe dagli angoli. */
  overflow: hidden;
}

/* Testata della card: il logo su fascia colorata, come la banda delle categorie
   nel pannello. Esce dal padding della card con margini negativi, così tocca i
   bordi invece di galleggiare, e separa il marchio dal titolo di pagina. I
   margini negativi sono per card, perché home e signup hanno padding diverso. */
.signup__head, .hero__head {
  background: var(--sb-chip, var(--c-azure-100));
  border-bottom: 1px solid var(--sb-line, var(--c-azure-100));
}
.signup__head { margin: -32px -26px 22px; padding: 20px 26px; }
.hero__head { margin: -32px -28px 22px; padding: 20px 28px; }
.signup__head .app-logo--hero, .hero__head .app-logo--hero { margin-bottom: 0; }

/* Accesso, recupero password e accettazione invito: form corti, card stretta
   come quella della home. */
.signup__card--auth { max-width: 460px; }

/* Rimando all'altra strada (accesso ↔ registrazione), staccato dal form. */
.signup__alt {
  margin: 20px 0 0;
  padding-top: 16px;
  border-top: 1px solid var(--c-azure-100);
  font-size: 0.9rem;
}

.signup__brand {
  display: inline-block;
  margin: 0 0 16px;
  padding: 6px 14px;
  font-weight: 700;
  color: var(--c-blue-700);
  background: var(--c-azure-100);
  border-radius: var(--radius-sm);
  font-size: 0.85rem;
}

.signup__title {
  margin: 0 0 8px;
  font-size: 1.8rem;
  color: var(--c-blue-900);
}

.signup__subtitle {
  margin: 0 0 24px;
  color: var(--c-ink-soft);
  line-height: 1.5;
}

/* --- Pannello camere (Manage::) ------------------------------------------- */
.panel {
  max-width: 1120px;
  margin: 0 auto;
  padding: 28px 24px 56px;
}

.panel__header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 16px;
  background: var(--c-white);
  border: 1px solid var(--c-azure-100);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 24px 26px;
  margin: 0 0 24px;
}

.panel__eyebrow {
  margin: 0 0 6px;
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  color: var(--c-blue-500);
}

.panel__title {
  margin: 0 0 12px;
  font-size: 1.8rem;
  color: var(--c-blue-900);
}

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

.panel__stat {
  font-weight: 600;
  color: var(--c-ink-soft);
}

.panel__actions {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
}

.panel__section {
  background: var(--c-white);
  border: 1px solid var(--c-azure-100);
  border-radius: var(--radius);
  padding: 20px 22px;
  margin: 0 0 24px;
}

.panel__section-title {
  margin: 0 0 14px;
  font-size: 1.05rem;
  color: var(--c-blue-900);
}

/* Tab di pagina (es. Statistiche: Attività ospiti | Assistente AI). Stile a
   sottolineatura, distinto dalle chip pillola del filtro periodo. */
.panel__tabs {
  display: flex;
  gap: 4px;
  margin: 0 0 18px;
  border-bottom: 1px solid var(--sb-line, var(--c-azure-100));
}
.panel__tab {
  padding: 10px 16px;
  font-weight: 600;
  color: var(--c-ink-soft);
  text-decoration: none;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
}
.panel__tab:hover { color: var(--sb-primary, var(--c-blue-500)); }
.panel__tab--active {
  color: var(--sb-primary, var(--c-blue-500));
  border-bottom-color: var(--sb-primary, var(--c-blue-500));
}

/* Overlay di caricamento a schermo intero (operazioni lunghe, es. traduzione AI). */
.app-loader {
  position: fixed; inset: 0; z-index: 9999;
  display: grid; place-items: center;
  background: rgba(15, 23, 42, 0.45);
}
.app-loader__box {
  display: flex; flex-direction: column; align-items: center; gap: 14px;
  background: #fff; border-radius: 16px; padding: 28px 40px;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.25);
}
.app-loader__spinner {
  width: 38px; height: 38px; border-radius: 50%;
  border: 3px solid var(--c-azure-100, #dbeafe); border-top-color: #178bc3;
  animation: app-loader-spin 0.7s linear infinite;
}
.app-loader__text { font-weight: 600; color: var(--c-blue-900, #0f2a4a); }
@keyframes app-loader-spin { to { transform: rotate(360deg); } }

/* Anagrafica di una pagina di dettaglio: etichetta sopra, valore sotto, in
   colonne che si adattano. Semanticamente è una <dl>; la griglia tiene le
   coppie incolonnate invece di farle correre come testo in linea. */
.panel__facts {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
  gap: 16px 24px; margin: 0;
}
.panel__fact { min-width: 0; }
.panel__fact-label {
  font-size: 0.72rem; font-weight: 700; letter-spacing: 0.04em;
  text-transform: uppercase; color: var(--sb-muted);
}
.panel__fact-value { margin: 4px 0 0; color: var(--sb-ink); font-weight: 600; word-break: break-word; }

/* Occhiello come varco verso la pagina padre: è la briciola di pane delle
   pagine di dettaglio, e toglie un bottone "Indietro" dalla riga delle azioni. */
.panel__eyebrow a { color: inherit; text-decoration: none; }
.panel__eyebrow a:hover { text-decoration: underline; }

.panel__empty {
  background: var(--c-white);
  border: 1px dashed var(--c-blue-300);
  border-radius: var(--radius);
  padding: 40px;
  text-align: center;
  color: var(--c-ink-soft);
}

/* I Turbo Frame sono elementi custom: senza display esplicito resterebbero
   inline e romperebbero i layout che li contengono. */
turbo-frame {
  display: block;
}

/* --- Desktop -------------------------------------------------------------- */
@media (min-width: 640px) {
  .hero__card {
    padding: 44px 40px;
  }

  .hero__title {
    font-size: 2.3rem;
  }

  .form__grid {
    grid-template-columns: 1fr 1fr;
  }
}

/* ==========================================================================
   App ospite (Guest::) — mobile-first, ispirazione StayBell.
   Card arrotondate, badge "In evidenza"/"Più scelto", footer neutro.
   ========================================================================== */
.g-body {
  background: linear-gradient(180deg, var(--c-azure-50) 0%, var(--c-azure-100) 100%);
}

.g-app {
  max-width: 560px;
  margin: 0 auto;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  padding: 0 16px calc(24px + env(safe-area-inset-bottom));
}

/* --- Top bar --------------------------------------------------------------- */
.g-topbar {
  position: sticky;
  top: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 14px 4px;
  background: rgba(244, 249, 255, 0.9);
  backdrop-filter: blur(8px);
}

.g-topbar__brand {
  font-weight: 800;
  font-size: 1.05rem;
  color: var(--c-blue-900);
  text-decoration: none;
  letter-spacing: 0.2px;
}

/* --- Selettore lingua (details nativo) ------------------------------------- */
.g-lang {
  position: relative;
}

.g-lang__current {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 6px 10px;
  border-radius: var(--radius-sm);
  background: var(--c-white);
  border: 1px solid var(--c-azure-100);
  color: var(--c-blue-700);
  font-size: 0.8rem;
  font-weight: 700;
  cursor: pointer;
  list-style: none;
}

.g-lang__current::-webkit-details-marker { display: none; }

.g-lang__menu {
  position: absolute;
  right: 0;
  margin: 6px 0 0;
  padding: 6px;
  list-style: none;
  background: var(--c-white);
  border: 1px solid var(--c-azure-100);
  border-radius: 14px;
  box-shadow: var(--shadow);
  min-width: 150px;
  z-index: 20;
}

.g-lang__item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 10px;
  border-radius: 10px;
  text-decoration: none;
  color: var(--c-ink);
  font-size: 0.9rem;
}

.g-lang__item:hover { background: var(--c-azure-50); }
.g-lang__item--active { background: var(--c-azure-100); font-weight: 700; }
.g-lang__code { font-weight: 700; color: var(--c-blue-700); font-size: 0.78rem; }

/* --- Flash ----------------------------------------------------------------- */
.g-flash {
  margin: 8px 0 0;
  padding: 10px 14px;
  border-radius: 12px;
  font-weight: 600;
  font-size: 0.9rem;
}
.g-flash--notice { background: rgba(70, 180, 80, 0.12); color: var(--c-ok); }
.g-flash--alert { background: #fdecec; color: var(--sb-danger, #C62828); }

.g-main {
  flex: 1;
  padding-top: 8px;
}

/* --- Saluto ---------------------------------------------------------------- */
/* Copertina della struttura in cima alla home. Rapporto fisso: la foto la
   sceglie la struttura e non deve poter allungare la pagina a piacere. */
.g-cover { margin: 12px 0 0; }
.g-cover__img {
  display: block; width: 100%; aspect-ratio: 16 / 9; object-fit: cover;
  border-radius: 18px; background: var(--c-azure-50);
  box-shadow: 0 8px 22px rgba(20, 94, 168, 0.12);
}
@media (min-width: 640px) {
  .g-cover__img { aspect-ratio: 21 / 9; }
}

.g-roombadge {
  display: inline-block;
  padding: 5px 12px;
  border-radius: var(--radius-sm);
  background: var(--c-blue-500);
  color: var(--c-white);
  font-size: 0.8rem;
  font-weight: 700;
  margin-bottom: 12px;
}

/* --- Card assistente (disabilitata MVP) ------------------------------------ */
.g-assistant {
  display: flex;
  align-items: center;
  gap: 14px;
  margin: 18px 0;
  padding: 16px;
  border-radius: var(--radius);
  background: var(--c-white);
  border: 1px solid var(--c-azure-100);
  box-shadow: var(--shadow);
}

.g-assistant__icon {
  flex: 0 0 auto;
  width: 44px;
  height: 44px;
  border-radius: 12px;
  display: grid;
  place-items: center;
  background: var(--c-azure-100);
  color: var(--c-blue-700);
  font-size: 1.3rem;
}

.g-assistant__title { margin: 0 0 2px; font-size: 1.05rem; color: var(--c-blue-900); }
.g-assistant__sub { margin: 0; font-size: 0.85rem; color: var(--c-ink-soft); }

/* --- Sezioni --------------------------------------------------------------- */
.g-section { margin: 22px 0; }

.g-section__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 12px;
}

.g-section__title {
  margin: 0 0 12px;
  font-size: 1.15rem;
  color: var(--c-blue-900);
}

.g-section__head .g-section__title { margin-bottom: 0; }

.g-link {
  color: var(--c-blue-700);
  font-weight: 600;
  font-size: 0.85rem;
  text-decoration: none;
  white-space: nowrap;
}

/* --- Griglia servizi ------------------------------------------------------- */
.g-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 12px;
}

.g-service {
  display: flex;
  flex-direction: column;
  background: var(--c-white);
  border: 1px solid var(--c-azure-100);
  border-radius: 18px;
  overflow: hidden;
  text-decoration: none;
  color: inherit;
  box-shadow: 0 6px 18px rgba(20, 94, 168, 0.08);
  transition: transform 0.12s ease, box-shadow 0.12s ease;
}

.g-service:active { transform: scale(0.99); }

.g-service__media {
  position: relative;
  aspect-ratio: 4 / 3;
  background: var(--c-azure-100);
  /* §E28 — il rapporto lo decide il RIQUADRO, mai l'immagine. Le varianti degli
     allegati arrivano già ritagliate su misura, le foto della galleria proposta
     no: sono asset statici con la LORO proporzione. Senza questi due vincoli
     l'altezza intrinseca della foto gonfia il riquadro (`min-height: auto` del
     flex item) e la card esce più alta delle vicine.
     Vale per tutti i template: quelli che ridefiniscono il riquadro cambiano
     misura e proporzione, non questa regola. */
  min-height: 0;
  overflow: hidden;
}

.g-service__img { width: 100%; height: 100%; object-fit: cover; display: block; }

.g-service__placeholder {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  font-size: 2rem;
  font-weight: 800;
  color: var(--c-blue-300);
}

.g-service__badges {
  position: absolute;
  top: 8px;
  left: 8px;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.g-service__body { padding: 10px 12px 14px; }
.g-service__cat {
  margin: 0 0 2px;
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.4px;
  color: var(--c-blue-500);
  font-weight: 700;
}
.g-service__name { margin: 0 0 8px; font-size: 0.98rem; color: var(--c-ink); line-height: 1.2; }
.g-service__meta { display: flex; flex-direction: column; gap: 2px; }
.g-service__hours { font-size: 0.8rem; color: var(--c-ink-soft); }
.g-service__price { font-size: 0.9rem; font-weight: 700; color: var(--c-blue-700); }

/* --- Badge ----------------------------------------------------------------- */
.g-badge {
  display: inline-block;
  padding: 3px 9px;
  border-radius: var(--radius-sm);
  font-size: 0.68rem;
  font-weight: 800;
  letter-spacing: 0.3px;
}
.g-badge--featured { background: var(--c-blue-500); color: var(--c-white); }
.g-badge--popular { background: #ffb020; color: #3a2600; }

/* --- CTA contenuti --------------------------------------------------------- */
.g-cta {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 16px;
  border-radius: var(--radius);
  background: var(--c-white);
  border: 1px solid var(--c-azure-100);
  box-shadow: var(--shadow);
  text-decoration: none;
  color: inherit;
}
.g-cta__icon {
  width: 44px; height: 44px; border-radius: 12px;
  display: grid; place-items: center;
  background: var(--c-azure-100); color: var(--c-blue-700); font-size: 1.2rem;
}
.g-cta__body { display: flex; flex-direction: column; flex: 1; }
.g-cta__title { font-weight: 700; color: var(--c-blue-900); }
.g-cta__sub { font-size: 0.85rem; color: var(--c-ink-soft); }
.g-cta__arrow { color: var(--c-blue-500); font-size: 1.2rem; }

/* --- Liste / contenuti ----------------------------------------------------- */
.g-page__title { margin: 8px 0 4px; font-size: 1.5rem; color: var(--c-blue-900); }
.g-page__sub { margin: 0 0 16px; color: var(--c-ink-soft); }

.g-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.g-list__item {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 16px; border-radius: 16px; background: var(--c-white);
  border: 1px solid var(--c-azure-100); box-shadow: 0 6px 18px rgba(20, 94, 168, 0.08);
  text-decoration: none; color: var(--c-ink); font-weight: 600;
}
.g-list__arrow { color: var(--c-blue-500); }

/* Allegato scaricabile nel dettaglio di un documento: icona, nome su più righe
   se serve (i nomi dei file sono lunghi e lo schermo è stretto), peso sotto. */
.g-file__icon {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: 38px; height: 38px; border-radius: 11px;
  background: var(--c-azure-50); color: var(--c-blue-700);
}
.g-file__body { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1 1 auto; }
.g-file__name { overflow-wrap: anywhere; }
.g-file__meta { font-size: 0.8rem; font-weight: 500; color: var(--c-ink-soft); }

.g-back {
  display: inline-flex; align-items: center; gap: 6px;
  margin: 10px 0 4px; color: var(--c-blue-700);
  text-decoration: none; font-weight: 600; font-size: 0.9rem;
}

/* §E27 — messaggi programmati dalla struttura (benvenuto, offerta del giorno).
   Prefisso `g-announce` e NON `g-msg`, che è già la bolla della chat: due cose
   diverse con lo stesso nome, in un CSS scritto a mano, si rompono a vicenda.

   Base: la stessa card di .g-cta (fondo bianco, bordo azzurro, ombra). Il non
   letto si distingue con un bordo a sinistra E l'etichetta "Nuovo": il colore da
   solo non comunica mai uno stato. */
.g-announces { display: flex; flex-direction: column; gap: 12px; }
.g-announces__intro { margin: 0 0 12px; font-size: 0.9rem; color: var(--c-ink-soft); }
.g-announce {
  display: flex; flex-direction: column; gap: 10px; padding: 16px;
  border-radius: var(--radius); background: var(--c-white);
  border: 1px solid var(--c-azure-100); box-shadow: var(--shadow);
}
.g-announce--unread { border-left: 3px solid var(--c-blue-500); }
.g-announce__head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.g-announce__icon {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: 38px; height: 38px; border-radius: 11px;
  background: var(--c-azure-100); color: var(--c-blue-700);
}
.g-announce__title { margin: 0; flex: 1 1 auto; min-width: 0; font-size: 1.02rem; color: var(--c-blue-900); overflow-wrap: anywhere; }
.g-announce__flag {
  flex: none; padding: 3px 9px; border-radius: var(--radius-sm);
  background: var(--c-blue-500); color: #fff;
  font-size: 0.68rem; font-weight: 800; letter-spacing: 0.3px; text-transform: uppercase;
}
.g-announce__body { font-size: 0.9rem; color: var(--c-ink); overflow-wrap: anywhere; }
.g-announce__body p { margin: 0 0 8px; }
.g-announce__body p:last-child { margin-bottom: 0; }
.g-announce__actions { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.g-announce__cta {
  display: inline-flex; align-items: center; min-height: 40px; padding: 0 16px;
  border-radius: var(--sb-r-btn); background: var(--c-blue-700); color: #fff;
  font-size: 0.88rem; font-weight: 700; text-decoration: none;
}
.g-announce__link { color: var(--c-blue-700); font-weight: 600; font-size: 0.85rem; text-decoration: none; }
/* "Non mostrare più" è un button_to: il form non deve aggiungere margine, e il
   bottone non deve sembrare l'azione principale della card. */
.g-announce__dismiss {
  margin-left: auto; padding: 0; min-height: 40px;
  background: none; border: 0; cursor: pointer;
  color: var(--c-ink-soft); font-size: 0.8rem; font-weight: 600;
}
.g-announce__dismiss:hover { color: var(--c-blue-700); text-decoration: underline; }
.g-announce__actions form { margin: 0; margin-left: auto; }
.g-announce__actions form .g-announce__dismiss { margin-left: 0; }
.g-announce__time { margin: 10px 0 0; font-size: 0.78rem; color: var(--c-ink-soft); }

/* Storico: già letti o messi via. Una riga, non una card: sono consultazione. */
.g-announces__past-title {
  margin: 24px 0 8px; font-size: 0.78rem; font-weight: 800;
  text-transform: uppercase; letter-spacing: 0.03em; color: var(--c-blue-700);
}
.g-announces__past { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.g-announce-row {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  min-height: 44px; padding: 8px 14px;
  border-radius: var(--radius-sm); background: var(--c-white);
  border: 1px solid var(--c-azure-100); text-decoration: none; color: inherit;
}
.g-announce-row__title { font-size: 0.88rem; font-weight: 600; color: var(--c-blue-900); overflow-wrap: anywhere; }
.g-announce-row__time { flex: none; font-size: 0.75rem; color: var(--c-ink-soft); }

/* Contatore dei non letti sulla voce di navigazione (chip e tab bar). */
.g-navbadge {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 18px; height: 18px; padding: 0 5px; border-radius: 9px;
  background: var(--sb-accent-strong); color: #fff;
  font-size: 0.68rem; font-weight: 800; line-height: 1;
}
.g-sectionnav__item--active .g-navbadge { background: #fff; color: var(--sb-primary); }

/* --- §E29 Sondaggio di fine soggiorno --------------------------------------
   Real radio inputs under every control: they work with no JavaScript, they are
   reachable from the keyboard and a screen reader names them for free. Stars and
   the 0-10 scale are CSS painted on top of those inputs, never a custom widget.

   Prefix `g-survey` and not `g-form`: the guest form classes (`form__*`) are
   shared with the panel, and repainting them here would follow the staff around
   the whole app. */
/* Introduzione: era una riga grigia piccola sopra la prima domanda e si perdeva
   del tutto. È il testo che spiega PERCHÉ stiamo chiedendo, cioè quello che
   decide se l'ospite comincia: ha bisogno di una superficie sua. */
.g-survey__intro {
  margin: 0 0 18px; padding: 14px 16px;
  border-radius: var(--radius); border-left: 3px solid var(--c-blue-500);
  background: var(--c-white); box-shadow: var(--shadow);
  font-size: 1rem; line-height: 1.5; color: var(--c-ink);
}
.g-survey__intro p { margin: 0 0 8px; }
.g-survey__intro p:last-child { margin-bottom: 0; }
.g-survey__questions { display: flex; flex-direction: column; gap: 12px; }

/* A fieldset and not a div: the legend is what ties the question to its group of
   radios, which is the whole accessible name of the control. */
/* `overflow: hidden` fa due lavori: arrotonda la fascia del titolo insieme alla
   card e contiene il float della legend qui sotto. */
.g-survey__q {
  margin: 0; padding: 0; border: 1px solid var(--c-azure-100);
  border-radius: var(--radius); background: var(--c-white); box-shadow: var(--shadow);
  overflow: hidden;
}
/* Il titolo resta un <legend> — è ciò che dà il nome accessibile al gruppo di
   radio, e un <div> lo perderebbe — ma `float: left; width: 100%` lo toglie
   dalla linea del bordo, dove il browser lo incastona di suo tagliando il testo
   a metà. Diventa così una piccola intestazione a tutta larghezza. */
.g-survey__q-title {
  float: left; width: 100%; box-sizing: border-box;
  display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
  padding: 12px 16px; margin: 0;
  background: var(--c-azure-100); border-bottom: 1px solid var(--c-azure-100);
  font-size: 1rem; font-weight: 700; color: var(--c-blue-900); line-height: 1.3;
}
.g-survey__q-body { clear: both; padding: 16px; }
.g-survey__q-num {
  flex: none; display: inline-grid; place-items: center;
  width: 22px; height: 22px; border-radius: 999px;
  background: var(--c-azure-100); color: var(--c-blue-700);
  font-size: 0.72rem; font-weight: 800;
}
.g-survey__q-req {
  flex: none; padding: 2px 8px; border-radius: var(--radius-sm);
  background: var(--c-azure-100); color: var(--c-blue-700);
  font-size: 0.66rem; font-weight: 800; letter-spacing: 0.3px; text-transform: uppercase;
}
.g-survey__q-help { margin: 0 0 10px; font-size: 0.82rem; color: var(--c-ink-soft); }

/* Stars. DOM order stays 1..5 — reversing it to make the sibling combinator work
   would reverse the tab order too — so the fill uses `:has()` on the container.
   The CSS `fill` property beats the `fill="none"` presentation attribute the
   icon helper writes, which is what turns the outline into a solid star. */
.g-stars { display: flex; gap: 4px; }
.g-stars__input { position: absolute; width: 1px; height: 1px; opacity: 0; }
.g-stars__label {
  display: inline-flex; padding: 4px; cursor: pointer;
  color: var(--c-blue-300); transition: color 0.12s ease;
}
.g-stars__input:focus-visible + .g-stars__label {
  outline: 2px solid var(--sb-primary-500); outline-offset: 2px; border-radius: 6px;
}
.g-stars:has(.g-stars__input[value="1"]:checked) .g-stars__label:nth-of-type(-n+1),
.g-stars:has(.g-stars__input[value="2"]:checked) .g-stars__label:nth-of-type(-n+2),
.g-stars:has(.g-stars__input[value="3"]:checked) .g-stars__label:nth-of-type(-n+3),
.g-stars:has(.g-stars__input[value="4"]:checked) .g-stars__label:nth-of-type(-n+4),
.g-stars:has(.g-stars__input[value="5"]:checked) .g-stars__label:nth-of-type(-n+5) {
  color: var(--sb-accent);
}
.g-stars__label svg { fill: currentColor; }
/* Fallback where `:has()` is missing: the chosen star at least paints itself, so
   the answer is never invisible. */
.g-stars__input:checked + .g-stars__label { color: var(--sb-accent); }

/* Scala 0-10 su UNA riga sola. Una griglia a 11 colonne uguali e non un flex che
   va a capo: mandando a capo, la scala si legge come due gruppi separati e il 10
   finisce da solo sotto lo zero, cioè accanto al suo opposto.
   Le celle si stringono quanto serve; l'altezza resta di 44px, così il bersaglio
   per il dito non si perde anche quando sono strette. */
.g-nps { display: grid; grid-template-columns: repeat(11, minmax(0, 1fr)); gap: 4px; }
.g-nps__input { position: absolute; width: 1px; height: 1px; opacity: 0; }
.g-nps__label {
  display: grid; place-items: center; min-width: 0; height: 44px;
  padding: 0 2px; border-radius: var(--sb-r-btn);
  border: 1px solid var(--c-azure-100); background: var(--c-white);
  color: var(--c-blue-900); font-weight: 700; font-size: 0.82rem; cursor: pointer;
}
.g-nps__input:checked + .g-nps__label {
  background: var(--c-blue-700); border-color: var(--c-blue-700); color: #fff;
}
.g-nps__input:focus-visible + .g-nps__label {
  outline: 2px solid var(--sb-primary-500); outline-offset: -2px;
}
.g-nps__scale {
  display: flex; justify-content: space-between; gap: 12px;
  margin-top: 6px; font-size: 0.74rem; color: var(--c-ink-soft);
}

/* Yes / no: the same pill as the scale, wide enough for a thumb. */
.g-choice { display: flex; gap: 8px; }
.g-choice__input { position: absolute; width: 1px; height: 1px; opacity: 0; }
.g-choice__label {
  display: inline-grid; place-items: center; min-width: 92px; height: 44px;
  padding: 0 18px; border-radius: var(--sb-r-btn);
  border: 1px solid var(--c-azure-100); background: var(--c-white);
  color: var(--c-blue-900); font-weight: 700; font-size: 0.9rem; cursor: pointer;
}
.g-choice__input:checked + .g-choice__label {
  background: var(--c-blue-700); border-color: var(--c-blue-700); color: #fff;
}
.g-choice__input:focus-visible + .g-choice__label {
  outline: 2px solid var(--sb-primary-500); outline-offset: 2px;
}

/* Foot: the autosave note on the left, the send button on the right. */
.g-survey__foot {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; flex-wrap: wrap; margin-top: 18px;
}
.g-survey__status {
  display: inline-flex; align-items: center; gap: 6px; min-height: 20px;
  font-size: 0.8rem; color: var(--c-ink-soft);
}
.g-survey__send { min-width: 160px; }

/* Closing screen. The review links are there for everyone: the score only moves
   the emphasis (see ADR-0022). */
.g-survey__thanks { display: flex; flex-direction: column; gap: 18px; }
.g-survey__thanks-lead { margin: 0; font-size: 1.05rem; font-weight: 700; color: var(--c-blue-900); }
.g-survey__thanks-note { margin: 0; font-size: 0.9rem; color: var(--c-ink-soft); }
.g-survey__thanks-back { margin: 0; }
.g-survey__recovery {
  padding: 16px; border-radius: var(--radius); background: var(--c-white);
  border: 1px solid var(--c-azure-100); box-shadow: var(--shadow);
}
.g-survey__recovery-title { margin: 0 0 4px; font-size: 1rem; color: var(--c-blue-900); }
.g-survey__reviews {
  padding: 16px; border-radius: var(--radius);
  background: var(--c-azure-100); border: 1px solid var(--c-blue-300);
}
/* Below the threshold the links stay, quietly: first we listen, then we ask. */
.g-survey__reviews--muted { background: var(--c-white); border-color: var(--c-azure-100); }
.g-survey__reviews-title { margin: 0 0 10px; font-size: 0.98rem; color: var(--c-blue-900); }
.g-survey__reviews-links { display: flex; flex-wrap: wrap; gap: 8px; }
.g-survey__review-link {
  display: inline-flex; align-items: center; gap: 6px;
  min-height: 44px; padding: 0 16px; border-radius: var(--sb-r-btn);
  border: 1px solid var(--c-blue-300); background: var(--c-white);
  color: var(--c-blue-700); font-size: 0.88rem; font-weight: 700; text-decoration: none;
}
.g-survey__review-link--primary {
  background: var(--c-blue-700); border-color: var(--c-blue-700); color: #fff;
}

/* Home card: the accent border is the only thing that sets it apart from the
   assistant card next to it — an ordinary card would go unnoticed on the one day
   it matters. */
.g-cta--survey { border-left: 3px solid var(--sb-accent); }

.g-empty {
  margin: 18px 0;
  padding: 28px;
  text-align: center;
  color: var(--c-ink-soft);
  background: var(--c-white);
  border: 1px dashed var(--c-blue-300);
  border-radius: var(--radius);
}

/* --- Dettaglio ------------------------------------------------------------- */
.g-detail { padding: 6px 0 8px; }
.g-detail__media {
  position: relative;
  aspect-ratio: 16 / 10;
  border-radius: var(--radius);
  overflow: hidden;
  min-height: 0; /* vedi .g-service__media */
  background: var(--c-azure-100);
  margin-bottom: 14px;
}
.g-detail__img { width: 100%; height: 100%; object-fit: cover; display: block; }
.g-detail__placeholder { position: absolute; inset: 0; display: grid; place-items: center; font-size: 3rem; font-weight: 800; color: var(--c-blue-300); }
.g-detail__badge { position: absolute; top: 12px; left: 12px; }
.g-detail__cat { margin: 0 0 2px; font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.4px; color: var(--c-blue-500); font-weight: 700; }
.g-detail__title { margin: 0 0 14px; font-size: 1.6rem; color: var(--c-blue-900); line-height: 1.15; }

/* §E23/UX — orari e prezzo: una scheda sola a righe piene.
   Prima erano due riquadri affiancati (`flex: 1 1 120px`) da ~170px in una
   colonna da 350px: il valore, a 1rem in grassetto, non ci stava e andava a
   capo su ogni riga. Ora la riga è larga quanto la colonna e giorni/orari si
   incolonnano in due tracce, come una tabella di apertura. */
/* La superficie sta su un modificatore, NON su `.g-facts`: il riepilogo del
   modulo usa le stesse righe dentro una card che ha già la sua, e i tre temi
   ridipingono le superfici con selettori più specifici — un reset sulla
   variante compatta perderebbe comunque. Meglio non darle mai lo stile card. */
.g-facts--card {
  margin-bottom: 16px;
  background: var(--c-white);
  border: 1px solid var(--c-azure-100);
  border-radius: 14px;
  overflow: hidden;
}
.g-fact { display: flex; gap: 12px; padding: 12px 14px; }
/* Il divisorio separa le righe SENZA chiudere la prima: un bordo in cima a
   ognuna tranne quella iniziale. */
.g-fact + .g-fact { border-top: 1px solid var(--sb-line, var(--c-azure-100)); }
.g-fact__icon { flex: none; margin-top: 1px; color: var(--c-blue-500); }
.g-fact__body { min-width: 0; flex: 1; }
.g-fact__label { display: block; font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.4px; color: var(--c-ink-soft); font-weight: 700; margin-bottom: 3px; }

/* Due tracce: la prima si adatta al giorno più lungo ("Tutti i giorni"), la
   seconda prende il resto. Allineando gli orari su una colonna sola la lista
   si scorre in verticale invece di rileggerla riga per riga. */
.g-fact__rows { display: grid; grid-template-columns: auto 1fr; gap: 2px 14px; align-items: baseline; }
.g-fact__key { color: var(--c-ink-soft); font-size: 0.92rem; font-weight: 500; }
/* `tabular-nums`: le cifre degli orari hanno tutte la stessa larghezza, quindi
   18:00–20:00 e 19:00–21:00 si incolonnano davvero. */
.g-fact__value {
  color: var(--c-blue-900); font-size: 0.92rem; font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.g-fact__value--wide { grid-column: 1 / -1; }
.g-fact__note { color: var(--c-ink-soft); font-size: 0.92rem; }

/* Riepilogo dentro il modulo di richiesta: niente etichette, che le icone
   bastano, e righe strette. La superficie non c'è perché non la si aggiunge
   (vedi `.g-facts--card`), non perché la si toglie. */
.g-facts--compact .g-fact { padding: 2px 0; }
.g-facts--compact .g-fact + .g-fact { border-top: 0; }
/* Nel riepilogo le due righe sono blocchi separati, quindi la seconda colonna
   non può allinearsi fra loro: meglio due frasi compatte che due mezze tabelle
   disallineate. */
.g-facts--compact .g-fact__rows { grid-template-columns: auto auto; justify-content: start; gap: 2px 8px; }

.g-detail__desc { color: var(--c-ink); line-height: 1.6; }
.g-detail__desc p { margin: 0 0 12px; }

/* --- Footer ---------------------------------------------------------------- */
.g-footer {
  margin-top: 28px;
  padding: 20px 0 8px;
  border-top: 1px solid var(--c-azure-100);
  text-align: center;
}
.g-footer__note { margin: 0; font-size: 0.78rem; color: var(--c-ink-soft); line-height: 1.6; }
.g-footer__contact { margin: 0 0 12px; }
.g-footer__name { margin: 0 0 2px; font-weight: 700; color: var(--c-ink); }
.g-footer__line { margin: 0; font-size: 0.85rem; color: var(--c-ink-soft); line-height: 1.5; }
.g-footer__link { color: var(--c-blue-700); text-decoration: none; }
.g-footer__link:hover { text-decoration: underline; }

/* --- Schermi più larghi ---------------------------------------------------- */
/* §E23/UX — la griglia NON passa più a 3 colonne su viewport ≥600px.
   `.g-app` è largo al massimo 560px: la colonna resta 520px comunque, e tre
   colonne lì dentro davano card da 165px, cioè PIÙ STRETTE dei 169px che si
   ottengono a 390px. Il layout peggiorava allargando lo schermo.
   Restando a due colonne la card cresce col contenitore: 169px a 390px, 254px
   a 760px. Il breakpoint era sul viewport, che qui non c'entra nulla. */
/* Sotto i 360px due colonne danno card da ~134px: il nome del servizio andava
   su tre righe e "35,00 € a persona" si spezzava. Meglio una colonna piena. */
@media (max-width: 359px) {
  .g-grid { grid-template-columns: 1fr; }
}

/* ==========================================================================
   §E4 — Richieste (ospite) e bacheca (Manage::)
   ========================================================================== */

/* --- Bottoni extra --------------------------------------------------------- */
.btn--block { display: flex; width: 100%; }
.chip--active { background: var(--c-blue-500); border-color: var(--c-blue-500); color: var(--c-white); }

/* --- Ospite: dettaglio CTA / servizio richiesto ---------------------------- */
.g-detail__cta { margin-top: 20px; }
.g-request-service {
  margin: 4px 0 16px;
  font-weight: 700;
  color: var(--c-blue-900);
  font-size: 1.1rem;
}

/* --- Ospite: schermata codice ---------------------------------------------- */
.g-code { text-align: center; }
.g-code__icon { font-size: 2.4rem; margin-bottom: 8px; }
.g-code__field {
  text-align: center;
  letter-spacing: 0.4em;
  text-transform: uppercase;
  font-size: 1.4rem;
  font-weight: 800;
}
.g-code__error { text-align: left; }

/* --- Ospite: conferma + stato ---------------------------------------------- */
.g-confirm { text-align: center; }
.g-confirm__check {
  width: 64px; height: 64px; margin: 0 auto 12px;
  border-radius: 50%;
  display: grid; place-items: center;
  background: rgba(70, 180, 80, 0.14);
  color: var(--c-ok);
  font-size: 2rem; font-weight: 800;
}
.g-status {
  display: inline-flex; align-items: center; gap: 9px;
  margin: 16px auto;
  padding: 9px 16px; border-radius: var(--radius-sm);
  font-weight: 700;
  background: var(--c-azure-100); color: var(--c-blue-700);
}
.g-status__dot { width: 10px; height: 10px; border-radius: 50%; background: currentColor; }
.g-status--received { background: var(--c-azure-100); color: var(--c-blue-700); }
.g-status--in_progress { background: #fff3d6; color: #8a5a00; }
.g-status--done { background: rgba(70, 180, 80, 0.14); color: var(--c-ok); }
.g-status--cancelled { background: #fdecec; color: var(--sb-danger, #C62828); }

/* --- "Le mie richieste" (Guest::) ------------------------------------------ */
.g-reqs { display: flex; flex-direction: column; gap: 12px; }
/* §E23/UX — i messaggi della reception vanno a capo su una riga tutta loro.
   `row-gap: 0` di proposito: il contenitore dei messaggi si rende SEMPRE (è il
   bersaglio del broadcast) e contiene spazi, quindi `:empty` non lo prende;
   con un gap di riga ogni richiesta senza messaggi si porterebbe dietro 12px
   di vuoto. Lo stacco quando servono lo dà il margine del titolo. */
.g-req {
  display: flex; flex-wrap: wrap; column-gap: 12px; row-gap: 0;
  justify-content: space-between; align-items: flex-start;
  padding: 14px 16px; border-radius: var(--radius-md, 14px);
  background: #fff; border: 1px solid var(--c-line, #e6edf3);
}
.g-req-notes { flex: 1 1 100%; min-width: 0; }
.g-req__main { min-width: 0; flex: 1; }
.g-req__subject { margin: 0 0 6px; font-weight: 700; color: var(--c-ink); line-height: 1.35; }
.g-req__pricing { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 6px; }
.g-req__people,
.g-req__price {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 0.8rem; font-weight: 600; padding: 2px 8px; border-radius: 999px;
  background: var(--c-azure-100); color: var(--c-blue-700);
}
.g-req__price { background: var(--sb-warn-bg, #FDF0DC); color: var(--sb-warn-fg, #92590F); }
.g-req__meta { margin: 0; font-size: 0.75rem; color: var(--c-ink-soft); }
.g-req__side { display: flex; flex-direction: column; align-items: flex-end; gap: 8px; flex-shrink: 0; }
.g-req__side .g-status { margin: 0; }
.g-req__cancel { display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; }

/* --- Bacheca (Manage::) ---------------------------------------------------- */
.board-counters {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 12px;
  margin: 0 0 20px;
}
.board-counter {
  background: var(--c-white);
  border: 1px solid var(--c-azure-100);
  border-radius: 16px;
  padding: 16px 18px;
  box-shadow: 0 6px 18px rgba(20, 94, 168, 0.08);
}
.board-counter__num { display: block; font-size: 1.8rem; font-weight: 800; color: var(--c-blue-900); line-height: 1; }
.board-counter__label { font-size: 0.82rem; color: var(--c-ink-soft); font-weight: 600; }
.board-counter--time .board-counter__num { color: var(--c-blue-500); }

.board-filter { display: flex; gap: 8px; flex-wrap: wrap; margin: 0 0 18px; }

.board {
  display: grid;
  grid-template-columns: 1fr;
  gap: 16px;
}
.board-col {
  background: rgba(255, 255, 255, 0.5);
  border: 1px solid var(--c-azure-100);
  border-radius: var(--radius);
  padding: 14px;
}
.board-col__title {
  margin: 0 0 12px;
  font-size: 0.95rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.4px;
  padding-left: 10px;
  border-left: 4px solid var(--c-blue-300);
}
.board-col__title--new { border-color: var(--c-blue-500); }
.board-col__title--progress { border-color: #ffb020; }
.board-col__title--done { border-color: var(--c-ok); }
.board-col__body { display: flex; flex-direction: column; gap: 12px; min-height: 40px; }

.req-card {
  background: var(--c-white);
  border: 1px solid var(--c-azure-100);
  border-radius: 16px;
  padding: 14px;
  box-shadow: 0 6px 18px rgba(20, 94, 168, 0.08);
}
/* Card arrivata in tempo reale: l'animazione parte da sola perché Turbo
   inserisce un nodo nuovo. */
@keyframes req-card-fresh {
  from { background: #eefaf0; box-shadow: 0 0 0 2px var(--sb-green); }
  to   { background: var(--c-white); box-shadow: 0 0 0 0 rgba(70, 180, 80, 0); }
}
.req-card--fresh { animation: req-card-fresh 1.6s ease-out 1; }
.req-card__head {
  display: flex; justify-content: space-between; align-items: flex-start; gap: 8px;
  margin-bottom: 12px; padding-bottom: 10px; border-bottom: 1px solid var(--sb-line, var(--c-azure-100));
}
.req-card__ident { display: flex; flex-direction: column; gap: 2px; }
.req-card__room { font-weight: 800; color: var(--c-blue-900); }
.req-card__guest { font-size: 0.85rem; font-weight: 600; color: var(--c-ink-soft); }
.req-card__badges { display: flex; flex-wrap: wrap; gap: 5px; justify-content: flex-end; }
.req-badge { padding: 2px 8px; border-radius: var(--radius-sm); font-size: 0.68rem; font-weight: 800; letter-spacing: 0.3px; }
.req-badge--lang { background: var(--c-azure-100); color: var(--c-blue-700); }
.req-badge--dep { background: #eef1f4; color: var(--c-ink-soft); text-transform: capitalize; }
.req-badge--ai { background: #efe6ff; color: #6b3fd0; }
.req-card__subject { margin: 0 0 2px; font-weight: 700; color: var(--c-ink); }
.req-card__body {
  margin: 0 0 4px; color: var(--c-ink); line-height: 1.4;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 4; line-clamp: 4; overflow: hidden;
}
.req-card__body--expanded { -webkit-line-clamp: unset; line-clamp: unset; overflow: visible; }
.req-card__more {
  margin: 0 0 8px; padding: 0; background: none; border: none; cursor: pointer;
  font: inherit; font-size: 0.82rem; font-weight: 600; color: #178bc3;
}
.req-card__more:hover { text-decoration: underline; }
.req-card__pricing { display: flex; flex-direction: column; align-items: flex-end; gap: 2px; margin: 0 0 8px; text-align: right; }
.req-card__people,
.req-card__price { font-size: 0.8rem; font-weight: 600; color: var(--c-blue-700); }
.req-card__price { color: var(--sb-warn-fg, #92590F); }
.req-card__time { margin: 0 0 6px; font-size: 0.85rem; color: var(--c-blue-700); font-weight: 600; }
.req-card__meta { margin: 0 0 10px; font-size: 0.75rem; color: var(--c-ink-soft); }
.req-card__actions { display: flex; gap: 8px; flex-wrap: wrap; justify-content: flex-end; align-items: center; }
.req-card__actions form { margin: 0; }
/* Annulla e Note restano a sinistra, le azioni principali a destra. Lo spazio
   elastico sta su Note perché è l'ultimo elemento del gruppo di sinistra ed è
   SEMPRE presente: l'annulla sparisce sulle richieste già annullate (§E20). */
.req-card__actions .req-card__notes { margin-right: auto; }
/* Annulla discreto: solo icona cestino, diventa rosso all'hover. Bordo, raggio e
   altezza sono quelli dei .btn--ghost che gli stanno accanto (§E20): senza, fra
   due pulsanti bordati sembrava un elemento non finito. Resta neutro a riposo —
   è un'azione distruttiva, ma secondaria: il rosso arriva quando ci si avvicina. */
.req-card__cancel-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 32px; height: 32px; padding: 0;
  border: 1px solid var(--sb-line); border-radius: var(--sb-r-btn);
  background: #fff; color: var(--c-ink-soft); cursor: pointer;
}
.req-card__cancel-btn:hover {
  background: #fdecec; border-color: #F1C7C7; color: var(--sb-danger, #C62828);
}

/* Storico richieste evase: giorno -> camera -> soggiorno -> item. */
/* Barra filtri dello storico: card dedicata sopra i giorni. */
.reqh-filters, .plan-filters, .rooms-filters, .mfilter-card { background: #fff; border: 1px solid var(--sb-line); border-radius: 16px; box-shadow: var(--sb-shadow); padding: 16px 20px; margin: 0 0 20px; }
.reqh-filter, .plan-filter, .rooms-filter { display: flex; align-items: flex-end; gap: 12px; flex-wrap: wrap; margin: 0; }
.reqh-filter__field, .plan-filter__field, .rooms-filter__field { display: flex; flex-direction: column; gap: 4px; font-size: 0.8rem; font-weight: 600; color: var(--c-ink-soft); }
/* Le azioni a destra finché c'è spazio; a capo con i campi quando manca. */
.reqh-filter__actions, .plan-filter__actions, .rooms-filter__actions { display: flex; align-items: flex-end; gap: 8px; margin-left: auto; }
/* Campi e pulsanti di una card filtri hanno la STESSA altezza: un "Azzera" più
   basso del campo che azzera si legge come un elemento di seconda classe.
   Il selettore a due classi batte l'altezza di .btn/.btn--sm dei layer tema. */
.reqh-filter .form__input, .plan-filter .form__input, .rooms-filter .form__input, .mfilter .form__input,
.reqh-filter .btn, .plan-filter .btn, .rooms-filter .btn, .mfilter .btn {
  height: 44px;
}
.reqh-day { background: #fff; border: 1px solid var(--sb-line); border-radius: 16px; box-shadow: var(--sb-shadow); padding: 18px 20px; margin: 0 0 20px; }
.reqh-day__title { margin: 0 0 14px; font-size: 1.05rem; color: var(--c-blue-900); font-family: var(--sb-display); text-transform: capitalize; }
/* Una RIGA per camera: etichetta a sinistra, card della giornata affiancate a
   destra (vanno a capo quando la riga è piena). */
.reqh-room { display: grid; grid-template-columns: 132px minmax(0, 1fr); gap: 16px; align-items: start; padding: 14px 0; border-top: 1px solid var(--sb-line-2); }
.reqh-room:first-of-type { border-top: 0; padding-top: 0; }
.reqh-room:last-child { padding-bottom: 0; }
.reqh-room__title { margin: 0; padding-top: 6px; font-size: 0.95rem; font-weight: 800; color: var(--c-ink); overflow-wrap: anywhere; }
.reqh-cards { display: flex; flex-wrap: wrap; gap: 12px; }

/* Card quadrata: il bordo colorato è lo stato (verde evasa / rosso annullata).
   L'altezza è fissata dall'aspect-ratio, quindi ogni blocco di testo va troncato
   o il contenuto sborderebbe. */
.reqh-card {
  width: 200px; aspect-ratio: 1 / 1; display: flex; flex-direction: column; gap: 6px;
  padding: 12px; border-radius: 14px; background: #fff;
  border: 2px solid var(--sb-line); box-shadow: 0 4px 14px rgba(20, 94, 168, 0.07);
  overflow: hidden;
}
.reqh-card--done { border-color: var(--sb-green); }
.reqh-card--cancelled { border-color: var(--sb-danger, #C62828); }
.reqh-card__head { display: flex; align-items: center; justify-content: space-between; gap: 6px; }
.reqh-card__time { font-size: 0.9rem; font-weight: 800; color: var(--c-ink); }
.reqh-card__state { flex: none; font-size: 0.65rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.03em; padding: 2px 8px; border-radius: 999px; }
.reqh-card--done .reqh-card__state { background: rgba(70, 180, 80, 0.14); color: var(--sb-green-fg, #147045); }
.reqh-card--cancelled .reqh-card__state { background: #fdecec; color: var(--sb-danger, #C62828); }
.reqh-card__name { margin: 0; font-size: 0.82rem; font-weight: 700; color: var(--c-ink); display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; overflow: hidden; }
.reqh-card--cancelled .reqh-card__name { text-decoration: line-through; color: var(--c-ink-soft); }
.reqh-card__text { margin: 0; flex: 1; min-height: 0; font-size: 0.78rem; color: var(--c-ink-soft); display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; line-clamp: 3; overflow: hidden; }
.reqh-card__foot { margin-top: auto; padding-top: 8px; border-top: 1px solid var(--sb-line-2); display: flex; flex-direction: column; gap: 2px; }
.reqh-card__guest { font-size: 0.75rem; font-weight: 700; color: var(--sb-primary, #178bc3); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.reqh-card__guest--none { font-weight: 600; color: var(--c-ink-soft); }
.reqh-card__staff { font-size: 0.7rem; font-weight: 600; color: var(--c-ink-soft); display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; overflow: hidden; }
/* Il pulsante note si stacca dalle due righe di testo del piede (§E20). */
.reqh-card__notes { align-self: flex-end; margin-top: 6px; }

/* Sotto i 720px l'etichetta della camera passa sopra le card. */
@media (max-width: 720px) {
  .reqh-room { grid-template-columns: minmax(0, 1fr); gap: 10px; }
  .reqh-room__title { padding-top: 0; }
}

/* Planning soggiorni (§E5): camere in riga, giorni in colonna, una barra per
   soggiorno. Un solo contenitore scorre entrambi gli assi — `overflow-x: auto`
   calcola comunque `overflow-y: auto`, quindi la testata dei giorni può essere
   sticky solo rispetto a questo elemento, che va limitato in altezza. */
.plan { background: #fff; border: 1px solid var(--sb-line); border-radius: 16px; box-shadow: var(--sb-shadow); padding: 12px; }
.plan__scroll {
  --plan-day-w: 40px; --plan-room-w: 110px;
  position: relative; overflow: auto; max-height: calc(100vh - 300px);
}
.plan__head {
  display: grid; grid-template-columns: var(--plan-room-w) repeat(var(--plan-days), var(--plan-day-w));
  position: sticky; top: 0; z-index: 3; background: #fff; border-bottom: 1px solid var(--sb-line);
}
.plan__corner {
  position: sticky; left: 0; z-index: 4; background: #fff;
  display: flex; align-items: flex-end; padding: 4px 8px 8px;
  font-size: 0.72rem; font-weight: 700; color: var(--c-ink-soft);
}
.plan__day {
  display: flex; flex-direction: column; align-items: center; gap: 1px; padding: 6px 0 8px;
  font-size: 0.7rem; color: var(--c-ink-soft); border-left: 1px solid var(--sb-line-2);
}
.plan__day--weekend { background: var(--sb-bg-2); }
.plan__day--today { color: var(--sb-warn-fg); font-weight: 800; }
.plan__day__dow { text-transform: uppercase; letter-spacing: 0.02em; }
.plan__day__num { font-size: 0.85rem; font-weight: 700; color: var(--c-ink); }
.plan__day--today .plan__day__num { color: var(--sb-warn-fg); }

/* La riga ha la stessa larghezza totale della testata: le colonne si allineano
   senza subgrid. */
.plan__row {
  display: grid; grid-template-columns: var(--plan-room-w) calc(var(--plan-days) * var(--plan-day-w));
  width: calc(var(--plan-room-w) + var(--plan-days) * var(--plan-day-w));
  border-bottom: 1px solid var(--sb-line-2);
}
.plan__room {
  position: sticky; left: 0; z-index: 2; background: #fff;
  display: flex; align-items: center; padding: 6px 8px;
  font-weight: 700; font-size: 0.85rem; color: var(--c-ink); overflow-wrap: anywhere;
}
.plan__lanes { display: flex; flex-direction: column; gap: 5px; padding: 7px 0; min-width: 0; }
/* Le linee dei giorni sono un gradiente, non celle: 30 camere × 92 giorni
   sarebbero quasi 3.000 nodi vuoti. */
.plan__lane {
  display: grid; grid-template-columns: repeat(var(--plan-days), var(--plan-day-w));
  height: 38px;
  background-image: repeating-linear-gradient(to right,
    transparent 0 calc(var(--plan-day-w) - 1px),
    var(--sb-line-2) calc(var(--plan-day-w) - 1px) var(--plan-day-w));
}

/* Barra e tessera della legenda condividono i colori: due elenchi di selettori
   invece di due palette che prima o poi divergono. */
.plan__bar, .plan__key__swatch {
  background: var(--sb-chip); color: var(--sb-primary-2);
  border-left: 3px solid var(--sb-primary);
}
.plan__bar {
  display: flex; align-items: center; min-width: 0; height: 100%;
  padding: 0 8px; border-radius: 8px; text-decoration: none;
  font-size: 0.78rem; font-weight: 700;
}
.plan__bar:hover { filter: brightness(0.97); }
.plan__bar__name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Mai testo bianco su --sb-green (2.8:1): tinta chiara + testo scuro. */
.plan__bar--checked_in, .plan__key__swatch--checked_in { background: rgba(70, 180, 80, 0.18); color: var(--sb-green-fg); border-left-color: var(--sb-green); }
.plan__bar--checked_out, .plan__key__swatch--checked_out { background: var(--sb-bg-2); color: var(--sb-muted); border-left-color: var(--sb-line); }
.plan__bar--overdue, .plan__key__swatch--overdue { background: var(--sb-warn-bg); color: var(--sb-warn-fg); border-left-color: var(--sb-accent); }

/* Legenda dei colori: sopra la griglia, allineata a destra. */
.plan__key { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 6px 16px; margin: 0 2px 10px; font-size: 0.78rem; color: var(--c-ink-soft); }
.plan__key__item { display: inline-flex; align-items: center; gap: 6px; }
.plan__key__swatch { width: 18px; height: 14px; border-radius: 5px; flex: none; }
/* Tagliata dal bordo del periodo (il soggiorno continua fuori) vs aperta perché
   la data non è indicata: due fatti diversi, due segni diversi. */
.plan__bar--clip-start { border-top-left-radius: 0; border-bottom-left-radius: 0; border-left-style: double; }
.plan__bar--clip-end { border-top-right-radius: 0; border-bottom-right-radius: 0; }
.plan__bar--open-start { border-left-style: dashed; }
.plan__bar--open-end { border-right: 2px dashed currentColor; }

/* Colonna di oggi: un solo overlay assoluto, non un marcatore per riga. */
.plan__today {
  position: absolute; top: 0; bottom: 0; pointer-events: none; z-index: 1;
  left: calc(var(--plan-room-w) + var(--plan-day-w) * var(--plan-today));
  width: var(--plan-day-w);
  background: rgba(242, 140, 0, 0.10);
  border-inline: 1px solid var(--sb-accent);
}
.plan__legend { margin: 10px 2px 0; font-size: 0.8rem; color: var(--c-ink-soft); }

@media (max-width: 720px) {
  .plan__scroll { --plan-day-w: 28px; --plan-room-w: 64px; max-height: none; }
  .plan__bar__name { display: none; }
}

@media (min-width: 720px) {
  .board-counters { grid-template-columns: repeat(4, 1fr); }
  .board { grid-template-columns: repeat(3, 1fr); align-items: start; }
}

/* ==========================================================================
   §E5 — CRUD gestione (Manage::)
   ========================================================================== */
.mnav {
  display: flex;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
  max-width: 1120px;
  margin: 0 auto;
  padding: 14px 24px;
}
.mnav__brand { font-weight: 800; color: var(--c-blue-900); }
.mnav__links { display: flex; gap: 6px; flex-wrap: wrap; flex: 1; }
.mnav__link {
  padding: 7px 12px; border-radius: 10px; text-decoration: none;
  color: var(--c-blue-700); font-weight: 600; font-size: 0.9rem;
}
.mnav__link:hover { background: var(--c-azure-100); }
.mnav__link--active { background: var(--c-blue-500); color: var(--c-white); }
.mnav__signout {
  border: 1px solid var(--c-azure-100); background: var(--c-white);
  color: var(--c-blue-700); border-radius: 10px; padding: 7px 12px;
  font-weight: 600; font-size: 0.85rem; cursor: pointer; font-family: inherit;
}

.form__row--check { display: flex; align-items: center; gap: 10px; }
.form__row--check .form__label { margin: 0; }

.chip--danger { background: #fdecec; border-color: #f3c9c9; color: var(--sb-danger, #C62828); }
.chip--danger:hover { background: #f9dada; }

/* Tiles dashboard */
.mtiles { display: grid; grid-template-columns: repeat(2, 1fr); gap: 14px; }
@media (min-width: 600px) { .mtiles { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 900px) { .mtiles { grid-template-columns: repeat(4, 1fr); } }
.mtile {
  aspect-ratio: 4 / 3;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px;
  padding: 16px; border-radius: var(--radius); text-align: center;
  background: #178bc3; border: 1px solid transparent;
  box-shadow: var(--shadow); text-decoration: none; color: #fff;
  font-weight: 700;
}
.mtile:hover { background: #46b450; border-color: transparent; }
.mtile__icon { font-size: 1.6rem; }

/* Dashboard: griglia unica a 5 colonne. Le card occupano le prime 4, il rail AI
   la 5ª — così il rail è largo come un contatore del riepilogo e le card si
   riducono sui monitor grandi. */
.dash-body { display: grid; grid-template-columns: 1fr; gap: 14px; }
@media (min-width: 900px) {
  .dash-body--with-ai { grid-template-columns: repeat(5, 1fr); align-items: start; }
  .dash-body--with-ai .mtiles { grid-column: 1 / 5; }
  .dash-body--with-ai .dash-ai { grid-column: 5 / 6; }
}
.dash-ai { margin: 0; }
/* Nel rail stretto i KPI vanno impilati (batte la media query .kpi-grid a repeat(4,1fr)). */
.dash-ai .kpi-grid { grid-template-columns: 1fr; max-width: none; }
/* Stacco fra i KPI e il bottone "Statistiche complete". */
.dash-ai .btn { margin-top: 16px; }
/* Riepilogo: stesse colonne del corpo (2 → 3 → 5) così si allinea alle card e al rail. */
.dash-summary { grid-template-columns: repeat(2, 1fr); gap: 14px; }
@media (min-width: 600px) { .dash-summary { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 900px) { .dash-summary { grid-template-columns: repeat(5, 1fr); } }

/* Liste servizi / documenti / stay */
/* Lista servizi: categoria come banda + servizi come griglia di card. */
.msvc-cat-card { background: #fff; border: 1px solid var(--sb-line); border-radius: 16px; box-shadow: var(--sb-shadow); overflow: hidden; margin: 0 0 20px; }
.msvc-cat { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 13px 18px; background: var(--sb-chip); border-bottom: 1px solid var(--sb-line); }
.msvc-cat__title { display: flex; align-items: center; gap: 10px; min-width: 0; }
.msvc-cat__icon { display: inline-flex; width: 34px; height: 34px; border-radius: 9px; background: #178bc3; color: #fff; align-items: center; justify-content: center; flex: none; }
.msvc-cat__name { margin: 0; font-size: 1.1rem; color: var(--c-blue-900); font-family: var(--sb-display); }
.msvc-cat__count { font-size: 0.8rem; font-weight: 600; color: var(--c-ink-soft); }
.msvc-cat__actions { display: flex; gap: 8px; flex-wrap: wrap; }
.msvc-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: 12px; padding: 16px 18px; }
.msvc-card { display: flex; flex-direction: column; gap: 8px; border: 1px solid var(--sb-line); border-radius: 12px; padding: 14px; background: #fff; }
.msvc-card:hover { border-color: #178bc3; box-shadow: var(--sb-shadow); }
.msvc-card__name { margin: 0; font-weight: 700; color: var(--c-ink); font-size: 0.95rem; }
.msvc-card__price { margin: 0; font-weight: 700; color: #178bc3; font-size: 0.9rem; }
.msvc-card__badges { display: flex; gap: 6px; flex-wrap: wrap; margin-top: auto; }
.msvc-card__actions { display: flex; gap: 6px; flex-wrap: wrap; padding-top: 8px; border-top: 1px solid var(--sb-line); }
.msvc-cat__actions form, .msvc-card__actions form { margin: 0; }

/* Pulsante-icona per azioni compatte (traduzioni / modifica / elimina). */
.icon-btn {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: 32px; height: 32px; padding: 0; border: 1px solid var(--sb-line); border-radius: 9px;
  background: #fff; color: var(--c-ink-soft); cursor: pointer; text-decoration: none;
}
.icon-btn:hover { border-color: #178bc3; color: #178bc3; }
.icon-btn--danger:hover { border-color: var(--sb-danger, #C62828); color: var(--sb-danger, #C62828); background: #fdecec; }
.icon-btn--warn { border-color: #f0dcb8; color: var(--sb-warn-fg, #92590F); background: var(--sb-warn-bg, #FDF0DC); }
.icon-btn--warn:hover { border-color: #e6c98a; }
.msvc-list, .mstay-list { list-style: none; margin: 8px 0 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.msvc-row, .mstay-row {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 12px 14px; border-radius: 12px; background: var(--c-azure-50);
  border: 1px solid var(--c-azure-100);
}
.msvc-row__main, .mstay-row__main { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.msvc-row__name, .mstay-row__room { font-weight: 700; color: var(--c-ink); }
.msvc-row__actions { display: flex; gap: 6px; }
.msvc-empty { color: var(--c-ink-soft); margin: 0; padding: 16px 18px; font-size: 0.9rem; }
.msvc-thumb { border-radius: 10px; margin: 6px 0; display: block; }
.mstay-row__guest { color: var(--c-ink); }
.mstay-row__period { color: var(--c-ink-soft); font-size: 0.9rem; }
.mstay-actions { display: flex; gap: 10px; flex-wrap: wrap; }

/* Riordino drag & drop (Sortable.js) di categorie e servizi. Le maniglie hanno
   classi diverse perché le liste sono annidate: una classe sola farebbe partire
   il drag della categoria dalla maniglia di una card. */
.msvc-cat__drag, .msvc-card__drag {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  color: #999; cursor: grab; touch-action: none; user-select: none;
}
.msvc-cat__drag { width: 24px; height: 24px; }
/* Sulla card servizio la maniglia sta accanto al titolo: più piccola, non deve
   competere con il nome. */
.msvc-card__drag { width: 18px; height: 18px; }
/* I sei punti a stroke 2 sparivano del tutto: ingrossati restano leggibili
   anche in grigio chiaro e senza cornice. */
.msvc-cat__drag .icon, .msvc-card__drag .icon { stroke-width: 3.4; }
.msvc-cat__drag:hover, .msvc-card__drag:hover { color: #178bc3; }
.msvc-cat__drag:active, .msvc-card__drag:active { cursor: grabbing; color: #178bc3; }
.msvc-card__head { display: flex; align-items: flex-start; gap: 6px; }
.msvc-card__head .msvc-card__name { flex: 1 1 auto; min-width: 0; }

/* Segnaposto lasciato dall'elemento in volo. */
.msvc-cat-card.sortable-ghost, .msvc-card.sortable-ghost {
  background: var(--sb-chip); border: 1px dashed #178bc3; box-shadow: none;
}
.msvc-cat-card.sortable-ghost > *, .msvc-card.sortable-ghost > * { visibility: hidden; }
.sortable-chosen { cursor: grabbing; }
.msvc-cat-card.sortable-drag, .msvc-card.sortable-drag { box-shadow: 0 12px 28px rgba(11, 58, 102, 0.22); }

/* Una categoria senza servizi deve restare un bersaglio di drop: la griglia
   c'è sempre, con il segnaposto dentro. */
.msvc-grid { min-height: 56px; }
.msvc-grid > .msvc-empty { grid-column: 1 / -1; padding: 6px 0; }

.msvc-badge { padding: 2px 9px; border-radius: var(--radius-sm); font-size: 0.7rem; font-weight: 800; }
.msvc-badge--on { background: rgba(70,180,80,0.14); color: var(--c-ok); }
.msvc-badge--off { background: #eef1f4; color: var(--c-ink-soft); }
.msvc-badge--ext { background: #efe6ff; color: #6b3fd0; }
/* Indicizzato: c'è, ma solo per l'assistente — né il verde del pubblicato né il
   grigio della bozza. */
.msvc-badge--ai { background: rgba(23,139,195,0.14); color: #0f6b98; }

/* Card FAQ: stessa anatomia delle card servizio (testa, corpo, badge in basso,
   azioni sotto una riga di separazione), senza il contenitore categoria — le FAQ
   sono una lista piatta. Card più larghe dei servizi: domanda e risposta sono
   testo esteso, non un'etichetta. */
.mfaq-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 12px; margin-top: 8px; }
.mfaq-card { display: flex; flex-direction: column; gap: 8px; border: 1px solid var(--sb-line); border-radius: 12px; padding: 14px; background: #fff; }
.mfaq-card:hover { border-color: #178bc3; box-shadow: var(--sb-shadow); }
.mfaq-card__head { display: flex; align-items: flex-start; gap: 8px; min-width: 0; }
.mfaq-card__icon { display: inline-flex; width: 30px; height: 30px; border-radius: 9px; background: var(--sb-chip); color: #178bc3; align-items: center; justify-content: center; flex: none; }
.mfaq-card__question { margin: 0; font-weight: 700; color: var(--c-ink); font-size: 0.95rem; overflow-wrap: anywhere; }
.mfaq-card__answer { margin: 0; font-size: 0.85rem; color: var(--c-ink-soft); overflow-wrap: anywhere; }
.mfaq-card__badges { display: flex; gap: 6px; flex-wrap: wrap; margin-top: auto; }
.mfaq-card__actions { display: flex; gap: 6px; flex-wrap: wrap; padding-top: 8px; border-top: 1px solid var(--sb-line); }
.mfaq-card__actions form { margin: 0; }
/* §E27 — messaggi programmati all'ospite. Stessa card di FAQ e documenti, con
   due righe in più: quando scatta e a chi arriva. Sono l'informazione che conta
   in questa lista (il titolo dice cosa, la programmazione dice quando), quindi
   stanno nel corpo della card e non fra i badge. */
.mmsg-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 12px; margin-top: 8px; }
.mmsg-card { display: flex; flex-direction: column; gap: 8px; border: 1px solid var(--sb-line); border-radius: 12px; padding: 14px; background: #fff; }
.mmsg-card:hover { border-color: #178bc3; box-shadow: var(--sb-shadow); }
.mmsg-card__head { display: flex; align-items: flex-start; gap: 8px; min-width: 0; }
.mmsg-card__icon { display: inline-flex; width: 30px; height: 30px; border-radius: 9px; background: var(--sb-chip); color: #178bc3; align-items: center; justify-content: center; flex: none; }
.mmsg-card__title { margin: 0; font-weight: 700; color: var(--c-ink); font-size: 0.95rem; overflow-wrap: anywhere; }
.mmsg-card__body { margin: 0; font-size: 0.85rem; color: var(--c-ink-soft); overflow-wrap: anywhere; }
.mmsg-card__schedule, .mmsg-card__audience {
  display: flex; align-items: center; gap: 6px; margin: 0;
  font-size: 0.8rem; font-weight: 600; color: var(--sb-primary-2); overflow-wrap: anywhere;
}
.mmsg-card__audience { color: var(--c-ink-soft); font-weight: 500; }
.mmsg-card__schedule .icon, .mmsg-card__audience .icon { flex: none; }
.mmsg-card__badges { display: flex; gap: 6px; flex-wrap: wrap; margin-top: auto; }
.mmsg-card__actions { display: flex; gap: 6px; flex-wrap: wrap; padding-top: 8px; border-top: 1px solid var(--sb-line); }
.mmsg-card__actions form { margin: 0; }

/* Maniglia delle card riordinabili (FAQ, documenti, messaggi): stessa resa di
   quella dei servizi (vedi .msvc-card__drag). */
.mfaq-card__drag, .mdoc-card__drag, .mmsg-card__drag {
  display: inline-flex; align-items: center; justify-content: center;
  width: 18px; height: 18px; flex: none; margin-top: 6px;
  color: var(--c-ink-soft); cursor: grab; touch-action: none;
}
.mfaq-card__drag .icon, .mdoc-card__drag .icon, .mmsg-card__drag .icon { stroke-width: 3.4; }
.mfaq-card__drag:hover, .mdoc-card__drag:hover, .mmsg-card__drag:hover { color: #178bc3; }
.mfaq-card__drag:active, .mdoc-card__drag:active, .mmsg-card__drag:active { cursor: grabbing; color: #178bc3; }
.mfaq-card.sortable-ghost, .mdoc-card.sortable-ghost, .mmsg-card.sortable-ghost {
  background: var(--sb-chip); border: 1px dashed #178bc3;
}
.mfaq-card.sortable-ghost > *, .mdoc-card.sortable-ghost > *, .mmsg-card.sortable-ghost > * { visibility: hidden; }
.mfaq-card.sortable-drag, .mdoc-card.sortable-drag, .mmsg-card.sortable-drag { box-shadow: 0 12px 28px rgba(11, 58, 102, 0.22); }
/* Il `margin-top` serve alla testa FAQ, allineata in alto perché la domanda va
   a capo; quella del documento è centrata e non lo vuole. */
.mdoc-card__drag { margin-top: 0; }

/* Liste con form nel rail destro (documenti, FAQ): card a sinistra, form per
   aggiungere a destra (stesso schema del rail AI in dashboard). Sotto i 1000px
   si impila, con le card sempre per prime. */
.mlist-layout { display: grid; grid-template-columns: 1fr; gap: 16px; }
.mlist-layout > * { min-width: 0; }
.mlist-layout > .panel__section { margin: 0; }
/* Colonna sinistra: card filtri sopra la card dell'elenco (come .rooms-main). */
.mlist-main > .panel__section { margin: 0; }
@media (min-width: 1000px) {
  .mlist-layout { grid-template-columns: minmax(0, 1fr) 340px; align-items: start; }
}

/* Card documento: stessa anatomia delle card servizio (testa, corpo, badge in
   basso, azioni sotto una riga di separazione), riordinabili trascinando come
   le FAQ. La colonna è stretta per via del rail, quindi le card partono da
   230px: sotto quella soglia il titolo andava a capo a ogni parola. */
.mdoc-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 12px; margin-top: 8px; }
.mdoc-card { display: flex; flex-direction: column; gap: 8px; border: 1px solid var(--sb-line); border-radius: 12px; padding: 14px; background: #fff; }
.mdoc-card:hover { border-color: #178bc3; box-shadow: var(--sb-shadow); }
.mdoc-card__head { display: flex; align-items: center; gap: 8px; min-width: 0; }
.mdoc-card__icon { display: inline-flex; width: 30px; height: 30px; border-radius: 9px; background: var(--sb-chip); color: #178bc3; align-items: center; justify-content: center; flex: none; }
.mdoc-card__name { margin: 0; font-weight: 700; color: var(--c-ink); font-size: 0.95rem; overflow-wrap: anywhere; }
.mdoc-card__body { margin: 0; font-size: 0.85rem; color: var(--c-ink-soft); }
.mdoc-card__files { display: flex; flex-wrap: wrap; gap: 6px; }
.mdoc-card__files .chip { max-width: 100%; overflow-wrap: anywhere; }
.mdoc-card__badges { display: flex; gap: 6px; flex-wrap: wrap; margin-top: auto; }
.mdoc-card__actions { display: flex; gap: 6px; flex-wrap: wrap; padding-top: 8px; border-top: 1px solid var(--sb-line); }
.mdoc-card__actions form { margin: 0; }

/* Filtri di una lista (documenti, FAQ, servizi): ricerca + stato su una riga
   sola finché c'è spazio, in una CARD sopra l'elenco — come nella pagina camere.
   Vedi manage/shared/_filter_bar. */
.mfilter { display: flex; align-items: flex-end; gap: 12px; flex-wrap: wrap; margin: 0; }
.mfilter__field { display: flex; flex-direction: column; gap: 4px; font-size: 0.8rem; font-weight: 600; color: var(--c-ink-soft); }
.mfilter__field--grow { flex: 1 1 220px; min-width: 0; }
/* Le azioni a destra finché c'è spazio, come nelle altre card filtri. */
.mfilter__actions { display: flex; align-items: flex-end; gap: 8px; margin-left: auto; }

/* File allegati nel form di modifica: nome scaricabile + spunta di rimozione. */
.mdoc-files { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.mdoc-files__item { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.mdoc-files__remove { display: flex; align-items: center; gap: 6px; font-size: 0.85rem; color: var(--c-ink-soft); }

/* Dropzone documenti */
.dropzone {
  border: 2px dashed var(--c-blue-300); border-radius: 14px;
  padding: 20px; text-align: center; background: var(--c-azure-50);
}
.dropzone__hint { margin: 8px 0 0; font-size: 0.82rem; color: var(--c-ink-soft); }

/* Codice accesso */
.access-panel { border-color: var(--c-blue-300); }
.access-code {
  background: var(--c-blue-900); color: var(--c-white);
  border-radius: 16px; padding: 20px; text-align: center; margin-bottom: 14px;
}
.access-code__label { margin: 0 0 6px; font-size: 0.8rem; opacity: 0.8; text-transform: uppercase; letter-spacing: 0.5px; }
.access-code__value {
  margin: 0; font-size: 2.4rem; font-weight: 800; letter-spacing: 0.35em;
  font-family: "SF Mono", ui-monospace, monospace;
}
.access-code__until { margin: 8px 0 0; font-size: 0.9rem; opacity: 0.9; }
.access-code__note { margin: 10px 0 0; font-size: 0.8rem; opacity: 0.75; }
.access-status { font-weight: 600; color: var(--c-blue-900); margin: 0 0 6px; }


/* ==========================================================================
   §E6 — Statistiche (Manage::)
   ========================================================================== */
.stats-grid { display: grid; grid-template-columns: 1fr; gap: 16px; }
.stat-card {
  background: var(--c-white); border: 1px solid var(--c-azure-100);
  border-radius: var(--radius); box-shadow: var(--shadow); padding: 20px 22px;
}
.stat-card--soon { opacity: 0.75; }
.stat-card__title { margin: 0 0 16px; font-size: 1.05rem; color: var(--c-blue-900); }
.stat-empty { color: var(--c-ink-soft); margin: 0; font-size: 0.9rem; }

.stat-bars { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.stat-bar { display: grid; grid-template-columns: 120px 1fr 40px; align-items: center; gap: 10px; }
.stat-bar__label { font-size: 0.88rem; color: var(--c-ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.stat-bar__track { height: 10px; background: var(--c-azure-100); border-radius: var(--radius-sm); overflow: hidden; }
/* Il colore arriva per `currentColor` dalla classe tono della barra
   (`.stat-seg--N`, la categoria del servizio). */
.stat-bar__fill { display: block; height: 100%; background: currentColor; border-radius: var(--radius-sm); }
.stat-bar__value { text-align: right; font-weight: 700; color: var(--c-blue-700); font-size: 0.9rem; }

.stat-counters { display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; }
.stat-counter { background: var(--c-azure-50); border-radius: 14px; padding: 14px 16px; }
.stat-counter__num { display: block; font-size: 1.7rem; font-weight: 800; color: var(--c-blue-900); line-height: 1; }
.stat-counter__label { font-size: 0.82rem; color: var(--c-ink-soft); font-weight: 600; }

/* Le quattro fasi di una richiesta, con i colori che il pannello usa già altrove
   (`.mreq__status--*`): non si inventa un quinto vocabolario di stato. Sono
   colori RISERVATI, non tinte di serie — non compaiono mai nei grafici accanto.
   L'etichetta sotto il numero resta sempre: il colore non è mai l'unico segnale. */
.stat-counter--received    { background: var(--sb-chip); }
.stat-counter--in_progress { background: var(--sb-warn-bg); }
.stat-counter--done        { background: #E7F5EC; }
.stat-counter--cancelled   { background: #FDECEC; }
.stat-counter--received    .stat-counter__num { color: var(--sb-primary-2); }
.stat-counter--in_progress .stat-counter__num { color: var(--sb-warn-fg); }
.stat-counter--done        .stat-counter__num { color: var(--sb-green-fg); }
.stat-counter--cancelled   .stat-counter__num { color: var(--sb-danger); }

.stat-hours { display: flex; align-items: flex-end; gap: 3px; height: 120px; padding-top: 8px; }
.stat-hours__col { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: flex-end; height: 100%; position: relative; }
/* Come le barre: il colore viene dalla fascia oraria (`.stat-band--*`). */
.stat-hours__bar { width: 100%; min-height: 2px; background: currentColor; border-radius: 4px 4px 0 0; }
.stat-hours__tick { position: absolute; bottom: -18px; font-size: 0.65rem; color: var(--c-ink-soft); }

/* --- Andamento della media dei feedback (§E29.4) ------------------------------
   Non riusa `.stat-hours*` benché la forma sia la stessa: lì l'altezza è un
   conteggio rapportato al massimo della serie, qui è già una percentuale su un
   asse FISSO 0-100. Stesso vocabolario visivo, unità diversa — e con il nome
   dell'altro grafico la differenza sparirebbe dalla vista. */
.stat-trend { display: flex; gap: 10px; padding: 8px 0 22px; }
.stat-trend__scale {
  list-style: none; margin: 0; padding: 0; flex: 0 0 auto;
  display: flex; flex-direction: column; justify-content: space-between;
  height: 140px; font-size: 0.65rem; color: var(--c-ink-soft);
  font-variant-numeric: tabular-nums;
}
/* La riga a metà altezza è il 50 dell'asse: un'altezza che È una percentuale,
   senza un riferimento a metà scala, si legge a occhio e male. */
.stat-trend__plot {
  flex: 1; min-width: 0; display: flex; align-items: flex-end; gap: 3px; height: 140px;
  border-bottom: 1px solid var(--sb-line);
  background: linear-gradient(var(--sb-line-2), var(--sb-line-2)) no-repeat center / 100% 1px;
}
.stat-trend__col {
  flex: 1; min-width: 0; height: 100%; position: relative;
  display: flex; flex-direction: column; justify-content: flex-end;
}
/* Come le altre barre: il colore arriva per `currentColor` dalla classe tono. */
.stat-trend__bar { width: 100%; min-height: 2px; background: currentColor; border-radius: 4px 4px 0 0; }
/* Ancorata a sinistra e non centrata: sulle colonne strette un'etichetta
   centrata sulla prima uscirebbe dal grafico. */
.stat-trend__tick {
  position: absolute; bottom: -20px; left: 0;
  font-size: 0.65rem; color: var(--c-ink-soft); white-space: nowrap;
}

/* Riga KPI dell'attività ospiti: piena larghezza come la griglia sottostante e
   con lo stacco che .kpi-grid non ha (stessa scelta di .mconv-kpis). */
.stats-kpis { max-width: none; margin: 0 0 16px; }

/* Chip di periodo dentro la card: i 18px di .board-filter sono pensati per una
   barra a sé e qui staccherebbero troppo dai campi data. */
.mfilter-card > .board-filter { margin: 0 0 12px; }

/* Preset di periodo fuori dal piano: reso e spento, con la spiegazione nel
   title (views/CLAUDE.md §7). Non è un link: non c'è niente da aprire. */
.chip--locked {
  display: inline-flex; align-items: center; gap: 5px;
  background: var(--sb-bg); border-color: var(--sb-line);
  color: var(--sb-muted-2); cursor: not-allowed;
}
.chip--locked:hover { background: var(--sb-bg); }

/* --- Barra a segmenti delle lingue -------------------------------------------
   Nessuna libreria di grafici (importmap, niente Node): il markup è la barra e i
   colori stanno qui. Il colore arriva per `currentColor` dalla classe di passo,
   così la stessa classe tinge il segmento e il pallino della legenda senza
   duplicare la rampa. */
.stat-stack-wrap { margin: 4px 0 0; }
.stat-stack {
  display: flex; height: 14px; border-radius: 999px; overflow: hidden;
  background: var(--sb-line-2);
}
/* Il bordo bianco separa i passi contigui senza rubare spazio al totale
   (box-sizing: border-box), quindi le larghezze continuano a sommare a 100%. */
.stat-stack__seg { min-width: 3px; box-sizing: border-box; background: currentColor; border-right: 2px solid #fff; }
.stat-stack__seg:last-child { border-right: none; }

.stat-legend {
  list-style: none; margin: 0; padding: 0; flex: 1 1 180px; min-width: 0;
  display: flex; flex-direction: column; gap: 8px;
}
.stat-legend__item { display: flex; align-items: center; gap: 8px; font-size: 0.86rem; }
.stat-legend__dot { width: 10px; height: 10px; border-radius: 50%; background: currentColor; flex: 0 0 auto; }
.stat-legend__label { color: var(--sb-ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.stat-legend__value {
  margin-left: auto; font-weight: 700; color: var(--sb-primary-2);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
/* Legenda su una riga: sotto la barra delle lingue, sopra gli altri due grafici. */
.stat-legend--inline { flex-direction: row; flex-wrap: wrap; gap: 6px 16px; margin: 0 0 14px; }
.stat-legend--inline .stat-legend__item { font-size: 0.8rem; }
.stat-stack-wrap .stat-legend--inline { margin: 12px 0 0; }
/* La sigla della lingua non è un'abbreviazione da sottolineare: il nome per
   esteso resta nel title, ma senza il tratteggio del browser. */
.stat-legend__label abbr { text-decoration: none; font-weight: 700; }

/* --- Tinte categoriche (barre dei servizi) -----------------------------------
   Quattro tinte da token esistenti. L'ordine non è a gusto: è il migliore fra
   tutte le combinazioni dei token del progetto, scelto massimizzando la distanza
   minima fra tinte (skill `dataviz`, scripts/validate_palette.js).

   Il test è quello ALL-PAIRS, non solo sulle coppie adiacenti: in un elenco due
   categorie QUALSIASI possono finire una sopra l'altra. Con le due sole famiglie
   del marchio — indaco e arancio — nessun insieme di cinque lo supera; questi
   quattro sì, con un peggior accoppiamento di ΔE 15.5 in protanopia.

   Il colore non porta MAI l'informazione da solo: ogni barra ha nome e numero
   accanto, e la legenda ripete le categorie. */
.stat-seg--1 { color: var(--sb-primary-600); }
.stat-seg--2 { color: var(--sb-primary-300); }
.stat-seg--3 { color: var(--sb-accent); }
.stat-seg--4 { color: var(--sb-accent-strong); }
/* Aggregato "Altre": grigio di proposito, fuori dalla palette delle serie. */
.stat-seg--other { color: var(--sb-muted-2); }

/* --- Rampa ordinale a quattro passi ------------------------------------------
   Una sola tinta, dal più scuro al più chiaro. La usano i dati che hanno un
   ORDINE, dove la sequenza va letta nel colore invece che nella legenda: le
   quote delle lingue (`.stat-ramp--N`, dal segmento più grande al più piccolo) e
   le fasce della giornata (`.stat-band--*`, che la percorre al contrario perché
   la giornata va dal chiaro allo scuro).
   Verificata come rampa ordinale: luminosità monotona, salti ΔL ≥ 0.06, estremo
   chiaro ancora leggibile sul bianco. Quattro è il massimo: un quinto passo
   starebbe a ΔL 0.054 dal vicino e sarebbe lo stesso blu. */
.stat-ramp--1 { color: var(--sb-primary); }
.stat-ramp--2 { color: var(--sb-primary-600); }
.stat-ramp--3 { color: var(--sb-primary-500); }
.stat-ramp--4 { color: var(--sb-primary-300); }

.stat-band--night     { color: var(--sb-primary-300); }
.stat-band--morning   { color: var(--sb-primary-500); }
.stat-band--afternoon { color: var(--sb-primary-600); }
.stat-band--evening   { color: var(--sb-primary); }

@media (min-width: 720px) {
  .stats-grid { grid-template-columns: repeat(2, 1fr); }
  .stat-counters { grid-template-columns: repeat(4, 1fr); }
  /* Card che occupa tutta la riga della griglia: la usano i grafici dei feedback
     (§E29.4), dove trenta colonne o un'etichetta come "Rapporto qualità-prezzo"
     in mezza larghezza diventano illeggibili. */
  .stat-card--wide { grid-column: 1 / -1; }
}

/* ==========================================================================
   §E7 — Traduzioni (Manage::)
   ========================================================================== */
.chip--warn { background: #fff3d6; border-color: #ffe0a3; color: #8a5a00; }
.chip--warn:hover { background: #ffecbf; }
.tr-source {
  display: flex; gap: 10px; align-items: baseline;
  background: var(--c-azure-50); border: 1px solid var(--c-azure-100);
  border-radius: 12px; padding: 10px 14px; margin: 0 0 14px;
}
.tr-source__lang { font-weight: 800; color: var(--c-blue-700); font-size: 0.72rem; }
.tr-source__text { color: var(--c-ink); }

/* Feedback "Copiato!" sul chip copia-link (§E2 QR page) */
.chip--copied { background: rgba(70, 180, 80, 0.14); border-color: rgba(70,180,80,0.3); color: var(--c-ok); }

/* ==========================================================================
   §E7.4 — Utenti staff (Manage::)
   ========================================================================== */
.muser-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.muser-row {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 12px 14px; border-radius: 12px; background: var(--c-azure-50);
  border: 1px solid var(--c-azure-100); flex-wrap: wrap;
}
.muser-row__main { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.muser-row__name { font-weight: 700; color: var(--c-ink); }
.muser-row__email { color: var(--c-ink-soft); font-size: 0.9rem; }
.muser-row__actions { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
.muser-status--active { background: rgba(70,180,80,0.14); color: var(--sb-green-fg, #147045); }
.muser-status--invited { background: var(--sb-warn-bg, #FDF0DC); color: var(--sb-warn-fg, #92590F); }
.muser-status--disabled { background: #FDECEC; color: var(--sb-danger, #C62828); }

/* ==========================================================================
   MATERIAL DESIGN 3 LAYER — token, elevazioni, forme, state layer, componenti.
   Seed primario = azzurro del brand. Cascata: sovrascrive gli stili precedenti.
   ========================================================================== */
:root {
  /* Ruoli colore (M3) — seed brand blue */
  --md-primary: #1f7ae0;
  --md-on-primary: #ffffff;
  --md-primary-container: #d6e8ff;
  --md-on-primary-container: #06305c;
  --md-secondary-container: #e6edf5;
  --md-on-secondary-container: #33424f;
  --md-surface: #ffffff;
  --md-surface-container-low: #f6f9fe;
  --md-surface-container: #eef3fb;
  --md-surface-container-high: #e7eef8;
  --md-on-surface: #1a1c1e;
  --md-on-surface-variant: #43474e;
  --md-outline: #c3c7cf;
  --md-outline-variant: #e0e5ee;
  --md-error: #b3261e;
  --md-error-container: #f9dedc;

  /* Elevazioni (tinta brand, leggere per superfici chiare) */
  --md-elev-0: none;
  --md-elev-1: 0 1px 2px rgba(16,42,74,.10), 0 1px 3px 1px rgba(16,42,74,.05);
  --md-elev-2: 0 1px 2px rgba(16,42,74,.12), 0 2px 6px 2px rgba(16,42,74,.07);
  --md-elev-3: 0 2px 6px rgba(16,42,74,.10), 0 6px 14px 4px rgba(16,42,74,.09);

  /* Forma (M3 shape scale) */
  --md-shape-xs: 8px;
  --md-shape-s: 12px;
  --md-shape-m: 16px;
  --md-shape-l: 24px;
  --md-shape-full: 999px;

  --md-font: "Roboto", "Helvetica Neue", system-ui, -apple-system, "Segoe UI", Arial, sans-serif;

  /* Remap dei token legacy sulle nuove scale */
  --radius: var(--md-shape-m);
  --radius-sm: var(--md-shape-full);
  --shadow: var(--md-elev-1);
  --c-white: var(--md-surface);
  --c-azure-50: var(--md-surface-container-low);
  --c-azure-100: var(--md-surface-container);
  --font: var(--md-font);
}

body {
  background: var(--md-surface-container-low);
  color: var(--md-on-surface);
  font-family: var(--md-font);
  letter-spacing: 0.1px;
}

/* --- Tipografia (M3 type scale, sintetica) -------------------------------- */
.hero__title, .panel__title, .g-detail__title, .signup__title {
  letter-spacing: 0; font-weight: 600;
}
.panel__eyebrow, .g-service__cat, .g-detail__cat, .board-col__title,
.stat-card__title, .panel__eyebrow { letter-spacing: 0.4px; }

/* --- Icone ----------------------------------------------------------------- */
.icon { display: inline-block; vertical-align: middle; flex: 0 0 auto; }
.btn .icon { width: 18px; height: 18px; }
.chip .icon { width: 16px; height: 16px; }

/* --- Bottoni (M3: filled / tonal / outlined / text) ----------------------- */
.btn {
  height: 40px; padding: 0 22px; border-radius: var(--md-shape-full);
  font-family: var(--md-font); font-weight: 500; font-size: 0.9rem; letter-spacing: 0.1px;
  gap: 8px; border: none; transition: box-shadow .18s ease, background-color .18s ease;
}
.btn--sm { height: 32px; padding: 0 16px; font-size: 0.82rem; }
.btn--block { display: flex; width: 100%; }

.btn--primary { background: var(--md-primary); color: var(--md-on-primary); box-shadow: var(--md-elev-1); }
.btn--primary:hover { background: color-mix(in srgb, var(--md-primary) 92%, #000); box-shadow: var(--md-elev-2); }
.btn--primary:active { background: color-mix(in srgb, var(--md-primary) 86%, #000); box-shadow: var(--md-elev-1); }

/* "ghost" -> pulsante tonale */
.btn--ghost { background: var(--md-secondary-container); color: var(--md-on-secondary-container); border: none; }
.btn--ghost:hover { background: color-mix(in srgb, var(--md-on-secondary-container) 8%, var(--md-secondary-container)); }

.btn--danger { background: var(--md-error-container); color: var(--md-error); border: none; }
.btn--danger:hover { background: color-mix(in srgb, var(--md-error) 12%, var(--md-error-container)); }

/* --- Chip (assist/filter) -------------------------------------------------- */
.chip {
  display: inline-flex; align-items: center; gap: 6px; height: 32px; padding: 0 14px;
  border-radius: var(--md-shape-xs); border: 1px solid var(--md-outline-variant);
  background: var(--md-surface); color: var(--md-on-surface-variant);
  font-weight: 500; font-size: 0.82rem; transition: background-color .15s ease;
}
.chip:hover { background: color-mix(in srgb, var(--md-primary) 8%, var(--md-surface)); }
.chip--active { background: var(--md-primary); border-color: var(--md-primary); color: var(--md-on-primary); }
.chip--danger { background: var(--md-surface); border-color: var(--md-outline-variant); color: var(--md-error); }
.chip--danger:hover { background: color-mix(in srgb, var(--md-error) 8%, var(--md-surface)); }
.chip--warn { background: #fff4d6; border-color: #ffe19c; color: #7a5300; }

/* --- Superfici / card (elevazione + forma M3) ----------------------------- */
.hero__card, .signup__card, .panel__header, .panel__section, .panel__empty,
.stat-card, .mtile, .req-card, .board-counter, .g-service,
.g-cta, .g-assistant, .g-list__item, .g-wifi, .g-contacts, .access-panel {
  border-radius: var(--md-shape-m);
  border: 1px solid var(--md-outline-variant);
  box-shadow: var(--md-elev-1);
}
.board-col { border-radius: var(--md-shape-m); border-color: var(--md-outline-variant); background: var(--md-surface-container-low); }
.msvc-row, .mstay-row, .muser-row, .stat-counter, .g-facts--card, .g-roombadge, .tr-source {
  border-radius: var(--md-shape-s);
}

/* --- Top app bar / navigation --------------------------------------------- */
.mnav {
  position: sticky; top: 0; z-index: 30;
  background: var(--md-surface-container);
  box-shadow: var(--md-elev-1);
  border-radius: 0 0 var(--md-shape-m) var(--md-shape-m);
  padding: 12px 24px; margin-bottom: 12px;
}
.mnav__link { display: inline-flex; align-items: center; gap: 8px; border-radius: var(--md-shape-full); padding: 8px 16px; }
.mnav__link .icon { width: 18px; height: 18px; }
.mnav__link:hover { background: color-mix(in srgb, var(--md-primary) 8%, transparent); }
.mnav__link--active { background: var(--md-primary-container); color: var(--md-on-primary-container); }
.mnav__signout {
  display: inline-flex; align-items: center; gap: 6px;
  border-radius: var(--md-shape-full); border: 1px solid var(--md-outline-variant);
  background: var(--md-surface); color: var(--md-on-surface-variant); padding: 8px 14px;
}
.mnav__signout:hover { background: color-mix(in srgb, var(--md-primary) 8%, var(--md-surface)); }

/* --- Campi di testo (M3 outlined) ----------------------------------------- */
.form__input {
  border-radius: var(--md-shape-xs); border: 1px solid var(--md-outline-variant);
  background: var(--md-surface); transition: border-color .15s ease, box-shadow .15s ease;
}
.form__input:hover { border-color: var(--md-outline); }
.form__input:focus { border-color: var(--md-primary); box-shadow: 0 0 0 1px var(--md-primary); outline: none; }
.form__label { color: var(--md-on-surface-variant); }

/* --- Tile dashboard (icona in "state container") -------------------------- */
.mtile:hover { box-shadow: var(--md-elev-2); background: color-mix(in srgb, var(--md-primary) 4%, var(--md-surface)); }
.mtile__icon {
  width: 48px; height: 48px; border-radius: var(--md-shape-s);
  display: grid; place-items: center; font-size: 0;
  background: var(--md-primary-container); color: var(--md-on-primary-container);
}
.mtile__icon .icon { width: 26px; height: 26px; }

/* --- App ospite: app bar + accenti ---------------------------------------- */
.g-topbar { box-shadow: var(--md-elev-1); border-radius: 0 0 var(--md-shape-m) var(--md-shape-m); margin-bottom: 8px; }
.g-service { box-shadow: var(--md-elev-1); border-radius: var(--md-shape-m); }
.g-service:hover { box-shadow: var(--md-elev-2); }
.g-assistant__icon, .g-cta__icon { border-radius: var(--md-shape-s); }
.g-lang__current { border-radius: var(--md-shape-full); }
.g-back { display: inline-flex; align-items: center; gap: 4px; }
.g-back .icon { width: 20px; height: 20px; }

/* --- Badge (M3) ------------------------------------------------------------ */
.badge, .msvc-badge, .req-badge, .g-badge { border-radius: var(--md-shape-full); font-weight: 600; }

/* --- Flash / snackbar ------------------------------------------------------ */
.flash, .g-flash { border-radius: var(--md-shape-xs); }

/* Badge camera (home ospite) + camera nell'app bar */
.g-roombadge { display: inline-flex; align-items: center; gap: 6px; }
.g-roombadge .icon { width: 15px; height: 15px; }
.g-topbar__id { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; min-width: 0; }
.g-topbar__room {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 10px; border-radius: var(--md-shape-full);
  background: var(--md-primary-container); color: var(--md-on-primary-container);
  font-size: 0.78rem; font-weight: 700;
}
.g-topbar__room .icon { width: 14px; height: 14px; }

/* ==========================================================================
   TEMA STAYBELL — allineamento al mockup (tema-consergio). Ultimo layer: vince.
   Font: Sora (titoli) + Inter (testo). Palette azzurro/dark/arancio/verde.
   ========================================================================== */
:root {
  /* Indigo scale — structure and action. Both logo blues sit at L~28%, too dark
     to also serve as chips, hovers, focus rings and the active nav item on a
     dark sidebar, hence the lighter steps. Ratios are against white. */
  --sb-primary: #002F91;      /* fills, links, active borders      — 11.57:1 */
  --sb-primary-2: #17008E;    /* hover/pressed, text on tints      — 14.72:1 */
  --sb-primary-600: #1A44B0;  /* fill hover, light gradient stop   —  8.41:1 */
  --sb-primary-500: #3B62D6;  /* active nav on dark, focus ring    —  5.38:1 */
  --sb-primary-300: #93A6EC;  /* decorative, placeholders */
  --sb-grad: linear-gradient(150deg, #1A44B0 0%, #17008E 100%);
  /* Active nav needs its own brighter ramp: the main gradient ends at #17008E
     and would melt into the #0D0B33 sidebar. */
  --sb-grad-nav: linear-gradient(150deg, #3B62D6 0%, #2438B8 100%);

  /* Warm accent. Never carries white text: white on #F28C00 is 2.46:1 and on
     #FFCE00 is 1.49:1. Pair it with --sb-primary-2 (5.98:1 / 9.87:1), or use
     --sb-accent-strong, the only warm step that holds white text (4.53:1). */
  --sb-accent: #F28C00;
  --sb-accent-strong: #B85E00;
  --sb-accent-tint: #FFF0DB;
  --sb-highlight: #FFCE00;
  --sb-highlight-tint: #FFF6CC;

  /* Neutrals — shifted from a cyan cast to an indigo one, to sit with the brand */
  --sb-dark: #0D0B33;
  --sb-ink: #191B33;
  --sb-muted: #5A5F80;
  --sb-muted-2: #8B90AD;
  --sb-line: #E2E4F0;
  --sb-line-2: #EFF0F7;
  --sb-bg: #F6F7FC;
  --sb-bg-2: #EFF0F7;
  --sb-page: #E9EBF5;
  --sb-chip: #E7EAFA;
  --sb-chip-line: #CBD3F2;

  /* Semantic. Warn moved to brown so it cannot be read as the brand orange.
     Green splits by role like the warm family: the bright one fills (dots,
     bars, borders — 3:1 target), the dark one is the only one allowed as text
     on the pale green, where the bright one sits at 3.04:1 and fails AA. */
  --sb-green: #46b450;
  --sb-green-fg: #147045;
  --sb-danger: #C62828;
  --sb-warn-bg: #FDF0DC;
  --sb-warn-fg: #92590F;

  --sb-r-card: 16px;
  --sb-r-btn: 12px;
  --sb-r-pill: 20px;
  --sb-shadow: 0 6px 18px rgba(23,0,142,.07);
  --sb-shadow-h: 0 8px 24px rgba(23,0,142,.12);
  --sb-sans: 'Inter', system-ui, -apple-system, "Segoe UI", Arial, sans-serif;
  --sb-display: 'Sora', 'Inter', system-ui, sans-serif;

  /* rimappa i token legacy/Material sul tema ConSergio */
  --font: var(--sb-sans);
  --md-primary: var(--sb-primary);
  --md-on-primary: #ffffff;
  --md-primary-container: var(--sb-chip);
  --md-on-primary-container: var(--sb-primary-2);
  --md-surface: #ffffff;
  --md-outline-variant: var(--sb-line);
  --md-on-surface: var(--sb-ink);
  --md-on-surface-variant: var(--sb-muted);
  /* These six were never remapped and kept injecting the old cold-blue cast. */
  --md-secondary-container: #E9EBF5;
  --md-on-secondary-container: #3A3F5C;
  --md-surface-container-low: #F6F7FC;
  --md-surface-container: #EFF0F7;
  --md-surface-container-high: #E7E9F3;
  --md-outline: #C5C8DA;
  --c-blue-900: var(--sb-ink);
  --c-blue-700: var(--sb-primary-2);
  --c-blue-500: var(--sb-primary);
  --c-blue-300: var(--sb-primary-300);
  --c-ink: var(--sb-ink);
  --c-ink-soft: var(--sb-muted);
  --c-azure-50: var(--sb-bg);
  --c-azure-100: var(--sb-line);
  --c-white: #ffffff;
  --c-ok: var(--sb-green);
  --radius: var(--sb-r-card);
  --radius-sm: var(--sb-r-pill);
  --shadow: var(--sb-shadow);
}

body { font-family: var(--sb-sans); color: var(--sb-ink); background: var(--sb-page); }
h1,h2,h3,.hero__title,.panel__title,.g-detail__title,.signup__title,
.stat-card__title,.board-col__title,.mtile__label,.g-service__name,.mnav__brand {
  font-family: var(--sb-display);
}

/* --- Bottoni StayBell ------------------------------------------------------ */
.btn { font-family: var(--sb-display); font-weight: 600; border-radius: var(--sb-r-btn); box-shadow: none; letter-spacing: 0; }
.btn--primary { background: #178bc3; color: #fff; box-shadow: 0 8px 20px rgba(23,139,195,.24); }
.btn--primary:hover { filter: brightness(1.05); background: #178bc3; }
.btn--ghost { background: #fff; border: 1px solid var(--sb-line); color: var(--sb-ink); }
.btn--ghost:hover { background: var(--sb-bg); }
.btn--danger { background: #fff; border: 1px solid #F1C7C7; color: var(--sb-danger, #C62828); }

/* --- Chip / pill ----------------------------------------------------------- */
.chip { border-radius: var(--sb-r-pill); background: var(--sb-chip); border: 1px solid var(--sb-chip-line); color: var(--sb-primary-2); font-weight: 600; }
.chip:hover { background: #dcf0fb; }
.chip--active { background: var(--sb-primary); border-color: var(--sb-primary); color: #fff; }
.chip--danger { background: #fff; border-color: var(--sb-line); color: var(--sb-danger); }
.chip--warn { background: var(--sb-warn-bg); border-color: #F0DCB8; color: var(--sb-warn-fg); }

/* --- Card / superfici ------------------------------------------------------ */
.hero__card, .signup__card, .panel__header, .panel__section, .panel__empty,
.stat-card, .mtile, .req-card, .board-counter, .g-service,
.g-cta, .g-assistant, .g-list__item, .g-wifi, .g-contacts, .access-panel, .tr-source,
.g-facts--card, .g-form-card, .g-recap {
  border-radius: var(--sb-r-card); border: 1px solid var(--sb-line); box-shadow: var(--sb-shadow); background: #fff;
}
.board-col { background: var(--sb-bg-2); border: none; border-radius: var(--sb-r-card); }
.badge, .msvc-badge, .req-badge, .g-badge { border-radius: var(--sb-r-pill); font-weight: 700; }

/* --- Campi ----------------------------------------------------------------- */
.form__input { border-radius: 11px; border: 1px solid var(--sb-line); background: var(--sb-bg); }
.form__input:focus { border-color: var(--sb-primary); box-shadow: 0 0 0 3px rgba(59,98,214,.25); }
.form__label { color: var(--sb-muted); font-weight: 600; }

/* --- Pannello: shell con sidebar scura (StayBell) -------------------------- */
.mng-body { background: var(--sb-bg); margin: 0; --mng-top-h: 0px; }
.mng-body--topbar { --mng-top-h: 58px; }
.mng-shell { display: flex; min-height: 100vh; align-items: stretch; }
.mng-side {
  width: 238px; flex: none; background: #000000db; color: #fff;
  display: flex; flex-direction: column; padding: 22px 16px;
  position: sticky; top: 0; height: 100vh; min-height: 0;
}
.mng-side__brand { display: flex; flex: none; align-items: center; gap: 10px; padding: 6px 4px 24px; }
.mng-side__plate { display: flex; flex: 1; align-items: center; justify-content: center; padding: 6px 4px; }
/* Logo orizzontale (~7.85:1): larghezza piena della targa, altezza proporzionale. */
.mng-side__logo-img { display: block; width: 100%; height: auto; }
.mng-side__logo { width: 34px; height: 34px; border-radius: 10px; background: var(--sb-grad); display: flex; align-items: center; justify-content: center; }
.mng-side__name { font-family: var(--sb-display); font-weight: 700; font-size: 18px; }
.mng-side__dot { color: var(--sb-primary); }

/* --- Logo applicativo ConSergio + logo struttura --------------------------- */
.app-logo { display: block; height: auto; max-width: 100%; }
.app-logo--hero { width: 260px; max-width: 80%; margin: 0 auto 18px; }
.signup .app-logo--hero, .hero .app-logo--hero { margin-left: 0; margin-right: auto; }
.g-topbar__plate { display: inline-flex; align-items: center; background: #fff; border-radius: 10px; padding: 5px 10px; box-shadow: 0 4px 12px rgba(13,11,51,.25); }
.g-topbar__logo { display: block; height: 30px; width: auto; }
.settings-logo { display: flex; align-items: center; gap: 14px; margin-bottom: 10px; }
.settings-logo__img { max-height: 64px; width: auto; border-radius: 10px; border: 1px solid var(--sb-line, #e6edf3); padding: 6px 10px; background: #fff; }
.settings-logo__remove { display: inline-flex; align-items: center; gap: 6px; font-size: 0.85rem; color: var(--c-ink-soft); }
.settings-cover { display: flex; flex-direction: column; align-items: flex-start; gap: 8px; margin-bottom: 10px; }
.settings-cover__img { max-width: 100%; border-radius: 12px; border: 1px solid var(--sb-line, #e6edf3); display: block; }

/* --- Form lunghe: campi raggruppati in card su due colonne ------------------
   Two column wrappers instead of grid auto-placement, so each column stacks its
   own cards at free height (same reason as .mconv-rail). */
.form__cards { display: grid; grid-template-columns: 1fr; gap: 16px; margin-bottom: 24px; }
.form__cards-col { display: flex; flex-direction: column; gap: 16px; min-width: 0; container-type: inline-size; }
.form__cards-col > .panel__section { margin: 0; }
@media (min-width: 1100px) {
  .form__cards { grid-template-columns: repeat(2, minmax(0, 1fr)); align-items: start; }
}
/* .form__grid splits at 640px of VIEWPORT width: inside a half-page card the two
   inputs would be cramped, so pair them only when the card is really wide enough. */
@container (max-width: 520px) {
  .form__cards-col .form__grid { grid-template-columns: 1fr; }
}
/* Card-level intro notes: .form__hint has no bottom margin (it normally sits
   last inside a .form__row), so as a direct child of the card it would stick to
   the label of the next field. */
.form__cards .panel__section > .form__hint:not(:last-child) { margin-bottom: 14px; }
.form__checks { display: flex; flex-wrap: wrap; gap: 8px 18px; }
.form__check-inline { display: inline-flex; align-items: center; gap: 6px; }
.form__static { margin: 2px 0; }
/* La nav prende lo spazio residuo e scrolla: con molte voci su schermi bassi
   l'ultima voce restava fuori viewport. */
.mng-side__nav {
  display: flex; flex-direction: column; gap: 4px;
  flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
  margin: 0 -6px; padding: 0 6px;
  scrollbar-width: thin; scrollbar-color: rgba(255,255,255,.28) transparent;
}
.mng-side__nav::-webkit-scrollbar { width: 6px; }
.mng-side__nav::-webkit-scrollbar-track { background: transparent; }
.mng-side__nav::-webkit-scrollbar-thumb { background: rgba(255,255,255,.28); border-radius: 3px; }
.mng-nav__item {
  display: flex; flex: none; align-items: center; gap: 11px; padding: 11px 12px; border-radius: 11px;
  color: rgba(255,255,255,.82); text-decoration: none; font-weight: 600; font-size: 14px;
}
.mng-nav__item:hover { background: #46b450; color: #fff; }
.mng-nav__item--active { background: #46b450; color: #fff; }
/* Raggruppamento del menu per area, con separatore fra i gruppi. */
.mng-nav__group { display: flex; flex-direction: column; gap: 4px; }
.mng-nav__group + .mng-nav__group { margin-top: 4px; padding-top: 8px; border-top: 1px solid rgba(255,255,255,.1); }
.mng-nav__group-label { margin: 0; padding: 6px 12px 2px; font-size: 11px; font-weight: 700; letter-spacing: .6px; text-transform: uppercase; color: rgba(255,255,255,.42); }
.mng-nav__label { flex: 1; }
/* Il badge resta nel DOM anche a 0 (per il Turbo Stream) e si nasconde con
   l'attributo hidden: serve il display esplicito qui sotto per la transform
   della pulsazione, e quindi anche la regola [hidden] — una dichiarazione
   d'autore batte il display:none dello user-agent stylesheet. */
.mng-nav__badge { display: inline-block; background: #fff; color: var(--sb-accent); font-size: 11px; font-weight: 700; padding: 2px 8px; border-radius: 20px; }
.mng-nav__badge[hidden] { display: none; }
@keyframes nav-badge-pulse { 0%, 100% { transform: scale(1); } 40% { transform: scale(1.3); } }
.mng-nav__badge--pulse { animation: nav-badge-pulse .5s ease-out 2; }
.mng-side__pulse { width: 7px; height: 7px; border-radius: 50%; background: var(--sb-green); }
.mng-main { flex: 1; min-width: 0; }

/* --- Fascia superiore: struttura + utente + logout ------------------------- */
.mng-top {
  position: sticky; top: 0; z-index: 20;
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  height: var(--mng-top-h); padding: 0 30px;
  background: #fff; border-bottom: 1px solid var(--sb-line);
}
.mng-top__property { display: flex; align-items: center; gap: 10px; min-width: 0; margin-right: auto; }
/* Hamburger: nascosto su desktop, compare solo quando la sidebar va off-canvas. */
.mng-top__burger {
  display: none; flex: none; align-items: center; justify-content: center;
  width: 40px; height: 40px; border-radius: 10px;
  background: var(--sb-bg); border: 1px solid var(--sb-line); color: var(--sb-dark); cursor: pointer;
}
.mng-top__burger:hover { border-color: var(--sb-primary); color: var(--sb-primary); }
/* Backdrop del drawer: inattivo su desktop, attivo solo sotto il breakpoint. */
.mng-side__backdrop { display: none; }
.mng-top__property-name {
  font-family: var(--sb-display); font-weight: 700; font-size: 15px; color: var(--sb-dark);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.mng-top__status { display: inline-flex; flex: none; align-items: center; gap: 7px; background: rgba(70,180,80,.12); color: #1f8b4c; font-size: 12px; font-weight: 600; padding: 5px 11px; border-radius: 20px; }
.mng-top__user { display: flex; flex: none; align-items: center; gap: 10px; }
.mng-top__avatar {
  display: flex; flex: none; width: 32px; height: 32px; border-radius: 50%;
  align-items: center; justify-content: center; background: var(--sb-grad);
  color: #fff; font-weight: 700; font-size: 13px;
}
/* §E17 — nel pannello l'identità è un link al proprio profilo: deve restare
   identica all'etichetta del back-office, che link non è. */
.mng-top__identity { display: flex; flex-direction: column; line-height: 1.25; min-width: 0; text-decoration: none; }
a.mng-top__identity:hover .mng-top__name { text-decoration: underline; }
/* max-width: senza nome/cognome full_name ricade sull'email, che sfonderebbe. */
.mng-top__name { font-weight: 600; font-size: 13px; color: var(--sb-dark); max-width: 180px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mng-top__role { font-size: 11px; color: var(--sb-muted); }
.mng-top__switch {
  display: inline-flex; align-items: center; gap: 7px; margin-left: 6px;
  background: rgba(59,98,214,.1); border: 1px solid rgba(59,98,214,.3);
  color: var(--sb-primary); border-radius: 10px; padding: 7px 12px;
  font-weight: 600; font-size: 13px; text-decoration: none; white-space: nowrap;
}
.mng-top__switch:hover { background: rgba(59,98,214,.18); }
.mng-top__signout {
  display: inline-flex; align-items: center; gap: 7px; margin-left: 6px;
  background: var(--sb-bg); border: 1px solid var(--sb-line); color: var(--sb-muted);
  border-radius: 10px; padding: 7px 12px; font-family: var(--sb-sans);
  font-weight: 600; font-size: 13px; cursor: pointer;
}
.mng-top__signout:hover { background: #fff; border-color: var(--sb-primary); color: var(--sb-primary); }

/* content: la .panel diventa l'area contenuto a tutta larghezza */
.mng-main .panel { max-width: none; margin: 0; padding: 0 0 40px; }
.mng-main .panel__header {
  background: #fff; border: none; border-bottom: 1px solid var(--sb-line); border-radius: 0;
  box-shadow: none; padding: 22px 30px; margin: 0 0 24px; position: sticky; top: var(--mng-top-h); z-index: 10;
}
/* Le <dialog> sono figlie della .panel ma vivono nel top layer: i margini di
   contenuto qui sotto sovrascriverebbero il `margin: auto` con cui il browser
   le centra, incollandole a sinistra. */
.mng-main .panel > *:not(.panel__header):not(dialog) { margin-left: 30px; margin-right: 30px; }
.mng-main .panel__eyebrow { color: var(--sb-primary); }

/* Schermi bassi (13"/notebook con molte toolbar): comprime il capo della sidebar
   così la nav resta quasi tutta visibile senza scrollare. */
@media (max-height: 800px) {
  .mng-side { padding: 14px 16px; }
  .mng-side__brand { padding: 2px 4px 14px; }
  .mng-side__plate { padding: 9px 12px; }
  .mng-nav__item { padding: 9px 12px; }
}

/* Sotto gli 860px (mobile / tablet in verticale) la sidebar diventa un drawer
   off-canvas: nascosto di default, apribile con l'hamburger nella topbar. */
@media (max-width: 860px) {
  .mng-top__burger { display: inline-flex; }

  .mng-side {
    position: fixed; top: 0; left: 0; z-index: 60;
    width: 264px; max-width: 84vw; height: 100vh; height: 100dvh;
    transform: translateX(-100%); transition: transform .25s ease;
    box-shadow: 0 0 40px rgba(0,0,0,.45);
  }
  .mng-shell--nav-open .mng-side { transform: translateX(0); }

  .mng-side__backdrop {
    display: block; position: fixed; inset: 0; z-index: 55;
    background: rgba(13,11,51,.55);
    opacity: 0; visibility: hidden; transition: opacity .25s ease, visibility .25s ease;
  }
  .mng-shell--nav-open .mng-side__backdrop { opacity: 1; visibility: visible; }

  .mng-top { padding: 0 16px; }
  .mng-top__identity { display: none; }
  .mng-top__signout-label, .mng-top__switch-label { display: none; }
  .mng-top__signout, .mng-top__switch { padding: 7px 9px; }
}

/* Blocca lo scroll della pagina mentre il drawer è aperto. */
.mng-body--nav-open { overflow: hidden; }

@media (prefers-reduced-motion: reduce) {
  .mng-side, .mng-side__backdrop { transition: none; }
  .mng-nav__badge--pulse, .req-card--fresh { animation: none; }
}

/* --- App ospite StayBell --------------------------------------------------- */
.g-body { background: var(--sb-bg); }
.g-app { padding: 0 0 24px; background: var(--sb-bg); }

/* app bar + hero gradiente (home) */
.g-topbar {
  background: var(--sb-grad); color: #fff; border-radius: 0; box-shadow: none;
  padding: 16px 20px 14px; margin: 0; position: sticky; top: 0; z-index: 30;
}

/* La topbar qui sopra è `sticky`, quindi un'ancora atterra ESATTAMENTE sotto la
   barra e il titolo della sezione resta coperto: è il caso di "Wi-Fi" toccato
   dalla home, che porta a /contents#wifi. `--g-topbar-h` è la barra nella sua
   versione più alta (con il badge camera); i template che la ridisegnano la
   ricalibrano nel proprio foglio. */
.g-body { --g-topbar-h: 104px; }
.g-main .g-section[id] { scroll-margin-top: calc(var(--g-topbar-h) + 12px); }
.g-topbar__brand { color: #fff; font-family: var(--sb-display); font-weight: 700; }
.g-topbar__room { background: rgba(255,255,255,.16); color: #fff; }
.g-lang__current { background: rgba(255,255,255,.16); border: none; color: #fff; }
/* .g-lang__code hardcodes the brand blue, and the same class serves both the
   dropdown items (white background, fine) and the pill on the gradient topbar,
   where an indigo label is unreadable. Scope the override to the pill. */
.g-lang__current .g-lang__code { color: inherit; }

.g-roombadge {
  background: var(--sb-dark); color: #fff; box-shadow: 0 8px 20px rgba(13,11,51,.4);
  border-radius: 11px; padding: 8px 14px; font-weight: 600;
}

/* le sezioni della home tornano su sfondo chiaro con padding */
.g-main { padding: 0 20px; }

/* CTA assistente */
.g-assistant { border-radius: var(--sb-r-card); box-shadow: var(--sb-shadow); }
.g-assistant__icon { background: var(--sb-grad); color: #fff; border-radius: 14px; }
.g-assistant__title { font-family: var(--sb-display); }

/* card CTA (richiesta/contenuti) */
.g-cta__icon { background: var(--sb-chip); color: var(--sb-primary-2); }
.g-cta__title { font-family: var(--sb-display); }
.g-cta__arrow { color: var(--sb-primary); }

/* sezioni / titoli */
.g-section__title { font-family: var(--sb-display); color: var(--sb-ink); }
.g-link { color: var(--sb-primary-2); font-weight: 600; }

/* card servizio */
.g-service { border-radius: 14px; border: 1px solid var(--sb-line); box-shadow: var(--sb-shadow); }
.g-service:hover { border-color: var(--sb-primary); box-shadow: var(--sb-shadow-h); transform: translateY(-2px); }
.g-service__media { background: var(--sb-chip); }
.g-service__placeholder { color: var(--sb-primary); }
.g-service__cat { color: var(--sb-primary-2); }
.g-service__name { font-family: var(--sb-display); }
.g-service__price { color: var(--sb-primary-2); }
/* These two sit on top of the card media. A brand-blue plate on the now deep
   indigo placeholder disappears; a white plate reads over any image beneath. */
.g-badge--featured { background: rgba(255,255,255,.94); color: var(--sb-primary-2); }
.g-badge--popular { background: var(--sb-chip); color: var(--sb-primary-2); }

/* dettaglio + footer */
.g-detail__title { font-family: var(--sb-display); }
.g-detail__media { background: repeating-linear-gradient(135deg,#E7EAFA,#E7EAFA 11px,#DCE1F7 11px,#DCE1F7 22px); }
.g-footer__note { color: var(--sb-muted-2); }

/* status richiesta / conferma */
.g-confirm__check { background: #E7F5EC; color: var(--sb-green-fg); }
.g-status--received { background: var(--sb-chip); color: var(--sb-primary-2); }
.g-status--done { background: #E7F5EC; color: var(--sb-green-fg); }

/* --- Pannello: rifiniture StayBell (KPI, board, card richiesta) ------------ */
.board-counter { border-radius: 14px; border: 1px solid var(--sb-line); box-shadow: none; }
.board-counter:first-child { border-left: 4px solid var(--sb-accent); }
.board-counter:first-child .board-counter__num { color: var(--sb-accent-strong); }
.board-counter:nth-child(3) { border-left: 4px solid var(--sb-green); }
.board-counter:nth-child(3) .board-counter__num { color: var(--sb-green); }
.board-counter--time .board-counter__num { color: var(--sb-ink); }
.board-counter__num { font-family: var(--sb-display); }

.board-col { padding: 14px; }
.board-col__title { font-family: var(--sb-display); text-transform: none; letter-spacing: 0; border-left: none; padding-left: 0; display: flex; align-items: center; gap: 9px; }
.board-col__title::before { content: ""; width: 9px; height: 9px; border-radius: 50%; background: var(--sb-primary); }
.board-col__title--new::before { background: var(--sb-accent); }
.board-col__title--progress::before { background: var(--sb-primary); }
.board-col__title--done::before { background: var(--sb-green); }

.req-card { border-radius: 13px; box-shadow: none; }
.req-card__room { font-family: var(--sb-display); }
.req-badge--ai { background: var(--sb-warn-bg); color: var(--sb-warn-fg); }

/* KPI/statistiche numeri in Sora */
.stat-counter__num, .panel__title, .panel__section-title { font-family: var(--sb-display); }
/* Il riempimento delle barre NON è più il gradiente unico: ogni barra porta la
   tinta della sua categoria e ogni colonna quella della sua fascia oraria
   (blocco §E6, `.stat-seg--*` / `.stat-band--*`). */

/* tile dashboard StayBell */
.mtile { border-radius: 14px; box-shadow: var(--sb-shadow); background: #178bc3; color: #fff; border-color: transparent; }
.mtile:hover { background: #46b450; border-color: transparent; box-shadow: var(--sb-shadow-h); transform: translateY(-2px); }
.mtile__icon { background: rgba(255,255,255,.16); color: #fff; border-radius: 12px; }
.mtile__label { font-family: var(--sb-display); }

/* liste gestione: bordo/hover StayBell */
.msvc-row, .mstay-row, .muser-row { background: #fff; }
.msvc-row:hover, .mstay-row:hover, .muser-row:hover { background: var(--sb-bg); }
.access-code { background: var(--sb-dark); }
.dropzone { border-color: #C9CDE2; background: #FAFBFE; border-radius: 14px; }

/* --- Categorie ospite + prezzo persone (StayBell) -------------------------- */
.g-cat {
  display: flex; flex-direction: column; background: #fff;
  border: 1px solid var(--sb-line); border-radius: 14px; overflow: hidden;
  text-decoration: none; color: inherit; box-shadow: var(--sb-shadow);
  transition: transform .12s ease, box-shadow .12s ease;
}
.g-cat:hover { transform: translateY(-2px); box-shadow: var(--sb-shadow-h); border-color: var(--sb-primary); }
/* min-height/overflow: vedi .g-service__media — il riquadro impone il ritaglio. */
.g-cat__media { aspect-ratio: 5 / 3; background: var(--sb-chip); min-height: 0; overflow: hidden; }
.g-cat__img { width: 100%; height: 100%; object-fit: cover; display: block; }
.g-cat__body { padding: 12px 14px 14px; }
.g-cat__name { font-family: var(--sb-display); margin: 0; font-size: 1rem; color: var(--sb-ink); }
.g-cat__desc { margin: 4px 0 0; font-size: 0.82rem; color: var(--sb-muted); line-height: 1.35; }
.g-cat__count { display: inline-block; margin-top: 8px; font-size: 0.75rem; font-weight: 700; color: var(--sb-primary-2); }

.g-cat-head { margin-bottom: 16px; }
.g-cat-head__media { aspect-ratio: 16 / 8; border-radius: var(--sb-r-card); overflow: hidden; min-height: 0; margin-bottom: 14px; background: var(--sb-chip); }
.g-cat-head__img { width: 100%; height: 100%; object-fit: cover; display: block; }

.price-row { display: flex; gap: 8px; align-items: center; }
.price-row .form__input--sm { max-width: 120px; }
.price-row select.form__input { width: auto; }

.mstay-total {
  display: flex; justify-content: space-between; align-items: center;
  margin-top: 12px; padding: 12px 14px; border-radius: 12px;
  background: var(--sb-bg); border: 1px solid var(--sb-line);
  font-family: var(--sb-display); font-weight: 700; color: var(--sb-ink);
}
.mstay-total strong { color: var(--sb-primary-2); font-size: 1.1rem; }
.mstay-row__cost { color: var(--sb-primary-2); }

/* --- §E9 Chat assistente (Guest::) ----------------------------------------- */
.g-chat { display: flex; flex-direction: column; gap: 12px; }
.g-chat__head { padding: 4px 0; }
.g-chat__title { margin: 0; font-family: var(--sb-display); font-size: 1.35rem; color: var(--c-ink); }
.g-chat__sub { margin: 2px 0 0; font-size: 0.85rem; color: var(--c-ink-soft); }
.g-chat__log {
  display: flex; flex-direction: column; gap: 10px;
  max-height: 58vh; overflow-y: auto; padding: 12px;
  background: var(--sb-bg-2, #f4f9ff); border-radius: var(--sb-r-card, 16px);
}
.g-msg { display: flex; flex-direction: column; max-width: 86%; }
.g-msg--user { align-self: flex-end; align-items: flex-end; }
.g-msg--assistant { align-self: flex-start; align-items: flex-start; }
.g-msg__bubble {
  padding: 10px 14px; border-radius: 16px; line-height: 1.45;
  background: #fff; color: var(--c-ink); box-shadow: var(--sb-shadow, 0 2px 8px rgba(14,27,42,.08));
}
.g-msg__bubble p { margin: 0 0 6px; }
.g-msg__bubble p:last-child { margin-bottom: 0; }
.g-msg--user .g-msg__bubble { background: var(--sb-grad, #17008E); color: #fff; }
.g-msg__bubble--error { background: #FDECEC; color: var(--sb-danger); }
.g-msg__meta { margin: 3px 4px 0; font-size: 0.7rem; color: var(--c-ink-soft); }
.g-msg__flag { color: var(--sb-warn-fg); font-weight: 600; }
.g-typing__bubble { display: inline-flex; gap: 4px; align-items: center; padding: 12px 14px; }
.g-typing__dot {
  width: 7px; height: 7px; border-radius: 50%; background: var(--c-ink-soft);
  animation: g-typing 1.2s infinite ease-in-out;
}
.g-typing__dot:nth-child(2) { animation-delay: .15s; }
.g-typing__dot:nth-child(3) { animation-delay: .3s; }
@keyframes g-typing { 0%, 60%, 100% { opacity: .3; transform: translateY(0); } 30% { opacity: 1; transform: translateY(-3px); } }
@media (prefers-reduced-motion: reduce) { .g-typing__dot { animation: none; opacity: .6; } }
.g-chat__form { display: flex; gap: 8px; align-items: center; }
.g-chat__input {
  flex: 1; padding: 12px 14px; border-radius: 999px;
  border: 1px solid var(--sb-line, #e6edf3); background: #fff; font-size: 1rem;
}
.g-chat__send { border-radius: 999px; white-space: nowrap; }

/* Variante d'attenzione del badge base (usata dai gap di contenuto in
   Statistiche). Le regole del thread conversazioni che stavano qui sono state
   riscritte in fondo al file — vedi §E9.5. */
.badge--warn { background: var(--sb-warn-bg); color: var(--sb-warn-fg); }

/* --- §E10 Formattazione risposte chat + fonti ------------------------------ */
.g-msg__bubble ul, .g-msg__bubble ol { margin: 6px 0; padding-left: 20px; }
.g-msg__list li { margin: 3px 0; line-height: 1.45; }
/* §E23/UX — niente sottolineato nelle risposte dell'assistente: su ogni
   servizio proposto spezzava la lettura. Al suo posto il grassetto, perché
   serve un segnale che NON sia il solo colore — link e testo corrente sono due
   blu scuri a 1.15:1 l'uno dall'altro (WCAG 1.4.1). Torna su hover e focus.
   `.g-offer` è una CARD, non un link di testo: dichiarava già
   `text-decoration: none`, ma questa regola — più specifica — glielo
   sovrascriveva, ed è per questo che nome, prezzo e "Richiedi" risultavano
   sottolineati tutti insieme. */
.g-msg__bubble a { color: var(--c-blue-700); text-decoration: none; }
.g-msg__bubble a:not(.g-offer) { font-weight: 600; }
.g-msg__bubble a:not(.g-offer):hover,
.g-msg__bubble a:not(.g-offer):focus-visible { text-decoration: underline; }
.g-msg--user .g-msg__bubble a { color: #fff; }
.g-msg__bubble strong { font-weight: 700; }
.g-msg__sources { margin-top: 10px; padding-top: 8px; border-top: 1px solid var(--sb-line, #e6edf3); }
.g-msg__sources-title {
  margin: 0 0 5px; font-size: 0.7rem; font-weight: 700; text-transform: uppercase;
  letter-spacing: .04em; color: var(--c-ink-soft);
}
.g-msg__source-list { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 6px; }
.g-msg__source {
  display: inline-block; max-width: 100%; padding: 4px 10px; border-radius: 999px;
  background: var(--sb-bg-2, #f4f9ff); color: var(--c-blue-700);
  font-size: 0.78rem; text-decoration: none; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
}
.g-msg__source:hover { text-decoration: underline; }

/* --- Azione secondaria nella topbar ospite --------------------------------- */
.g-topbar__actions { display: flex; align-items: center; gap: 8px; }
.g-topbar__action {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 10px; border-radius: 999px;
  background: rgba(255, 255, 255, .16); color: #fff;
  font-size: .8rem; font-weight: 600; text-decoration: none; white-space: nowrap;
}
.g-topbar__action:hover { background: rgba(255, 255, 255, .26); }
/* Su schermi stretti resta la sola icona: l'azione non deve competere col brand. */
@media (max-width: 30rem) { .g-topbar__action-label { display: none; } }

/* --- FAQ nella sezione informazioni ---------------------------------------- */
.g-faqs { display: flex; flex-direction: column; gap: 8px; }
.g-faq {
  background: #fff; border: 1px solid var(--sb-line, #e6edf3);
  border-radius: var(--sb-r-card, 14px); padding: 12px 14px;
}
.g-faq__q { cursor: pointer; font-weight: 700; color: var(--c-ink); list-style: none; }
.g-faq__q::-webkit-details-marker { display: none; }
.g-faq__q::after { content: "+"; float: right; color: var(--c-ink-soft); font-weight: 400; }
.g-faq[open] .g-faq__q::after { content: "−"; }
.g-faq__a { margin-top: 8px; color: var(--c-ink-soft); line-height: 1.5; }
.g-faq__a p { margin: 0 0 6px; }
.g-faq__a p:last-child { margin-bottom: 0; }

/* --- Wi-Fi nella sezione informazioni --------------------------------------
   Una card per rete (camera e/o struttura). Il valore è in monospace: si copia
   col pulsante, ma va anche letto e digitato a mano dal dispositivo. */
.g-wifi { padding: 12px 14px; }
.g-wifi + .g-wifi { margin-top: 10px; }
.g-wifi__label {
  margin: 0 0 8px; font-size: .82rem; font-weight: 700; text-transform: uppercase;
  letter-spacing: .04em; color: var(--c-ink-soft);
}
.g-wifi__row {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 8px 0; border-top: 1px solid var(--sb-line, #e6edf3);
}
.g-wifi__row:first-of-type { border-top: none; padding-top: 0; }
.g-wifi__field { color: var(--c-ink-soft); min-width: 5.5rem; }
/* Il valore prende lo spazio residuo e va a capo: SSID e password possono
   essere lunghi e non devono far scorrere la pagina in orizzontale. */
.g-wifi__value {
  flex: 1 1 8rem; font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-weight: 700; color: var(--c-ink); word-break: break-all;
}
.g-wifi__copy { flex: none; }

/* --- Contatti diretti nella sezione informazioni ---------------------------
   UNA card: il telefono come riga cliccabile, WhatsApp come pulsante sotto.
   Il numero WhatsApp non si mostra: all'ospite serve aprire la chat, non
   leggerlo. */
.g-section__sub { margin: -6px 0 10px; color: var(--c-ink-soft); font-size: 0.9rem; }
.g-contacts { display: flex; flex-direction: column; gap: 12px; padding: 14px; }
/* Telefono: icona sopra, numero sotto, tutto centrato e tutto cliccabile. */
.g-contact {
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  padding: 6px 0 2px; text-decoration: none; color: inherit; text-align: center;
}
.g-contact__icon {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: 38px; height: 38px; border-radius: 12px;
  background: var(--sb-chip); color: var(--c-blue-500);
}
.g-contact__value {
  font-weight: 700; font-size: 1.1rem; color: var(--c-ink); overflow-wrap: anywhere;
}

/* Pulsante WhatsApp: verde del canale, l'unico elemento fuori palette dell'app
   ospite — è il segnale che lo rende riconoscibile senza leggere. Il verde è
   quello scuro del marchio: su #25D366 il testo bianco non sarebbe leggibile.
   Nessun separatore sopra: lo darebbe dentro l'area verde, basta il gap. */
.g-wa-btn {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  min-height: 46px; padding: 12px 16px; border-radius: 12px;
  background: #128C4A; color: #fff; font-weight: 700; text-decoration: none;
}
.g-wa-btn:hover { background: #0f7a40; }

/* --- §E11 KPI tile (Insight / dashboard) -----------------------------------
   Il colore sta sull'ICONA, non sul numero: il valore resta in inchiostro
   (leggibilità e coerenza tipografica). Ogni tile ha icona + etichetta, quindi
   il significato non è mai affidato al solo colore. */
.kpi-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 14px;
  /* Oltre questa soglia le tile diventerebbero enormi e illeggibili. */
  max-width: 1120px;
}
@media (min-width: 1100px) { .kpi-grid { grid-template-columns: repeat(4, 1fr); } }

.kpi {
  display: flex; align-items: center; gap: 12px;
  padding: 16px; background: #fff;
  border: 1px solid var(--sb-line, #e2eaf0);
  border-radius: var(--sb-r-card, 14px);
  box-shadow: var(--sb-shadow, 0 2px 8px rgba(14, 27, 42, .06));
  border-left: 4px solid var(--kpi-color, var(--sb-primary, #002F91));
}
.kpi__icon {
  flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center;
  width: 38px; height: 38px; border-radius: 11px;
  background: var(--kpi-tint, var(--sb-chip, #E7EAFA)); color: var(--kpi-color, var(--sb-primary-2, #17008E));
}
.kpi__body { min-width: 0; }
.kpi__value {
  margin: 0; font-family: var(--sb-display, inherit);
  font-size: 1.6rem; font-weight: 700; line-height: 1.1; color: var(--c-ink);
}
.kpi__label { margin: 2px 0 0; font-size: .78rem; color: var(--c-ink-soft); line-height: 1.3; }

/* Stato: blu = informativo, verde = va bene, ambra = richiede attenzione. */
.kpi--info { --kpi-color: var(--sb-primary-2); --kpi-tint: var(--sb-chip); }
.kpi--ok   { --kpi-color: var(--sb-green-fg); --kpi-tint: #E7F6EE; }
.kpi--warn { --kpi-color: var(--sb-warn-fg); --kpi-tint: var(--sb-warn-bg); }

/* --- §E11 Extra proposti in chat: CTA di richiesta -------------------------- */
.g-msg__offers { display: flex; flex-direction: column; gap: 8px; margin-top: 10px; }
.g-offer {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 10px 12px; border-radius: 12px; text-decoration: none;
  background: var(--sb-bg-2, #eef3f7);
  border: 1px solid var(--sb-line, #e2eaf0);
}
.g-offer:hover { border-color: var(--sb-primary, #002F91); }
.g-offer__body { display: flex; flex-direction: column; min-width: 0; }
.g-offer__name { font-weight: 700; color: var(--c-ink); line-height: 1.3; }
.g-offer__price { font-size: .8rem; color: var(--c-ink-soft); }
.g-offer__cta {
  flex: 0 0 auto; padding: 6px 12px; border-radius: 999px;
  background: var(--sb-grad, #17008E); color: #fff;
  font-size: .8rem; font-weight: 700; white-space: nowrap;
}

/* --- Tabella dati (Manage::) ------------------------------------------------
   Mancava del tutto: le tabelle risultavano testo nudo. Il wrapper permette lo
   scorrimento orizzontale su schermi stretti senza far scrollare la pagina. */
.table-card {
  max-width: 1120px; margin-top: 16px;
  background: #fff; border: 1px solid var(--sb-line, #e2eaf0);
  border-radius: var(--sb-r-card, 14px); box-shadow: var(--sb-shadow, 0 2px 8px rgba(14,27,42,.06));
  overflow-x: auto;
}
.data-table { width: 100%; border-collapse: collapse; font-size: .9rem; }
.data-table th, .data-table td { padding: 11px 16px; text-align: left; white-space: nowrap; }
.data-table thead th {
  font-size: .72rem; text-transform: uppercase; letter-spacing: .04em;
  color: var(--c-ink-soft); font-weight: 700;
  background: var(--sb-bg-2, #eef3f7); border-bottom: 1px solid var(--sb-line, #e2eaf0);
}
.data-table tbody td { color: var(--c-ink); border-top: 1px solid var(--sb-line-2, #eef3f7); }
.data-table tbody tr:first-child td { border-top: none; }
.data-table tbody tr:hover td { background: var(--sb-bg-2, #eef3f7); }
/* Prima colonna = etichetta della riga; le altre sono numeri, allineati a destra. */
.data-table td:not(:first-child), .data-table th:not(:first-child) { text-align: right; }
.data-table td:first-child { font-weight: 600; white-space: normal; }

/* --- §E18 Reparti: tabella con editing inline ------------------------------ */
/* Variante non numerica di .data-table: qui le colonne sono etichette e
   controlli, non cifre, quindi si torna all'allineamento a sinistra. */
.data-table--form td:not(:first-child), .data-table--form th:not(:first-child) { text-align: left; }
.data-table--form td { vertical-align: middle; }
.dtable__name { width: 40%; }
/* Cella numerica dentro una tabella di testo: `data-table--form` riporta tutto
   a sinistra, ma le cifre si confrontano solo se incolonnate a destra. */
.dtable__num { text-align: right !important; font-variant-numeric: tabular-nums; }
.dtable__muted { color: var(--c-ink-soft); }
.dtable__empty { color: var(--c-ink-soft); font-weight: 400 !important; text-align: center !important; padding: 22px 16px; }
/* button_to emette un <form>: senza flex i pulsanti andrebbero a capo. Il flex
   sta su un wrapper INTERNO e non sul <td>: un table-cell con display non
   tabellare esce dal contesto della tabella e il browser gli costruisce attorno
   una cella anonima trasparente, che lascia una striscia bianca sotto la riga. */
.dtable__actions { width: 1%; } /* si stringe sui pulsanti: lo spazio va al nome */
.dtable__actions-inner { display: flex; gap: 6px; align-items: center; justify-content: flex-end; }
.dtable__actions-inner form { margin: 0; }
/* Elimina non disponibile (servizi collegati): resta leggibile e col motivo nel
   title, invece di sparire senza spiegazione. */
.dtable__locked {
  padding: 6px 10px; font-size: .82rem; font-weight: 600;
  color: var(--c-ink-soft); opacity: .55; cursor: not-allowed;
}
.dtable__note { margin-top: 10px; max-width: 1120px; } /* stessa larghezza di .table-card */
.dtable__row--editing td { background: var(--sb-chip, #eaf6fd); }
.dtable__row--editing .form__input { width: 100%; }
.dtable__error { margin: 6px 0 0; font-size: .8rem; font-weight: 500; color: var(--sb-danger, #c0392b); }

/* Etichetta per i soli screen reader (intestazioni e campi senza testo visibile). */
.visually-hidden {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0;
}

/* --- §E12 Abbonamento: listino e avviso di stato --------------------------- */
.panel__section-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 16px; flex-wrap: wrap;
}

.plan-grid {
  display: grid; gap: 16px; margin-top: 14px; max-width: 1120px;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
}
.plan-card {
  display: flex; flex-direction: column; gap: 8px; padding: 20px;
  background: #fff; border: 1px solid var(--sb-line, #e2eaf0);
  border-radius: var(--sb-r-card, 14px); box-shadow: var(--sb-shadow, 0 2px 8px rgba(14,27,42,.06));
}
/* Il piano attivo si riconosce dal bordo E dall'etichetta: mai dal solo colore. */
.plan-card--current { border-color: var(--sb-primary, #002F91); border-width: 2px; }
.plan-card__name { margin: 0; font-size: 1.05rem; font-weight: 700; color: var(--c-ink, #1a2733); }
.plan-card__price { margin: 0; font-size: 1.8rem; font-weight: 700; color: var(--c-ink, #1a2733); }
.plan-card__period { font-size: .9rem; font-weight: 500; color: var(--c-ink-soft, #4a5b6b); }
.plan-card__saving { margin: 0; font-size: .85rem; font-weight: 600; color: var(--sb-green-fg, #147045); }
.plan-card__features { margin: 6px 0 auto; padding-left: 18px; color: var(--c-ink-soft, #4a5b6b); font-size: .9rem; }
.plan-card__features li { margin-bottom: 4px; }
.plan-card__badge {
  margin: 10px 0 0; padding: 8px; text-align: center; font-size: .85rem; font-weight: 600;
  color: var(--sb-primary-2, #17008E); background: var(--sb-chip, #E7EAFA); border-radius: 10px;
}
/* Piano non attivabile (troppe camere per il suo tetto): il motivo prende il
   posto del pulsante, così non si scopre il blocco dopo il click. */
.plan-card__note {
  margin: 10px 0 0; padding: 8px; text-align: center; font-size: .85rem;
  color: var(--c-ink-soft, #4a5b6b); background: var(--sb-bg, #f4f7fa); border-radius: 10px;
}
.btn--block { width: 100%; }

/* Avviso di stato abbonamento: icona + testo, non il solo colore. */
.billing-banner {
  display: flex; align-items: flex-start; justify-content: center; gap: 10px; margin-bottom: 16px;
  padding: 12px 14px; border-radius: 12px; font-size: .92rem;
  border: 1px solid; background: #fff; text-align: center;
}
.billing-banner__text { margin: 0; }
.billing-banner__link { font-weight: 600; color: inherit; }
.billing-banner--info  { border-color: #bcdcf5; background: #eef7fd; color: #0f5c85; }
.billing-banner--warn  { border-color: #f0dcb8; background: #fdf6ea; color: #7d5210; }
.billing-banner--error { border-color: #f0c4c1; background: #fdeeed; color: #8c2b25; }
/* §E17 — il rinvio della mail di conferma è un POST, quindi un form: va reso
   inline come gli altri link del banner. */
.billing-banner__form { display: inline; }
.billing-banner__link--button {
  font-weight: 600; color: inherit; background: none; border: 0; padding: 0;
  font-size: inherit; font-family: inherit; text-decoration: underline; cursor: pointer;
}

/* §E16 — avviso in evidenza sulla dashboard quando la struttura non è attiva:
   icona + testo + CTA per attivare/riattivare l'abbonamento. */
.structure-alert {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  margin: 0 0 22px; padding: 16px 20px; border-radius: 16px; border: 1px solid;
}
.structure-alert__icon { flex: 0 0 auto; line-height: 0; }
.structure-alert__body { flex: 1 1 260px; }
.structure-alert__title { margin: 0 0 4px; font-size: 1.05rem; font-weight: 700; }
.structure-alert__text { margin: 0; font-size: .93rem; }
.structure-alert__note { margin: 0; font-size: .88rem; font-weight: 600; }
.structure-alert__actions { flex: 0 0 auto; margin-left: auto; }
.structure-alert--warn   { border-color: #f0dcb8; background: #fdf6ea; color: #7d5210; }
.structure-alert--danger { border-color: #f0c4c1; background: #fdeeed; color: #8c2b25; }

/* --- §E13 Contatore di consumo del ciclo ---------------------------------- */
.usage-bar { max-width: 1120px; margin: 18px 0 6px; }
.usage-bar__head {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: 12px; margin-bottom: 6px; font-size: .9rem;
}
.usage-bar__label { font-weight: 600; color: var(--c-ink, #1a2733); }
.usage-bar__figures { color: var(--c-ink-soft, #4a5b6b); font-variant-numeric: tabular-nums; }
.usage-bar__track {
  height: 10px; border-radius: 999px; overflow: hidden;
  background: var(--sb-bg-2, #eef3f7); border: 1px solid var(--sb-line, #e2eaf0);
}
.usage-bar__fill { height: 100%; background: var(--sb-primary, #002F91); }
/* Oltre la quota inclusa il riempimento cambia tono: la cifra accanto resta
   comunque scritta, il colore non è mai l'unico segnale. */
.usage-bar__fill--over { background: var(--sb-warn-fg, #92590F); }

/* --- §E14 Back-office di piattaforma --------------------------------------- */
.adm-badge {
  display: inline-block; padding: 6px 12px; border-radius: 999px;
  background: var(--sb-primary-2, #17008E); color: #fff; font-size: .78rem; font-weight: 700;
  letter-spacing: .06em; text-transform: uppercase;
}
/* The back-office brand plate stacks the product logo over the DevInterface
   badge: the logo says WHICH product, the badge says you are behind it. The
   base block is a row (logo beside name), hence the direction override — and
   the plate must stay stretched, or the logo's width: 100% collapses. */
.mng-side__brand--admin { flex-direction: column; align-items: stretch; gap: 10px; }
.mng-side__brand--admin .adm-badge { align-self: center; }
/* Etichette di stato: sempre accompagnate dal testo, mai solo colore. */
.tag {
  display: inline-block; padding: 2px 8px; margin-left: 6px;
  border-radius: 999px; font-size: .75rem; font-weight: 600; white-space: nowrap;
}
.tag--ok    { background: #e4f4ec; color: var(--sb-green-fg, #147045); }
.tag--warn  { background: var(--sb-warn-bg, #FDF0DC); color: var(--sb-warn-fg, #92590F); }
.tag--loss  { background: #fdeeed; color: #8c2b25; }
.tag--info  { background: var(--sb-chip, #E7EAFA); color: var(--sb-primary-2, #17008E); }

/* Form in linea del back-office: campi affiancati su desktop, impilati sotto. */
.form--inline { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 16px; }
.form--inline .form__row { margin: 0; }

/* §E16 — menu a tendina della topbar: selettore di struttura e selettore di lingua.
   Classi distinte perché sono due cose diverse (una c'è solo con più strutture),
   stessa meccanica di apertura. */
.mng-top__selector,
.mng-top__lang { position: relative; }
.mng-top__selector > summary,
.mng-top__lang > summary { cursor: pointer; list-style: none; display: inline-flex; align-items: center; gap: 6px; }
.mng-top__selector > summary::-webkit-details-marker,
.mng-top__lang > summary::-webkit-details-marker { display: none; }
.mng-top__caret { font-size: 0.7em; opacity: 0.7; }
.mng-top__menu { position: absolute; z-index: 30; margin: 8px 0 0; padding: 6px; min-width: 220px; list-style: none;
  background: #fff; border: 1px solid var(--c-blue-300, #cbd5e1); border-radius: 12px; box-shadow: 0 10px 30px rgba(2, 32, 71, 0.14); }
.mng-top__menu li { margin: 0; }
.mng-top__menu-item { display: block; width: 100%; text-align: left; padding: 8px 10px; border: 0; background: transparent;
  border-radius: 8px; cursor: pointer; font: inherit; color: var(--c-blue-900, #0b2447); }
.mng-top__menu-item:hover { background: var(--c-blue-100, #eff6ff); }
.mng-top__menu-item.is-current { font-weight: 700; }

/* Selettore di lingua: stessa meccanica, ma sta in fondo alla fascia, quindi il
   pannello si apre allineato a destra per non uscire dal viewport. */
.mng-top__menu--right { right: 0; min-width: 160px; }
.mng-top__lang > summary { color: var(--c-blue-700, #1d4ed8); padding: 6px 8px; border-radius: 8px; }
.mng-top__lang > summary:hover { background: var(--c-blue-100, #eff6ff); }
.mng-top__lang-code { font-size: 0.82rem; font-weight: 600; letter-spacing: 0.04em; }

/* --- §E2 Camere: tabella, miniatura QR, menu download, modal ---------------
   La griglia di card non regge un hotel: con 40+ camere serviva un elenco
   compatto. Si riusa .table-card/.data-table--form dei reparti; qui sotto solo
   ciò che la tabella camere aggiunge. */
/* Elenco a sinistra, form di aggiunta nel rail destro: stesso schema dei
   documenti. Sotto i 1100px si impila, con la tabella sempre per prima. */
.rooms-layout { display: grid; grid-template-columns: 1fr; gap: 16px; align-items: start; }
.rooms-layout > * { min-width: 0; }
.rooms-add { margin: 0; }
@media (min-width: 1100px) {
  .rooms-layout { grid-template-columns: minmax(0, 1fr) 340px; }
  /* Senza il permesso di creare il rail non c'è: niente colonna vuota. */
  .rooms-layout--full { grid-template-columns: minmax(0, 1fr); }
}

/* La card di filtro ha già il suo margine inferiore: la tabella la segue. */
.rooms-filters { max-width: none; }
.rooms-filter__field--grow { flex: 1 1 240px; min-width: 0; }

/* Dentro il rail la tabella non ha più il tetto dei 1120px del pannello. */
.rooms-main .table-card { max-width: none; margin-top: 0; }

/* La colonna del QR si stringe sulla miniatura: lo spazio va a numero e nome. */
.rooms-table__qr { width: 1%; }
.rooms-table td:first-child { font-weight: 400; }
.rooms-table .dtable__name { width: auto; font-weight: 700; }

/* Colonna Wi-Fi: sola lettura anche in modifica (si cambia dalla modal). */
.rooms-table__wifi { display: table-cell; min-width: 8rem; }

/* Miniatura: riconoscibile come QR, non leggibile — serve ad aprire la modal. */
.room-qr-thumb {
  display: inline-flex; width: 44px; height: 44px; padding: 3px;
  border: 1px solid var(--sb-line); border-radius: 10px; background: #fff;
  cursor: pointer;
}
.room-qr-thumb svg { width: 100%; height: 100%; display: block; }
button.room-qr-thumb:hover { border-color: #178bc3; }
.room-qr-thumb--off { filter: grayscale(1); opacity: 0.5; cursor: default; }

/* Camera disattivata: riga in secondo piano, resta leggibile. */
.rooms-table__row--off td { color: var(--c-ink-soft); }

/* Segnaposto di un'azione non disponibile (riattivare a piano pieno): stesso
   ingombro di un .icon-btn, ma spento e non cliccabile. */
.icon-btn--locked { opacity: 0.45; cursor: not-allowed; }
.icon-btn--locked:hover { border-color: var(--sb-line); color: var(--c-ink-soft); }

/* --- Menu a tendina generico (<details>) -----------------------------------
   Stessa meccanica dei menu della topbar, ma il pannello è in position:fixed:
   dentro .table-card (overflow-x: auto) un position:absolute verrebbe
   ritagliato. Le coordinate le calcola dropdown_controller. */
.dropdown { position: relative; display: inline-flex; }
.dropdown > summary { list-style: none; cursor: pointer; }
.dropdown > summary::-webkit-details-marker { display: none; }
.dropdown__menu {
  position: fixed; z-index: 40; top: 0; left: 0; min-width: 160px; padding: 6px;
  display: flex; flex-direction: column;
  background: #fff; border: 1px solid var(--sb-line); border-radius: 12px;
  box-shadow: 0 10px 30px rgba(2, 32, 71, 0.14);
}
.dropdown__item {
  display: flex; align-items: center; gap: 9px; width: 100%; text-align: left; padding: 8px 10px;
  border: 0; background: transparent; border-radius: 8px; cursor: pointer;
  font: inherit; font-weight: 600; color: var(--sb-ink); text-decoration: none;
  white-space: nowrap;
}
.dropdown__item:hover { background: var(--sb-chip); }
.dropdown__item .icon { flex: none; color: var(--sb-muted); }
/* button_to emette un <form>: qui il pulsante deve restare una voce di menu. */
.dropdown__menu form { margin: 0; }
.dropdown__item--danger { color: var(--sb-danger, #C62828); }
.dropdown__item--danger:hover { background: #fdecec; }
.dropdown__item--danger .icon { color: inherit; }
/* Azione non disponibile (riattivare a piano pieno): resta leggibile, col
   motivo nel title, invece di sparire senza spiegazione. */
.dropdown__item--locked { opacity: 0.5; cursor: not-allowed; }
.dropdown__item--locked:hover { background: transparent; }
.dropdown__sep { margin: 5px 4px; border: 0; border-top: 1px solid var(--sb-line-2, #eef3f7); }
/* Un separatore in testa o in coda al menu non separa niente. */
.dropdown__menu > .dropdown__sep:first-child,
.dropdown__menu > .dropdown__sep:last-child { display: none; }

/* --- Modal del QR ---------------------------------------------------------- */
.qr-dialog {
  border: 0; border-radius: 16px; padding: 0; max-width: 420px; width: calc(100% - 32px);
  margin: auto; /* centratura: è il margine, non left/top, a farla */
  background: #fff; color: var(--sb-ink); box-shadow: 0 24px 70px rgba(2, 32, 71, 0.28);
}
.qr-dialog::backdrop { background: rgba(15, 23, 42, 0.45); }
.qr-dialog__box { padding: 22px 24px 24px; }
.qr-dialog__head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
.qr-dialog__title { margin: 0; font-size: 1.15rem; color: var(--c-blue-900); }
.qr-dialog__sub { margin: 2px 0 0; font-size: 0.9rem; color: var(--c-ink-soft); }
.qr-dialog__qr {
  margin: 16px 0 12px; padding: 14px; border-radius: 14px; background: var(--c-azure-50);
}
.qr-dialog__qr svg { width: 100%; max-width: 280px; height: auto; display: block; margin: 0 auto; }
.qr-dialog__hint { margin: 0 0 6px; font-size: 0.85rem; color: var(--c-ink-soft); }
.qr-dialog__url { margin: 0 0 14px; font-size: 0.78rem; color: var(--c-ink-soft); word-break: break-all; }
.qr-dialog__actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.qr-dialog__label { font-size: 0.82rem; font-weight: 600; color: var(--c-ink-soft); }

/* --- Modal generica (contenuto caricato in un Turbo Frame) ------------------ */
.modal {
  border: 0; border-radius: 16px; padding: 0; max-width: 440px; width: calc(100% - 32px);
  margin: auto; /* centratura: è il margine, non left/top, a farla */
  background: #fff; color: var(--sb-ink); box-shadow: 0 24px 70px rgba(2, 32, 71, 0.28);
}
.modal::backdrop { background: rgba(15, 23, 42, 0.45); }
.modal__box { padding: 22px 24px 24px; }
.modal__head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
.modal__title { margin: 0; font-size: 1.15rem; color: var(--c-blue-900); }
.modal__sub { margin: 0 0 14px; font-size: 0.9rem; color: var(--c-ink-soft); }
.modal__body { display: block; margin-top: 14px; }
.modal__loading { margin: 0; font-size: 0.9rem; color: var(--c-ink-soft); }
/* Dettaglio richiesta (§E20): 440px sono troppo stretti per un contenuto lungo.
   max-height + overflow perché il thread delle note cresce senza limite. */
.modal--wide { max-width: 720px; }
.modal--wide .modal__body { max-height: 70vh; overflow-y: auto; }

/* --- §E9.5 Conversazioni (Manage::) -----------------------------------------
   Elenco come tabella dati (stesso impianto di camere e reparti) e dettaglio
   come thread di chat: bolle a destra per l'ospite, a sinistra per
   l'assistente, con i card di contesto nel rail.

   IL BLOCCO STA IN FONDO di proposito: `.mconv-table td:first-child` ha la
   STESSA specificità di `.data-table td:first-child` (riga ~2446), quindi a
   decidere è l'ordine di sorgente. Piazzato più in alto, il grassetto della
   prima colonna vincerebbe in silenzio — stesso motivo per cui `.rooms-table`
   sta dove sta. */

/* Pillola d'attenzione: completa la famiglia .msvc-badge, così stato e "senza
   risposta" nella stessa cella hanno lo stesso ingombro. */
.msvc-badge--warn { background: var(--sb-warn-bg); color: var(--sb-warn-fg); }

/* La tabella occupa tutta la larghezza del pannello: il tetto di 1120px di
   .table-card serve alle tabelle strette (fatturazione, reparti), qui lascerebbe
   una fascia vuota a destra sotto la card dei filtri, che è già a piena
   larghezza. Il margine superiore lo porta già la card dei filtri. */
.mconv-card { max-width: none; margin-top: 0; }
/* Checkbox in una card filtri: etichetta ACCANTO al controllo, non sopra, e
   stessa altezza dei campi. Doppia classe per battere `.mfilter__field`. */
.mfilter__field.mfilter__field--check {
  flex-direction: row; align-items: center; gap: 8px; height: 44px;
}

/* Tabella conversazioni. La prima colonna è una data, non l'etichetta della
   riga: niente grassetto (come nella tabella camere). */
.mconv-table td:first-child { font-weight: 400; }
.mconv-table__when { color: var(--sb-muted); }
/* Il nome dell'ospite può essere lungo: va a capo invece di allargare la tabella. */
.mconv-table__guest { white-space: normal; min-width: 12rem; }
.mconv-table__sub {
  display: block; margin-top: 2px; font-size: 0.78rem; font-weight: 400; color: var(--sb-muted);
}
.mconv-table__count { font-variant-numeric: tabular-nums; }
.mconv-table__status .msvc-badge + .msvc-badge { margin-left: 6px; }

/* Valore non numerico in una tile KPI (una data, una lingua, uno stato): a
   1.6rem andrebbe a capo dentro i 190px minimi della griglia. */
.kpi--compact .kpi__value { font-size: 1.05rem; line-height: 1.25; }
/* Le .panel__section hanno lo stacco di serie, la .kpi-grid no. E come la
   tabella, la riga di tile va a piena larghezza: deve allinearsi al contenuto
   sottostante invece di fermarsi ai 1120px di .kpi-grid. */
.mconv-kpis { max-width: none; margin-bottom: 24px; }

/* Rail del dettaglio: i card devono stare in UN SOLO figlio della .mlist-layout,
   altrimenti diventano due celle della griglia e il secondo va a capo sotto il
   thread. La regola `.mlist-layout > .panel__section` colpisce i figli diretti,
   quindi il margine va tolto anche qui. */
.mconv-rail { display: flex; flex-direction: column; gap: 16px; min-width: 0; }
.mconv-rail > .panel__section { margin: 0; }

/* --- Thread dei messaggi ---------------------------------------------------- */
.mconv { display: flex; flex-direction: column; gap: 14px; margin-top: 14px; }
.mconv__msg { display: flex; align-items: flex-start; gap: 10px; max-width: 82%; }
/* Ospite a destra con l'avatar dal lato suo; assistente e sistema a sinistra. */
.mconv__msg--user { flex-direction: row-reverse; margin-left: auto; }
.mconv__msg--assistant, .mconv__msg--system { margin-right: auto; }

.mconv__avatar {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; border-radius: 50%;
  background: var(--sb-bg-2); color: var(--sb-muted); border: 1px solid var(--sb-line);
}
.mconv__msg--user .mconv__avatar {
  background: var(--sb-chip); color: var(--sb-primary-2); border-color: var(--sb-chip-line);
}
/* Avatar del marchio: l'immagine è già un cerchio bianco con il suo bordo, il
   contenitore ne disegnerebbe un secondo. Vale anche per la card assistente
   della home ospite, che nel tema ha un fondo in gradiente. */
.mconv__avatar--brand, .g-assistant__icon--brand {
  background: none; border: 0; padding: 0; overflow: hidden; border-radius: 50%;
}
.mconv__avatar--brand img, .g-assistant__icon--brand img {
  width: 100%; height: 100%; display: block; object-fit: contain;
}

/* --- Card assistente della home ospite -------------------------------------
   La card è un <a> ma non aveva `text-decoration: none` (a differenza di
   .g-cta): il testo usciva sottolineato. */
.g-assistant { text-decoration: none; color: inherit; }

/* Titolo e sottotitolo su righe separate. Nella variante attiva sono due
   <span> — inline, quindi scorrevano di seguito e i loro margini verticali non
   avevano effetto; in quella disabilitata sono <h2>/<p> e si impilavano già.
   Stessa colonna flex di .g-cta__body, che ha lo stesso markup. */
.g-assistant__body { display: flex; flex-direction: column; flex: 1; min-width: 0; }

/* Chiedere all'assistente è L'azione della home, non una delle tante: la
   versione attiva prende il gradiente del marchio, mentre quella disabilitata
   (senza sessione da QR) resta bianca — la differenza si legge a colpo d'occhio
   invece di affidarsi alla sola opacità. Il logo è un cerchio bianco: sul
   gradiente stacca da solo. */
a.g-assistant {
  background: var(--sb-grad); border-color: transparent; color: #fff;
  box-shadow: var(--sb-shadow-h);
}
a.g-assistant:hover { filter: brightness(1.08); }
a.g-assistant .g-assistant__title { color: #fff; }
a.g-assistant .g-assistant__sub { color: rgba(255, 255, 255, 0.85); }
a.g-assistant .g-cta__arrow { color: #fff; }

.mconv__bubble {
  min-width: 0; padding: 10px 14px; border-radius: 14px; line-height: 1.45;
  background: #fff; border: 1px solid var(--sb-line); color: var(--sb-ink);
}
.mconv__msg--user .mconv__bubble {
  background: var(--sb-grad); border-color: transparent; color: #fff;
}

.mconv__head {
  margin: 0 0 6px; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; font-size: 0.7rem;
}
.mconv__role { font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: var(--sb-muted); }
.mconv__time { color: var(--sb-muted-2); }
.mconv__msg--user .mconv__role, .mconv__msg--user .mconv__time { color: rgba(255, 255, 255, 0.8); }

/* Lingua del messaggio: pillola neutra, che dentro la bolla in gradiente si
   ribalta in chiaro (.msvc-badge non saprebbe farlo). */
.mconv__lang {
  padding: 1px 7px; border-radius: var(--sb-r-pill);
  background: var(--sb-bg-2); color: var(--sb-muted); font-weight: 700; letter-spacing: 0.04em;
}
.mconv__msg--user .mconv__lang { background: rgba(255, 255, 255, 0.2); color: #fff; }
/* "Senza risposta": tinta propria, leggibile su entrambe le bolle. */
.mconv__flag {
  padding: 1px 7px; border-radius: var(--sb-r-pill);
  background: var(--sb-warn-bg); color: var(--sb-warn-fg); font-weight: 700;
}

/* Il testo passa da chat_format: paragrafi, elenchi e link sono nostri. */
.mconv__text { overflow-wrap: anywhere; }
.mconv__text p { margin: 0 0 6px; }
.mconv__text p:last-child { margin-bottom: 0; }
.mconv__text ul, .mconv__text ol { margin: 6px 0; padding-left: 20px; }
.mconv__text li { margin: 3px 0; }
.mconv__text a { color: var(--sb-primary-2); text-decoration: underline; }
.mconv__msg--user .mconv__text a { color: #fff; }

/* --- Card di contesto nel rail ---------------------------------------------- */
.mconv-guest {
  display: flex; align-items: center; gap: 12px;
  padding-bottom: 12px; margin-bottom: 4px; border-bottom: 1px solid var(--sb-line-2);
}
.mconv-guest__avatar {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; border-radius: 50%;
  background: var(--sb-chip); color: var(--sb-primary-2);
  font-family: var(--sb-display); font-size: 1rem; font-weight: 700;
}
.mconv-guest__name {
  margin: 0; font-family: var(--sb-display); font-size: 1rem; font-weight: 700;
  color: var(--sb-ink); overflow-wrap: anywhere;
}
.mconv-guest__sub { margin: 2px 0 0; font-size: 0.82rem; color: var(--sb-muted); }

.mconv-facts { margin: 0; }
.mconv-fact {
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
  padding: 9px 0; border-top: 1px solid var(--sb-line-2);
}
.mconv-fact:first-child { border-top: 0; }
.mconv-fact:last-child { padding-bottom: 0; }
.mconv-fact__label { flex: none; font-size: 0.8rem; color: var(--sb-muted); }
.mconv-fact__value {
  margin: 0; min-width: 0; text-align: right; font-weight: 600;
  color: var(--sb-ink); overflow-wrap: anywhere;
}

/* Badge "riservato a N camere": completa la famiglia .msvc-badge nell'elenco
   servizi (§E19). */
.msvc-badge--rooms { background: var(--sb-chip); color: var(--sb-primary-2); }

/* ==========================================================================
   §E19 — Selettore a tag (servizio ↔ camere)
   Autocomplete client-side: chip rimovibili + menu dei risultati. Il menu può
   stare in position: absolute perché .panel__section non ha overflow (è il
   vincolo che aveva costretto .dropdown al position: fixed dentro .table-card).
   ========================================================================== */
.tagsel { position: relative; }

.tagsel__field {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
  min-height: 44px; padding: 6px 8px; cursor: text;
  background: #fff; border: 1px solid var(--sb-line); border-radius: var(--sb-r-btn);
}
.tagsel__field:focus-within {
  border-color: var(--sb-primary);
  box-shadow: 0 0 0 3px rgba(59, 98, 214, .25);
}

.tagsel__input {
  flex: 1 1 140px; min-width: 140px; padding: 4px 2px;
  border: 0; outline: none; background: transparent; font: inherit; color: var(--sb-ink);
}

.tagsel__chip {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 4px 5px 4px 12px; border-radius: var(--sb-r-pill);
  background: var(--sb-chip); border: 1px solid var(--sb-chip-line);
  color: var(--sb-primary-2); font-size: .82rem; font-weight: 600; white-space: nowrap;
}
.tagsel__remove {
  display: inline-flex; align-items: center; justify-content: center;
  width: 20px; height: 20px; padding: 0; border: 0; border-radius: 50%;
  background: transparent; color: inherit; cursor: pointer; line-height: 1;
}
.tagsel__remove:hover { background: rgba(0, 0, 0, .09); }
.tagsel__remove .icon { width: 14px; height: 14px; }

.tagsel__menu {
  position: absolute; z-index: 40; top: calc(100% + 4px); left: 0; right: 0;
  max-height: 240px; margin: 0; padding: 6px; overflow-y: auto; list-style: none;
  background: #fff; border: 1px solid var(--sb-line); border-radius: 12px;
  box-shadow: 0 10px 30px rgba(2, 32, 71, .14);
}
.tagsel__option {
  padding: 8px 10px; border-radius: 8px; cursor: pointer;
  font-weight: 600; color: var(--sb-ink);
}
.tagsel__option:hover, .tagsel__option.is-active { background: var(--sb-chip); }
.tagsel__hint { padding: 8px 10px; color: var(--sb-muted); font-size: .85rem; }

/* --- §E20 Pulsante "Note" sulle card (bacheca e storico) --------------------
   È un btn--ghost btn--sm: prende dai pulsanti tutta la resa, qui restano solo
   l'allineamento dell'icona e la pastiglia del contatore. */
.req-card__notes,
.reqh-card__notes {
  display: inline-flex; align-items: center; gap: 6px; text-decoration: none;
}
.req-card__notes .icon,
.reqh-card__notes .icon { flex: none; }
/* Pastiglia piena solo quando le note ci sono davvero: un "0" occuperebbe spazio
   per dire che non c'è niente da leggere. */
.req-card__notes-count {
  min-width: 18px; padding: 0 5px; border-radius: 999px; text-align: center;
  background: var(--sb-primary); color: #fff; font-size: 0.7rem; font-weight: 800;
}

/* --- §E20 Dettaglio richiesta e note di lavorazione (Manage::) ---------------
   Il dettaglio vive dentro .modal--wide: niente card/ombre proprie, il riquadro
   ce l'ha già la modal. */
.mreq__head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.mreq__ident { display: flex; flex-direction: column; gap: 2px; }
.mreq__room { font-size: 1rem; font-weight: 800; color: var(--c-blue-900); }
.mreq__guest { font-size: 0.82rem; font-weight: 600; color: var(--sb-primary, #178bc3); }
.mreq__badges { display: flex; gap: 6px; flex-wrap: wrap; }

.mreq__status {
  display: inline-block; margin: 12px 0 0; padding: 3px 10px; border-radius: 999px;
  font-size: 0.7rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.03em;
  background: var(--sb-chip); color: var(--c-ink-soft);
}
.mreq__status--received { background: var(--c-azure-100); color: var(--c-blue-700); }
.mreq__status--in_progress { background: var(--sb-warn-bg, #FDF3DC); color: var(--sb-warn-fg, #92590F); }
.mreq__status--done { background: rgba(70, 180, 80, 0.14); color: var(--sb-green-fg, #147045); }
.mreq__status--cancelled { background: #fdecec; color: var(--sb-danger, #C62828); }

.mreq__subject { margin: 12px 0 4px; font-weight: 700; color: var(--c-ink); }
.mreq__body { margin: 0; color: var(--c-ink); }
.mreq__body p { margin: 0 0 6px; }

.mreq__facts {
  display: flex; flex-wrap: wrap; gap: 6px 14px; margin: 12px 0 0; padding: 0;
  list-style: none; font-size: 0.8rem; color: var(--c-ink-soft);
}
.mreq__staff { margin: 6px 0 0; font-size: 0.78rem; color: var(--c-ink-soft); }

.mreq__actions {
  display: flex; gap: 8px; flex-wrap: wrap; align-items: center;
  margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--sb-line-2);
}
.mreq__actions form { margin: 0; }

.mreq__notes { margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--sb-line-2); }
.mreq__section-title { margin: 0 0 10px; font-size: 0.95rem; color: var(--c-blue-900); }
.mreq__note-readonly { margin: 10px 0 0; font-size: 0.85rem; color: var(--sb-warn-fg, #92590F); }
.mreq__back { margin: 18px 0 0; }

.mreq-notes { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.mreq-notes__empty { font-size: 0.85rem; color: var(--c-ink-soft); }
/* Le due visibilità si distinguono per LUMINOSITÀ e saturazione, non solo per
   tinta: due azzurri chiari vicini (era chip vs azure-100) si leggevano uguali.
   Interna = quasi bianca e desaturata, sta sullo sfondo. Per l'ospite = azzurro
   pieno e bordo di brand, perché quel testo è USCITO dalla struttura. */
.mreq-note {
  padding: 10px 12px; border-radius: 12px;
  background: #F4F5F9; border-left: 3px solid var(--sb-muted-2);
}
.mreq-note--guest { background: #CFE0FF; border-left: 4px solid var(--sb-primary); }
.mreq-note__head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; font-size: 0.72rem; color: var(--c-ink-soft); }
.mreq-note__badge { font-weight: 800; text-transform: uppercase; letter-spacing: 0.03em; color: var(--sb-muted); }
/* Pillola piena: la differenza regge anche a colpo d'occhio, in scala di grigi
   e per chi non distingue bene i colori. */
.mreq-note--guest .mreq-note__badge {
  padding: 1px 8px; border-radius: 999px;
  background: var(--sb-primary); color: #fff;
}
.mreq-note--guest .mreq-note__head { color: var(--sb-primary-2); }
.mreq-note__author { font-weight: 700; }
.mreq-note__time { margin-left: auto; }
.mreq-note__delete { margin: 0; }
.mreq-note__delete-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; padding: 0; border: none; border-radius: 8px;
  background: none; color: var(--c-ink-soft); cursor: pointer;
}
.mreq-note__delete-btn:hover { background: #fdecec; color: var(--sb-danger, #C62828); }
.mreq-note__body { margin-top: 4px; font-size: 0.88rem; color: var(--c-ink); }
.mreq-note__body p { margin: 0 0 4px; }

.mreq-note-form { margin-top: 14px; }
.mreq-note-form__visibility { border: 0; padding: 0; margin: 0 0 12px; }
.mreq-note-form__choice { display: grid; grid-template-columns: auto 1fr; gap: 2px 8px; align-items: center; margin-top: 6px; cursor: pointer; }
.mreq-note-form__choice-label { font-weight: 600; color: var(--c-ink); }
.mreq-note-form__choice-hint { grid-column: 2; font-size: 0.75rem; color: var(--c-ink-soft); }

/* Note della reception nella schermata ospite (mobile-first). */
.g-req-notes:empty { display: none; }
.g-req-notes__title { margin: 10px 0 4px; font-size: 0.72rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.03em; color: var(--c-blue-700); }
.g-req-notes__list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
/* §E23/UX — non più il grigio neutro delle superfici: è un messaggio di
   qualcuno, e nella palette della struttura si legge come tale. L'angolo in
   alto a sinistra resta squadrato — il verso da cui "arriva" — così non si
   confonde con la pillola di stato, che ha lo stesso fondo ma forma diversa.
   Il token è `--sb-chip`, che ogni template ridefinisce nella propria palette. */
.g-req-note {
  padding: 9px 12px; border-radius: 4px 14px 14px 14px;
  background: var(--sb-chip, #E7EAFA);
}
.g-req-note__body { font-size: 0.85rem; color: var(--c-ink); }
.g-req-note__body p { margin: 0 0 4px; }
.g-req-note__time { margin: 2px 0 0; font-size: 0.7rem; color: var(--c-ink-soft); }

/* ==========================================================================
   §E21 — Editor rich text (Lexxy) sui campi descrizione
   Toolbar volutamente minima: link, grassetto, corsivo, sottolineato, elenco
   puntato, elenco numerato (+ annulla/ripristina). Lexxy non espone la
   configurazione per singolo bottone — il preset di default ha solo
   `toolbar.upload` — quindi il resto si nasconde qui. È solo l'aspetto: il
   confine vero è l'allowlist di RichTextFields, che al salvataggio scarta ciò
   che le hotkey native di Lexical riuscissero comunque a produrre.
   ========================================================================== */
.form__rte lexxy-toolbar button[name="strikethrough"],
.form__rte lexxy-toolbar button[name="quote"],
.form__rte lexxy-toolbar button[name="code"],
.form__rte lexxy-toolbar button[name="table"],
.form__rte lexxy-toolbar button[name="divider"],
.form__rte lexxy-toolbar .lexxy-editor__toolbar-dropdown--highlight,
.form__rte lexxy-toolbar lexxy-toolbar-dropdown:has(button[name="format"]) { display: none; }

/* Il campo deve leggersi come gli altri .form__input della scheda. */
.form__rte lexxy-editor {
  border-radius: 11px; border: 1px solid var(--sb-line); background: var(--sb-bg);
}
.form__rte lexxy-editor:focus-within {
  border-color: var(--sb-primary); box-shadow: 0 0 0 3px rgba(59,98,214,.25);
}
.form__rte .lexxy-editor__content { min-height: 7rem; }

/* --- Resa dei contenuti rich text (ospite + pannello) ---------------------- */
.rich-text > :first-child { margin-top: 0; }
.rich-text > :last-child { margin-bottom: 0; }
.rich-text p { margin: 0 0 0.6em; }
.rich-text ul, .rich-text ol { margin: 0 0 0.6em; padding-inline-start: 1.35em; }
.rich-text li { margin-bottom: 0.2em; }
.rich-text a { color: var(--sb-primary); text-decoration: underline; overflow-wrap: anywhere; }

/* ==========================================================================
   §E22 — Fasce di disponibilità dei servizi (pannello) e selettore slot (ospite)
   Righe ripetibili: giorni a checkbox + orario di apertura/chiusura. I giorni
   occupano tutta la larghezza (flex-basis 100%) perché sette caselle non stanno
   accanto a due campi orario dentro una colonna a metà pagina.
   ========================================================================== */
.svc-avail { display: flex; flex-direction: column; gap: 10px; margin-bottom: 12px; }

.svc-avail__row {
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px;
  padding: 10px 12px;
  border: 1px solid var(--sb-line); border-radius: var(--sb-r-btn);
}
.svc-avail__days { flex: 1 1 100%; }
.svc-avail__times { display: flex; align-items: center; gap: 8px; }
.svc-avail__times .form__input--sm { max-width: 130px; }
.svc-avail__sep { color: var(--sb-muted); }

.svc-avail__remove {
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; margin-left: auto; padding: 0;
  border: 0; border-radius: 50%; background: transparent;
  color: var(--sb-muted); cursor: pointer; line-height: 1;
}
.svc-avail__remove:hover { background: rgba(0, 0, 0, .07); color: var(--sb-danger); }
.svc-avail__remove .icon { width: 14px; height: 14px; }

.form__hint--warn { color: var(--sb-warn-fg, #92590F); }

/* Selettore data + orario dell'ospite: senza JS resta un solo <select> con gli
   orari raggruppati per data, quindi il campo delle date parte nascosto. */
.g-slot { display: flex; flex-direction: column; gap: 10px; }

/* ==========================================================================
   §E23/UX — Anteprima del template dell'app ospite (pannello struttura)
   Sostituisce le vecchie radio-card `.tplpick*`: erano miniature disegnate in
   CSS, quindi mostravano un layout astratto e mai il logo, la copertina e i
   servizi DI QUESTA struttura. Qui la dropdown sceglie e l'iframe rende la home
   ospite vera.

   L'iframe si rende alla larghezza logica reale del telefono (390px) e si
   rimpicciolisce con `transform`: restringerlo davvero farebbe scattare le
   @media dell'app ospite e mostrerebbe un layout che nessun ospite vede.
   `pointer-events: none` è il secondo strato dopo `sandbox`: la cornice è una
   fotografia, non un'app da usare (per quella c'è il link sotto).
   ========================================================================== */
.tplprev { --tplprev-w: 390px; --tplprev-h: 760px; --tplprev-scale: .70; margin: 4px 0 12px; }

.tplprev__phone {
  width: max-content; margin: 0 auto; padding: 8px;
  border-radius: 30px; background: #14162a; box-shadow: var(--sb-shadow);
}

.tplprev__stage {
  width: calc(var(--tplprev-w) * var(--tplprev-scale));
  height: calc(var(--tplprev-h) * var(--tplprev-scale));
  border-radius: 22px; overflow: hidden; background: #fff;
}

.tplprev__frame {
  display: block; width: var(--tplprev-w); height: var(--tplprev-h);
  border: 0; pointer-events: none;
  transform: scale(var(--tplprev-scale)); transform-origin: top left;
  transition: opacity .15s;
}
/* Fra il cambio di `src` e il `load` l'iframe mostra ancora il template
   precedente: attenuarlo dice che la scelta è stata registrata. */
.tplprev__frame--busy { opacity: .35; }

/* `.form__cards-col` dichiara già container-type: inline-size. Sul telefono la
   colonna scende sotto i 380px e il telaio a scala piena traboccherebbe. */
@container (max-width: 380px) {
  .tplprev { --tplprev-scale: .56; }
}

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

/* ==========================================================================
   §E23/UX — Apertura della home del template "classic"
   Prima erano tre blocchi impilati: testata (101px) + copertina (197px) +
   saluto su gradiente (206px) = 504px di intestazione su 844, con la prima
   azione a 533px. Ora l'apertura è una sola e porta il saluto dentro di sé.

   Tutto scoped su `classic`: `.gt-hero*` esiste anche nei tre template nuovi,
   che lo ridefiniscono nei propri fogli. Senza questo scoping il gradiente
   indigo colerebbe dentro `night`, `warm` e `utility`.
   ========================================================================== */
.g-body[data-guest-template="classic"] .g-main { padding: 6px 20px 0; }

/* Con la copertina la testata galleggia sulla foto: 100px di intestazione in
   meno, e la foto torna a essere l'apertura invece di un inserto fra due bande. */
.g-body[data-guest-template="classic"][data-guest-hero="cover"] .g-topbar {
  position: absolute; top: 0; left: 0; right: 0; z-index: 30;
  background: transparent; box-shadow: none;
}
.g-body[data-guest-template="classic"] .g-app { position: relative; }

/* Senza copertina la testata è in tinta piatta e la fascia del saluto riparte
   dallo STESSO colore: prima i due gradienti si toccavano ripartendo entrambi
   da capo e lasciavano una giunzione visibile. */
.g-body[data-guest-template="classic"][data-guest-hero="plain"] .g-topbar {
  background: var(--sb-primary-600);
}

.g-body[data-guest-template="classic"] .gt-hero--cover {
  position: relative; height: 260px; overflow: hidden; background: var(--sb-chip);
}
.g-body[data-guest-template="classic"] .gt-hero--cover .gt-hero__img {
  width: 100%; height: 100%; object-fit: cover; display: block;
}
.g-body[data-guest-template="classic"] .gt-hero__scrim {
  position: absolute; inset: 0;
  background: linear-gradient(180deg,
    rgba(13, 11, 51, .60) 0%, rgba(13, 11, 51, .06) 26%,
    rgba(13, 11, 51, .80) 58%, rgba(13, 11, 51, .97) 100%);
}
.g-body[data-guest-template="classic"] .gt-hero--cover .gt-hero__body {
  position: absolute; left: 20px; right: 20px; bottom: 18px;
}

.g-body[data-guest-template="classic"] .gt-hero--plain {
  background: linear-gradient(180deg, var(--sb-primary-600) 0%, var(--sb-primary-2) 100%);
  padding: 8px 20px 26px;
}

.g-body[data-guest-template="classic"] .gt-hero__title {
  margin: 0; font-family: var(--sb-display); font-weight: 600;
  font-size: 1.7rem; line-height: 1.15; color: #fff;
}
.g-body[data-guest-template="classic"] .gt-hero__sub {
  margin: 6px 0 0; line-height: 1.5; color: rgba(255, 255, 255, .85);
}
/* Sulla foto il badge camera ha bisogno del proprio fondo per restare leggibile
   qualunque cosa ci sia sotto. */
.g-body[data-guest-template="classic"] .gt-hero__badge {
  display: inline-flex; align-items: center; gap: 6px;
  margin-bottom: 10px; padding: 6px 13px; border-radius: var(--sb-r-pill);
  background: rgba(13, 11, 51, .62); backdrop-filter: blur(6px);
  color: #fff; font-size: 0.8rem; font-weight: 700;
}

/* ==========================================================================
   §E23/UX — Card del catalogo
   ========================================================================== */

/* Il nome del servizio era 0.98rem: PIÙ PICCOLO del testo corrente, con sopra
   una eyebrow maiuscola che gli rubava l'attenzione. È l'elemento che l'ospite
   sta cercando, quindi sale e si prende due righe piene. */
.g-service__name {
  font-size: 1.02rem; line-height: 1.25;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}
.g-cat__name { font-size: 1.02rem; line-height: 1.25; }

/* --- Card alte uguali e testo troncato ------------------------------------
   Due categorie affiancate si sfalsavano per la sola lunghezza della
   descrizione (misurato in home: 216px e 233px). `grid-auto-rows: 1fr` pareggia
   TUTTE le righe, non solo quelle affiancate, così la griglia resta regolare
   anche scorrendo.
   `night` e `utility` disegnano le categorie come righe di elenco a una
   colonna: lì pareggiare vorrebbe dire allungare ogni riga fino alla più
   lunga, quindi si tirano fuori nei propri fogli. */
/* Le righe si dimensionano sul contenuto e le card si allungano fino al bordo
   della PROPRIA riga: due categorie affiancate diventano uguali, che è dove lo
   sfalsamento si vede. Pareggiare anche fra righe diverse (`grid-auto-rows: 1fr`)
   costringerebbe le card senza foto — molto più basse — a riempire un'altezza
   che non hanno. */
.g-grid--even > :not(.g-cat--flat) { align-self: stretch; }

/* Lo spazio in più deve finire in un posto solo e prevedibile: il conteggio
   scende in fondo alla card invece di lasciare un vuoto sotto di sé. */
.g-cat__body { display: flex; flex-direction: column; flex: 1; }
.g-cat__count { margin-top: auto; align-self: start; }

/* Senza immagine la card si adatta al contenuto: non c'è un riquadro foto da
   pareggiare, e allungarla fino a una con foto (114px contro 233) vorrebbe dire
   riempire di vuoto. Il conteggio segue il testo invece di essere spinto in
   fondo: senza spazio da distribuire, `margin-top: auto` varrebbe zero e la
   riga si appiccicherebbe alla descrizione. */
.g-cat--flat .g-cat__count { margin-top: 8px; }

/* Il testo si tronca: un nome o una descrizione lunghi non devono decidere
   l'altezza dell'intera griglia. `.g-cat__desc` è già accorciato a 70 caratteri
   lato server, ma in una card da 169px quei 70 caratteri sono tre righe. */
.g-cat__name, .g-cat__desc, .g-service__hours {
  display: -webkit-box; -webkit-box-orient: vertical; overflow: hidden;
}
/* Il `max-height` NON è ridondante: questi tre sono elementi di un contenitore
   flex, quindi `-webkit-box` viene blockificato e il vecchio WebKit smette di
   applicare il clamp. Dove il clamp funziona si vedono i puntini; dove non
   funziona il testo si taglia comunque, e l'altezza resta quella prevista —
   che è l'unica cosa da cui dipende la griglia. */
.g-cat__name { -webkit-line-clamp: 2; line-clamp: 2; max-height: 2.5em; }   /* 2 × 1.25 */
.g-cat__desc { -webkit-line-clamp: 2; line-clamp: 2; max-height: 2.7em; }   /* 2 × 1.35 */
/* Gli orari sono una riga sola per costruzione, ma una fascia con più
   intervalli ("09:00–12:00, 15:00–18:00") ne occupa due. */
.g-service__hours { -webkit-line-clamp: 1; line-clamp: 1; max-height: 1.5em; }

/* Card senza foto: non c'è riquadro da riempire, quindi il corpo respira come
   una card a sé invece di sembrare monco. */
.g-service--flat .g-service__body,
.g-cat--flat .g-cat__body { padding: 14px; }

/* La griglia è a righe: una card con foto allunga la propria riga e quella
   accanto restava orfana in cima, con la successiva mandata a capo nell'altra
   colonna (misurato in "In evidenza": 393px, ~121 di spazio morto).
   Una card con foto è alta all'incirca quanto DUE senza (251px contro 130):
   facendogliene occupare due, le card basse le si impilano accanto — 272px.
   La classe c'è già sulla card, quindi niente `:has()` e nessun dubbio sul
   supporto nei WebKit più vecchi. Dove la griglia ha una colonna sola
   (`night`, `utility`) o è un rail (`warm`, in evidenza) non ha effetto. */
.g-grid > .g-service:not(.g-service--flat) { grid-row: span 2; align-self: stretch; }

/* Lo spazio che avanza fra l'altezza naturale della card con foto e quella
   delle due che le stanno accanto lo prende la FOTO, non il corpo: il testo
   resta allineato a quello delle card vicine invece di avere sotto un margine
   che le altre non hanno. `flex-grow` e basta — con `flex: 1` la base andrebbe
   a zero e l'immagine collasserebbe dove non c'è spazio da distribuire. */
.g-service__media { flex-grow: 1; }

.g-service__badges--inline {
  position: static; margin: 0 0 8px; display: flex; flex-wrap: wrap; gap: 6px;
}

/* Prezzo e orari: due righe distinte, non due frammenti che si accavallano. */
.g-service__meta { gap: 3px; }

/* ==========================================================================
   §E23/UX — Aree toccabili dell'app ospite
   Su ~22 elementi interattivi solo 7 arrivavano a 44px, e uno solo per scelta
   (`.g-wa-btn`). I tre peggiori erano azioni frequenti: il link "indietro"
   (~20px, navigazione primaria di 9 viste su 12), il titolo di una FAQ (~20px,
   il modo per leggerle) e l'email nel footer (~19px).
   ========================================================================== */
/* Il margine negativo compensa il padding: l'area toccabile cresce, il testo
   resta allineato al resto della pagina. */
.g-back { min-height: 44px; padding: 0 10px; margin: 0 0 2px -10px; }
.g-faq__q { padding: 12px 0; min-height: 44px; display: flex; align-items: center; }
.g-faq__q::after { margin-left: auto; float: none; }
.g-faq { padding: 0 14px; }
.g-faq__a { padding-bottom: 12px; }
.g-footer__link { display: inline-block; min-height: 44px; line-height: 44px; }

/* Chip e bottoni piccoli: 32px è sotto la soglia di qualunque linea guida. */
.g-wifi__copy, .btn--sm { min-height: 36px; height: auto; }
/* L'area toccabile arriva a 44px senza spostare la grafica. */
.g-wifi__copy::after, .btn--sm::after {
  content: ""; position: absolute; inset: -4px; border-radius: inherit;
}
.g-wifi__copy, .btn--sm { position: relative; }

/* Selettore lingua: era 30px. */
.g-lang__current { min-height: 40px; }
.g-lang__item { min-height: 44px; }

/* Il bottone primario è `#178bc3`, un azzurro che non sta in nessun token del
   tema: nell'app ospite stona con l'indigo di testata, link e badge. Corretto
   SOLO lato ospite — nel pannello è una scelta di marca, non un difetto. */
.g-body .btn--primary {
  background: var(--sb-primary-600); box-shadow: 0 6px 16px rgba(23, 0, 142, .18);
}
.g-body .btn--primary:hover { background: var(--sb-primary-2); filter: none; }

/* Da quando le card senza foto non disegnano il riquadro, una riga può mettere
   accanto una card alta (con foto) e una bassa: senza questo, la bassa si
   stirava all'altezza dell'altra e restava con un buco bianco dentro. Ora ogni
   card è alta quanto il suo contenuto e lo spazio avanza SOTTO, dove non si
   legge come un errore. */
.g-grid { align-items: start; }

/* ==========================================================================
   §E23/UX — Moduli dell'app ospite.

   Il form era l'UNICO blocco interattivo senza superficie: `.g-service`,
   `.g-wifi`, `.g-contacts` e `.g-list__item` sono card bianche, il modulo
   galleggiava sulla pagina. E i campi non staccavano perché erano LO STESSO
   COLORE della pagina: `.form__input` prende `background: var(--sb-bg)` e
   `.g-body` prende lo stesso token (#F6F7FC). L'unico confine era il bordo
   `--sb-line`, che contro la pagina misura 1.18:1 — WCAG 1.4.11 ne chiede 3.
   ========================================================================== */
.g-form-card { padding: 18px 16px; margin-bottom: 4px; }

/* Il campo si INCASSA nella card: fondo smorzato e contorno a tono medio, che
   sul bianco della card misura 3.14:1. Il solo riempimento non basterebbe
   (#EFF0F7 su bianco è 1.14:1): è il contorno a portare il contrasto, ed è per
   questo che serve la card sotto. Scopato a `.g-body` — nel pannello i campi
   stanno già dentro `.panel__section` bianche e leggono correttamente. */
.g-body .form__input {
  background: var(--sb-bg-2);
  border: 1px solid var(--sb-muted-2);
  padding: 12px 14px;
}
.g-body .form__input:focus {
  background: #fff;
  border-color: var(--sb-primary);
  box-shadow: 0 0 0 3px rgba(59, 98, 214, .25);
}
.g-body .form__label { color: var(--sb-ink); }

/* Un `select` non deve somigliare a un campo di testo: il selettore di data e
   quello di orario erano indistinguibili da una casella scrivibile. */
.g-body select.form__input {
  appearance: none; -webkit-appearance: none;
  padding-right: 40px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 24 24' fill='none' stroke='%235A5F80' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
}

/* Il selettore data e quello orario sono due righe simmetriche: prima la label
   era figlia diretta di `.g-slot`, accanto al blocco della data, e le due
   etichette si accavallavano finché Stimulus non entrava in gioco. */
.g-slot__date, .g-slot__time { display: block; }

/* L'azione principale della pagina era il bersaglio più piccolo: bottone
   inline da 40px, dopo che la CTA che ci ha portato qui era a tutta larghezza. */
.g-form-card .form__actions { margin-top: 18px; }
.g-form-card .form__actions .btn { width: 100%; height: 48px; }

/* --- Riepilogo del servizio richiesto --------------------------------------
   Sostituisce la coppia eyebrow + nome: l'ospite vede orari e prezzo MENTRE
   sceglie, invece di doverli ricordare dalla pagina precedente. */
.g-recap { display: flex; gap: 12px; padding: 14px; margin-bottom: 12px; }
.g-recap__media { flex: none; width: 68px; height: 68px; border-radius: 12px; overflow: hidden; }
.g-recap__img { width: 100%; height: 100%; object-fit: cover; display: block; }
.g-recap__body { flex: 1; min-width: 0; }
.g-recap__cat {
  margin: 0; font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.4px;
  color: var(--c-blue-500); font-weight: 700;
}
.g-recap__name { margin: 1px 0 6px; font-size: 1.05rem; font-weight: 700; color: var(--c-blue-900); line-height: 1.25; }

/* --- Contatore persone -----------------------------------------------------
   Un campo numerico su mobile è un bersaglio scomodo e le frecce native non
   esistono. I bottoni li aggiunge Stimulus: senza JS resta il campo, che
   funziona come prima. */
.g-stepper { display: flex; align-items: center; gap: 10px; }
.g-stepper__btn {
  flex: none; width: 44px; height: 44px; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--sb-muted-2); border-radius: 12px;
  background: #fff; color: var(--sb-ink);
  font-size: 1.3rem; font-weight: 600; line-height: 1; cursor: pointer;
}
.g-stepper__btn:hover:not(:disabled) { background: var(--sb-bg-2); }
.g-stepper__btn:disabled { opacity: .45; cursor: default; }
.g-body .g-stepper .form__input {
  width: 72px; max-width: none; text-align: center;
  font-weight: 600; font-variant-numeric: tabular-nums;
}
.g-total { margin: 8px 0 0; font-size: 0.92rem; font-weight: 600; color: var(--c-blue-900); }

/* ==========================================================================
   §E23/UX — Navigazione fra le sezioni (tutti i template tranne `utility`,
   che ha la tab bar in fondo). Sta sotto l'apertura e sopra il contenuto, su
   OGNI pagina: prima, fuori dalla home, l'unica navigazione era il link
   "indietro" e il catalogo non si raggiungeva da nessun'altra parte.
   Scorre in orizzontale se le voci non ci stanno: meglio che mandarle a capo
   e far ballare l'altezza della testata da una pagina all'altra.
   ========================================================================== */
.g-sectionnav { margin: 0; }

.g-sectionnav__list {
  display: flex; gap: 8px; margin: 0; padding: 12px 20px 6px;
  list-style: none; overflow-x: auto; scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}
.g-sectionnav__list::-webkit-scrollbar { display: none; }

.g-sectionnav__item {
  display: inline-flex; align-items: center; gap: 6px;
  min-height: 40px; padding: 0 14px; white-space: nowrap;
  border-radius: var(--sb-r-pill); border: 1px solid var(--sb-line);
  background: #fff; color: var(--sb-muted);
  font-size: 0.85rem; font-weight: 600; text-decoration: none;
}
.g-sectionnav__item .icon { width: 16px; height: 16px; flex: none; }
.g-sectionnav__item:hover { border-color: var(--sb-primary-300); color: var(--sb-ink); }

/* La voce corrente non si affida al solo colore: cambia anche fondo e bordo. */
.g-sectionnav__item--active {
  background: var(--sb-primary); border-color: var(--sb-primary); color: #fff;
}
.g-sectionnav__item--active:hover { background: var(--sb-primary-2); color: #fff; }

/* §E23/UX — "Le mie richieste" vive nella testata, non fra le sezioni: segna
   comunque la pagina corrente, con fondo pieno oltre che col colore. Il minimo
   di 40px porta il bersaglio a misura di dito (era ~28px). */
.g-topbar__action { min-height: 40px; }
.g-topbar__action--active { background: #fff; color: var(--sb-primary); }

/* ============================================================================
   §E28 — Selettore immagine: nessuna / galleria proposta / foto propria.
   Usato dal form categoria e dal form servizio (manage/shared/_photo_picker).
   ========================================================================= */

/* Il fieldset serve per legend + gruppo di radio: la cornice del browser no. */
.imgpick__fieldset { border: 0; padding: 0; margin: 0; min-width: 0; }
.imgpick__fieldset > .form__label { padding: 0; }

.imgpick__modes { margin-top: 6px; }

.imgpick__preview { margin: 6px 0 10px; }
.imgpick__current {
  display: block; width: 120px; height: 80px; object-fit: cover;
  border-radius: 10px; border: 1px solid var(--sb-line);
}

.imgpick__panel { margin-top: 10px; }
.imgpick__panel[hidden] { display: none; }

/* La galleria scorre dentro il suo riquadro: trenta foto nella colonna stretta
   del form servizio spingerebbero il pulsante Salva fuori da due schermate. */
.imgpick__panel--gallery {
  max-height: 380px; overflow-y: auto; padding: 10px;
  border: 1px solid var(--sb-line); border-radius: var(--sb-r-card);
  background: var(--sb-bg);
}

.imgpick__group {
  margin: 12px 0 6px; font-size: 0.8rem; font-weight: 600;
  color: var(--sb-muted); text-transform: uppercase; letter-spacing: 0.04em;
}
.imgpick__group:first-of-type { margin-top: 0; }

.imgpick__grid {
  display: grid; gap: 10px;
  grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
}

.imgpick__tile { display: block; cursor: pointer; }
.imgpick__tile-img {
  display: block; width: 100%; aspect-ratio: 4 / 3; object-fit: cover;
  border-radius: var(--sb-r-btn); border: 2px solid var(--sb-line);
}
.imgpick__tile:hover .imgpick__tile-img { border-color: var(--sb-primary-300); }

/* Selezione: bordo pieno PIÙ anello esterno. Il solo cambio di colore del bordo
   si perde su una foto scura quanto il blu del tema. */
.imgpick__tile input:checked + .imgpick__tile-img {
  border-color: var(--sb-primary);
  box-shadow: 0 0 0 3px var(--sb-chip);
}
/* Il radio è visually-hidden ma resta raggiungibile da tastiera: il focus deve
   comunque vedersi, e l'unica cosa visibile è l'immagine accanto. */
.imgpick__tile input:focus-visible + .imgpick__tile-img {
  outline: 2px solid var(--sb-primary-500); outline-offset: 2px;
}

.imgpick__file { max-width: 100%; }

/* ==========================================================================
   §E30 — Documenti legali di piattaforma
   Pagina pubblica (prosa lunga) + sorgente markdown in back-office.
   .rich-text non basta qui: copre solo paragrafi, elenchi e link, mentre un
   testo legale ha titoli, tabelle e citazioni.
   ========================================================================== */
.legal {
  min-height: 100vh;
  display: flex;
  justify-content: center;
  padding: 32px 20px;
}

.legal__card {
  background: var(--c-white);
  border-radius: var(--sb-r-card);
  box-shadow: var(--sb-shadow);
  /* 72ch: la misura oltre cui l'occhio perde la riga tornando a capo, ed è
     esattamente quello che si fa leggendo venti paragrafi di contratto. */
  max-width: 72ch;
  width: 100%;
  margin: auto;
  padding: 32px 34px;
}

.legal__brand { display: inline-block; margin-bottom: 18px; }

.legal__head { border-bottom: 1px solid var(--sb-line); padding-bottom: 18px; margin-bottom: 24px; }

.legal__title { font-family: var(--sb-display); margin: 0 0 8px; color: var(--sb-ink); }

.legal__meta { margin: 0; color: var(--sb-muted); font-size: 0.9rem; }

/* Avviso "stai leggendo una versione superata": icona + testo, mai il solo colore. */
.legal__notice {
  display: flex; gap: 10px; align-items: flex-start;
  margin: 16px 0 0; padding: 12px 14px;
  border-radius: var(--sb-r-btn);
  background: var(--sb-warn-bg); color: var(--sb-warn-fg);
  font-size: 0.9rem;
}
.legal__notice a { color: inherit; font-weight: 600; }

/* --- Prosa del documento --------------------------------------------------- */
.legal__body { color: var(--sb-ink); line-height: 1.65; overflow-wrap: anywhere; }
.legal__body > :first-child { margin-top: 0; }
.legal__body > :last-child { margin-bottom: 0; }
.legal__body h1, .legal__body h2, .legal__body h3,
.legal__body h4, .legal__body h5, .legal__body h6 {
  font-family: var(--sb-display); color: var(--sb-ink); line-height: 1.25;
  margin: 1.8em 0 0.6em;
}
.legal__body h1 { font-size: 1.5rem; }
.legal__body h2 { font-size: 1.25rem; }
.legal__body h3 { font-size: 1.05rem; }
.legal__body h4, .legal__body h5, .legal__body h6 { font-size: 1rem; }
.legal__body p { margin: 0 0 1em; }
.legal__body ul, .legal__body ol { margin: 0 0 1em; padding-inline-start: 1.4em; }
.legal__body li { margin-bottom: 0.35em; }
.legal__body dt { font-weight: 600; margin-top: 0.6em; }
.legal__body dd { margin: 0 0 0.4em 1.4em; }
.legal__body a { color: var(--sb-primary); text-decoration: underline; }
.legal__body hr { border: 0; border-top: 1px solid var(--sb-line); margin: 2em 0; }
.legal__body blockquote {
  margin: 0 0 1em; padding: 2px 0 2px 16px;
  border-inline-start: 3px solid var(--sb-line);
  color: var(--sb-muted);
}
.legal__body code {
  background: var(--sb-page); border-radius: 6px; padding: 1px 5px; font-size: 0.9em;
}

/* Una tabella di trattamento dati è larga: scorre da sola invece di allargare
   la pagina e mandare in orizzontale tutto il resto del testo. */
.legal__body table {
  display: block; overflow-x: auto; max-width: 100%;
  border-collapse: collapse; margin: 0 0 1.2em; font-size: 0.92rem;
}
.legal__body th, .legal__body td {
  border: 1px solid var(--sb-line); padding: 8px 10px; text-align: start; vertical-align: top;
}
.legal__body th { background: var(--sb-page); font-weight: 600; }

/* --- Piede: lingua e altre versioni ---------------------------------------- */
.legal__foot { border-top: 1px solid var(--sb-line); padding-top: 18px; margin-top: 28px; }
.legal__langs, .legal__versions {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 0 0 12px;
}
.legal__langs-label { color: var(--sb-muted); font-size: 0.85rem; }
.legal__version {
  padding: 3px 9px; border-radius: var(--sb-r-pill);
  border: 1px solid var(--sb-line); color: var(--sb-muted);
  font-size: 0.8rem; text-decoration: none;
}
.legal__version--active { border-color: var(--sb-primary); color: var(--sb-primary); font-weight: 600; }

/* --- Sorgente markdown in back-office --------------------------------------
   È un SORGENTE, non un campo rich text: a spaziatura proporzionale una tabella
   markdown diventa illeggibile e il rientro degli elenchi non si vede. */
.form__input--code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.88rem;
  line-height: 1.55;
  min-height: 24rem;
  white-space: pre;
  overflow-wrap: normal;
  overflow-x: auto;
}

/* --- §E30.1 Nav di paginazione (elenchi di back-office) ---------------------
   Precedente / stato / successiva. Lo stato sta al centro anche quando manca una
   delle due frecce (prima e ultima pagina): senza `margin-inline: auto` il testo
   salterebbe da un lato all'altro sfogliando. */
.pagenav {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 16px;
  flex-wrap: wrap;
}

.pagenav__status {
  margin: 0 auto;
  color: var(--sb-muted);
  font-size: 0.88rem;
}

/* Le frecce hanno icona + testo: l'icona da sola non dice quale delle due è,
   a chi sfoglia con lo screen reader come a chi guarda di fretta. */
.pagenav .btn { display: inline-flex; align-items: center; gap: 6px; }
