/* =============================================================================
   XV AÑOS INVITATION — Liquid Glass / Glassmorphism
   Theme: "La Princesa y el Sapo" — bayou greens + princess gold.
   -----------------------------------------------------------------------------
   ORGANIZATION
   1. Theme variables (CENTRALIZED PALETTE — change colors here)
   2. Reset & base
   3. Background with depth
   4. Reusable "glass" material (.glass)
   5. Typography / titles / buttons
   6. Per-section components
   7. Micro-interactions (reveal on scroll)
   8. Side navigation + theme toggle
   9. Responsive (mobile-first is the base; here are >= tablet enhancements)
   ============================================================================= */

/* =============================================================================
   1. THEME VARIABLES  ·  the WHOLE palette lives here
   ============================================================================= */
:root {
  /* Typography */
  --font-serif: "Cormorant Garamond", Georgia, serif;
  --font-sans:  "Jost", system-ui, -apple-system, sans-serif;

  /* Shared measurements / shapes */
  --radius-lg: 24px;
  --radius-md: 16px;
  --radius-sm: 10px;
  --maxw: 720px;
  --blur: 18px;               /* glass blur intensity */
  --ease: cubic-bezier(.22, 1, .36, 1);
}

/* ---- THEME A · LIGHT (mármol claro + oro) ---------------------------------
   Valores tomados del mockup «Glass Neumorph», sección 4a. El verde es más
   cálido y olivo que el menta anterior, y el oro (--accent-2) pesa mucho más:
   es el hilo que cose toda la invitación (filetes, aros, acentos). ---------- */
body.theme-light {
  --bg-base:        #f4f5ec;                        /* background fallback */

  /* MÁRMOL CLARO (se combina en .bg-image) — crema y salvia, no verde menta */
  --marble-base:    #f2f4e9;
  --marble-1:       #faf9f4;                        /* light veins/areas */
  --marble-2:       #e2e9d3;                        /* deeper sage */
  --marble-3:       #f7f6ef;
  --marble-vein:    rgba(122, 145, 98, 0.09);       /* fine marble veins */
  --marble-gold:    rgba(201, 162, 39, 0.55);       /* GOLD veining (firma del mockup) */
  --bg-overlay:     rgba(250, 251, 244, 0.10);      /* VERY subtle veil (marble shows through) */

  --text:           #22400f;                        /* main text (deep forest) */
  --text-soft:      rgba(45, 72, 22, 0.70);         /* secondary text */
  --accent:         #4a7025;                        /* verde hoja */
  --accent-soft:    rgba(74, 112, 37, 0.14);
  --accent-2:       #c9a227;                        /* ORO */
  --accent-2-soft:  rgba(201, 162, 39, 0.18);

  /* Court of honor roles (dama = rosa, chambelán = oro), tuned for enough
     contrast over the light glass. */
  --dama:           #c2557e;                         /* rosa (pink) */
  --caballero:      #a07a26;                         /* oro (gold) */

  /* --- Semantic colors for panel features (tables, zones, door mode, tickets) --- */
  --table-partial:      #d9a441;                      /* amber/gold for partial occupancy */
  --table-partial-soft: rgba(217, 164, 65, 0.16);
  --table-full:         #6f9e6a;                      /* green for full occupancy */
  --table-full-soft:    rgba(111, 158, 106, 0.18);
  --zone-pista:         var(--accent-soft);           /* dance floor */
  --zone-honor:         var(--accent);                /* honor table (was novios) */
  --zone-honor-soft:    var(--accent-soft);
  --zone-entrada:       var(--glass-border);          /* entrance */
  --zone-columna:       var(--glass-bg-strong);       /* column */
  --zone-muro:          var(--text-soft);             /* wall */
  --door-valid:         var(--accent);                /* valid entry */
  --door-valid-soft:    var(--accent-soft);
  --door-used:          var(--accent-2);              /* already used (gold) */
  --door-used-soft:     var(--accent-2-soft);
  --door-invalid:       #c4746e;                      /* invalid entry (coral) */
  --door-invalid-soft:  rgba(179, 38, 30, 0.16);
  --ticket-cancelled:   #c4746e;                      /* cancelled ticket */
  --ticket-cancelled-soft: rgba(179, 38, 30, 0.12);

  /* --- MATERIAL 1 · VIDRIO (tarjetas grandes de sección) --- */
  --glass-bg:       linear-gradient(150deg, rgba(255,255,255,.62), rgba(232,242,214,.34));
  --glass-bg-strong:linear-gradient(145deg, rgba(255,255,255,.72), rgba(226,238,206,.36));
  --glass-border:   rgba(255, 255, 255, 0.72);
  --glass-highlight:rgba(255, 255, 255, 0.92);
  --glass-shadow:   0 24px 54px rgba(52, 72, 32, 0.22), inset 0 1px 0 rgba(255,255,255,.92);

  /* --- MATERIAL 2 · RELIEVE (píldoras, casillas, círculos) --- */
  --soft-raised:    6px 6px 16px rgba(120,132,96,.24), -5px -5px 14px rgba(255,255,255,.90);
  --soft-raised-sm: 4px 4px 11px rgba(120,132,96,.22), -3px -3px 9px rgba(255,255,255,.85);
  /* --- MATERIAL 3 · HUNDIDO (campos, mapas, fotos, mini-calendario) --- */
  --soft-inset:     inset 8px 8px 20px rgba(86,106,62,.26), inset -6px -6px 16px rgba(255,255,255,.35);
  --soft-inset-sm:  inset 6px 6px 16px rgba(120,132,96,.16), inset -5px -5px 14px rgba(255,255,255,.70);
  --well-bg:        rgba(255, 255, 255, 0.50);      /* fondo de lo hundido */

  /* Botón principal: gradiente verde con filo de luz arriba */
  --btn-grad:       linear-gradient(150deg, #5b8a2c, #3c6117);
  --btn-shadow:     0 12px 26px rgba(48,74,22,.40), inset 0 1px 0 rgba(255,255,255,.40);

  --on-accent:      #f4f8ec;                          /* text over the button */

  /* Organizer console surfaces (validar.html · section 13). The console dims the
     marble so it reads as an admin panel instead of the invitation. */
  --dash-veil:
    radial-gradient(130% 120% at 50% -10%, rgba(255,255,255,.55), transparent 62%),
    linear-gradient(180deg, rgba(250,251,244,.82), rgba(232,238,220,.90));
  --dash-sidebar-bg: rgba(255,255,255,.70);
  --dash-topbar-bg:  rgba(255,255,255,.56);
  /* El modal va sobre un velo oscuro: necesita una superficie casi sólida,
     el vidrio translúcido se ensucia y deja los campos ilegibles. */
  --modal-bg:        rgba(250,253,246,.96);
}

/* ---- THEME B · DARK (mármol oscuro + oro) ---------------------------------
   Mockup sección 4b. El vidrio se vuelve casi negro-verdoso y el filo de luz
   baja a rgba(255,255,255,.10): en oscuro un blanco fuerte "mancha" el borde.
   El oro se mantiene idéntico en los dos temas — es el ancla de la identidad. */
body.theme-dark {
  --bg-base:        #0e1508;

  --marble-base:    #131c0d;
  --marble-1:       #1b2413;
  --marble-2:       #0f150b;
  --marble-3:       #1a2312;
  --marble-vein:    rgba(140, 175, 96, 0.06);
  --marble-gold:    rgba(201, 162, 39, 0.30);        /* la veta dorada, más contenida */
  --bg-overlay:     rgba(10, 18, 8, 0.55);           /* night veil over the marble */

  --text:           #f0f6e6;
  --text-soft:      rgba(216, 230, 196, 0.65);
  --accent:         #8caf60;                          /* verde hoja iluminado */
  --accent-soft:    rgba(140, 175, 96, 0.18);
  --accent-2:       #c9a227;                          /* ORO — mismo en ambos temas */
  --accent-2-soft:  rgba(201, 162, 39, 0.20);

  /* Court of honor roles — lighter tints so they pop on the dark glass */
  --dama:           #f0a0c0;                          /* rosa (pink) */
  --caballero:      #e6cf86;                          /* oro (gold) */

  /* --- Semantic colors for panel features (tables, zones, door mode, tickets) --- */
  --table-partial:      #d9a441;                      /* amber/gold for partial occupancy */
  --table-partial-soft: rgba(217, 164, 65, 0.16);
  --table-full:         #6f9e6a;                      /* green for full occupancy */
  --table-full-soft:    rgba(111, 158, 106, 0.18);
  --zone-pista:         var(--accent-soft);           /* dance floor */
  --zone-honor:         var(--accent);                /* honor table (was novios) */
  --zone-honor-soft:    var(--accent-soft);
  --zone-entrada:       var(--glass-border);          /* entrance */
  --zone-columna:       var(--glass-bg-strong);       /* column */
  --zone-muro:          var(--text-soft);             /* wall */
  --door-valid:         var(--accent);                /* valid entry */
  --door-valid-soft:    var(--accent-soft);
  --door-used:          var(--accent-2);              /* already used (gold) */
  --door-used-soft:     var(--accent-2-soft);
  --door-invalid:       #e88d8d;                      /* invalid entry (light coral for dark bg) */
  --door-invalid-soft:  rgba(179, 38, 30, 0.16);
  --ticket-cancelled:   #e88d8d;                      /* cancelled ticket */
  --ticket-cancelled-soft: rgba(179, 38, 30, 0.12);

  --glass-bg:       linear-gradient(150deg, rgba(255,255,255,.045), rgba(140,175,96,.06));
  --glass-bg-strong:linear-gradient(145deg, rgba(255,255,255,.08), rgba(140,175,96,.06));
  --glass-border:   rgba(255, 255, 255, 0.10);
  --glass-highlight:rgba(255, 255, 255, 0.14);
  --glass-shadow:   0 24px 54px rgba(0, 0, 0, 0.50), inset 0 1px 0 rgba(255,255,255,.10);

  --soft-raised:    6px 6px 16px rgba(0,0,0,.50), -5px -5px 14px rgba(255,255,255,.045);
  --soft-raised-sm: 4px 4px 11px rgba(0,0,0,.45), -3px -3px 9px rgba(255,255,255,.04);
  --soft-inset:     inset 8px 8px 20px rgba(0,0,0,.55), inset -6px -6px 16px rgba(255,255,255,.05);
  --soft-inset-sm:  inset 6px 6px 16px rgba(0,0,0,.45), inset -5px -5px 14px rgba(255,255,255,.04);
  --well-bg:        rgba(255, 255, 255, 0.02);

  --btn-grad:       linear-gradient(150deg, #5b8a2c, #3c6117);
  --btn-shadow:     0 12px 26px rgba(0,0,0,.50), inset 0 1px 0 rgba(255,255,255,.18);

  --on-accent:      #f4f8ec;

  /* Organizer console surfaces (validar.html · section 13). */
  --dash-veil:
    radial-gradient(130% 120% at 50% -10%, rgba(30,50,26,.30), transparent 62%),
    linear-gradient(180deg, rgba(14,21,8,.86), rgba(9,14,6,.93));
  --dash-sidebar-bg: rgba(19,28,13,.82);
  --dash-topbar-bg:  rgba(15,22,11,.60);
  --modal-bg:        rgba(26,35,18,.97);
}

/* =============================================================================
   2. RESET & BASE
   ============================================================================= */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

/* overflow-x:hidden must be on <html> too — on mobile, setting it only on
   <body> does NOT stop the viewport from scrolling horizontally, which lets
   any stray overflow push fixed overlays (like the .entry envelope) off-center. */
html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; overflow-x: hidden; }

body {
  font-family: var(--font-sans);
  color: var(--text);
  background: var(--bg-base);
  line-height: 1.65;
  font-weight: 300;
  /* El recorte horizontal vive SOLO en `html` (arriba). Aquí no va ningún
     overflow-x: `hidden` convertía al body en contenedor de scroll y eso anulaba
     el `position: sticky` de la barra lateral del panel, y `clip` arrastra el eje
     vertical a `clip` y deja la página sin scroll. */
  transition: color .5s var(--ease), background .5s var(--ease);
}

img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }

/* Respect users who prefer reduced motion */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  * { animation: none !important; transition: none !important; }
}

/* =============================================================================
   3. BACKGROUND — GREEN MARBLE
   The marble is generated with CSS gradients (looks crisp, little blur) so the
   Liquid Glass style stands out over it. To use a marble PHOTO instead, place
   assets/img/fondo.jpg: it shows on top of the CSS marble automatically.
   Fixed so the glass "floats" while scrolling.
   ============================================================================= */
.bg-layer { position: fixed; inset: 0; z-index: -2; overflow: hidden; }

.bg-image {
  position: absolute; inset: -4%;
  background-color: var(--marble-base);
  background-image:
    /* Optional layer: your marble photo (ignored if it doesn't exist) */
    url("../assets/img/fondo.jpg"),
    /* GOLD veining — firma del mockup: hilos finos de oro que cruzan la piedra.
       Va ARRIBA de las vetas verdes para que se lea como metal, no como sombra. */
    repeating-linear-gradient(106deg,
      transparent 0 120px,
      var(--marble-gold) 120px 122px,
      transparent 122px 136px,
      var(--marble-gold) 136px 137px,
      transparent 137px 280px),
    /* Fine diagonal marble veins */
    repeating-linear-gradient(118deg, var(--marble-vein) 0 1px, transparent 1px 46px),
    repeating-linear-gradient(64deg,  var(--marble-vein) 0 1px, transparent 1px 70px),
    /* Soft blooms of light and pink for the marble veining */
    radial-gradient(60% 50% at 18% 22%, var(--marble-1) 0%, transparent 60%),
    radial-gradient(55% 45% at 82% 18%, var(--marble-3) 0%, transparent 55%),
    radial-gradient(70% 60% at 72% 82%, var(--marble-2) 0%, transparent 60%),
    radial-gradient(50% 50% at 30% 78%, var(--marble-1) 0%, transparent 55%),
    linear-gradient(125deg, var(--marble-3), var(--marble-base) 55%, var(--marble-2));
  /* Una entrada por capa de background-image (ahora 9: la veta dorada es nueva). */
  background-size: cover, auto, auto, auto, cover, cover, cover, cover, cover;
  background-position: center;
  background-repeat: no-repeat;
  filter: saturate(1.03);
  transform: none;
  transition: filter .5s var(--ease);
}
/* En tema oscuro las variables --marble-* no bastan: `fondo.jpg` va ENCIMA de
   ellas y es una foto clara, así que el mármol seguía saliendo crema y el texto
   blanco encima resultaba ilegible. Se oscurece la FOTO en lugar de taparla con
   un velo plano: así conserva su veteado y el oro sigue brillando. */
body.theme-dark .bg-image {
  filter: saturate(.92) brightness(.30);
}

/* Color veil over the marble (subtle in light, darkens in dark theme) */
.bg-gradient {
  position: absolute; inset: 0;
  background: var(--bg-overlay);
  transition: background .5s var(--ease);
}

/* =============================================================================
   4. REUSABLE "GLASS" MATERIAL
   ============================================================================= */
.glass {
  position: relative;
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--glass-shadow);
  -webkit-backdrop-filter: blur(var(--blur)) saturate(1.4);
  backdrop-filter: blur(var(--blur)) saturate(1.4);
  transition: transform .45s var(--ease), box-shadow .45s var(--ease),
              background .5s var(--ease), border-color .5s var(--ease);
}

/* Subtle highlight on the top edge (light glint) */
.glass::before {
  content: "";
  position: absolute; inset: 0;
  border-radius: inherit;
  padding: 1px;
  background: linear-gradient(140deg, var(--glass-highlight), transparent 40%, transparent 70%, var(--glass-highlight));
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
  opacity: .6;
  pointer-events: none;
}

/* =============================================================================
   5. TYPOGRAPHY, TITLES, BUTTONS
   ============================================================================= */
.container { width: min(100% - 2.5rem, var(--maxw)); margin-inline: auto; }

.section { padding: clamp(3.5rem, 9vw, 6.5rem) 0; }

.section__index,
.hero__index {
  font-family: var(--font-sans);
  font-size: .72rem;
  letter-spacing: .35em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 1rem;
  font-weight: 400;
}

.section__title {
  font-family: var(--font-serif);
  font-weight: 500;
  font-size: clamp(2rem, 7vw, 2.9rem);
  line-height: 1.1;
  letter-spacing: .01em;
  margin-bottom: .35rem;
}

.section__subtitle {
  color: var(--text-soft);
  font-size: 1rem;
  margin-bottom: 1.75rem;
  max-width: 46ch;
}

/* Lead heading (e.g. "When & Where") centered above a group of cards */
.section__index--lead,
.section__title--lead { text-align: center; }
.section__title--lead { margin-bottom: 2rem; }

/* Standard glass card for content */
.card { padding: clamp(1.6rem, 5vw, 2.75rem); }
.card--center { text-align: center; }
.card--center .section__subtitle { margin-inline: auto; }

/* Buttons */
.btn {
  display: inline-block;
  font-family: var(--font-sans);
  font-size: .85rem;
  letter-spacing: .18em;
  text-transform: uppercase;
  padding: .95em 2.2em;
  border-radius: 999px;
  border: 1px solid var(--glass-border);
  cursor: pointer;
  transition: transform .3s var(--ease), box-shadow .3s var(--ease),
              background .3s var(--ease), color .3s var(--ease);
}

.btn--primary {
  background: var(--accent);
  color: var(--on-accent);
  border-color: transparent;
  box-shadow: 0 8px 24px var(--accent-soft);
}
.btn--primary:hover {
  transform: translateY(-3px);
  box-shadow: 0 14px 32px var(--accent-soft);
}
.btn--full { width: 100%; margin-top: .5rem; }

/* Delicate glass lift on hover (only on hover-capable devices) */
@media (hover: hover) {
  .card.glass:hover { transform: translateY(-4px); box-shadow: 0 20px 60px rgba(0,0,0,.22); }
}

/* "Placeholder" tag over photo blocks */
.placeholder-tag {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  text-align: center; padding: 1rem;
  font-size: .72rem; letter-spacing: .12em; text-transform: uppercase;
  color: var(--text-soft);
  background: repeating-linear-gradient(45deg, var(--accent-soft) 0 12px, transparent 12px 24px);
}

/* =============================================================================
   6. PER-SECTION COMPONENTS
   ============================================================================= */

/* ---- HERO ---------------------------------------------------------------- */
.section--hero {
  min-height: 100svh;
  display: flex; align-items: center; justify-content: center;
  position: relative;
  padding: 2rem 0;
  text-align: center;
}
.hero__photo {
  position: absolute; inset: 0; z-index: -1;
  background-image: url("../assets/img/portada.jpg");
  background-size: cover; background-position: center;
}
/* Scrim over the cover photo. The hero text sits on translucent glass, so a
   bright, busy photo washes it out. The veil goes in the DIRECTION of each
   theme's text color — pale under dark text (light theme), dark under light
   text (dark theme) — so the names stay legible with ANY cover photo.
   Tune the alphas if your final photo needs less veiling. */
.hero__photo::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(
    to bottom,
    rgba(239, 247, 230, 0.34) 0%,
    rgba(239, 247, 230, 0.46) 55%,
    rgba(239, 247, 230, 0.36) 100%
  );
}
body.theme-dark .hero__photo::after {
  background: linear-gradient(
    to bottom,
    rgba(8, 18, 11, 0.52) 0%,
    rgba(8, 18, 11, 0.66) 55%,
    rgba(8, 18, 11, 0.58) 100%
  );
}
.hero__photo .placeholder-tag {
  background: rgba(0,0,0,.25); color: #fff;
  align-items: flex-start; padding-top: 2rem;
}

.hero__panel {
  width: min(100% - 2.5rem, 540px);
  padding: clamp(2.2rem, 8vw, 3.5rem) clamp(1.5rem, 6vw, 3rem);
  text-align: center;
}
.hero__phrase {
  font-family: var(--font-sans);
  text-transform: uppercase; letter-spacing: .32em;
  font-size: .82rem; color: var(--accent); margin-bottom: 1.2rem;
}
.hero__names {
  font-family: var(--font-serif);
  font-weight: 500;
  font-size: clamp(2.8rem, 13vw, 4.5rem);
  line-height: 1.02;
  display: flex; flex-direction: column; gap: .1em;
  margin-bottom: 1.2rem;
}
.hero__amp { font-style: italic; color: var(--accent); font-size: .7em; }
/* XV: one celebrant instead of a couple — a single (often two-word) name needs
   a slightly smaller cap so it doesn't overflow narrow phones. */
.hero__names--single { font-size: clamp(2.4rem, 11vw, 4rem); }
.footer__names--single { font-size: clamp(1.8rem, 8vw, 2.6rem); }
.hero__date {
  font-family: var(--font-sans); letter-spacing: .2em; text-transform: uppercase;
  font-size: .9rem; color: var(--text-soft); margin-bottom: 2rem;
}

/* HOME-only notice: hidden until the guest taps the "Mensaje importante" button
   (main.js adds .is-open). Keeping it behind a tap makes it feel less invasive.
   Only ever shown on the public Home page (body.is-home), never on /i/<token>. */
.hero__notice { display: none; }
.is-home .hero__notice.is-open {
  display: flex;
  flex-direction: column;
  animation: noticeIn .45s var(--ease) both;
  align-items: center;
  gap: .5rem;
  text-align: center;
  margin: 1.8rem auto 0;
  padding: 1.1rem 1.3rem;
  max-width: 34rem;
  /* Opaque enough to stay readable over the bright cover photo, in both themes. */
  background: rgba(255, 255, 255, 0.72);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-md);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
}
/* Keep this box light with dark text in both themes so it stays readable over
   the bright cover photo (do NOT flip to light text in dark mode here). */
.theme-dark .hero__notice {
  background: rgba(255, 255, 255, 0.82);
}
.hero__notice-icon { font-size: 1.4rem; line-height: 1; }
.hero__notice-text {
  font-family: var(--font-sans);
  font-weight: 300;
  font-size: .84rem;
  line-height: 1.55;
  color: #4a3940;
}
.hero__notice-text strong { font-weight: 500; color: #2c2025; }
@keyframes noticeIn {
  from { opacity: 0; transform: translateY(-10px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* Attention-drawing pulse for the HOME "Mensaje importante" button. It nudges the
   guest to tap; main.js removes the class after the first tap. */
.btn--pulse { animation: btnPulse 1.9s ease-in-out infinite; }
@keyframes btnPulse {
  0%, 100% { box-shadow: 0 8px 24px var(--accent-soft); transform: translateY(0); }
  50%      { box-shadow: 0 10px 28px var(--accent-soft), 0 0 0 7px var(--accent-soft); transform: translateY(-2px); }
}
@media (prefers-reduced-motion: reduce) {
  .btn--pulse { animation: none; }
}

/* Scroll indicator */
.hero__scroll {
  position: absolute; bottom: 2rem; left: 50%; transform: translateX(-50%);
  width: 26px; height: 42px; border: 1.5px solid var(--glass-border);
  border-radius: 999px; display: flex; justify-content: center; padding-top: 8px;
}
.hero__scroll span {
  width: 4px; height: 8px; border-radius: 4px; background: var(--accent);
  animation: scrollDot 1.8s infinite var(--ease);
}
@keyframes scrollDot { 0%{opacity:0;transform:translateY(-4px)} 40%{opacity:1} 80%,100%{opacity:0;transform:translateY(10px)} }

/* ---- COUNTDOWN ----------------------------------------------------------- */
.countdown {
  display: grid; grid-template-columns: repeat(4, 1fr);
  gap: .6rem; margin-top: 2rem;
}
.countdown__unit {
  background: var(--glass-bg-strong);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-md);
  padding: 1rem .4rem; text-align: center;
}
.countdown__num {
  display: block;
  font-family: var(--font-serif); font-weight: 600;
  font-size: clamp(1.8rem, 9vw, 3rem); line-height: 1; color: var(--text);
  font-variant-numeric: tabular-nums;
}
.countdown__label {
  display: block; margin-top: .4rem;
  font-size: .65rem; letter-spacing: .18em; text-transform: uppercase; color: var(--text-soft);
}

/* ---- MINI CALENDAR ------------------------------------------------------- */
.minical {
  max-width: 340px; margin: 2rem auto 0;
  background: var(--glass-bg-strong);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-md);
  padding: 1.1rem 1rem 1.25rem;
}
.minical__title {
  text-align: center; margin-bottom: .9rem;
  font-family: var(--font-serif); font-weight: 600; font-size: 1.1rem; color: var(--text);
}
.minical__grid {
  display: grid; grid-template-columns: repeat(7, 1fr); gap: .25rem;
}
.minical__grid--head { margin-bottom: .35rem; }
.minical__dow {
  text-align: center; font-size: .6rem; letter-spacing: .12em;
  text-transform: uppercase; color: var(--text-soft);
}
.minical__day {
  display: grid; place-items: center; aspect-ratio: 1;
  font-size: .8rem; color: var(--text); border-radius: 50%;
  font-variant-numeric: tabular-nums;
}
.minical__day--empty { visibility: hidden; }
/* Weekend columns (Domingo & Sábado) highlighted as a continuous band. */
.minical__dow--weekend { color: var(--accent); }
.minical__day--weekend {
  background: var(--accent-soft);
  border-radius: 0;
}
.minical__grid .minical__day--weekend:first-child,
.minical__grid .minical__day--weekend:nth-child(7n + 1) {
  border-top-left-radius: var(--radius-sm);
  border-bottom-left-radius: var(--radius-sm);
}
.minical__grid .minical__day--weekend:nth-child(7n) {
  border-top-right-radius: var(--radius-sm);
  border-bottom-right-radius: var(--radius-sm);
}
.minical__day--event {
  background: var(--accent); color: #fff; font-weight: 600;
  box-shadow: 0 6px 16px var(--accent-soft);
  border-radius: 50%;
}

/* ---- ADD TO CALENDAR ----------------------------------------------------- */
.addcal { text-align: center; margin-top: 1.1rem; }
.addcal__btn {
  display: inline-flex; align-items: center; gap: .5rem;
  background: transparent; border: 1px solid var(--glass-border);
  border-radius: 999px; padding: .55rem 1.15rem;
  font-size: .78rem; letter-spacing: .04em; color: var(--text-soft);
  cursor: pointer; transition: color .2s ease, border-color .2s ease, background .2s ease;
}
.addcal__btn:hover {
  color: var(--accent); border-color: var(--accent);
  background: var(--accent-soft);
}

/* ---- OUR STORY ----------------------------------------------------------- */
.story__grid { display: grid; gap: 1.25rem; }
.story__photo {
  position: relative; min-height: clamp(340px, 80vw, 460px);
  background-image: url("../assets/img/historia.jpg");
  background-size: cover; background-position: center;
  overflow: hidden;
}
/* Subtle floral icon while there is no photo (assets/img/historia.jpg).
   main.js adds .has-photo when the image exists, and the icon disappears. */
.story__photo::after {
  content: "❀"; position: absolute; inset: 0;
  display: grid; place-items: center;
  font-size: 2rem; color: var(--accent); opacity: .4;
}
.story__photo.has-photo::after { content: none; }
#story-paragraphs p { margin-bottom: 1rem; color: var(--text-soft); }
#story-paragraphs p:last-child { margin-bottom: 0; }

/* ---- WHEN & WHERE (two venue cards, each with its own map) --------------- */
.venues { display: grid; gap: 1.5rem; }
.venue { text-align: center; display: flex; flex-direction: column; }
.venue__title { font-family: var(--font-serif); font-size: 1.7rem; font-weight: 500; }
.venue__time { color: var(--accent); letter-spacing: .12em; font-size: .9rem; margin: .25rem 0 .7rem; }
.venue__place { font-weight: 400; font-size: 1.1rem; }
.venue__address { color: var(--text-soft); font-size: .9rem; }
.venue__note { color: var(--text-soft); font-size: .85rem; font-style: italic; margin-top: .5rem; }

.map {
  border-radius: var(--radius-md); overflow: hidden;
  border: 1px solid var(--glass-border);
  aspect-ratio: 16 / 11;
  margin: 1.25rem 0;
}
.map iframe { width: 100%; height: 100%; border: 0; display: block; filter: grayscale(.15); }

.venue__directions {
  align-self: center; margin-top: auto;
  background: var(--glass-bg-strong); color: var(--text);
}
.venue__directions:hover { background: var(--accent-soft); transform: translateY(-2px); }

/* ---- SCHEDULE (timeline) ------------------------------------------------- */
.timeline { list-style: none; margin-top: 1.5rem; position: relative; }
.timeline::before {
  content: ""; position: absolute; left: 26px; top: 6px; bottom: 6px;
  width: 1px; background: var(--glass-border);
}
.timeline__item {
  position: relative; padding-left: 4.2rem; padding-bottom: 1.8rem;
}
.timeline__item:last-child { padding-bottom: 0; }
.timeline__dot {
  position: absolute; left: 12px; top: 2px;
  width: 30px; height: 30px; border-radius: 50%;
  display: grid; place-items: center; font-size: .9rem;
  background: var(--glass-bg-strong); border: 1px solid var(--glass-border);
}
.timeline__time { color: var(--accent); font-size: .82rem; letter-spacing: .12em; }
.timeline__title { font-family: var(--font-serif); font-size: 1.35rem; font-weight: 500; line-height: 1.2; }
.timeline__detail { color: var(--text-soft); font-size: .92rem; }

/* ---- SCHEDULE · sección desplegable "La Celebración" -------------------- */
.timeline__reveal-btn {
  display: flex; align-items: center; gap: .75rem;
  width: 100%; text-align: left; cursor: pointer;
  background: none; border: 0; padding: 0; color: inherit; font: inherit;
  -webkit-user-select: none; user-select: none;   /* no text selection on tap */
  -webkit-tap-highlight-color: transparent;         /* no grey flash on mobile */
}
/* Circular liquid-glass toggle with a triangle, next to "La Celebración". */
.timeline__reveal-toggle {
  flex: 0 0 auto;
  display: grid; place-items: center;
  width: 2.1rem; height: 2.1rem;
  border-radius: 50%;
  color: var(--accent); font-size: .7rem; line-height: 1;
  transition: transform .3s var(--ease), box-shadow .45s var(--ease),
              background .5s var(--ease);
}
@media (hover: hover) {
  .timeline__reveal-btn:hover .timeline__reveal-toggle { transform: scale(1.08); }
}
.timeline__item--reveal.is-open .timeline__reveal-toggle { transform: rotate(180deg); }
@media (hover: hover) {
  .timeline__item--reveal.is-open .timeline__reveal-btn:hover .timeline__reveal-toggle {
    transform: rotate(180deg) scale(1.08);
  }
}

.timeline__reveal-panel {
  margin-top: 1.1rem;
  animation: revealFade .35s ease both;
}
.timeline__reveal-panel[hidden] { display: none; }

.timeline--nested { margin-top: 0; }
.timeline--nested::before { left: 14px; }
.timeline--nested .timeline__item { padding-left: 3.4rem; padding-bottom: 1.4rem; }
.timeline--nested .timeline__dot { left: 0; }

.timeline__reveal-note {
  color: var(--text-soft); font-size: .88rem; font-style: italic;
  margin-top: .4rem; padding-left: 3.4rem;
}

@keyframes revealFade {
  from { opacity: 0; transform: translateY(-6px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ---- DRESS CODE ---------------------------------------------------------- */
.dresscode__label {
  font-family: var(--font-serif); font-size: clamp(1.6rem, 7vw, 2.2rem);
  color: var(--accent); margin: .4rem 0 .8rem;
}
/* Two "avoid these colors" panels (ellas / ellos) inside the same card */
.dresscode__avoid {
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: 1.2rem; margin-top: 1.5rem;
}
.dresscode__panel {
  flex: 1 1 240px; max-width: 320px;
  padding: 1.4rem 1.1rem;
  background: var(--glass-bg-strong); border: 1px solid var(--glass-border);
  border-radius: var(--radius-md);
}
.dresscode__group {
  font-family: var(--font-serif); font-size: 1.45rem; color: var(--accent);
  margin-bottom: .35rem;
}
.dresscode__note { color: var(--text-soft); font-size: .9rem; margin-bottom: 1.1rem; }
.dresscode__swatches {
  display: flex; flex-wrap: wrap; justify-content: center; gap: 1.4rem;
}
.dresscode__swatch { display: flex; flex-direction: column; align-items: center; gap: .5rem; }
.dresscode__dot {
  width: 46px; height: 46px; border-radius: 50%;
  border: 1px solid var(--glass-border);
  box-shadow: var(--glass-shadow), inset 0 0 0 3px rgba(255,255,255,.12);
}
.dresscode__color-name {
  font-size: .72rem; letter-spacing: .14em; text-transform: uppercase;
  color: var(--text-soft);
}

/* ---- HONOR PARTY (Damas & Caballeros de Honor) --------------------------- */
.honor__grid {
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: 1.4rem; margin-top: 2rem;
}
/* One compact card per couple: the dama and the caballero shown together.
   7 pairs, so cards are kept small and multiple fit per row. */
.honor__grid { gap: 1rem; }
.honor__pair {
  flex: 1 1 260px; max-width: 320px;
  display: grid; gap: .65rem;
  padding: 1rem 1.25rem;
  background: var(--glass-bg-strong); border: 1px solid var(--glass-border);
  border-radius: var(--radius-md);
}
.honor__person {
  padding-bottom: .6rem;
  border-bottom: 1px solid var(--glass-border);
}
.honor__person:last-child {
  padding-bottom: 0;
  border-bottom: none;
}
.honor__name { font-size: .98rem; line-height: 1.25; font-weight: 500; }

/* Color-code each name so it's obvious who is the dama and who the caballero. */
.honor__person--dama .honor__name { color: var(--dama); }
.honor__person--caballero .honor__name { color: var(--caballero); }

/* Legend under the intro: colored dot + label for each role. */
.honor__legend {
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: 1.5rem; margin-top: 1.2rem;
  font-size: .95rem; letter-spacing: .04em;
}
.honor__legend-item { display: inline-flex; align-items: center; gap: .5rem; }
.honor__legend-item--dama { color: var(--dama); }
.honor__legend-item--caballero { color: var(--caballero); }
.honor__dot {
  width: .8rem; height: .8rem; border-radius: 50%;
  background: currentColor;
  box-shadow: 0 0 0 3px color-mix(in srgb, currentColor 22%, transparent);
}

/* ---- GODPARENTS ---------------------------------------------------------- */
/* Flex + center so any number of cards (incl. an odd 5) stays evenly centered,
   with the last partial row centered instead of left-aligned with a gap. */
.godparents__grid {
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: 1.6rem 1rem; margin-top: 2rem;
}
.godparent { text-align: center; flex: 0 0 calc(50% - 0.5rem); } /* 2 per row on mobile */
/* Circular couple photo (elegant placeholder if there is no photo) */
.godparent__photo {
  width: clamp(96px, 28vw, 130px); aspect-ratio: 1; margin: 0 auto .9rem;
  border-radius: 50%;
  background: var(--glass-bg-strong);
  border: 1px solid var(--glass-border);
  box-shadow: var(--glass-shadow), inset 0 0 0 4px rgba(255,255,255,.12);
  background-size: cover; background-position: center; background-repeat: no-repeat;
  display: grid; place-items: center;
  transition: transform .4s var(--ease);
}
.godparent__photo::after {          /* subtle icon only when there is NO photo */
  content: "❀"; font-size: 1.6rem; color: var(--accent); opacity: .5;
}
.godparent__photo.has-photo::after { content: none; }
@media (hover: hover) { .godparent:hover .godparent__photo { transform: translateY(-4px) scale(1.03); } }
.godparent__role {
  font-size: .72rem; letter-spacing: .18em; text-transform: uppercase;
  color: var(--accent); margin-bottom: .25rem;
}
.godparent__names { font-family: var(--font-serif); font-size: 1.15rem; line-height: 1.25; }

/* ---- GIFTS --------------------------------------------------------------- */
.gifts__list { display: grid; gap: .9rem; margin-top: 1.5rem; }
.gift {
  display: flex; flex-direction: column; align-items: center; text-align: center; gap: .5rem;
  padding: 1rem 1.2rem;
  background: var(--glass-bg-strong); border: 1px solid var(--glass-border);
  border-radius: var(--radius-md);
  transition: transform .3s var(--ease);
}
@media (hover: hover) { .gift:hover { transform: translateY(-2px); } }
.gift__icon { font-size: 1.5rem; }
.gift__label { font-weight: 400; }
.gift__value { color: var(--text-soft); font-size: .85rem; }
/* Only long URLs need to break anywhere — plain notes must NOT split words. */
.gift__value a { color: var(--accent); word-break: break-all; }
/* Registry link not ready yet: muted italic placeholder, not a link. */
.gift__value--soon { font-style: italic; opacity: .75; letter-spacing: .04em; }

/* "Lluvia de sobres" legend (type "note"): larger serif label, no button. */
.gift--note .gift__label { font-family: var(--font-serif); font-size: 1.15rem; }
.gift__copy {
  margin-left: auto; flex-shrink: 0;
  font-size: .68rem; letter-spacing: .1em; text-transform: uppercase;
  padding: .5em 1em; border-radius: 999px;
  border: 1px solid var(--glass-border); background: transparent; color: var(--text);
  cursor: pointer; transition: background .25s var(--ease);
}
.gift__copy:hover { background: var(--accent-soft); }

/* ---- RSVP ---------------------------------------------------------------- */
.rsvp__deadline { font-size: .9rem; color: var(--text-soft); margin-bottom: 1.75rem; }
.rsvp__deadline strong { color: var(--accent); font-weight: 400; }

.rsvp-form { display: grid; gap: 1.25rem; text-align: left; }
/* A class-level `display` beats the UA [hidden] rule, so restore it explicitly
   (subir/mensaje hide the whole form when the organizer closes the feature). */
.rsvp-form[hidden] { display: none; }
.field { display: grid; gap: .5rem; }
.field label, .field__label {
  font-size: .95rem; letter-spacing: .04em; color: var(--text-soft);
}
.field .opt { color: var(--text-soft); opacity: .7; text-transform: none; letter-spacing: 0; }

.field input,
.field select,
.field textarea {
  width: 100%; font-family: var(--font-sans); font-size: 1rem; color: var(--text);
  padding: .85em 1em; border-radius: var(--radius-sm);
  background: var(--glass-bg-strong);
  border: 1px solid var(--glass-border);
  transition: border-color .25s var(--ease), box-shadow .25s var(--ease);
}
.field input::placeholder,
.field textarea::placeholder { color: var(--text-soft); opacity: .6; }
.field input:focus,
.field select:focus,
.field textarea:focus {
  outline: none; border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.field select { appearance: none; cursor: pointer; }
.field textarea { resize: vertical; min-height: 7em; line-height: 1.6; }

.radio-row { display: flex; gap: .75rem; flex-wrap: wrap; }
.radio-pill { flex: 1 1 140px; cursor: pointer; }
.radio-pill input { position: absolute; opacity: 0; pointer-events: none; }
.radio-pill span {
  display: block; text-align: center; padding: .85em 1em;
  border-radius: var(--radius-sm);
  background: var(--glass-bg-strong); border: 1px solid var(--glass-border);
  font-size: .92rem; transition: all .25s var(--ease);
}
.radio-pill input:checked + span {
  background: var(--accent); color: var(--on-accent); border-color: transparent;
}
.radio-pill input:focus-visible + span { box-shadow: 0 0 0 3px var(--accent-soft); }

/* Fields that only apply if attending: dim out when "No" is chosen */
[data-only-yes].is-hidden {
  opacity: .4; filter: grayscale(.5);
  pointer-events: none;
  max-height: 0; overflow: hidden; margin: 0;
  transition: opacity .35s var(--ease), max-height .35s var(--ease);
}

/* Success message */
.rsvp-success { text-align: center; padding: 1rem 0; animation: fadeUp .6s var(--ease); }
.rsvp-success__mark {
  width: 64px; height: 64px; margin: 0 auto 1rem;
  border-radius: 50%; display: grid; place-items: center;
  font-size: 1.8rem; color: var(--on-accent); background: var(--accent);
  box-shadow: 0 10px 30px var(--accent-soft);
}
.rsvp-success h3 { font-family: var(--font-serif); font-size: 2rem; font-weight: 500; margin-bottom: .4rem; }
.rsvp-success p { color: var(--text-soft); }

/* ---- GALLERY (horizontal film-strip carousel) ---------------------------- */
.section__subtitle--lead { text-align: center; margin-inline: auto; margin-bottom: 2rem; }

/* Full-bleed viewport: native horizontal scroll, snap, hidden scrollbar */
/* "Sube tus fotos" call-to-action under the carousel */
.gallery__upload { text-align: center; margin-top: 2rem; }
.gallery__upload-note {
  margin-top: .8rem; font-size: .8rem; letter-spacing: .12em; text-transform: uppercase;
  color: var(--text-soft);
}
.btn:disabled,
.btn[aria-disabled="true"] {
  opacity: .55; cursor: not-allowed; box-shadow: none;
}
.btn:disabled:hover,
.btn[aria-disabled="true"]:hover { transform: none; box-shadow: none; }

/* Lightbox */
.lightbox {
  position: fixed; inset: 0; z-index: 80;
  display: grid; place-items: center; padding: 1.5rem;
  background: rgba(20, 12, 18, 0.78);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  opacity: 0; transition: opacity .3s var(--ease);
}
.lightbox.is-open { opacity: 1; }
.lightbox[hidden] { display: none; }   /* keep the attribute working despite display:grid */
.lightbox__img {
  max-width: 92vw; max-height: 82vh; border-radius: var(--radius-md);
  box-shadow: 0 20px 60px rgba(0,0,0,.5);
}
.lightbox__close {
  position: absolute; top: 1.1rem; right: 1.1rem;
  width: 44px; height: 44px; border-radius: 50%;
  border: 1px solid var(--glass-border); background: var(--glass-bg-strong);
  color: var(--text); font-size: 1.1rem; cursor: pointer;
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
}

/* ---- FOOTER -------------------------------------------------------------- */
/* Extra bottom room so the credit lines clear the floating side-nav button. */
.section--footer { padding-bottom: 5.5rem; }
.footer__names {
  font-family: var(--font-serif); font-weight: 500;
  font-size: clamp(2rem, 9vw, 3rem); line-height: 1.1; margin-bottom: .3rem;
}
.footer__date { letter-spacing: .25em; color: var(--text-soft); font-size: .85rem; margin-bottom: 1.5rem; }
.footer__contacts { display: grid; gap: .6rem; margin-bottom: 1.5rem; }
.footer__contact-label { font-size: .72rem; letter-spacing: .12em; text-transform: uppercase; color: var(--text-soft); }
.footer__contact-value { font-size: 1.05rem; }
.footer__hashtag { font-family: var(--font-serif); font-style: italic; color: var(--accent); font-size: 1.3rem; margin-bottom: .5rem; }
.footer__message { letter-spacing: .15em; text-transform: uppercase; font-size: .8rem; color: var(--text-soft); }
.footer__credit { text-align: center; margin-top: 1.5rem; font-size: .72rem; letter-spacing: .1em; color: var(--text-soft); opacity: .7; }
.footer__dev {
  display: flex; align-items: center; justify-content: center; gap: .5rem;
  margin-top: .5rem; font-size: .7rem; letter-spacing: .08em;
  color: var(--text-soft); opacity: .6;
}
.footer__dev-link {
  display: inline-flex; color: inherit;
  transition: color .3s var(--ease), opacity .3s var(--ease), transform .3s var(--ease);
}
.footer__dev-link:hover { color: var(--accent); opacity: 1; transform: translateY(-1px); }
.footer__dev-link svg { display: block; }

/* =============================================================================
   7. MICRO-INTERACTIONS — reveal on scroll (IntersectionObserver)
   Soft animation that replays each time the section enters the viewport.
   ============================================================================= */
.reveal {
  opacity: 0; transform: translateY(24px);
  transition: opacity .7s var(--ease), transform .7s var(--ease);
  will-change: opacity, transform;
}
.reveal.is-visible { opacity: 1; transform: none; }

@keyframes fadeUp { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: none; } }

/* =============================================================================
   8. NAVIGATION: MENU BUTTON (top-left) + SIDE NAV + THEME TOGGLE
   ============================================================================= */

/* ---- Menu button (hamburger → X) ----------------------------------------- */
.menu-toggle {
  position: fixed; top: 1.1rem; left: 1.1rem; z-index: 60;
  width: 46px; height: 46px; border-radius: 50%;
  display: grid; place-items: center; cursor: pointer;
  border: 1px solid var(--glass-border); color: var(--text);
  transition: transform .3s var(--ease), background .5s var(--ease), border-color .5s var(--ease);
}
.menu-toggle:hover { transform: scale(1.06); }
.menu-toggle__bars { position: relative; width: 20px; height: 14px; }
.menu-toggle__bars i {
  position: absolute; left: 0; width: 100%; height: 1.5px; border-radius: 2px;
  background: var(--text);
  transition: transform .35s var(--ease), opacity .25s var(--ease), top .35s var(--ease);
}
.menu-toggle__bars i:nth-child(1) { top: 0; }
.menu-toggle__bars i:nth-child(2) { top: 6px; }
.menu-toggle__bars i:nth-child(3) { top: 12px; }
/* Open state: the bars form an X */
.menu-toggle.is-open .menu-toggle__bars i:nth-child(1) { top: 6px; transform: rotate(45deg); }
.menu-toggle.is-open .menu-toggle__bars i:nth-child(2) { opacity: 0; }
.menu-toggle.is-open .menu-toggle__bars i:nth-child(3) { top: 6px; transform: rotate(-45deg); }

/* ---- Veil behind the panel ----------------------------------------------- */
.menu-overlay {
  position: fixed; inset: 0; z-index: 55;
  background: rgba(20, 12, 18, 0.35);
  -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px);
  opacity: 0; transition: opacity .4s var(--ease);
}
.menu-overlay.is-open { opacity: 1; }

/* ---- Menu panel (opens from the top-left corner) ------------------------- */
.menu-panel {
  position: fixed; top: 1.1rem; left: 1.1rem; z-index: 58;
  width: min(82vw, 320px);
  padding: 4.2rem 1.4rem 1.6rem;
  border-radius: var(--radius-lg);
  transform-origin: top left;
  transform: scale(.7) translateY(-8px);
  opacity: 0; visibility: hidden;
  transition: transform .42s var(--ease), opacity .32s var(--ease), visibility 0s linear .42s;
}
.menu-panel.is-open {
  transform: none; opacity: 1; visibility: visible;
  transition: transform .42s var(--ease), opacity .3s var(--ease), visibility 0s;
}
.menu-panel__title {
  font-size: .68rem; letter-spacing: .22em; text-transform: uppercase;
  color: var(--accent); margin-bottom: 1rem;
}
.menu-panel ul { list-style: none; display: grid; gap: .15rem; }
.menu-panel a {
  display: flex; align-items: baseline; gap: .8rem;
  padding: .7em .6em; border-radius: var(--radius-sm);
  font-family: var(--font-serif); font-size: 1.25rem; line-height: 1.1;
  color: var(--text);
  opacity: 0; transform: translateX(-10px);
  transition: background .25s var(--ease), color .25s var(--ease),
              opacity .4s var(--ease), transform .4s var(--ease);
}
.menu-panel.is-open a { opacity: 1; transform: none; transition-delay: calc(.06s * var(--i, 0) + .1s); }
.menu-panel a:hover { background: var(--accent-soft); color: var(--accent); }
.menu-panel a .menu-num {
  font-family: var(--font-sans); font-size: .7rem; letter-spacing: .1em;
  color: var(--accent); min-width: 1.6em;
}
.menu-panel a.is-active { color: var(--accent); }

/* ---- Theme toggle -------------------------------------------------------- */
.theme-toggle {
  position: fixed; top: 1.1rem; right: 1.1rem; z-index: 50;
  width: 46px; height: 46px; border-radius: 50%;
  display: grid; place-items: center; cursor: pointer;
  font-size: 1.2rem; color: var(--text);
  border: 1px solid var(--glass-border);
}
.theme-toggle:hover { transform: scale(1.06); }

/* ---- Background music button (bottom-left) -------------------------------- */
.music-toggle {
  position: fixed; bottom: 1.1rem; left: 1.1rem; z-index: 50;
  width: 46px; height: 46px; border-radius: 50%;
  display: grid; place-items: center; cursor: pointer;
  color: var(--text); border: 1px solid var(--glass-border);
  transition: transform .3s var(--ease), background .5s var(--ease), border-color .5s var(--ease);
}
.music-toggle:hover { transform: scale(1.06); }
.music-toggle__eq { display: flex; align-items: flex-end; gap: 2px; height: 16px; }
.music-toggle__eq i { width: 3px; height: 5px; border-radius: 2px; background: var(--accent); transition: height .2s var(--ease); }
/* Animated equalizer while playing; flat bars when paused */
.music-toggle.is-playing .music-toggle__eq i { animation: eq .9s ease-in-out infinite; }
.music-toggle.is-playing .music-toggle__eq i:nth-child(2) { animation-delay: .2s; }
.music-toggle.is-playing .music-toggle__eq i:nth-child(3) { animation-delay: .4s; }
@keyframes eq { 0%, 100% { height: 5px; } 50% { height: 15px; } }

/* ---- Welcome screen: liquid-glass envelope ------------------------------- */
.entry {
  position: fixed; inset: 0; z-index: 200;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 2rem; padding: 1.5rem;
  perspective: 1200px;                  /* 3D space for the flap */
  background:
    radial-gradient(60% 50% at 18% 22%, var(--marble-1) 0%, transparent 60%),
    radial-gradient(70% 60% at 82% 85%, var(--marble-2) 0%, transparent 60%),
    linear-gradient(125deg, var(--marble-3), var(--marble-base) 55%, var(--marble-2));
  opacity: 1; transition: opacity .9s var(--ease);
}
/* Final state: fade the whole screen out while the envelope zooms in */
.entry.is-zooming { opacity: 0; pointer-events: none; }

.envelope {
  position: relative;
  width: clamp(280px, 82vw, 400px);
  aspect-ratio: 7 / 5;
  transform-style: preserve-3d;
  transition: transform .9s var(--ease);
  animation: fadeUp .7s var(--ease);
  cursor: pointer;
}
.entry.is-zooming .envelope { transform: scale(8); }   /* zoom "into" the envelope */

/* Body / pocket (glass) */
.envelope__body {
  position: absolute; inset: 0; border-radius: 14px; overflow: hidden;
  background: var(--glass-bg-strong); border: 1px solid var(--glass-border);
  box-shadow: var(--glass-shadow);
  -webkit-backdrop-filter: blur(var(--blur)) saturate(1.4); backdrop-filter: blur(var(--blur)) saturate(1.4);
}
/* Front pocket triangle (rises from the bottom corners to the centre) */
.envelope__body::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(var(--glass-highlight), transparent);
  opacity: .22;
  clip-path: polygon(0 100%, 50% 44%, 100% 100%);
  border-top: 1px solid var(--glass-border);
}

/* Closed flap (triangle pointing down); flips up to open */
.envelope__flap {
  position: absolute; top: 0; left: 0; right: 0; height: 60%;
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  border-radius: 14px 14px 0 0;
  clip-path: polygon(0 0, 100% 0, 50% 100%);
  transform-origin: top center; transform: rotateX(0deg);
  transition: transform .7s var(--ease), opacity .4s var(--ease);
  -webkit-backdrop-filter: blur(var(--blur)); backdrop-filter: blur(var(--blur));
  z-index: 3;
}
.envelope.is-open .envelope__flap { transform: rotateX(180deg); z-index: 0; }

/* Wax-seal disc at the flap tip */
.envelope__seal {
  position: absolute; top: calc(60% - 27px); left: 50%; transform: translateX(-50%);
  width: 54px; height: 54px; border-radius: 50%;
  display: grid; place-items: center; font-size: 1.4rem;
  color: var(--on-accent); background: var(--accent);
  box-shadow: 0 8px 22px var(--accent-soft), inset 0 0 0 2px rgba(255,255,255,.3);
  z-index: 4; transition: opacity .3s var(--ease);
}
.envelope.is-open .envelope__seal { opacity: 0; }

/* Open button */
.entry__open { animation: fadeUp .7s var(--ease); }
.entry.is-opening .entry__open { opacity: 0; pointer-events: none; transition: opacity .3s var(--ease); }

.side-nav {
  position: fixed; top: 50%; right: 1.1rem; transform: translateY(-50%);
  z-index: 40; display: none;          /* hidden on mobile; visible >= tablet */
}
.side-nav ul { list-style: none; display: grid; gap: .85rem; }
.side-nav a {
  display: block; width: 10px; height: 10px; border-radius: 50%;
  background: var(--glass-border); position: relative;
  transition: background .3s var(--ease), transform .3s var(--ease);
}
.side-nav a:hover { transform: scale(1.4); }
.side-nav a.is-active { background: var(--accent); transform: scale(1.4); }
.side-nav a::after {
  content: attr(data-label);
  position: absolute; right: 22px; top: 50%; transform: translateY(-50%);
  white-space: nowrap; font-size: .7rem; letter-spacing: .1em; text-transform: uppercase;
  color: var(--text); background: var(--glass-bg-strong);
  padding: .3em .7em; border-radius: 999px; border: 1px solid var(--glass-border);
  opacity: 0; pointer-events: none; transition: opacity .25s var(--ease);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
}
.side-nav a:hover::after { opacity: 1; }

/* =============================================================================
   9. RESPONSIVE — tablet/desktop enhancements (mobile-first is the base)
   ============================================================================= */
@media (min-width: 768px) {
  .side-nav { display: block; }

  .story__grid { grid-template-columns: 1fr 1fr; align-items: stretch; }
  .story__photo { min-height: 100%; }

  .venues { grid-template-columns: 1fr 1fr; align-items: stretch; gap: 1.75rem; }

  .godparents__grid { gap: 2.2rem 1.6rem; }
  .godparent { flex: 0 0 clamp(140px, 16%, 180px); } /* fits the 5 cards centered in one row */
}

@media (min-width: 1024px) {
  :root { --maxw: 760px; }
}

/* =============================================================================
   10. PHASE 2 — GROUP RSVP, QR TICKETS, VALIDATOR
   ============================================================================= */

/* ---- Personalized greeting + per-person name inputs ---------------------- */
.rsvp-greeting { margin: 0 0 1.5rem; text-align: center; }
.rsvp-greeting__hi { font-family: var(--font-serif); font-size: 1.7rem; font-weight: 500; }
.rsvp-greeting__quota { color: var(--text-soft); }
.rsvp-greeting__quota strong { color: var(--accent); font-weight: 500; }
.rsvp-greeting__loading { color: var(--text-soft); }
.rsvp-greeting__error { color: #b3261e; }

.group-names { display: grid; gap: .6rem; }
.group-names__input {
  width: 100%; font-family: var(--font-sans); font-size: 1rem; color: var(--text);
  padding: .75em 1em; border-radius: var(--radius-sm);
  background: var(--glass-bg-strong); border: 1px solid var(--glass-border);
}
.group-names__input::placeholder { color: var(--text-soft); opacity: .6; }
.group-names__input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }

/* ---- RSVP instructions accordion (task 1) -------------------------------- */
.rsvp-help-toggle {
  display: flex; width: fit-content; align-items: center; gap: .55rem;
  margin: .5rem auto 1.5rem; padding: .72em 1.35em;
  border-radius: 999px; cursor: pointer;
  background: var(--glass-bg-strong); border: 1px solid var(--glass-border);
  color: var(--text); font-family: var(--font-sans); font-size: .95rem;
  transition: transform .2s var(--ease), background .25s var(--ease);
  animation: helpPulse 2.4s var(--ease) infinite;
}
.rsvp-help-toggle:hover { transform: translateY(-1px); }
.rsvp-help-toggle.is-open { animation: none; background: var(--accent-soft); }
.rsvp-help-toggle__icon { color: var(--accent); }
.rsvp-help-toggle__chev { color: var(--text-soft); transition: transform .25s var(--ease); }
.rsvp-help-toggle.is-open .rsvp-help-toggle__chev { transform: rotate(180deg); }
@keyframes helpPulse {
  0%, 100% { box-shadow: 0 0 0 0 var(--accent-soft); }
  60%      { box-shadow: 0 0 0 9px transparent; }
}
@media (prefers-reduced-motion: reduce) { .rsvp-help-toggle { animation: none; } }

.rsvp-help {
  text-align: left; margin: 0 auto 1.5rem; padding: 1.1rem 1.25rem;
  border-radius: var(--radius-sm); animation: fadeUp .4s var(--ease);
  background: var(--glass-bg); border: 1px solid var(--glass-border);
}
.rsvp-help__title { font-family: var(--font-serif); font-size: 1.15rem; font-weight: 500; margin-bottom: .6rem; }
.rsvp-help__list { list-style: none; display: grid; gap: .55rem; padding: 0; margin: 0; }
.rsvp-help__list li {
  position: relative; padding-left: 1.3rem;
  color: var(--text-soft); font-size: .92rem; line-height: 1.5;
}
.rsvp-help__list li::before { content: "✦"; position: absolute; left: 0; color: var(--accent); }

/* RSVP header centered (title, intro, deadline) — the form itself stays left. */
#rsvp .section__title,
#rsvp .rsvp__deadline { text-align: center; }
#rsvp .section__subtitle { text-align: center; margin-inline: auto; }

/* Attendance question centered (same concept as the header). */
.field--attendance { text-align: center; }
.field--attendance .radio-row { justify-content: center; }

/* ---- Attendees mini-section (tasks 3 & 4) -------------------------------- */
/* Head = the question on its own line, then a row: "+ Agregar" pinned left and
   the "N restantes" legend pinned right. */
.attendees__head { display: flex; flex-direction: column; gap: .5rem; }
.attendees__head .field__label { text-align: center; }
.attendees__actions { display: flex; align-items: center; justify-content: space-between; gap: .75rem; }
.attendees__remaining { font-size: .72rem; color: var(--text-soft); text-align: right; }
.attendees__add {
  border: 1px solid var(--glass-border); background: var(--glass-bg-strong);
  color: var(--accent); border-radius: 999px; padding: .35em .95em;
  font-size: .82rem; cursor: pointer; transition: all .2s var(--ease);
}
.attendees__add:hover:not(:disabled) { background: var(--accent-soft); }
.attendees__add:disabled { opacity: .45; cursor: not-allowed; }
.attendees { display: grid; gap: .55rem; margin-top: .6rem; }
.attendee { display: flex; align-items: center; gap: .5rem; }
.attendee__input {
  flex: 1 1 auto; width: 100%; font-family: var(--font-sans); font-size: 1rem; color: var(--text);
  padding: .75em 1em; border-radius: var(--radius-sm);
  background: var(--glass-bg-strong); border: 1px solid var(--glass-border);
}
.attendee__input::placeholder { color: var(--text-soft); opacity: .6; }
.attendee__input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.attendee__remove {
  flex: 0 0 auto; width: 2.2em; height: 2.2em; border-radius: 50%;
  border: 1px solid var(--glass-border); background: var(--glass-bg-strong);
  color: var(--text-soft); font-size: 1.25rem; line-height: 1; cursor: pointer;
  transition: color .2s var(--ease), border-color .2s var(--ease);
}
.attendee__remove:hover { color: #b3261e; border-color: #b3261e; }

/* ---- Song suggestions (task 6) ------------------------------------------- */
.songs { display: grid; gap: .5rem; }
.song__input {
  width: 100%; font-family: var(--font-sans); font-size: 1rem; color: var(--text);
  padding: .75em 1em; border-radius: var(--radius-sm);
  background: var(--glass-bg-strong); border: 1px solid var(--glass-border);
}
.song__input::placeholder { color: var(--text-soft); opacity: .6; }
.song__input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }

/* ---- QR tickets ---------------------------------------------------------- */
.tickets__list { display: flex; flex-wrap: wrap; justify-content: center; gap: 1.5rem; margin-top: 1.5rem; }
.tickets__actions { text-align: center; margin-top: 1.5rem; }
.ticket-cell { display: flex; flex-direction: column; align-items: center; gap: .7rem; }

/* The ticket has its OWN opaque gradient (no backdrop-filter) so it exports
   cleanly to PNG/PDF and looks good as a standalone image. */
.ticket {
  width: 280px; padding: 1.6rem 1.4rem; border-radius: var(--radius-lg);
  text-align: center; color: #4a3940;
  background:
    radial-gradient(120% 80% at 50% 0%, #fdeff2 0%, #f6dde6 45%, #ecc7d6 100%);
  border: 1px solid rgba(255,255,255,.7);
  box-shadow: 0 14px 40px rgba(120, 70, 90, 0.22);
}
.ticket__couple { font-family: var(--font-serif); font-size: 1.4rem; font-weight: 600; line-height: 1.1; }
.ticket__date { font-size: .72rem; letter-spacing: .18em; text-transform: uppercase; color: #b06a79; margin-top: .2rem; }
.ticket__qr {
  width: 168px; height: 168px; margin: 1rem auto; padding: 9px;
  background: #fff; border-radius: 12px; box-shadow: inset 0 0 0 1px rgba(0,0,0,.05);
  display: grid; place-items: center;
}
.ticket__qr canvas, .ticket__qr img {
  width: 150px; height: 150px; display: block;
  image-rendering: pixelated;   /* keep QR modules crisp when scaled */
}
.ticket__person { font-family: var(--font-serif); font-size: 1.2rem; font-weight: 500; }
/* No `.ticket__mesa`: the table is deliberately absent from the ticket and is
   revealed by the scanner instead (see .validator__result-mesa). */
.ticket__folio {
  margin-top: .55rem; color: #b06a79;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: .74rem; letter-spacing: .14em; text-transform: uppercase;
}
.ticket__hint {
  margin-top: 1rem; padding-top: .8rem; border-top: 1px dashed rgba(120,70,90,.3);
  font-size: .68rem; letter-spacing: .12em; text-transform: uppercase; color: #9c8088;
}
.ticket__download {
  font-size: .7rem; padding: .55em 1.2em;
  background: var(--glass-bg-strong); color: var(--text);
}
.ticket__download:hover { background: var(--accent-soft); }

/* ---- Validator (entrance scanner) page ----------------------------------- */
.validator__main { min-height: 100svh; display: flex; align-items: center; padding: 2.5rem 0; }
/* A class-level `display` beats the UA [hidden] rule, so restore it explicitly
   (the gate view is toggled via the hidden attribute). */
.validator__main[hidden] { display: none; }
.validator__header { text-align: center; margin-bottom: 1.5rem; }
.validator__gate { max-width: 420px; margin: 0 auto; text-align: center; }
.validator__gate .section__subtitle { margin-inline: auto; }

.validator__reader {
  width: 100%; max-width: 360px; margin: 0 auto 1.25rem;
  border-radius: var(--radius-md); overflow: hidden; border: 1px solid var(--glass-border);
  background: rgba(0,0,0,.15);
}
.validator__reader video { width: 100% !important; height: auto !important; display: block; }

.validator__result {
  text-align: center; padding: 1.25rem; border-radius: var(--radius-md);
  margin: 1rem 0; border: 1px solid var(--glass-border); background: var(--glass-bg-strong);
}
.validator__result-title { font-family: var(--font-serif); font-size: 1.6rem; font-weight: 600; }
.validator__result-person { font-size: 1.05rem; margin-top: .3rem; }
.validator__result-group { color: var(--text-soft); font-size: .88rem; }
/* The table is only revealed here (never on the ticket), so it dominates the
   result card: the person at the door reads it out at a glance. */
.validator__result-mesa {
  display: block; margin-top: .7rem; padding: .35em .6em;
  font-family: var(--font-serif); font-size: 2.1rem; font-weight: 600; line-height: 1.1;
  background: var(--glass-bg-strong); border: 1px solid var(--glass-border);
  border-radius: var(--radius-sm);
}
.validator__result-mesa.is-pending {
  font-family: var(--font-sans); font-size: .9rem; font-weight: 400;
  letter-spacing: .1em; text-transform: uppercase; color: var(--text-soft);
}
.validator__result-when { color: var(--text-soft); font-size: .82rem; margin-top: .3rem; }
.validator__result.is-valid   { background: rgba(46,160,90,.18);  border-color: rgba(46,160,90,.5); }
.validator__result.is-used    { background: rgba(224,160,60,.18); border-color: rgba(224,160,60,.55); }
.validator__result.is-invalid { background: rgba(179,38,30,.16);  border-color: rgba(179,38,30,.5); }
.validator__result.is-loading,
.validator__result.is-error   { background: var(--glass-bg-strong); }

.validator__manual { margin-top: 1rem; }
.validator__manual summary { cursor: pointer; color: var(--accent); font-size: .9rem; }
.validator__logout {
  display: block; margin: 1.25rem auto 0; font-size: .72rem;
  background: transparent; color: var(--text-soft);
}
.validator__error { color: #b3261e; text-align: center; margin-top: 1rem; }

/* ---- Scanner cooldown (after each scan) ---------------------------------- */
.validator__cooldown { text-align: center; margin: .8rem 0 0; }
.validator__cooldown-text { color: var(--text-soft); font-size: .85rem; margin-bottom: .6rem; }
.validator__cooldown-text strong { color: var(--accent); font-weight: 500; }
/* «Escanear siguiente»: el escáner espera a este botón después de cada boleto,
   así que tiene que ser lo más fácil de tocar de la pantalla. */
.validator__siguiente { max-width: 420px; margin: 0 auto; padding: .95rem 1rem; }
body.modo-puerta .validator__siguiente { max-width: none; padding: 1.15rem 1rem; font-size: 1.05rem; }

/* ---- Cámara que no abre (permiso negado, sin cámara, ocupada) -------------
   Aviso fijo en lugar del recuadro negro vacío: dice por qué, cómo dar el
   permiso en ese teléfono y deja reintentar. El folio queda a la vista, también
   en modo puerta, que normalmente lo esconde. */
.validator__camara {
  margin: 0 auto 1rem; max-width: 520px; padding: 1rem 1.1rem;
  border-radius: var(--radius-md); border: 1px solid var(--accent-2);
  background: var(--accent-2-soft);
}
.validator__camara-titulo { font-family: var(--font-serif); font-size: 1.25rem; font-weight: 600; }
.validator__camara-texto { margin-top: .3rem; font-size: .92rem; }
.validator__camara-pasos { margin: .7rem 0 .9rem 1.1rem; font-size: .86rem; color: var(--text-soft); }
.validator__camara-pasos li + li { margin-top: .35rem; }
.validator__camara-pasos strong { color: var(--text); font-weight: 500; }
.validator--sin-camara .validator__reader { display: none; }
body.modo-puerta .validator--sin-camara .validator__manual { display: block; }

/* ---- Organizer dashboard ------------------------------------------------- */
.dash { max-width: 760px; margin: 0 auto; }
.dash__metrics { display: grid; grid-template-columns: repeat(2, 1fr); gap: .9rem; margin: 1.25rem 0; }
@media (min-width: 680px) { .dash__metrics { grid-template-columns: repeat(4, 1fr); } }
.metric {
  background: var(--glass-bg-strong); border: 1px solid var(--glass-border);
  border-radius: var(--radius-md); padding: 1.1rem .8rem; text-align: center;
}
.metric__num { font-family: var(--font-serif); font-weight: 600; font-size: 2rem; line-height: 1; color: var(--text); font-variant-numeric: tabular-nums; }
.metric__label { margin-top: .35rem; font-size: .66rem; letter-spacing: .1em; text-transform: uppercase; color: var(--text-soft); }
.metric__sub { font-size: .72rem; color: var(--accent); margin-top: .25rem; }
.metric--accent .metric__num { color: var(--accent); }

.dash__actions { display: flex; gap: .8rem; justify-content: center; flex-wrap: wrap; margin: 1.25rem 0; }
.dash__section-title { font-family: var(--font-serif); font-size: 1.3rem; margin: 1.75rem 0 .6rem; }
.dash__table { display: grid; gap: .4rem; }
.dash__row {
  display: flex; align-items: center; gap: .6rem; justify-content: space-between;
  padding: .6em .9em; border-radius: var(--radius-sm);
  background: var(--glass-bg-strong); border: 1px solid var(--glass-border); font-size: .9rem;
}
.dash__row-main { display: flex; flex-direction: column; text-align: left; }
.dash__row-meta { color: var(--text-soft); font-size: .8rem; }
.dash__badge { flex-shrink: 0; font-size: .64rem; letter-spacing: .08em; text-transform: uppercase; padding: .3em .7em; border-radius: 999px; border: 1px solid var(--glass-border); }
.dash__badge.is-yes { background: rgba(52,199,109,.34); border-color: rgba(90,214,140,.72); color: #d8ffe7; }
/* On the light console the pale green text would wash out — go dark instead. */
body.theme-light .dash__badge.is-yes { background: rgba(52,199,109,.26); color: #14532d; }
.dash__badge.is-pending { background: var(--accent-soft); }
.dash__badge.is-no { background: rgba(179,38,30,.14); }
.dash__empty { color: var(--text-soft); font-size: .85rem; text-align: center; padding: .6rem; }
.dash__refresh { display: block; margin: 0 auto; font-size: .72rem; background: transparent; color: var(--text-soft); }

/* Expandable group → per-group people (organizer only) */
.dash__group { display: grid; gap: .35rem; }
.dash__row--toggle { cursor: pointer; -webkit-tap-highlight-color: transparent; }
.dash__row--toggle:hover { border-color: var(--accent); }
.dash__row--toggle .dash__row-name { display: inline-flex; align-items: center; gap: .4em; }
.dash__chevron { display: inline-block; transition: transform .2s ease; color: var(--text-soft); font-size: .8em; }
.dash__group.is-open .dash__chevron { transform: rotate(90deg); }
.dash__people {
  display: grid; gap: .3rem; padding: .5rem .9rem .7rem;
  border-radius: var(--radius-sm); background: var(--glass-bg); border: 1px solid var(--glass-border);
}
/* A class-level `display` beats the UA [hidden] rule, so restore it explicitly. */
.dash__people[hidden] { display: none; }
.dash__people-title { font-size: .66rem; letter-spacing: .1em; text-transform: uppercase; color: var(--text-soft); margin: .3rem 0 .1rem; }
.dash__person { display: flex; align-items: center; gap: .5rem; justify-content: space-between; font-size: .85rem; }
.dash__person-name { text-align: left; }
.dash__person-name.is-empty { color: var(--text-soft); font-style: italic; }
.dash__person-tag {
  flex-shrink: 0; font-size: .58rem; letter-spacing: .06em; text-transform: uppercase;
  padding: .2em .55em; border-radius: 999px; border: 1px solid var(--glass-border); color: var(--text-soft);
}
.dash__person-tag.is-used { background: rgba(46,160,90,.18); color: var(--text); }

/* ---- roster editable (personas de un grupo sin confirmar) --------------- */
.person {
  display: flex; align-items: center; gap: .5rem; flex-wrap: wrap;
  padding: .35rem 0;
}
.person__names { display: flex; gap: .4rem; flex: 1 1 220px; min-width: 0; }
.person__input {
  flex: 1 1 0; min-width: 0; width: 100%;
  font: inherit; font-size: .85rem; color: var(--text);
  padding: .45em .7em; border-radius: var(--radius-sm);
  background: var(--glass-bg-strong); border: 1px solid var(--glass-border);
  transition: border-color .2s var(--ease), box-shadow .2s var(--ease);
}
.person__input::placeholder { color: var(--text-soft); opacity: .55; font-style: italic; }
.person__input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.person__input.is-saving { opacity: .6; }
.person__input.is-saved { border-color: var(--accent); }

.person__flags { display: flex; align-items: center; gap: .35rem; flex-shrink: 0; }
.person__flag {
  font: inherit; font-size: .64rem; letter-spacing: .06em; text-transform: uppercase;
  padding: .32em .6em; border-radius: 999px; cursor: pointer;
  color: var(--text-soft); background: transparent; border: 1px solid var(--glass-border);
  transition: all .2s var(--ease);
}
.person__flag:hover { border-color: var(--accent); color: var(--text); }
.person__flag[aria-pressed="true"] { background: var(--accent-soft); border-color: var(--accent); color: var(--accent); }
.person__remove {
  width: 1.9em; height: 1.9em; flex-shrink: 0; border-radius: 50%;
  font: inherit; font-size: .8rem; line-height: 1; cursor: pointer;
  color: var(--text-soft); background: transparent; border: 1px solid var(--glass-border);
}
.person__remove:hover { color: #b3261e; border-color: #b3261e; }
.person__remove.is-armed {
  width: auto; padding: 0 .7em; border-radius: 999px;
  color: #b3261e; border-color: #b3261e; background: rgba(179,38,30,.12);
}

.person__add-row {
  display: flex; align-items: center; gap: .6rem; flex-wrap: wrap;
  margin-top: .6rem; padding-top: .6rem; border-top: 1px dashed var(--glass-border);
}
.person__add { font-size: .74rem; padding: .38rem .9rem; }
.person__hint { font-size: .72rem; color: var(--text-soft); }
.person__locked { font-size: .74rem; color: var(--text-soft); font-style: italic; margin-top: .4rem; }

/* =============================================================================
   11. ANÉCDOTAS — el muro vive ahora en 16.3 (cuadrícula que voltea)
   ============================================================================= */


/* =============================================================================
   12. PHASE 3 · Guest uploads + moderation
   Guest photo upload (subir.html) and message posting (mensaje.html), plus the
   two moderation queues in the organizer console (validar.html).
   ============================================================================= */
/* ---- upload page ------------------------------------------------------- */
.upload { max-width: 480px; margin: 0 auto; }
.upload input[type="file"] {
  width: 100%; padding: .7rem .9rem; font: inherit; color: var(--text-soft);
  background: var(--glass-bg); border: 1px solid var(--glass-border);
  border-radius: var(--radius-md); cursor: pointer;
}
.upload input[type="file"]::-webkit-file-upload-button,
.upload input[type="file"]::file-selector-button {
  font: inherit; margin-right: .8rem; padding: .4rem .9rem; cursor: pointer;
  color: var(--text); background: var(--accent-soft);
  border: 1px solid var(--glass-border); border-radius: 999px;
}
.upload__preview { display: flex; flex-wrap: wrap; gap: .6rem; margin-top: .3rem; }
.upload__thumb {
  width: 76px; height: 76px; border-radius: var(--radius-md);
  background-size: cover; background-position: center;
  border: 1px solid var(--glass-border); box-shadow: var(--glass-shadow);
}
.upload__status { margin-top: 1.1rem; padding: .9rem 1rem; border-radius: var(--radius-md); font-size: .92rem; text-align: center; border: 1px solid var(--glass-border); }
.upload__status.is-loading { background: var(--glass-bg-strong); color: var(--text-soft); }
.upload__status.is-ok      { background: rgba(46,160,90,.16);  border-color: rgba(46,160,90,.45); }
.upload__status.is-warn    { background: rgba(224,160,60,.16); border-color: rgba(224,160,60,.5); }
.upload__status.is-error   { background: rgba(179,38,30,.14);  border-color: rgba(179,38,30,.45); }
.upload__back { margin-top: 1.4rem; }
/* Shown instead of the form while the organizer keeps the feature closed. */
.upload__closed {
  text-align: center; padding: 1.2rem 1rem; border-radius: var(--radius-md);
  background: var(--glass-bg); border: 1px solid var(--glass-border);
  color: var(--text-soft); font-size: .92rem;
}
.upload__closed-title {
  font-family: var(--font-serif); font-size: 1.25rem; color: var(--text); margin-bottom: .35rem;
}

/* ---- feature switch (organizer opens/closes a guest feature) ------------ */
/* Lives at the top of the view it governs: Galería → subida de fotos,
   Mensajes → envío de mensajes. */
.modswitch {
  display: flex; align-items: center; justify-content: space-between;
  gap: .9rem 1.2rem; flex-wrap: wrap;
  padding: .85rem 1rem; margin-bottom: 1.1rem;
  background: var(--glass-bg); border: 1px solid var(--glass-border);
  border-radius: var(--radius-md);
}
.modswitch__text { flex: 1 1 220px; min-width: 0; }
.modswitch__title { font-family: var(--font-serif); font-size: 1.1rem; line-height: 1.2; }
.modswitch__note { font-size: .78rem; color: var(--text-soft); margin-top: .15rem; }
.modswitch__note.is-on { color: var(--accent); }

.switch {
  display: inline-flex; align-items: center; gap: .6rem; flex-shrink: 0;
  font: inherit; color: var(--text); background: transparent; border: 0;
  padding: 0; cursor: pointer;
}
.switch:disabled { opacity: .5; cursor: default; }
.switch__track {
  position: relative; width: 48px; height: 27px; border-radius: 999px; flex-shrink: 0;
  background: var(--glass-bg-strong); border: 1px solid var(--glass-border);
  transition: background .25s var(--ease), border-color .25s var(--ease);
}
.switch__knob {
  position: absolute; top: 2px; left: 2px; width: 21px; height: 21px; border-radius: 50%;
  background: var(--text-soft);
  transition: transform .25s var(--ease), background .25s var(--ease);
}
.switch[aria-checked="true"] .switch__track { background: var(--accent-soft); border-color: var(--accent); }
.switch[aria-checked="true"] .switch__knob { transform: translateX(21px); background: var(--accent); }
.switch:focus-visible .switch__track { box-shadow: 0 0 0 3px var(--accent-soft); }
.switch__label {
  font-size: .72rem; letter-spacing: .1em; text-transform: uppercase; color: var(--text-soft);
  min-width: 6.5em;   /* keeps the row from jumping between the two labels */
}
.switch[aria-checked="true"] .switch__label { color: var(--accent); }

/* ---- moderation grid --------------------------------------------------- */
.modtabs { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; margin-bottom: 1.1rem; }
.modtabs__btn {
  font: inherit; font-size: .82rem; padding: .4rem 1rem; cursor: pointer;
  color: var(--text-soft); background: transparent;
  border: 1px solid var(--glass-border); border-radius: 999px;
}
.modtabs__btn.is-active { color: var(--text); background: var(--accent-soft); border-color: var(--accent); }
.modtabs .dash__refresh { margin-left: auto; }

/* Roomy moderation grid: one big photo per row on phones (so the couple can
   actually SEE what they're approving), two columns on wider screens. */
.modgrid { display: grid; grid-template-columns: 1fr; gap: 1.1rem; }
@media (min-width: 640px) { .modgrid { grid-template-columns: repeat(2, 1fr); } }

.modcard {
  display: flex; flex-direction: column; gap: .7rem;
  background: var(--glass-bg); border: 1px solid var(--glass-border);
  border-radius: var(--radius-md); box-shadow: var(--glass-shadow); padding: .8rem;
}
.modcard.is-busy { opacity: .5; pointer-events: none; }
/* Show the WHOLE photo (no cropping) so nothing is hidden from the reviewer. */
.modcard__img {
  display: block; width: 100%; max-height: 70vh; object-fit: contain;
  border-radius: var(--radius-sm); background-color: var(--accent-soft);
}
.modcard__img--missing {
  display: flex; align-items: center; justify-content: center;
  min-height: 200px; font-size: .78rem; color: var(--text-soft); text-align: center; padding: .5rem;
}
.modcard__meta { text-align: center; }
.modcard__who { font-size: .85rem; color: var(--text-soft); }
.modcard__actions { display: flex; gap: .6rem; }
.modcard__btn { flex: 1; font-size: .82rem; padding: .55rem .4rem; }

/* ---- message posting page (mensaje.html) -------------------------------- */
.msgform__count {
  font-size: .72rem; color: var(--text-soft); text-align: right;
  font-variant-numeric: tabular-nums;
}

/* ---- message moderation queue (validar.html → Mensajes) ---------------- */
.modmsgs { display: grid; grid-template-columns: 1fr; gap: 1rem; }
@media (min-width: 760px) { .modmsgs { grid-template-columns: repeat(2, 1fr); } }

.modmsg {
  display: flex; flex-direction: column; gap: .7rem;
  background: var(--glass-bg); border: 1px solid var(--glass-border);
  border-radius: var(--radius-md); box-shadow: var(--glass-shadow); padding: 1rem 1.1rem;
}
.modmsg.is-busy { opacity: .5; pointer-events: none; }
.modmsg__text {
  font-family: var(--font-serif); font-style: italic; font-size: 1.05rem; line-height: 1.45;
  overflow-wrap: anywhere;   /* a guest can paste one very long "word" */
}
.modmsg__meta {
  display: flex; align-items: baseline; justify-content: space-between; gap: .6rem;
  font-size: .74rem; color: var(--text-soft);
}
.modmsg__who { color: var(--accent); letter-spacing: .06em; text-transform: uppercase; }
.modmsg__actions { display: flex; gap: .6rem; margin-top: auto; }
.modmsg__btn { flex: 1; font-size: .82rem; padding: .55rem .4rem; }

/* =============================================================================
   13. ORGANIZER DASHBOARD SHELL (validar.html · .dash-app)
   Full-viewport admin layout: collapsible sidebar + main. Dimmed marble so it
   reads as a console, not the invitation. Reuses .metric / .dash__* / .modcard.
   Both palettes: the surfaces come from --dash-* (section 1) and the theme is
   switched at runtime by js/panel-theme.js.
   ============================================================================= */

/* Flatter, more opaque veil over the marble on this page only (texture stays). */
.dash-app .dash-veil {
  position: absolute; inset: 0; pointer-events: none;
  background: var(--dash-veil);
}

/* Theme switch on the passcode gate (the topbar one covers the console itself). */
.panel-theme-float { position: fixed; top: 1rem; right: 1rem; z-index: 10; }

.dashx[hidden] { display: none; }
.dashx { display: flex; min-height: 100svh; align-items: stretch; }

/* ---- sidebar ---------------------------------------------------------- */
.dashx__sidebar {
  width: 250px; flex-shrink: 0;
  display: flex; flex-direction: column;
  padding: 1rem .8rem 1.1rem;
  background: var(--dash-sidebar-bg);
  border-right: 1px solid var(--glass-border);
  -webkit-backdrop-filter: blur(var(--blur)); backdrop-filter: blur(var(--blur));
  /* `align-self` es lo que hace que el sticky funcione: sin él, el `stretch`
     del contenedor flex estira la barra a toda la altura del contenido y ya no
     le queda recorrido donde pegarse (se iba con el scroll). Con su propia
     altura de 100svh se queda visible siempre. */
  align-self: flex-start;
  position: sticky; top: 0; height: 100svh;
  overflow-y: auto;                 /* si el menú creciera, scrollea él, no la página */
  transition: width .28s var(--ease), transform .28s var(--ease);
}
.dashx__brand { display: flex; align-items: center; gap: .6rem; padding: .3rem .5rem 1rem; }
.dashx__logo { display: inline-flex; flex-shrink: 0; }
.dashx__wordmark {
  font-family: var(--font-serif); font-size: 1.55rem; font-weight: 600;
  letter-spacing: .04em; color: var(--text); white-space: nowrap;
}
.dashx__collapse {
  margin-left: auto; width: 26px; height: 26px; border-radius: 8px; flex-shrink: 0;
  background: transparent; border: 1px solid var(--glass-border); color: var(--text-soft);
  cursor: pointer; line-height: 1; font-size: 1rem;
}
.dashx__collapse:hover { color: var(--text); border-color: var(--accent); }

.dashx__nav { display: flex; flex-direction: column; gap: .12rem; flex: 1; overflow-y: auto; }
.dashx__nav-group {
  font-size: .6rem; letter-spacing: .14em; text-transform: uppercase;
  color: var(--text-soft); margin: .9rem .7rem .3rem;
}
.dashx__nav-group[hidden] { display: none; }
.dashx__navitem, .dashx__logout {
  display: flex; align-items: center; gap: .7rem; width: 100%;
  padding: .58rem .7rem; border-radius: var(--radius-sm);
  font: inherit; font-size: .9rem; color: var(--text-soft);
  background: transparent; border: 1px solid transparent; cursor: pointer; text-align: left;
  transition: background .2s, color .2s, border-color .2s;
}
.dashx__navitem[hidden] { display: none; }
.dashx__navitem:hover, .dashx__logout:hover { color: var(--text); background: var(--glass-bg); }
.dashx__navitem.is-active { color: var(--text); background: var(--accent-soft); border-color: var(--accent); }
.dashx__navicon { width: 1.3em; text-align: center; flex-shrink: 0; opacity: .9; }
.dashx__logout { margin-top: .4rem; }

/* Collapsed rail (desktop only) */
@media (min-width: 861px) {
  .dashx--collapsed .dashx__sidebar { width: 68px; }
  .dashx--collapsed .dashx__wordmark,
  .dashx--collapsed .dashx__navlabel,
  .dashx--collapsed .dashx__nav-group { display: none; }
  .dashx--collapsed .dashx__navitem,
  .dashx--collapsed .dashx__logout { justify-content: center; }
  .dashx--collapsed .dashx__collapse { transform: rotate(180deg); margin: 0 auto; }
  .dashx--collapsed .dashx__brand { justify-content: center; }
}

/* ---- main column ------------------------------------------------------ */
.dashx__main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.dashx__topbar {
  display: flex; align-items: center; gap: 1rem;
  padding: .85rem clamp(1rem, 3vw, 2rem);
  border-bottom: 1px solid var(--glass-border);
  background: var(--dash-topbar-bg);
  -webkit-backdrop-filter: blur(var(--blur)); backdrop-filter: blur(var(--blur));
  position: sticky; top: 0; z-index: 5;
}
.dashx__title { font-family: var(--font-serif); font-size: 1.5rem; font-weight: 600; flex: 1; }
.dashx__iconbtn {
  font: inherit; font-size: 1.1rem; line-height: 1; cursor: pointer;
  width: 40px; height: 40px; border-radius: 10px;
  background: var(--glass-bg); border: 1px solid var(--glass-border); color: var(--text);
  display: inline-flex; align-items: center; justify-content: center;
}
.dashx__iconbtn:hover { border-color: var(--accent); }
.dashx__iconbtn--text { width: auto; padding: 0 .9rem; font-size: .82rem; }
#sidebar-toggle { display: none; }

.dashx__content { flex: 1; padding: clamp(1rem, 3vw, 2rem); width: 100%; max-width: 1440px; }
.dashx__view[hidden] { display: none; }
.dashx__content .dash__metrics { margin: 0 0 1.4rem; }

/* ---- chart cards ------------------------------------------------------ */
.dashx__cards { display: grid; grid-template-columns: 1fr; gap: 1.2rem; margin-bottom: 1.4rem; }
@media (min-width: 760px) { .dashx__cards { grid-template-columns: 1fr 1fr; } }
.dashx__chartcard--wide { grid-column: 1 / -1; }
.dashx__chartcard { padding: 1.2rem 1rem 1rem; }
.dashx__chart-title {
  font-size: .68rem; letter-spacing: .12em; text-transform: uppercase;
  color: var(--text-soft); margin-bottom: .4rem; text-align: center;
}
.dashx__chart { min-height: 230px; }
/* RSVP history card: scrolls internally so it stays the height of its chart row. */
.dashx__histlist { max-height: 300px; overflow-y: auto; gap: .4rem; padding-right: .15rem; }

.dashx__panel { padding: 1.3rem clamp(1rem, 2vw, 1.5rem); }
.dashx__panel-head { display: flex; align-items: center; justify-content: space-between; gap: 1rem; margin-bottom: .8rem; flex-wrap: wrap; }
.dashx__content .dash__section-title { margin-top: 0; }

/* ---- group controls: ticket stepper + link ---------------------------- */
.dash__controls { display: flex; flex-wrap: wrap; gap: .55rem .9rem; align-items: center; padding: .15rem .25rem; }
.dash__stepper {
  display: inline-flex; align-items: center; gap: .5rem;
  padding: .22rem .5rem; border: 1px solid var(--glass-border);
  border-radius: 999px; background: var(--glass-bg);
}
.dash__stepper-label { font-size: .6rem; letter-spacing: .1em; text-transform: uppercase; color: var(--text-soft); padding-left: .3rem; }
.dash__step {
  width: 28px; height: 28px; border-radius: 50%; flex-shrink: 0;
  border: 1px solid var(--glass-border); background: var(--glass-bg-strong);
  color: var(--text); font-size: 1.15rem; line-height: 1; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
}
.dash__step:disabled { opacity: .4; cursor: default; }
.dash__step:hover:not(:disabled) { border-color: var(--accent); color: var(--accent); }
.dash__stepper-val { min-width: 1.4em; text-align: center; font-variant-numeric: tabular-nums; font-weight: 500; }

.dash__linkbox { display: flex; align-items: center; gap: .4rem; flex: 1; min-width: 220px; }
.dash__link {
  flex: 1; min-width: 0; font: inherit; font-size: .76rem; color: var(--text-soft);
  padding: .42rem .6rem; border-radius: var(--radius-sm);
  background: var(--glass-bg); border: 1px solid var(--glass-border);
}
.dash__copy { flex-shrink: 0; font-size: .76rem; padding: .42rem .85rem; }
.dash__copy.is-ok { color: var(--accent); border-color: var(--accent); }
.dash__aviso { font-size: .78rem; color: var(--accent); padding: .1rem .3rem; }
.dash__aviso[hidden] { display: none; }

/* ---- bitácora de envío: contador + checkbox "Enviada" ------------------- */
.dash__count {
  font-size: .82rem; color: var(--text-soft);
  padding: 0 .1rem .7rem;
}
.dash__count strong { color: var(--accent); font-weight: 500; }

/* Barra superior de Grupos: contador a la izquierda, alta a la derecha. */
.dash__toolbar {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: .8rem; flex-wrap: wrap; padding-bottom: .5rem;
}
.dash__toolbar .dash__count { padding-bottom: 0; }
.dash__newbtn { font-size: .78rem; padding: .45rem 1rem; flex-shrink: 0; }
.dash__edit { font-size: .74rem; padding: .4rem .9rem; flex-shrink: 0; }
.dash__restore { font-size: .74rem; padding: .4rem .9rem; flex-shrink: 0; }
.dash__group.is-archived .dash__row { opacity: .75; }

/* Aviso de archivados en el Resumen: aparte de las métricas, nunca dentro. */
.dash__archnote {
  display: flex; align-items: center; justify-content: space-between;
  gap: .8rem; flex-wrap: wrap;
  margin: -.6rem 0 1.4rem; padding: .7rem 1rem;
  font-size: .84rem; color: var(--text-soft);
  background: var(--glass-bg); border: 1px dashed var(--glass-border);
  border-radius: var(--radius-md);
}
.dash__archnote[hidden] { display: none; }
.dash__archnote strong { color: var(--text); font-weight: 500; }
.dash__archnote-btn { font-size: .74rem; padding: .35rem .9rem; }

/* Checkbox real (role="checkbox"), no un switch: es una lista de pendientes. */
.dash__check {
  display: inline-flex; align-items: center; gap: .5rem; flex-shrink: 0;
  font: inherit; font-size: .78rem; color: var(--text-soft);
  background: transparent; border: 0; padding: .2rem .1rem; cursor: pointer;
}
.dash__check-box {
  width: 20px; height: 20px; border-radius: 6px; flex-shrink: 0;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: .8rem; line-height: 1; color: transparent;
  background: var(--glass-bg-strong); border: 1px solid var(--glass-border);
  transition: background .2s var(--ease), border-color .2s var(--ease), color .2s var(--ease);
}
.dash__check:hover .dash__check-box { border-color: var(--accent); }
.dash__check[aria-checked="true"] .dash__check-box {
  background: var(--accent); border-color: var(--accent); color: var(--on-accent);
}
.dash__check[aria-checked="true"] { color: var(--accent); }
.dash__check:disabled { opacity: .5; cursor: default; }
.dash__check:focus-visible .dash__check-box { box-shadow: 0 0 0 3px var(--accent-soft); }

/* ---- vista Envíos: una tarjeta por grupo con su mensaje listo ---------- */
.envio {
  display: grid; gap: .7rem;
  padding: .9rem 1rem; margin-bottom: .9rem;
  background: var(--glass-bg); border: 1px solid var(--glass-border);
  border-radius: var(--radius-md);
}
.envio__head { display: flex; align-items: center; justify-content: space-between; gap: .8rem; }
.envio__msg {
  width: 100%; resize: vertical; font: inherit; font-size: .82rem; line-height: 1.5;
  color: var(--text); padding: .7em .9em; border-radius: var(--radius-sm);
  background: var(--glass-bg-strong); border: 1px solid var(--glass-border);
}
.envio__msg:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.envio__actions { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; }
.envio__btn { font-size: .78rem; padding: .45rem 1rem; }
.envio__actions .dash__check { margin-left: auto; }

/* ---- songs view ------------------------------------------------------- */
.songs { display: grid; gap: 1rem; }
@media (min-width: 640px) { .songs { grid-template-columns: 1fr 1fr; } }
.songs__group { background: var(--glass-bg); border: 1px solid var(--glass-border); border-radius: var(--radius-md); padding: .9rem 1rem; }
.songs__group-name { font-family: var(--font-serif); font-size: 1.05rem; margin-bottom: .35rem; }
.songs__list { list-style: none; display: grid; gap: .22rem; }
.songs__item { font-size: .88rem; color: var(--text-soft); }

/* ---- modal (alta / edición de grupo) ---------------------------------- */
.modal { position: fixed; inset: 0; z-index: 60; display: flex; align-items: center; justify-content: center; padding: 1rem; }
.modal[hidden] { display: none; }
.modal__scrim { position: absolute; inset: 0; background: rgba(0,0,0,.55); }
.modal__box {
  position: relative; z-index: 1;
  width: min(100%, 460px); max-height: 90svh; overflow-y: auto;
  padding: 1.4rem clamp(1rem, 3vw, 1.6rem);
  background: var(--modal-bg);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-lg);
  box-shadow: 0 24px 70px rgba(0,0,0,.45);
  -webkit-backdrop-filter: blur(var(--blur)); backdrop-filter: blur(var(--blur));
  animation: fadeUp .28s var(--ease);
}
.modal__title { font-family: var(--font-serif); font-size: 1.5rem; margin-bottom: 1rem; }
.modal__actions { display: flex; gap: .6rem; justify-content: flex-end; flex-wrap: wrap; }
.modal__actions .btn { flex: 1 1 auto; }
.field__hint { font-size: .74rem; color: var(--text-soft); }
.field__hint[hidden] { display: none; }

/* Zona de riesgo: separada del formulario y con su propio lenguaje visual. */
.modal__danger {
  margin-top: 1.4rem; padding-top: 1.1rem;
  border-top: 1px dashed var(--glass-border);
}
.modal__danger[hidden] { display: none; }
.modal__danger-title { font-size: .68rem; letter-spacing: .12em; text-transform: uppercase; color: var(--text-soft); }
.modal__danger-text { font-size: .82rem; color: var(--text-soft); margin: .35rem 0 .7rem; line-height: 1.5; }
/* Transparente a propósito: no debe competir con "Guardar" ni invitar al toque. */
.modal__danger-btn {
  width: 100%; font-size: .8rem; box-shadow: none;
  background: transparent; color: #b3261e; border: 1px solid rgba(179,38,30,.45);
}
.modal__danger-btn:hover:not(:disabled) { background: rgba(179,38,30,.12); }
.modal__danger-btn:disabled { opacity: .45; cursor: not-allowed; }
.modal__danger-btn.is-armed { background: rgba(179,38,30,.16); border-color: #b3261e; font-weight: 500; }

/* ---- mobile drawer ---------------------------------------------------- */
.dashx__scrim { position: fixed; inset: 0; z-index: 20; background: rgba(0,0,0,.5); }
.dashx__scrim[hidden] { display: none; }
@media (max-width: 860px) {
  #sidebar-toggle { display: inline-flex; }
  .dashx__collapse { display: none; }
  .dashx__sidebar {
    position: fixed; top: 0; left: 0; z-index: 30; height: 100svh; width: 260px;
    transform: translateX(-100%);
  }
  .dashx--drawer .dashx__sidebar { transform: translateX(0); box-shadow: 0 0 60px rgba(0,0,0,.6); }
}
@media (min-width: 861px) {
  .dashx__scrim { display: none; }
}

/* =============================================================================
   14. CONFIGURATION VIEW (organizer panel → Configuración)
   Styles for the deadline date-time input row and its save button.
   ============================================================================= */
.config__row {
  display: flex;
  flex-direction: column;
  gap: .6rem;
  margin-top: 1rem;
}
.config__input {
  width: 100%; max-width: 100%;
  font-family: var(--font-sans); font-size: 1rem; color: var(--text);
  padding: .85em 1em; border-radius: var(--radius-sm);
  background: var(--glass-bg-strong);
  border: 1px solid var(--glass-border);
  transition: border-color .25s var(--ease), box-shadow .25s var(--ease);
}
.config__input:focus {
  outline: none; border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.config__input::placeholder { color: var(--text-soft); opacity: .6; }

/* =============================================================================
   15. MESAS — Vista "Asignar" (organizer panel → Asignar mesas)
   Layout de dos columnas: pool de personas sin sentar a la izquierda,
   rejilla de mesas a la derecha. En <900px se apila en una columna.
   Reutiliza variables del tema (--glass-*, --radius-*, --text*, --accent*).
   ============================================================================= */

/* Contenedor principal: dos columnas en ancho, una en móvil */
.mesas-layout {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.25rem;
  align-content: start;
}
@media (min-width: 900px) {
  .mesas-layout {
    grid-template-columns: 320px 1fr;
    align-items: start;
  }
}

/* Barra superior con contador "X sentados de Y" */
.mesas-counter {
  font-size: .78rem;
  color: var(--text-soft);
  padding: .4rem .6rem;
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-sm);
  text-align: center;
}
.mesas-counter strong { color: var(--accent); font-weight: 500; }

/* Columna izquierda: pool de personas sin sentar */
.mesas-pool {
  display: flex;
  flex-direction: column;
  gap: .75rem;
  max-height: calc(100svh - 8rem);
  overflow-y: auto;
  padding-right: .25rem; /* espacio para scrollbar */
}

/* Grupo familiar dentro del pool (título + personas) */
.mesas-pool-group { display: grid; gap: .35rem; }
.mesas-pool-group-title {
  font-size: .64rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--text-soft);
  padding-left: .25rem;
}

/* Persona arrastrable en el pool */
.mesas-pool-person {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .5rem .65rem;
  background: var(--glass-bg-strong);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-sm);
  cursor: grab;
  -webkit-user-select: none;
  user-select: none;
  transition: border-color .2s var(--ease), box-shadow .2s var(--ease);
}
.mesas-pool-person:active { cursor: grabbing; }
.mesas-pool-person:hover {
  border-color: var(--accent);
  box-shadow: 0 0 0 2px var(--accent-soft);
}
.mesas-pool-person.is-dragging { opacity: .5; }

/* Columna derecha: rejilla de tarjetas de mesa */
.mesas-tables {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 1rem;
}

/* Tarjeta de una mesa: mismo lenguaje visual que .glass / .dash__row */
.mesas-table-card {
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-md);
  box-shadow: var(--glass-shadow);
  -webkit-backdrop-filter: blur(var(--blur)) saturate(1.4);
  backdrop-filter: blur(var(--blur)) saturate(1.4);
  display: flex;
  flex-direction: column;
}

/* Cabecera de la tarjeta: nombre de mesa + contador ocupación */
.mesas-table-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .75rem;
  padding: .75rem 1rem;
  border-bottom: 1px solid var(--glass-border);
}
.mesas-table-name { font-family: var(--font-serif); font-size: 1.1rem; font-weight: 500; }
.mesas-table-count {
  font-size: .7rem;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--text-soft);
  background: var(--glass-bg-strong);
  border: 1px solid var(--glass-border);
  border-radius: 999px;
  padding: .2em .65em;
}

/* Rejilla de asientos DENTRO de una mesa (12 plazas = 3x4 visual) */
/* Los asientos van en LISTA. Antes era una rejilla de cajas fijas: con 11 o 12
   nombres por mesa cada caja recortaba por los DOS lados —el texto iba
   centrado— y salían cosas como "gélica Garcí". */
.mesas-seats {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: .15rem;
}

/* Un asiento (ocupado o vacío) */
.mesas-seat {
  display: flex;
  align-items: baseline;
  gap: .4rem;
  padding: .25rem .45rem;
  font-size: .78rem;
  line-height: 1.25;
  background: var(--glass-bg-strong);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-sm);
  color: var(--text);
  cursor: grab;
  -webkit-user-select: none;
  user-select: none;
  transition: border-color .2s var(--ease), background .2s var(--ease), box-shadow .2s var(--ease);
}
.mesas-seat-n {
  flex: none;
  width: 1.25rem;
  font-size: .66rem;
  color: var(--text-soft);
  text-align: right;
}
/* El nombre manda: ocupa lo que necesite y ENVUELVE antes que recortarse. */
.mesas-seat-nom { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.mesas-seat-nom.is-ph { color: var(--text-soft); font-style: italic; }
.mesas-seat-grp {
  flex: none;
  max-width: 38%;
  font-size: .64rem;
  color: var(--text-soft);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Asiento vacío: punteado, apagado */
.mesas-seat.is-empty {
  cursor: default;
  background: transparent;
  border-style: dashed;
  border-color: var(--glass-border);
  color: var(--text-soft);
  opacity: .55;
}

/* Estado drop: resaltado con color de acento.
   Va en los TRES destinos que acepta el JS, no sólo en el asiento: soltar sobre
   el cuerpo de la mesa (sienta en el primer hueco) y soltar de vuelta en el pool
   (quita de la mesa) son gestos válidos, y sin resaltado parecían zonas muertas. */
.mesas-seat.is-drop,
.mesas-table-card.is-drop,
#mesas-pool.is-drop {
  border-color: var(--accent);
  background: var(--accent-soft);
  box-shadow: 0 0 0 2px var(--accent-soft);
}

/* Selección por CLIC: la alternativa al arrastre. En tablet —que es lo que se
   usa el día del evento— arrastrar es incómodo, así que se toca a la persona y
   luego la mesa. Sin este resaltado el primer toque no se ve y parece que el
   panel no responde. */
.mesas-pool-person.is-selected,
.mesas-pool-group-title.is-selected,
.mesas-seat.is-selected {
  border-color: var(--accent);
  background: var(--accent-soft);
  box-shadow: 0 0 0 2px var(--accent-soft);
}

/* Mensaje vacío: "aún no hay mesas" / "no queda nadie sin sentar" */
.mesas-empty {
  text-align: center;
  padding: 2.5rem 1.5rem;
  color: var(--text-soft);
  font-size: .9rem;
  background: var(--glass-bg);
  border: 1px dashed var(--glass-border);
  border-radius: var(--radius-md);
}

/* =============================================================================
   16 · CROQUIS DEL SALÓN — la vista primaria de Mesas
   El plano en cuadrícula: el organizador coloca mesas y zonas (entrada, baños,
   pista, columnas) para simular el salón, y toca una mesa para ver y cambiar
   quién se sienta ahí. Las posiciones se guardan en casillas, no en píxeles.
   ============================================================================= */

/* Sub-pestañas Croquis / Asignar */
.mesas-subtabs {
  display: flex;
  gap: .4rem;
  margin: 0 0 .9rem;
  border-bottom: 1px solid var(--glass-border);
  padding-bottom: .55rem;
}
.mesas-subtab {
  appearance: none;
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  color: var(--text-soft);
  font: inherit;
  font-size: .85rem;
  padding: .38rem .95rem;
  cursor: pointer;
  transition: color .2s var(--ease), background .2s var(--ease), border-color .2s var(--ease);
}
.mesas-subtab:hover { color: var(--text); }
.mesas-subtab.is-active {
  color: var(--text);
  background: var(--accent-soft);
  border-color: var(--accent);
}

/* Barra de herramientas del croquis */
.mesas-croquis-bar {
  display: flex;
  align-items: center;
  gap: .6rem;
  flex-wrap: wrap;
  margin-bottom: .8rem;
}
.mesas-zonabar { display: inline-flex; align-items: center; gap: .4rem; }
.mesas-zona-select { width: auto; min-width: 9rem; padding: .35rem .6rem; font-size: .82rem; }
.mesas-croquis-hint { color: var(--text-soft); font-size: .78rem; }

/* Plano + inspector */
/* El croquis manda en la pantalla: el lienzo se lleva todo el alto disponible y
   el inspector FLOTA encima en una esquina, en vez de robarle una columna. Con
   una columna fija el plano se quedaba en media pantalla y el salón no se veía. */
.mesas-croquis {
  position: relative;
  height: calc(100vh - 300px);
  min-height: 460px;
}

/* La cuadrícula. El patrón de fondo ES la retícula: no hay un elemento por
   casilla, así que mover una mesa no repinta cientos de nodos. */
/* El VIEWPORT es la ventana: se queda dentro del panel y hace el scroll. El
   lienzo de dentro mide lo que mide el plano en píxeles. Antes el lienzo hacía
   las dos cosas y por eso se salía del recuadro del dashboard en vez de
   desplazarse dentro de él.
   `margin: auto` sobre el lienzo lo CENTRA cuando cabe y no recorta cuando no
   cabe, que es lo que sí pasa con justify-content: center. */
.mesas-viewport {
  position: relative;
  display: flex;
  width: 100%;
  height: 100%;
  max-width: 100%;
  overflow: auto;
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-md);
  background: var(--glass-bg);
}
.mesas-viewport.is-paneando { cursor: grab; }
.mesas-viewport.is-paneando .croquis-mesa,
.mesas-viewport.is-paneando .croquis-zona { pointer-events: none; }
.mesas-viewport.is-agarrando { cursor: grabbing; }

.mesas-canvas {
  position: relative;
  flex: none;
  margin: auto;
  background-color: var(--glass-bg);
  background-image:
    linear-gradient(to right, var(--glass-border) 1px, transparent 1px),
    linear-gradient(to bottom, var(--glass-border) 1px, transparent 1px);
  touch-action: none;   /* el arrastre con el dedo lo maneja el JS, no el scroll */
}

/* Mesas y zonas comparten posicionamiento absoluto sobre la cuadrícula */
.croquis-mesa,
.croquis-zona {
  position: absolute;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: .1rem;
  cursor: grab;
  -webkit-user-select: none;
  user-select: none;
  overflow: hidden;
  text-align: center;
  transition: border-color .15s var(--ease), box-shadow .15s var(--ease);
}
.croquis-mesa.is-dragging,
.croquis-zona.is-dragging { cursor: grabbing; opacity: .8; z-index: 5; }

.croquis-mesa {
  overflow: visible;
  border: 1.5px solid var(--accent);
  border-radius: var(--radius-sm);
  background: var(--glass-bg-strong);
  color: var(--text);
  padding: .2rem;
}
/* El texto de una caja del plano SE ENVUELVE y su tamaño lo pone el JS según
   mida la caja (ver tamTexto). Antes iba en una línea con puntos suspensivos y
   al alejarse quedaba "Gonzal…", ilegible justo cuando hace falta ver el plano
   entero. Envolver además aprovecha las cajas altas y estrechas. */
.croquis-mesa-nombre,
.croquis-mesa-familias,
.croquis-zona-txt {
  max-width: 100%;
  overflow: hidden;
  white-space: normal;
  overflow-wrap: anywhere;
  line-height: 1.05;
  text-align: center;
}
.croquis-mesa-cuenta {
  color: var(--text-soft);
  line-height: 1.05;
  white-space: nowrap;
}
.croquis-mesa.is-empty { border-style: dashed; }
.croquis-mesa.is-full { background: var(--accent-soft); }
.croquis-mesa.is-selected,
.croquis-zona.is-selected {
  box-shadow: 0 0 0 2px var(--accent), var(--glass-shadow);
  z-index: 4;
}

/* Zonas: más apagadas que las mesas, porque son el decorado del plano y no
   deben competir visualmente con lo que sí se manipula todo el tiempo. */
.croquis-zona {
  border: 1px dashed var(--glass-border);
  border-radius: var(--radius-sm);
  background: var(--glass-bg);
  color: var(--text-soft);
  font-size: .7rem;
  line-height: 1.15;
  padding: .15rem;
}
.croquis-zona--pista   { background: var(--zone-pista); border-style: solid; }
.croquis-zona--novios  { border-color: var(--zone-honor); border-style: solid; color: var(--text); }
.croquis-zona--entrada { border-style: solid; }
.croquis-zona--columna { border-style: solid; background: var(--zone-columna); }

/* Inspector lateral */
.mesas-inspector {
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-md);
  background: var(--glass-bg-strong);
  backdrop-filter: blur(var(--blur));
  -webkit-backdrop-filter: blur(var(--blur));
  padding: .9rem 1rem;
  box-shadow: var(--glass-shadow);
}
@media (min-width: 1000px) {
  .mesas-inspector {
    position: absolute;
    top: .7rem;
    right: .7rem;
    width: 300px;
    max-height: calc(100% - 1.4rem);
    overflow: auto;
    z-index: 6;
    transition: width .18s var(--ease), padding .18s var(--ease);
  }
  /* Minimizado: se queda una pestaña estrecha que devuelve el plano completo. */
  .mesas-inspector.is-min {
    width: 2.1rem;
    padding: .35rem .25rem;
    overflow: hidden;
  }
}
.mesas-inspector.is-min .inspector-body { display: none; }
.inspector-toggle {
  position: absolute;
  top: .35rem;
  right: .4rem;
  z-index: 2;
  appearance: none;
  border: 1px solid var(--glass-border);
  background: var(--glass-bg);
  color: var(--text-soft);
  border-radius: var(--radius-sm);
  width: 1.5rem;
  height: 1.5rem;
  line-height: 1;
  cursor: pointer;
  font-size: .85rem;
}
.inspector-toggle:hover { color: var(--text); }
.mesas-inspector.is-min .inspector-toggle { position: static; }
.inspector-body { padding-right: 1.6rem; }
.mesas-inspector.is-min .inspector-body { padding-right: 0; }
@media (max-width: 999px) {
  .mesas-croquis { height: auto; }
  .mesas-viewport { height: 62vh; }
  .mesas-inspector { margin-top: .8rem; }
}
.mesas-inspector-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: .6rem;
  margin-bottom: .6rem;
}
.mesas-inspector-sub {
  margin: .8rem 0 .35rem;
  font-size: .78rem;
  color: var(--text-soft);
}
.mesas-inspector-lista {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: .3rem;
}
/* El nombre del INVITADO es lo que se busca aquí, así que va entero en su propia
   línea y el grupo debajo, chico. Antes compartían fila y a 300 px el nombre se
   recortaba mientras el grupo se leía completo: justo al revés de lo útil. */
.mesas-inspector-lista li {
  display: grid;
  grid-template-columns: 1.4rem 1fr auto;
  grid-template-rows: auto auto;
  align-items: center;
  gap: .1rem .45rem;
  font-size: .82rem;
  padding: .3rem .4rem;
  border-radius: var(--radius-sm);
  background: var(--glass-bg-strong);
}
.mesas-inspector-lista li > .croquis-asiento-n { grid-row: 1 / span 2; }
.mesas-inspector-lista li > .dashx__iconbtn { grid-row: 1 / span 2; }
.mesas-inspector-lista li > .croquis-asiento-nombre { grid-column: 2; }
.mesas-inspector-lista li > .dash__row-meta {
  grid-column: 2;
  font-size: .68rem;
  opacity: .8;
}
.croquis-asiento-n {
  flex: none;
  width: 1.4rem;
  height: 1.4rem;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--accent-soft);
  font-size: .7rem;
}
.croquis-asiento-nombre {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.mesas-inspector-actions {
  display: flex;
  flex-wrap: wrap;
  gap: .4rem;
  margin-top: .7rem;
}
.mesas-inspector-actions .btn { font-size: .75rem; padding: .3rem .7rem; }

/* --- Controles del croquis: zoom y tamaño de la cuadrícula ---------------- */
.croquis-ctrl {
  display: inline-flex;
  align-items: center;
  gap: .25rem;
  padding: .12rem .3rem;
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-sm);
  background: var(--glass-bg);
}
.croquis-ctrl-lbl {
  font-size: .72rem;
  color: var(--text-soft);
  min-width: 2.6rem;
  text-align: center;
}
.croquis-ctrl-btn {
  padding: .1rem .45rem;
  font-size: .85rem;
  line-height: 1.3;
  min-width: 1.7rem;
}

/* Iconos de mesa y zona: identifican el bloque sin depender de la etiqueta,
   que en una zona chica se recorta. Se apagan un poco para no competir con el
   nombre de la mesa, que es lo que de verdad se lee. */
.croquis-ico {
  line-height: 1;
  opacity: .85;
}


/* El muro delimita la forma del salón: sólido, sin relleno de zona y sin el
   icono compitiendo, porque suele quedar de una sola casilla de grueso. */
/* El muro es la pared del salón: sólido y opaco, sin icono ni texto (el JS ya no
   los dibuja para este tipo). Antes iba translúcido y con emoji dentro, y a una
   casilla de grueso se leía como un borrón en vez de como una pared. */
.croquis-zona--muro {
  border: none;
  background: var(--zone-muro);
  opacity: .9;
  border-radius: 1px;
}

/* --- Puntos de asiento y tirador de redimensionar ------------------------- */

/* Un punto por lugar, repartido en los cuatro lados igual que en la mesa real
   (12 lugares = 3 por lado). Lleno = alguien sentado. Dice de un vistazo cuánto
   le falta a cada mesa sin leer el contador. */
.croquis-pip {
  position: absolute;
  width: 6px;
  height: 6px;
  margin: -3px 0 0 -3px;
  border-radius: 50%;
  background: var(--glass-bg);
  border: 1px solid var(--accent);
  pointer-events: none;
}
.croquis-pip.is-taken { background: var(--accent); }

/* Tirador de la esquina: sólo aparece en lo seleccionado. Es deliberadamente
   más grande que su marca visual, para poder agarrarlo con el dedo en tablet. */
.croquis-handle {
  position: absolute;
  width: 16px;
  height: 16px;
  margin: -8px 0 0 -8px;
  border-radius: 50%;
  background: var(--accent);
  border: 2px solid var(--glass-bg-strong);
  touch-action: none;
  z-index: 7;
}
.croquis-handle--nw { left: 0;    top: 0;    cursor: nwse-resize; }
.croquis-handle--n  { left: 50%;  top: 0;    cursor: ns-resize; }
.croquis-handle--ne { left: 100%; top: 0;    cursor: nesw-resize; }
.croquis-handle--e  { left: 100%; top: 50%;  cursor: ew-resize; }
.croquis-handle--se { left: 100%; top: 100%; cursor: nwse-resize; }
.croquis-handle--s  { left: 50%;  top: 100%; cursor: ns-resize; }
.croquis-handle--sw { left: 0;    top: 100%; cursor: nesw-resize; }
.croquis-handle--w  { left: 0;    top: 50%;  cursor: ew-resize; }
.croquis-zona.is-resizing { opacity: .85; z-index: 6; }

/* --- Formas de mesa, color por ocupación y modo trazado ------------------- */

/* Color por OCUPACIÓN. Es la señal que más se mira al acomodar: dónde queda
   hueco. Vacía apagada, a medias ámbar, llena verde. */
.croquis-mesa.is-empty   { border-style: dashed; opacity: .75; }
/* El rgba va primero como respaldo: si el navegador no entiende color-mix
   simplemente ignora la segunda línea y el color de estado se conserva. */
.croquis-mesa.is-partial { border-color: var(--table-partial); background: var(--table-partial-soft); }
.croquis-mesa.is-full    { border-color: var(--table-full); background: var(--table-full-soft); }
.croquis-mesa.is-partial .croquis-pip { border-color: var(--table-partial); }
.croquis-mesa.is-partial .croquis-pip.is-taken { background: var(--table-partial); }
.croquis-mesa.is-full .croquis-pip { border-color: var(--table-full); }
.croquis-mesa.is-full .croquis-pip.is-taken { background: var(--table-full); }

/* Formas. Redonda y de honor sólo cambian el contorno; el tamaño ya lo decide
   mesaDims() en el JS y su gemela del servidor. */
.croquis-mesa--redonda { border-radius: 50%; }
.croquis-mesa--novios  { border-width: 2px; border-radius: var(--radius-md); }
.croquis-mesa--novios::after {
  content: "👑";
  position: absolute;
  top: 2px; right: 3px;
  font-size: .62rem;
  opacity: .9;
}
.croquis-mesa--imperial { border-radius: var(--radius-sm); }


/* Modo "trazar muro": la cruz avisa de que el lienzo ya no selecciona, marca. */
.mesas-canvas.is-trazando { cursor: crosshair; }
.mesas-canvas.is-trazando .croquis-mesa,
.mesas-canvas.is-trazando .croquis-zona { pointer-events: none; }

/* Rejilla tipo papel milimétrico: línea tenue en cada casilla y una más marcada
   cada 5, para alinear sin ir contando cuadros. El tamaño del bloque de 5 lo
   pone el JS junto con el de la casilla. */
.mesas-canvas {
  background-image:
    linear-gradient(to right, var(--accent-soft) 1px, transparent 1px),
    linear-gradient(to bottom, var(--accent-soft) 1px, transparent 1px),
    linear-gradient(to right, var(--glass-border) 1px, transparent 1px),
    linear-gradient(to bottom, var(--glass-border) 1px, transparent 1px);
}

/* Pantalla completa. La API del navegador pinta el fondo del elemento en negro
   por defecto, así que hay que devolverle el color y el alto. */
#mesas-pane-croquis:fullscreen,
#mesas-pane-croquis:-webkit-full-screen,
#mesas-pane-croquis.is-maximizado {
  background: var(--bg-base);
  padding: 1rem;
  overflow: auto;
}
#mesas-pane-croquis:fullscreen .mesas-croquis,
#mesas-pane-croquis.is-maximizado .mesas-croquis {
  height: calc(100vh - 120px);
}

/* Fuera de pantalla completa el panel del dashboard es el que manda: el croquis
   no puede pasarse de su ancho, o el lienzo se sale del recuadro. */
.mesas-pane { max-width: 100%; overflow: hidden; }
.mesas-croquis { max-width: 100%; }

/* --- Selección múltiple, aviso propio y menú lateral -----------------------
   El aviso vive DENTRO del panel del croquis a propósito: alert() y confirm()
   cierran la pantalla completa, que es el modo en el que se trabaja el plano. */
.croquis-aviso {
  position: absolute;
  top: .7rem;
  left: 50%;
  transform: translateX(-50%);
  z-index: 9;
  margin: 0;
  padding: .45rem .9rem;
  border-radius: var(--radius-sm);
  border: 1px solid var(--accent);
  background: var(--glass-bg-strong);
  backdrop-filter: blur(var(--blur));
  -webkit-backdrop-filter: blur(var(--blur));
  font-size: .82rem;
  box-shadow: var(--glass-shadow);
}
.croquis-aviso.is-error { border-color: var(--door-invalid); }

/* Marco de selección por arrastre sobre el plano vacío */
.croquis-marco {
  position: absolute;
  border: 1px dashed var(--accent);
  background: var(--accent-soft);
  opacity: .5;
  pointer-events: none;
  z-index: 8;
}

/* Chips del inspector: tipo de zona y forma de mesa */
.mesas-inspector-chips {
  display: flex;
  flex-wrap: wrap;
  gap: .3rem;
  margin-bottom: .2rem;
}
.chip {
  appearance: none;
  font: inherit;
  font-size: .72rem;
  padding: .22rem .55rem;
  border-radius: 999px;
  border: 1px solid var(--glass-border);
  background: var(--glass-bg);
  color: var(--text-soft);
  cursor: pointer;
  transition: border-color .15s var(--ease), color .15s var(--ease), background .15s var(--ease);
}
.chip:hover { color: var(--text); }
.chip.is-on {
  border-color: var(--accent);
  background: var(--accent-soft);
  color: var(--text);
}

.mesas-inspector-row {
  display: flex;
  gap: .35rem;
  align-items: center;
}
.mesas-inspector-row .config__input { flex: 1; min-width: 0; padding: .3rem .55rem; font-size: .8rem; }
.mesas-inspector-row .btn { flex: none; font-size: .74rem; padding: .3rem .65rem; }

.mesas-inspector-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: .35rem;
}
.mesas-num { display: flex; flex-direction: column; gap: .15rem; }
.mesas-num span { font-size: .68rem; color: var(--text-soft); }
.mesas-num .config__input { padding: .28rem .45rem; font-size: .8rem; }

.mesas-inspector-tip {
  margin: .5rem 0 0;
  font-size: .7rem;
  line-height: 1.35;
  color: var(--text-soft);
}

/* --- Asistencia al trazar muros ------------------------------------------
   Antes había que dar dos clics a ciegas: nada indicaba en qué casilla iba a
   caer la esquina ni qué muro saldría. Ahora hay guías, vista previa y una
   banda que recuerda cómo salir (importante en pantalla completa). */
/* `hidden` no basta cuando la regla trae su propio `display`: la banda salía
   vacía y flotando aunque estuviera oculta. */
.croquis-modo[hidden] { display: none; }
.croquis-modo {
  position: absolute;
  top: .7rem;
  left: 50%;
  transform: translateX(-50%);
  z-index: 10;
  margin: 0;
  display: flex;
  align-items: center;
  gap: .6rem;
  padding: .4rem .5rem .4rem .9rem;
  border-radius: 999px;
  border: 1px solid var(--accent);
  background: var(--glass-bg-strong);
  backdrop-filter: blur(var(--blur));
  -webkit-backdrop-filter: blur(var(--blur));
  font-size: .78rem;
  color: var(--text);
  box-shadow: var(--glass-shadow);
  white-space: nowrap;
}
.croquis-modo kbd {
  font: inherit;
  font-size: .72rem;
  padding: .05rem .3rem;
  border: 1px solid var(--glass-border);
  border-radius: 4px;
  background: var(--glass-bg);
}
.croquis-modo-salir { font-size: .72rem; padding: .18rem .6rem; }

/* Guías de cruz: marcan la fila y la columna de la casilla apuntada. */
.croquis-guia {
  position: absolute;
  background: var(--accent-soft);
  pointer-events: none;
  z-index: 3;
}
.croquis-guia--v { top: 0; bottom: 0; }
.croquis-guia--h { left: 0; right: 0; }

/* Vista previa del muro: lo que se ve es exactamente lo que se va a crear. */
.croquis-muro-preview {
  position: absolute;
  background: var(--zone-muro);
  opacity: .55;
  outline: 1px solid var(--accent);
  pointer-events: none;
  z-index: 8;
}

/* =============================================================================
   14. GLASS NEUMORPH — la receta del mockup (data/Mockup_1, sección 4)
   -----------------------------------------------------------------------------
   No es neumorfismo puro: es un HÍBRIDO de tres materiales sobre el mármol.

     1. VIDRIO   → tarjetas grandes. Translúcido, deja ver el mármol detrás.
                   Borde blanco de 1px + filo de luz interior arriba.
     2. RELIEVE  → píldoras, casillas, círculos. Doble sombra EXTERIOR.
     3. HUNDIDO  → campos, mapas, fotos, calendario. Doble sombra INTERIOR.

   El oro (--accent-2) cose el conjunto: filetes separadores, aros de las fotos
   y acentos. Es lo que distingue este estilo del glassmorphism anterior.

   ALCANCE: global (invitación, panel y páginas de invitados). Las recetas están
   en los TOKENS de la sección 1, así que las ~50 reglas que ya consumían
   var(--glass-*) heredan el material nuevo sin tocarlas.
   ============================================================================= */

/* -----------------------------------------------------------------------------
   14.1 VIDRIO — el filo de luz sustituye al degradado de borde anterior
   -------------------------------------------------------------------------- */
.glass {
  -webkit-backdrop-filter: blur(26px) saturate(160%);
          backdrop-filter: blur(26px) saturate(160%);
}
/* El antiguo ::before dibujaba un marco degradado; el mockup usa un filo de luz
   recto en el canto superior, que ya viaja dentro de --glass-shadow. */
.glass::before { display: none; }

@media (hover: hover) {
  .card.glass:hover {
    transform: translateY(-3px);
    box-shadow: 0 32px 66px rgba(52,72,32,.28), inset 0 1px 0 rgba(255,255,255,.92);
  }
  body.theme-dark .card.glass:hover {
    box-shadow: 0 32px 66px rgba(0,0,0,.58), inset 0 1px 0 rgba(255,255,255,.10);
  }
}

/* -----------------------------------------------------------------------------
   14.2 FILETE DORADO — el separador del mockup
   Se usa como elemento (.rule) y como borde inferior heredado.
   -------------------------------------------------------------------------- */
.rule,
.rule--gold {
  height: 1px; border: 0; margin: 1rem 0;
  background: linear-gradient(90deg, transparent, var(--accent-2), transparent);
  opacity: .85;
}
/* Variante alineada a la izquierda (listas del itinerario). */
.rule--left {
  background: linear-gradient(90deg, var(--accent-2), transparent);
  opacity: .55;
}

/* -----------------------------------------------------------------------------
   14.3 RELIEVE — botones y píldoras
   -------------------------------------------------------------------------- */
.btn {
  background: var(--glass-bg-strong);
  color: var(--text);
  border: 1px solid var(--glass-border);
  box-shadow: var(--soft-raised-sm);
}
@media (hover: hover) {
  .btn:hover { box-shadow: var(--soft-raised); }
}
.btn:active { box-shadow: var(--soft-inset-sm); }

.btn--primary {
  background: var(--btn-grad);
  color: var(--on-accent);
  border-color: rgba(255,255,255,.30);
  box-shadow: var(--btn-shadow);
}
@media (hover: hover) {
  .btn--primary:hover {
    transform: translateY(-2px);
    box-shadow: 0 18px 34px rgba(48,74,22,.46), inset 0 1px 0 rgba(255,255,255,.40);
  }
}
.btn--primary:active { transform: none; box-shadow: var(--soft-inset-sm); }

.btn:disabled,
.btn[aria-disabled="true"] {
  box-shadow: var(--soft-inset-sm);
  color: var(--text-soft);
  transform: none;
}

/* -----------------------------------------------------------------------------
   14.4 HUNDIDO — campos de formulario
   -------------------------------------------------------------------------- */
.field input,
.field select,
.field textarea {
  background: var(--well-bg);
  border: 1px solid var(--glass-border);
  border-radius: 16px;
  box-shadow: var(--soft-inset-sm);
}
.field input:focus,
.field select:focus,
.field textarea:focus {
  border-color: var(--accent-2);
  box-shadow: var(--soft-inset-sm), 0 0 0 2px var(--accent-2-soft);
}
/* Etiquetas en versalitas espaciadas, como el mockup. */
.field label,
.field__label {
  font-size: .72rem;
  letter-spacing: .24em;
  text-transform: uppercase;
  color: var(--text-soft);
}
.field .opt { letter-spacing: .06em; }

/* Píldoras de opción: salientes en reposo, gradiente verde al elegirlas. */
.radio-pill span {
  background: var(--glass-bg-strong);
  border: 1px solid var(--glass-border);
  box-shadow: var(--soft-raised-sm);
}
.radio-pill input:checked + span {
  background: var(--btn-grad);
  color: var(--on-accent);
  border-color: rgba(255,255,255,.30);
  box-shadow: var(--btn-shadow);
}

/* -----------------------------------------------------------------------------
   14.5 ÍCONOS
   Trazo fino que hereda el color del contexto (`currentColor`), así el mismo
   símbolo sirve en verde sobre la tarjeta y en dorado dentro de un aro.
   -------------------------------------------------------------------------- */
.ico {
  width: 1.15em; height: 1.15em;
  flex: none;
  vertical-align: -.2em;
  color: inherit;
}

/* Círculo con relieve que envuelve al ícono — el patrón del mockup.
   OJO: .timeline__dot NO entra aquí. Va `position: absolute` con 30px exactos,
   calzado con la línea vertical del itinerario; cambiarle el tamaño lo descuadra.
   Se le da el relieve por separado, más abajo. */
.icon-badge,
.venue__icon,
.gift__icon {
  display: inline-flex; align-items: center; justify-content: center;
  flex: none;
  width: 2.9rem; height: 2.9rem;
  border-radius: 50%;
  font-size: 1.05rem;
  color: var(--accent);
  background: var(--glass-bg-strong);
  border: 1px solid var(--glass-border);
  box-shadow: var(--soft-raised-sm);
}
/* Dentro del aro, el ícono va en oro: es el acento que cose la invitación. */
.timeline__dot .ico,
.venue__icon .ico,
.gift__icon .ico { color: var(--accent-2); }

/* La tarjeta de sede es de texto centrado: el aro tiene que acompañar.
   `inline-flex` no se centra con margin auto, por eso pasa a `flex`. */
.venue__icon {
  display: flex;
  margin: 0 auto 1rem;
}

/* Botón de calendario: ícono + texto alineados. */
.addcal__btn {
  display: inline-flex; align-items: center; gap: .6rem;
}
.addcal__btn .ico { color: var(--accent-2); }

/* -----------------------------------------------------------------------------
   14.6 MAPAS — marco hundido dentro de la tarjeta de cada sede
   -------------------------------------------------------------------------- */
.map {
  border-radius: var(--radius-md);
  overflow: hidden;
  background: var(--well-bg);
  border: 1px solid var(--glass-border);
  box-shadow: var(--soft-inset);
}
.map iframe { display: block; border: 0; width: 100%; }

/* -----------------------------------------------------------------------------
   14.7 ITINERARIO
   El mockup separa los pasos con filetes dorados, no con una línea vertical
   continua. Se apaga la línea y se pone un filete entre pasos.
   -------------------------------------------------------------------------- */
.timeline::before { display: none; }

.timeline__dot {
  color: var(--accent);
  box-shadow: var(--soft-raised-sm);
}

.timeline__item + .timeline__item { padding-top: 1.6rem; }
.timeline__item + .timeline__item::before {
  content: "";
  position: absolute; left: 0; right: 0; top: 0;
  height: 1px;
  background: linear-gradient(90deg, var(--accent-2), transparent);
  opacity: .45;
}
/* El punto va `absolute` respecto al item: con el padding nuevo hay que bajarlo
   o quedaría montado sobre el filete. */
.timeline__item + .timeline__item .timeline__dot { top: calc(1.6rem + 2px); }

/* -----------------------------------------------------------------------------
   14.8 MINI-CALENDARIO Y CASILLAS DE LA CUENTA REGRESIVA
   -------------------------------------------------------------------------- */
.minical {
  background: var(--well-bg);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-md);
  box-shadow: var(--soft-inset-sm);
  padding: 1rem .9rem;
}
.countdown__unit {
  background: var(--glass-bg-strong);
  border: 1px solid var(--glass-border);
  box-shadow: var(--soft-raised-sm);
}

/* -----------------------------------------------------------------------------
   14.9 PADRINOS — marco circular hundido con aro dorado
   Sin foto muestra la inicial del rol (data-initial, lo calcula roleInitial()
   en js/main.js). Con foto, la inicial desaparece sola.
   -------------------------------------------------------------------------- */
.godparent__photo {
  background: var(--well-bg);
  border: 1px solid var(--glass-border);
  /* Hundido + aro dorado fino por dentro: el marco del mockup. */
  box-shadow: var(--soft-inset-sm), inset 0 0 0 2px var(--accent-2-soft);
}
.godparent__photo::after {
  content: attr(data-initial);
  font-family: var(--font-serif);
  font-size: 2.1rem;
  font-weight: 500;
  line-height: 1;
  color: var(--accent-2);
  opacity: .75;
}
.godparent__photo.has-photo {
  /* Con foto el hundido taparía la imagen: queda sólo el aro dorado. */
  box-shadow: inset 0 0 0 2px var(--accent-2-soft), var(--soft-raised-sm);
}
.godparent__photo.has-photo::after { content: none; }

/* Los roles miden distinto ("de Vals" vs "de la Zapatilla"): unos ocupan una
   línea y otros dos, y sin esto los nombres de cada columna quedan a distinta
   altura. Se reserva el alto de dos líneas para que la fila case. */
.godparent__role {
  color: var(--text-soft);
  letter-spacing: .22em;
  min-height: 2.7em;
  display: flex; align-items: center; justify-content: center;
}

/* -----------------------------------------------------------------------------
   14.10 PADRES — foto y, debajo, una placa ENCIMADA
   -------------------------------------------------------------------------- */
.parents {
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: 2.5rem 1.5rem; margin-top: 2rem;
}
.parents__figure {
  flex: 1 1 min(100%, 340px);
  max-width: 420px;
  display: flex; flex-direction: column; align-items: center;
}
.parents__photo {
  width: 100%; aspect-ratio: 4 / 3;
  border-radius: var(--radius-lg);
  background: var(--well-bg);
  background-size: cover; background-position: center; background-repeat: no-repeat;
  border: 1px solid var(--glass-border);
  box-shadow: var(--soft-inset), inset 0 0 0 2px var(--accent-2-soft);
  display: grid; place-items: center;
}
.parents__photo::after {
  content: attr(data-initial);
  font-family: var(--font-serif); font-size: 3rem; line-height: 1;
  color: var(--accent-2); opacity: .55;
}
.parents__photo.has-photo {
  box-shadow: inset 0 0 0 2px var(--accent-2-soft), var(--glass-shadow);
}
.parents__photo.has-photo::after { content: none; }

/* La placa "muerde" la foto: es lo que da el efecto de encimado. */
.parents__plate {
  position: relative;
  margin-top: -2.6rem;
  width: min(100% - 2.5rem, 300px);
  padding: 1.1rem 1.4rem 1.2rem;
  border-radius: var(--radius-md);
  text-align: center;
}
.parents__role {
  font-size: .68rem; letter-spacing: .26em; text-transform: uppercase;
  color: var(--text-soft); margin-bottom: .45rem;
}
.parents__names {
  font-family: var(--font-serif); font-size: 1.3rem; line-height: 1.35;
  color: var(--text);
}
/* Filete dorado bajo el rol, como el mockup. */
.parents__role::after {
  content: ""; display: block; height: 1px; margin: .5rem auto 0; width: 60%;
  background: linear-gradient(90deg, transparent, var(--accent-2), transparent);
}

/* -----------------------------------------------------------------------------
   14.11 RSVP
   Mismo formulario y misma lógica; sólo cambia el material. Los campos de
   asistentes y canciones no son `.field input`, así que necesitan la receta
   hundida por separado.
   -------------------------------------------------------------------------- */
.attendee__input,
.song__input,
.group-names__input {
  border-radius: 16px;
  background: var(--well-bg);
  border: 1px solid var(--glass-border);
  box-shadow: var(--soft-inset-sm);
}
.attendee__input:focus,
.song__input:focus,
.group-names__input:focus {
  outline: none;
  border-color: var(--accent-2);
  box-shadow: var(--soft-inset-sm), 0 0 0 2px var(--accent-2-soft);
}

/* Controles pequeños: relieve. */
.attendee__remove,
.attendees__add,
.rsvp-help-toggle {
  background: var(--glass-bg-strong);
  border: 1px solid var(--glass-border);
  box-shadow: var(--soft-raised-sm);
}
.rsvp-help-toggle__icon { color: var(--accent-2); }
.rsvp-help-toggle.is-open { box-shadow: var(--soft-inset-sm); }

/* El panel de instrucciones va hundido: es contenido, no un control. */
.rsvp-help {
  background: var(--well-bg);
  border: 1px solid var(--glass-border);
  box-shadow: var(--soft-inset-sm);
}

/* Fecha límite en oro, como la línea "Antes del…" del mockup. */
.rsvp__deadline strong { color: var(--accent-2); }

/* Encabezado de asistentes/canciones: mismas versalitas que las etiquetas. */
.attendees__remaining { color: var(--text-soft); font-size: .78rem; letter-spacing: .1em; }

/* La marca de confirmación reutiliza el gradiente del botón principal. */
.rsvp-success__mark {
  background: var(--btn-grad);
  color: var(--on-accent);
  box-shadow: var(--btn-shadow);
}

/* -----------------------------------------------------------------------------
   14.12 PANEL DEL ORGANIZADOR
   Hereda los tres materiales por los tokens; aquí sólo se ajusta lo que en una
   consola necesita otra intención que en la invitación.
   -------------------------------------------------------------------------- */
/* El panel es dato denso: el desenfoque de la invitación (26px) lo enturbia y
   cuesta rendimiento en la barra lateral, que va fija. */
.dash-app .glass,
.dashx__sidebar,
.dashx__topbar {
  -webkit-backdrop-filter: blur(14px) saturate(140%);
          backdrop-filter: blur(14px) saturate(140%);
}
/* Las tarjetas del panel no "flotan" al pasar el ratón: son superficies de
   lectura, no elementos con los que se juega. */
@media (hover: hover) {
  .dash-app .card.glass:hover { transform: none; box-shadow: var(--glass-shadow); }
}
.dashx__navitem.is-active {
  border-color: var(--accent-2);
  box-shadow: var(--soft-raised-sm);
}
.dash__metric,
.metric {
  background: var(--glass-bg-strong);
  border: 1px solid var(--glass-border);
  box-shadow: var(--soft-raised-sm);
}
.dashx__iconbtn {
  background: var(--glass-bg-strong);
  border: 1px solid var(--glass-border);
  box-shadow: var(--soft-raised-sm);
}

/* =============================================================================
   15. AJUSTES SOBRE EL MOCKUP (revisión)
   ============================================================================= */

/* -----------------------------------------------------------------------------
   15.1 PORTADA — tres planos que se tienen que leer
   mármol (fondo) → foto EMBUTIDA → tarjeta SALIENTE.
   -------------------------------------------------------------------------- */
.section--hero {
  /* Más aire para que el mármol se vea alrededor del pozo de la foto. */
  padding: clamp(3.5rem, 9vw, 5rem) 0;
}
.hero__photo {
  inset: clamp(1.5rem, 6vw, 4rem);
  border-radius: var(--radius-lg);
  overflow: hidden;
  z-index: 0;
  /* Hundido marcado + aro dorado: es un pozo excavado en el mármol. */
  box-shadow:
    var(--soft-inset),
    inset 0 0 0 2px var(--accent-2-soft),
    0 2px 3px rgba(255,255,255,.45);
}
.hero__photo::after { border-radius: inherit; }

.hero__panel {
  position: relative;
  z-index: 1;
  /* Relieve más alto que el resto de tarjetas: es el primer plano. */
  box-shadow:
    0 34px 70px rgba(52,72,32,.30),
    var(--soft-raised),
    inset 0 1px 0 rgba(255,255,255,.92);
}
body.theme-dark .hero__panel {
  box-shadow:
    0 34px 70px rgba(0,0,0,.60),
    var(--soft-raised),
    inset 0 1px 0 rgba(255,255,255,.12);
}
/* El indicador de scroll conserva su `position: absolute` original: dárselo a
   `relative` lo convertía en ítem flex del hero y descuadraba la tarjeta. */
.hero__scroll { z-index: 1; }

/* -----------------------------------------------------------------------------
   15.2 MI HISTORIA — retrato vertical + placa encimada (como los padres)
   -------------------------------------------------------------------------- */
.story__grid {
  display: flex; flex-direction: column; align-items: center;
  gap: 0;
}
.story__photo {
  width: min(100%, 380px);
  min-height: 0;                 /* anula el alto fijo anterior */
  aspect-ratio: 3 / 4;           /* retrato */
  border-radius: var(--radius-lg);
  background: var(--well-bg);
  background-size: cover; background-position: center;
  border: 1px solid var(--glass-border);
  box-shadow: var(--soft-inset), inset 0 0 0 2px var(--accent-2-soft);
  -webkit-backdrop-filter: none; backdrop-filter: none;
}
.story__photo::after {
  content: "❀"; position: absolute; inset: 0;
  display: grid; place-items: center;
  font-size: 2.4rem; color: var(--accent-2); opacity: .5;
}
.story__photo.has-photo {
  box-shadow: inset 0 0 0 2px var(--accent-2-soft), var(--glass-shadow);
}
.story__photo.has-photo::after { content: none; }

/* La placa muerde el retrato, igual que en padres, pero más ancha: aquí hay
   dos párrafos, no un rótulo. */
.story__plate {
  position: relative;
  margin-top: -3rem;
  width: min(100% - 1.5rem, 560px);
  padding: 1.6rem clamp(1.3rem, 5vw, 2.2rem) 1.8rem;
  border-radius: var(--radius-md);
  text-align: center;
}
.story__plate .section__title { margin-bottom: .2rem; }
.story__plate .section__index { margin-bottom: .6rem; }
.story__plate .section__index::after {
  content: ""; display: block; height: 1px; margin: .7rem auto 0; width: 55%;
  background: linear-gradient(90deg, transparent, var(--accent-2), transparent);
}
#story-paragraphs { margin-top: 1rem; text-align: left; }
#story-paragraphs p { color: var(--text-soft); }

/* -----------------------------------------------------------------------------
   15.3 ITINERARIO — el ícono, centrado vertical
   El punto iba `position: absolute` clavado arriba (top: 2px), así que en pasos
   de dos líneas quedaba desalineado. Pasa a una fila flex.
   -------------------------------------------------------------------------- */
.timeline__item {
  display: flex;
  align-items: center;          /* ← lo que centra el ícono */
  gap: 1.1rem;
  position: relative;
  padding-left: 0;
  padding-bottom: 1.4rem;
}
.timeline__item > .timeline__dot {
  position: static;             /* deja de estar clavado arriba */
  flex: none;
  width: 44px; height: 44px;
  font-size: 1rem;
}
.timeline__item > :not(.timeline__dot) { flex: 1 1 auto; min-width: 0; }
/* Los tres párrafos del paso van juntos en una columna a la derecha del ícono. */
.timeline__body { display: flex; flex-direction: column; gap: .1rem; }
.timeline__item + .timeline__item { padding-top: 1.4rem; }
.timeline__item + .timeline__item .timeline__dot { top: auto; }

/* El paso desplegable lleva ícono + botón + panel. Con la fila flex, el panel
   tiene que caer a una línea propia o quedaría comprimido a la derecha. */
.timeline__item--reveal { flex-wrap: wrap; }
.timeline__item--reveal > .timeline__reveal-btn { flex: 1 1 auto; }
.timeline__item--reveal > .timeline__reveal-panel { flex: 1 0 100%; margin-top: .9rem; }
/* El itinerario anidado dentro del panel no lleva la sangría del externo. */
.timeline--nested .timeline__item { padding-left: 0; }

/* El botón del paso desplegable venía con `width: 100%`, pensado para el layout
   anterior. Dentro de la fila flex eso lo empuja debajo del ícono. */
.timeline__item--reveal > .timeline__reveal-btn { width: auto; flex: 1 1 auto; }

/* El pozo del retrato se leía muy plano sobre el mármol claro: se marca el
   hundido y se le da algo más de cuerpo al fondo. */
.story__photo {
  background-color: rgba(255,255,255,.34);
  box-shadow:
    var(--soft-inset),
    inset 0 0 0 2px var(--accent-2-soft),
    0 2px 3px rgba(255,255,255,.45);
}

/* -----------------------------------------------------------------------------
   15.4 GALERÍA — baraja de cuadrículas
   Cinco páginas con patrones distintos dentro de una tarjeta de vidrio. El
   desplazamiento lateral es NATIVO (scroll-snap): el dedo manda y las flechas
   sólo llaman a scrollTo, así se siente igual con gesto que con botón.
   -------------------------------------------------------------------------- */
.gallery__wrap { margin-top: 1.75rem; }
.gallery__frame {
  border-radius: var(--radius-lg);
  padding: clamp(.7rem, 2.4vw, 1.1rem);
}
.gallery__pages {
  /* Casi el alto de la pantalla, pero NO todo: con la barra de puntos debajo el
     conjunto queda en ~90 vh y los puntos siguen a la vista en móvil. */
  height: min(76vh, 660px);
  display: flex;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none; -ms-overflow-style: none;
  border-radius: var(--radius-md);
}
.gallery__pages::-webkit-scrollbar { display: none; }
.gallery__pages:focus-visible { outline: 2px solid var(--accent-2); outline-offset: 3px; }

.gallery__page {
  flex: 0 0 100%;
  scroll-snap-align: center;
  scroll-snap-stop: always;
  display: grid;
  gap: clamp(.5rem, 2vw, .8rem);
  height: 100%;
}

/* --- Los cinco patrones ---------------------------------------------------
   Cada uno reparte los mismos huecos de otra forma, para que pasar de una
   cuadrícula a la siguiente se note como un cambio de composición y no como
   más de lo mismo. */

/* p1 · una grande a la izquierda + dos apiladas a la derecha */
.gallery__page--p1 {
  grid-template-columns: 1.35fr 1fr;
  grid-template-rows: 1fr 1fr;
}
.gallery__page--p1 > :nth-child(1) { grid-row: 1 / span 2; }

/* p2 · dos y dos */
.gallery__page--p2 {
  grid-template-columns: 1fr 1fr;
  grid-template-rows: 1fr 1fr;
}

/* p3 · una vertical a la izquierda + tres apiladas */
.gallery__page--p3 {
  grid-template-columns: 1fr 1fr;
  grid-template-rows: repeat(3, 1fr);
}
.gallery__page--p3 > :nth-child(1) { grid-row: 1 / span 3; }

/* p4 · mosaico 3x2 */
.gallery__page--p4 {
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: 1fr 1fr;
}

/* p5 · una panorámica arriba + dos abajo */
.gallery__page--p5 {
  grid-template-columns: 1fr 1fr;
  grid-template-rows: 1.3fr 1fr;
}
.gallery__page--p5 > :nth-child(1) { grid-column: 1 / span 2; }

/* --- Los huecos ----------------------------------------------------------- */
.gallery__tile {
  width: auto; height: auto;          /* el grid manda, no el tamaño fijo viejo */
  aspect-ratio: auto;
  border-radius: var(--radius-md);
  background: var(--well-bg);
  background-size: cover; background-position: center;
  border: 1px solid var(--glass-border);
  box-shadow: var(--soft-inset), inset 0 0 0 2px var(--accent-2-soft);
  display: grid; place-items: center;
  padding: 0; overflow: hidden;
  transition: box-shadow .3s var(--ease), transform .3s var(--ease);
}
.gallery__tile.has-photo {
  cursor: zoom-in;
  box-shadow: inset 0 0 0 2px var(--accent-2-soft), var(--soft-raised-sm);
}
@media (hover: hover) {
  .gallery__tile.has-photo:hover { transform: scale(1.015); box-shadow: var(--soft-raised); }
}
.gallery__tile--placeholder { cursor: default; }
.gallery__tile--placeholder .ico {
  width: 1.9rem; height: 1.9rem;
  color: var(--accent-2); opacity: .45;
}

/* --- Navegación: flechas + puntos ----------------------------------------- */
/* Barra separada del marco, como en el mockup: es su propia píldora. */
.gallery__nav {
  display: flex; align-items: center; justify-content: space-between;
  gap: 1rem;
  width: fit-content; margin: clamp(.9rem, 3vw, 1.3rem) auto 0;
  padding: .5rem .7rem;
  border-radius: 999px;
}
.gallery__arrow {
  flex: none;
  width: 2.6rem; height: 2.6rem; border-radius: 50%;
  display: grid; place-items: center; cursor: pointer;
  color: var(--accent);
  background: var(--glass-bg-strong);
  border: 1px solid var(--glass-border);
  box-shadow: var(--soft-raised-sm);
  transition: box-shadow .2s var(--ease), color .2s var(--ease);
}
.gallery__arrow:hover { color: var(--accent-2); box-shadow: var(--soft-raised); }
.gallery__arrow:active { box-shadow: var(--soft-inset-sm); }
.gallery__arrow .ico { width: 1.1rem; height: 1.1rem; }

.gallery__dots { display: flex; align-items: center; gap: .55rem; }

/* El tamaño lo decide la DISTANCIA al centro, no qué página sea: por eso al
   avanzar los puntos parecen desfilar sin principio ni fin. */
.gallery__dot {
  flex: none;
  border-radius: 50%; padding: 0; cursor: pointer;
  border: 1px solid transparent;
  background: var(--text-soft);
  opacity: .45;
  transition: width .35s var(--ease), height .35s var(--ease),
              opacity .35s var(--ease), background .35s var(--ease);
}
.gallery__dot[data-dist="2"] { width: 5px;  height: 5px; opacity: .28; }
.gallery__dot[data-dist="1"] { width: 7px;  height: 7px; opacity: .45; }
.gallery__dot[data-dist="0"] {
  width: 11px; height: 11px; opacity: 1;
  background: var(--accent-2);
  box-shadow: 0 0 0 3px var(--accent-2-soft);
}

/* La cuenta atrás: el punto siguiente crece hasta casi el tamaño del activo
   justo antes de que la galería pase de cuadrícula. */
@keyframes galleryCountdown {
  from { width: 7px;  height: 7px;  opacity: .45; background: var(--text-soft); }
  to   { width: 10px; height: 10px; opacity: .9;  background: var(--accent-2); }
}
.gallery__dot.is-counting {
  animation: galleryCountdown 6s linear forwards;
}
@media (prefers-reduced-motion: reduce) {
  .gallery__dot.is-counting { animation: none; }
  .gallery__pages { scroll-behavior: auto; }
}


.anecdotas__share { text-align: center; margin-top: 1.75rem; }
.anecdotas__share-note {
  margin-top: .8rem; font-size: .8rem; letter-spacing: .12em; text-transform: uppercase;
  color: var(--text-soft);
}

/* =============================================================================
   16. SEGUNDA REVISIÓN
   ============================================================================= */

/* -----------------------------------------------------------------------------
   16.1 PORTADA
   -------------------------------------------------------------------------- */
.section--hero {
  /* Un solo sitio donde vive la geometría del hero: el pozo de la foto y el
     ancho de la tarjeta se derivan de aquí, así no se descuadran entre sí. */
  --hero-inset-x:   clamp(1.5rem, 6vw, 4rem);
  /* Arriba hace falta más aire: los botones flotantes (46 px a 1.1 rem del
     borde) llegan a ~4 rem y el pozo quedaba por detrás de ellos. */
  --hero-inset-top: clamp(4.8rem, 11vw, 6.5rem);
}
.hero__photo {
  inset: var(--hero-inset-top) var(--hero-inset-x) var(--hero-inset-x);
}

/* El velo del modo claro tapaba la foto. Se deja casi imperceptible: la
   legibilidad ya la resuelve la tarjeta, que es opaca y va encima.
   En OSCURO no se toca — ahí el velo sí hace falta para el texto claro. */
.hero__photo::after {
  background: linear-gradient(
    to bottom,
    rgba(239, 247, 230, 0.08) 0%,
    rgba(239, 247, 230, 0.12) 55%,
    rgba(239, 247, 230, 0.09) 100%
  );
}

/* La tarjeta tiene que caber DENTRO del pozo: se calcula desde el mismo margen
   en vez de fijar un ancho suelto, que en pantallas medias se salía por los lados. */
.hero__panel {
  width: min(calc(100% - 2 * var(--hero-inset-x) - 3rem), 460px);
  padding: clamp(1.9rem, 6vw, 2.9rem) clamp(1.3rem, 5vw, 2.4rem);
}

/* ---- Indicador de scroll: rombo dorado que respira ----------------------- */
.hero__scroll {
  position: absolute; bottom: clamp(2rem, 6vw, 3rem); left: 50%;
  transform: translateX(-50%);
  width: auto; height: auto;
  border: 0; border-radius: 0; padding: 0;
  display: flex; flex-direction: column; align-items: center; gap: .45rem;
  z-index: 1;
}
.hero__scroll span {
  width: 9px; height: 9px;
  background: transparent;
  border: 1.5px solid var(--accent-2);
  border-radius: 2px;
  transform: rotate(45deg);
  animation: heroDiamond 2.6s var(--ease) infinite;
}
.hero__scroll::after {
  content: "";
  width: 1px; height: clamp(20px, 4vw, 30px);
  background: linear-gradient(var(--accent-2), transparent);
  opacity: .65;
}
/* Tras el `rotate(45deg)`, trasladar (3,3) en el espacio girado equivale a
   bajar en vertical en pantalla: el rombo desciende sin ladearse. */
@keyframes heroDiamond {
  0%, 100% { transform: rotate(45deg) translate(0, 0);     opacity: .5; }
  50%      { transform: rotate(45deg) translate(3px, 3px); opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .hero__scroll span { animation: none; opacity: .8; }
}

/* -----------------------------------------------------------------------------
   16.2 CROMO DE NAVEGACIÓN
   Los botones flotantes sólo tenían borde: sobre el mármol no se leía ningún
   relieve. Ahora llevan las dobles sombras como el resto de controles.
   -------------------------------------------------------------------------- */
.menu-toggle,
.theme-toggle,
.music-toggle {
  background: var(--glass-bg-strong);
  border: 1px solid var(--glass-border);
  box-shadow: var(--soft-raised);
}
@media (hover: hover) {
  .menu-toggle:hover,
  .theme-toggle:hover,
  .music-toggle:hover { transform: none; box-shadow: var(--soft-deep, var(--soft-raised)); }
}
.menu-toggle:active,
.theme-toggle:active,
.music-toggle:active { box-shadow: var(--soft-inset-sm); }
.theme-toggle { color: var(--accent-2); }
.menu-toggle__bars i { background: var(--accent); }

/* El velo del menú seguía con el morado de la boda (rgba(20,12,18,.35)). */
.menu-overlay {
  background: rgba(22, 34, 16, 0.40);
  -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px);
}
.menu-panel { box-shadow: var(--glass-shadow), var(--soft-raised); }
.menu-panel__title { color: var(--text-soft); letter-spacing: .26em; }
.menu-panel__title::after {
  content: ""; display: block; height: 1px; margin-top: .7rem;
  background: linear-gradient(90deg, var(--accent-2), transparent);
  opacity: .7;
}
.menu-panel a .menu-num { color: var(--accent-2); }
.menu-panel a:hover { background: var(--accent-2-soft); color: var(--text); }
.menu-panel a.is-active { color: var(--accent-2); }

/* Puntos laterales: se veían casi transparentes sobre el mármol claro. */
.side-nav a {
  background: var(--text-soft); opacity: .40;
  box-shadow: 0 1px 2px rgba(255,255,255,.5);
}
.side-nav a:hover { opacity: .75; }
.side-nav a.is-active {
  background: var(--accent-2); opacity: 1;
  box-shadow: 0 0 0 3px var(--accent-2-soft);
}
.side-nav a::after { box-shadow: var(--soft-raised-sm); }

/* -----------------------------------------------------------------------------
   16.3 MURO DE MENSAJES — cuadrícula que voltea
   Marco del mismo tamaño que la galería. Las celdas ocupan 2, 3 o 6 espacios de
   una rejilla de 6 columnas, para que el muro no parezca una tabla.

   OJO — las caras van OPACAS a propósito: un `backdrop-filter` dentro de un
   elemento con transformación 3D se rompe en Safari y cuesta caro en móvil, así
   que aquí el vidrio se cambia por una superficie sólida. El marco exterior sí
   conserva el vidrio.
   -------------------------------------------------------------------------- */
.anecdotas__frame {
  border-radius: var(--radius-lg);
  padding: clamp(.7rem, 2.4vw, 1.1rem);
  margin-top: 1.75rem;
}
.anecdotas__grid {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  grid-auto-rows: minmax(0, 1fr);
  gap: clamp(.5rem, 2vw, .8rem);
  height: min(76vh, 660px);
}
.anecdota {
  grid-column: span var(--span, 3);
  perspective: 1200px;          /* sin esto el giro se ve plano, sin volumen */
  min-height: 0;
}
@media (max-width: 620px) {
  /* En móvil, seis columnas dejan celdas ilegibles: se pasa a dos y cada celda
     usa su propio reparto (--span-sm, que fija js/main.js junto con --span). */
  .anecdotas__grid { grid-template-columns: repeat(2, 1fr); }
  .anecdota { grid-column: span var(--span-sm, 1); }
}

.anecdota__inner {
  position: relative; width: 100%; height: 100%;
  transform-style: preserve-3d;
  transition: transform .9s var(--ease);
}
.anecdota.is-flipped .anecdota__inner { transform: rotateY(180deg); }

.anecdota__face {
  position: absolute; inset: 0;
  display: flex; flex-direction: column;
  padding: clamp(.9rem, 2.6vw, 1.3rem);
  border-radius: var(--radius-md);
  background: var(--well-bg);
  border: 1px solid var(--glass-border);
  box-shadow: var(--soft-raised-sm), inset 0 0 0 1px var(--accent-2-soft);
  -webkit-backface-visibility: hidden; backface-visibility: hidden;
  overflow: hidden;
}
body.theme-light .anecdota__face { background: rgba(255,255,255,.72); }
body.theme-dark  .anecdota__face { background: rgba(26,42,30,.92); }
.anecdota__face.is-back { transform: rotateY(180deg); }

/* La comilla iba a 2.3rem con line-height .6: entre ella y la firma no dejaban
   altura al mensaje, que se encogía a cero dentro del flex. Ahora es pequeña y
   `flex: none`, para que el texto se quede con el espacio que sobra. */
.anecdota__mark {
  flex: none;
  font-family: var(--font-serif);
  font-size: clamp(1.1rem, 2.4vw, 1.5rem); line-height: 1;
  color: var(--accent-2); opacity: .5;
  margin-bottom: .35rem;
}
.anecdota__text {
  flex: 1 1 auto; min-height: 0;
  font-family: var(--font-serif); font-style: italic;
  font-size: clamp(.9rem, 2.2vw, 1.05rem); line-height: 1.45;
  color: var(--text);
  overflow: hidden;
  overflow-wrap: anywhere;      /* un invitado puede pegar una "palabra" larguísima */
  /* Recorta por líneas COMPLETAS y con puntos suspensivos: `overflow: hidden`
     a secas rebanaba la última línea por la mitad. */
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 5;
}
.anecdota__author {
  flex: none;
  margin-top: .7rem; padding-top: .6rem;
  font-size: .62rem; letter-spacing: .22em; text-transform: uppercase;
  color: var(--text-soft);
  background: linear-gradient(90deg, var(--accent-2), transparent) top left / 45% 1px no-repeat;
}
.anecdota__face.is-empty { box-shadow: var(--soft-inset-sm); }
.anecdota__face.is-empty .anecdota__mark { opacity: .25; }
.anecdota__face.is-empty .anecdota__text {
  font-style: normal; color: var(--text-soft); opacity: .8;
}

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

/* =============================================================================
   17 · LISTA DE ACOMODO — la hoja para el capitán de meseros, y el buscador
   que responde "¿dónde me toca?" en la puerta sin abrir el croquis.
   ============================================================================= */
.lista-bar { align-items: center; }
.lista-buscar { flex: 1; min-width: 12rem; max-width: 26rem; padding: .4rem .7rem; font-size: .85rem; }

.lista-content {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: .9rem;
  align-items: start;
}
.lista-hits {
  grid-column: 1 / -1;
  margin: 0;
  font-size: .78rem;
  color: var(--text-soft);
}

.lista-mesa {
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-md);
  background: var(--glass-bg);
  padding: .7rem .85rem .8rem;
  break-inside: avoid;
}
.lista-mesa--pendiente { border-style: dashed; }
.lista-mesa-head {
  display: flex;
  flex-direction: column;
  gap: .1rem;
  margin-bottom: .5rem;
  padding-bottom: .4rem;
  border-bottom: 1px solid var(--glass-border);
}
.lista-mesa-head h3 {
  margin: 0;
  font-family: var(--font-serif);
  font-size: 1rem;
  font-weight: 600;
}
.lista-mesa-meta { font-size: .72rem; color: var(--text-soft); }
.lista-grupo-titulo {
  margin: .5rem 0 .2rem;
  font-size: .72rem;
  color: var(--text-soft);
}
.lista-vacia { margin: 0; font-size: .78rem; color: var(--text-soft); }

.lista-personas { list-style: none; margin: 0; padding: 0; }
.lista-personas li {
  display: flex;
  align-items: baseline;
  gap: .45rem;
  padding: .2rem 0;
  font-size: .84rem;
  border-bottom: 1px solid transparent;
}
.lista-personas li.is-hit {
  background: var(--accent-soft);
  border-radius: var(--radius-sm);
  padding-left: .3rem;
  padding-right: .3rem;
}
.lista-nombre { flex: 1; min-width: 0; }
.lista-grupo {
  flex: none;
  max-width: 40%;
  font-size: .68rem;
  color: var(--text-soft);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* --- Impresión -----------------------------------------------------------
   Sólo se activa cuando el botón marca el body, para que imprimir desde otra
   vista del panel siga saliendo como siempre. Tinta negra sobre blanco: el
   tema oscuro del panel gastaría un cartucho por hoja. */
@media print {
  body.imprimiendo-lista .dashx__sidebar,
  body.imprimiendo-lista .dashx__topbar,
  body.imprimiendo-lista .dashx__scrim,
  body.imprimiendo-lista .bg-layer,
  body.imprimiendo-lista .dash__toolbar,
  body.imprimiendo-lista .mesas-subtabs,
  body.imprimiendo-lista .lista-bar,
  body.imprimiendo-lista #mesas-pane-croquis,
  body.imprimiendo-lista #mesas-pane-asignar,
  body.imprimiendo-lista .dashx__view:not(#view-mesas) { display: none !important; }

  body.imprimiendo-lista,
  body.imprimiendo-lista .dashx,
  body.imprimiendo-lista .dashx__main,
  body.imprimiendo-lista .dashx__content,
  body.imprimiendo-lista .dashx__panel {
    background: #fff;
    color: #000;
    margin: 0;
    padding: 0;
    box-shadow: none;
    border: none;
    display: block;
  }
  body.imprimiendo-lista .lista-content {
    grid-template-columns: repeat(2, 1fr);
    gap: .5rem;
  }
  body.imprimiendo-lista .lista-mesa {
    border: 1px solid #999;
    background: #fff;
    color: #000;
  }
  body.imprimiendo-lista .lista-mesa-meta,
  body.imprimiendo-lista .lista-grupo,
  body.imprimiendo-lista .lista-grupo-titulo { color: #444; }
  body.imprimiendo-lista .lista-personas li.is-hit { background: none; }
}

/* --- Estado de guardado del croquis --------------------------------------
   Antes cada arrastre volvía a pedir todo el acomodo y repintaba el lienzo, y
   eso se sentía como si algo fallara en cada movimiento. Ahora el cambio se ve
   al instante y la escritura va aparte; este indicador dice en qué va. */
.croquis-estado {
  font-size: .7rem;
  color: var(--text-soft);
  min-width: 5.2rem;
  text-align: center;
}
.croquis-estado.is-dirty { color: var(--table-partial); }
.croquis-estado.is-saving { color: var(--accent); }
.croquis-ctrl-btn[disabled] { opacity: .45; cursor: default; }

/* --- Boletos emitidos dentro de la fila de un grupo -----------------------
   Cada boleto se puede cancelar (archivar) para quien confirmó y luego avisó
   que no va. No se borra: se conserva para poder deshacer y para que la puerta
   pueda decir "cancelado" en vez de "no existe". */
.boleto-row {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .3rem .45rem;
  border-radius: var(--radius-sm);
  font-size: .84rem;
  border-bottom: 1px solid var(--glass-border);
}
.boleto-row:last-of-type { border-bottom: none; }
.boleto-row.is-used { opacity: .7; }
.boleto-row.is-cancelado { opacity: .6; }
.boleto-row.is-cancelado .boleto-nombre { text-decoration: line-through; }
.boleto-nombre { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.boleto-nombre.is-ph { color: var(--text-soft); font-style: italic; }
.boleto-meta { flex: none; font-size: .7rem; color: var(--text-soft); }
.boleto-btn { flex: none; font-size: .72rem; padding: .18rem .6rem; }
.boleto-btn.is-warn { border-color: var(--door-invalid); color: var(--door-invalid); }

/* El nombre de un boleto vigente se edita en línea: el invitado que no puede ir
   cede su lugar a otra persona del grupo, y el boleto (con su QR) sigue siendo
   el mismo. Parece texto hasta que se toca, para no llenar la fila de cajas. */
.boleto-input {
  appearance: none;
  font: inherit;
  font-size: .84rem;
  color: var(--text);
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  padding: .12rem .3rem;
  min-width: 0;
  transition: border-color .15s var(--ease), background .15s var(--ease);
}
.boleto-input::placeholder { color: var(--text-soft); font-style: italic; }
.boleto-input:hover { border-color: var(--glass-border); }
.boleto-input:focus {
  outline: none;
  border-color: var(--accent);
  background: var(--glass-bg-strong);
}

/* --- Confirmación manual: una fila por persona ---------------------------
   Los nombres vienen precargados del roster previsto y cada uno se quita o se
   agrega. La cantidad de asistentes ES el número de filas, así que no hay dos
   cuentas que puedan discrepar. */
.dash__confirm-form {
  padding: .9rem 1rem;
  margin-top: .5rem;
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-md);
}
.confirm-fila {
  display: flex;
  align-items: center;
  gap: .7rem;
  flex-wrap: wrap;
  margin-bottom: .7rem;
}
.confirm-acciones { margin-top: .8rem; margin-bottom: 0; }
.confirm-lbl { font-size: .82rem; color: var(--text-soft); margin: 0; }
.confirm-sub { margin: .2rem 0 .4rem; }
.confirm-radio {
  font-size: .84rem;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: .3rem;
}
.confirm-personas { display: flex; flex-direction: column; gap: .3rem; margin-bottom: .5rem; }
.confirm-persona { display: flex; align-items: center; gap: .35rem; }
.confirm-persona .config__input { flex: 1; min-width: 0; padding: .3rem .55rem; font-size: .82rem; }
.confirm-check { cursor: pointer; display: inline-flex; align-items: center; gap: .4rem; }
.confirm-hint { margin: .2rem 0 0 1.4rem; }
.dash__confirm-count { font-weight: 600; color: var(--text); }

/* Aviso de boletos pendientes de emitir dentro de la fila del grupo. */
.boleto-aviso {
  display: flex;
  align-items: center;
  gap: .6rem;
  flex-wrap: wrap;
  margin: .5rem 0;
  padding: .5rem .7rem;
  border: 1px solid var(--table-partial);
  border-radius: var(--radius-sm);
  background: var(--table-partial-soft);
  font-size: .78rem;
}


/* =============================================================================
   18 · MODO PUERTA, TARJETAS DE LUGAR Y PDF COMPLETO
   ============================================================================= */

/* --- Modo puerta ---------------------------------------------------------
   Quien recibe en la entrada lee de reojo y a metro y medio, con gente detrás
   esperando. Se esconde todo menos la cámara y el resultado, y el resultado
   crece hasta que se lea de lejos. */
.puerta-bar { display: flex; align-items: center; gap: .7rem; flex-wrap: wrap; margin-bottom: .8rem; }

body.modo-puerta .dashx__sidebar,
body.modo-puerta .dashx__topbar,
body.modo-puerta .validator__manual { display: none; }
body.modo-puerta .dashx__main { margin: 0; }
body.modo-puerta .dashx__content { padding: .5rem; }
body.modo-puerta .dashx__panel { padding: .6rem; }
body.modo-puerta .validator__reader { max-width: 40vh; margin: 0 auto; }
body.modo-puerta .validator__result { padding: 1.2rem 1rem; text-align: center; }
body.modo-puerta .validator__result-title { font-size: clamp(1.4rem, 5vw, 2.6rem); }
body.modo-puerta .validator__result-person { font-size: clamp(1.6rem, 6vw, 3.2rem); line-height: 1.1; }
body.modo-puerta .validator__result-group { font-size: clamp(.9rem, 2.4vw, 1.3rem); }
body.modo-puerta .validator__result-mesa {
  font-size: clamp(2rem, 8vw, 4.5rem);
  line-height: 1.05;
  margin-top: .4rem;
}

/* --- Tarjetas de lugar ----------------------------------------------------
   Sólo existen al imprimir: generarlas siempre metería 115 nodos en el panel
   que nadie mira en pantalla. Ocho por hoja A4. */
.tarjetas-hoja { display: none; }
@media print {
  body.imprimiendo-tarjetas .dashx__sidebar,
  body.imprimiendo-tarjetas .dashx__topbar,
  body.imprimiendo-tarjetas .bg-layer,
  body.imprimiendo-tarjetas .dash__toolbar,
  body.imprimiendo-tarjetas .mesas-subtabs,
  body.imprimiendo-tarjetas .lista-bar,
  body.imprimiendo-tarjetas .lista-content,
  body.imprimiendo-tarjetas #mesas-pane-croquis,
  body.imprimiendo-tarjetas #mesas-pane-asignar,
  body.imprimiendo-tarjetas .dashx__view:not(#view-mesas) { display: none !important; }

  body.imprimiendo-tarjetas,
  body.imprimiendo-tarjetas .dashx,
  body.imprimiendo-tarjetas .dashx__main,
  body.imprimiendo-tarjetas .dashx__content,
  body.imprimiendo-tarjetas .dashx__panel,
  body.imprimiendo-tarjetas .mesas-pane {
    background: #fff; color: #000; margin: 0; padding: 0;
    border: none; box-shadow: none; display: block;
  }
  body.imprimiendo-tarjetas .tarjetas-hoja {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 0;
  }
  .tarjeta {
    break-inside: avoid;
    height: 6.6cm;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    padding: .5cm;
    border: 1px dashed #bbb;   /* guía de corte */
    color: #000;
  }
  .tarjeta-pareja { margin: 0 0 .35cm; font-size: 8pt; letter-spacing: .08em; text-transform: uppercase; color: #666; }
  .tarjeta-nombre { margin: 0; font-family: var(--font-serif); font-size: 16pt; line-height: 1.15; }
  .tarjeta-mesa { margin: .35cm 0 0; font-size: 12pt; font-weight: 600; }
  .tarjeta-fecha { margin: .35cm 0 0; font-size: 7.5pt; color: #888; }
}

/* --- PDF completo: croquis y lista en un solo documento ------------------- */
@media print {
  body.imprimiendo-todo .dashx__sidebar,
  body.imprimiendo-todo .dashx__topbar,
  body.imprimiendo-todo .bg-layer,
  body.imprimiendo-todo .dash__toolbar,
  body.imprimiendo-todo .mesas-subtabs,
  body.imprimiendo-todo .mesas-croquis-bar,
  body.imprimiendo-todo .lista-bar,
  body.imprimiendo-todo .mesas-inspector,
  body.imprimiendo-todo .croquis-modo,
  body.imprimiendo-todo .croquis-aviso,
  body.imprimiendo-todo .tarjetas-hoja,
  body.imprimiendo-todo #mesas-pane-asignar,
  body.imprimiendo-todo .dashx__view:not(#view-mesas) { display: none !important; }

  body.imprimiendo-todo,
  body.imprimiendo-todo .dashx,
  body.imprimiendo-todo .dashx__main,
  body.imprimiendo-todo .dashx__content,
  body.imprimiendo-todo .dashx__panel,
  body.imprimiendo-todo .mesas-pane {
    background: #fff; color: #000; margin: 0; padding: 0;
    border: none; box-shadow: none; display: block; overflow: visible;
  }
  body.imprimiendo-todo .mesas-croquis,
  body.imprimiendo-todo .mesas-viewport {
    height: auto; min-height: 0; max-height: none; overflow: visible;
    border: none; display: block;
  }
  body.imprimiendo-todo .mesas-canvas { background: #fff; }
  body.imprimiendo-todo .croquis-mesa { background: #fff; border-color: #333; color: #000; }
  body.imprimiendo-todo .croquis-mesa-cuenta { color: #444; }
  body.imprimiendo-todo .croquis-zona { background: #f2f2f2; border-color: #888; color: #333; }
  body.imprimiendo-todo .croquis-zona--muro { background: #555; opacity: 1; }
  body.imprimiendo-todo .croquis-pip { background: #fff; border-color: #333; }
  body.imprimiendo-todo .croquis-pip.is-taken { background: #333; }
  body.imprimiendo-todo .croquis-handle { display: none; }
  /* El plano en su hoja y la lista en la siguiente. */
  body.imprimiendo-todo #mesas-pane-lista { break-before: page; }
  body.imprimiendo-todo .lista-content { grid-template-columns: repeat(2, 1fr); gap: .5rem; }
  body.imprimiendo-todo .lista-mesa { border: 1px solid #999; background: #fff; color: #000; }
  body.imprimiendo-todo .lista-mesa-meta,
  body.imprimiendo-todo .lista-grupo,
  body.imprimiendo-todo .lista-grupo-titulo { color: #444; }
}

/* --- Sub-modo de la lista: por mesa o por grupo --------------------------- */
.lista-modo { display: inline-flex; gap: .25rem; }
.lista-sub { margin: -.2rem 0 .6rem; font-size: .78rem; color: var(--text-soft); }
/* En pantalla se ve una de las dos; en el PDF salen las dos, una tras otra. */
#lista-grupos-content, .lista-sub, .print-titulo { display: none; }
#mesas-pane-lista.ver-grupos #lista-content { display: none; }
#mesas-pane-lista.ver-grupos #lista-grupos-content { display: grid; }
#mesas-pane-lista.ver-grupos .lista-sub { display: block; }

/* =============================================================================
   19 · IMPRESIÓN — correcciones de estructura y legibilidad
   ============================================================================= */
@media print {
  /* LOS NAVEGADORES QUITAN LOS FONDOS AL IMPRIMIR por defecto, y eso se llevaba
     por delante la cuadrícula del croquis (que es un background-image) y los
     muros (un background-color): el plano salía flotando sin paredes ni retícula.
     Esto los obliga a respetarlos. */
  body.imprimiendo-todo *,
  body.imprimiendo-croquis *,
  body.imprimiendo-lista *,
  body.imprimiendo-tarjetas * {
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }

  /* Encabezados de sección: en papel hay que saber qué se está leyendo. */
  body.imprimiendo-todo .print-titulo,
  body.imprimiendo-croquis .print-titulo,
  body.imprimiendo-lista .print-titulo {
    display: block;
    margin: 0 0 .5cm;
    padding-bottom: .2cm;
    border-bottom: 1.5px solid #222;
    font-family: var(--font-serif);
    font-size: 15pt;
    color: #000;
  }
  body.imprimiendo-todo .print-salto { break-before: page; margin-top: 0; }
  body.imprimiendo-todo .lista-sub,
  body.imprimiendo-lista .lista-sub { display: block; color: #555; font-size: 8.5pt; margin: -.3cm 0 .4cm; }

  /* En el PDF salen LAS DOS listas, sin importar cuál se esté viendo en pantalla. */
  body.imprimiendo-todo #lista-grupos-content,
  body.imprimiendo-lista #lista-grupos-content { display: grid !important; }
  body.imprimiendo-todo #mesas-pane-lista.ver-grupos #lista-content,
  body.imprimiendo-lista #mesas-pane-lista.ver-grupos #lista-content { display: grid !important; }

  /* La cuadrícula del croquis, con la retícula visible en papel. */
  body.imprimiendo-todo .mesas-canvas,
  body.imprimiendo-croquis .mesas-canvas {
    background-color: #fff;
    /* Las tintas de pantalla no sirven en papel: #ededed sobre blanco es
       invisible impreso, así que sólo se veía la retícula de cada 5 casillas y
       el plano parecía flotar sobre bandas sueltas. */
    background-image:
      linear-gradient(to right, #9a9a9a 1px, transparent 1px),
      linear-gradient(to bottom, #9a9a9a 1px, transparent 1px),
      linear-gradient(to right, #d2d2d2 1px, transparent 1px),
      linear-gradient(to bottom, #d2d2d2 1px, transparent 1px);
    border: 1px solid #666;
  }
  /* Los muros son la forma del salón: sólidos y bien negros. */
  body.imprimiendo-todo .croquis-zona--muro,
  body.imprimiendo-croquis .croquis-zona--muro {
    background: #333 !important;
    border: none !important;
    opacity: 1 !important;
  }
  body.imprimiendo-todo .croquis-mesa-familias,
  body.imprimiendo-croquis .croquis-mesa-familias,
  body.imprimiendo-todo .croquis-mesa-nombre,
  body.imprimiendo-croquis .croquis-mesa-nombre { color: #000; font-weight: 600; }

  /* El croquis ocupa su propia hoja y la lista empieza en la siguiente: antes
     la lista se colaba en el hueco de abajo del plano. */
  body.imprimiendo-todo #mesas-pane-croquis { break-after: page; }

  /* TEXTO DE LAS LISTAS. En pantalla el gris claro funciona sobre el tema
     oscuro; en papel blanco quedaba casi invisible y demasiado chico. */
  body.imprimiendo-todo .lista-mesa,
  body.imprimiendo-lista .lista-mesa {
    border: 1px solid #888;
    border-radius: 4px;
    padding: .35cm .4cm;
    background: #fff;
  }
  body.imprimiendo-todo .lista-mesa-head h3,
  body.imprimiendo-lista .lista-mesa-head h3 { font-size: 11.5pt; color: #000; }
  body.imprimiendo-todo .lista-mesa-meta,
  body.imprimiendo-lista .lista-mesa-meta { font-size: 8pt; color: #444; }
  body.imprimiendo-todo .lista-personas li,
  body.imprimiendo-lista .lista-personas li {
    font-size: 9.5pt;
    padding: .06cm 0;
    color: #000;
    border-bottom: .5px solid #e4e4e4;
  }
  body.imprimiendo-todo .lista-nombre,
  body.imprimiendo-lista .lista-nombre { color: #000; }
  body.imprimiendo-todo .lista-grupo,
  body.imprimiendo-lista .lista-grupo { color: #555; font-size: 8pt; max-width: 45%; }
  body.imprimiendo-todo .lista-hits,
  body.imprimiendo-lista .lista-hits { display: none; }
  body.imprimiendo-todo .lista-personas li.is-hit,
  body.imprimiendo-lista .lista-personas li.is-hit { background: none; }

  /* Márgenes de hoja: sin esto el navegador mete su propio encabezado con la
     URL pegado al contenido. */
  @page { margin: 1.2cm; }
}

/* --- Correcciones de paginación de las listas -----------------------------
   Con CSS grid, `break-inside: avoid` no impide que el navegador parta una fila
   al saltar de página: las tarjetas salían cortadas por arriba. En columnas el
   flujo pagina bien y cada tarjeta se queda entera. */
@media print {
  body.imprimiendo-todo .lista-content,
  body.imprimiendo-lista .lista-content {
    display: block;
    column-count: 2;
    column-gap: .6cm;
  }
  body.imprimiendo-todo .lista-mesa,
  body.imprimiendo-lista .lista-mesa {
    display: inline-block;   /* mantiene la tarjeta entera dentro de su columna */
    width: 100%;
    margin: 0 0 .45cm;
    break-inside: avoid;
    -webkit-column-break-inside: avoid;
  }
  /* El lienzo se redibuja al tamaño de la hoja, así que ocupa lo que necesite. */
  body.imprimiendo-todo .mesas-viewport,
  body.imprimiendo-croquis .mesas-viewport { width: auto; height: auto; }
  body.imprimiendo-todo .mesas-canvas,
  body.imprimiendo-croquis .mesas-canvas { margin: 0; }
}

/* El número de mesa en el croquis impreso: es lo único que lleva la mesa en
   papel, así que va en negro y en negrita para leerse de un vistazo. */
.croquis-mesa-num {
  font-weight: 700;
  line-height: 1;
  color: #000;
}
@media print {
  /* Los puntos de asiento se pintan con `background`, que algunos ajustes de
     impresión descartan: se refuerzan con borde para que el ocupado se vea
     lleno en cualquier caso. */
  body.imprimiendo-todo .croquis-pip.is-taken,
  body.imprimiendo-croquis .croquis-pip.is-taken {
    background: #333;
    border: 3px solid #333;
    width: 5px; height: 5px;
    margin: -2.5px 0 0 -2.5px;
  }
  body.imprimiendo-todo .croquis-pip,
  body.imprimiendo-croquis .croquis-pip { border-color: #555; }
}

/* ---- Mini-plano del escáner (js/minicroquis.js) ---- */
.minicroquis { margin: .9rem auto 0; max-width: 520px; }
.minicroquis__svg { display:block; width:100%; height:auto; max-height:42vh; margin:0 auto; }
.minicroquis__pie { font-size:.75rem; color:var(--text-soft); text-align:center; margin-top:.35rem; }
.minicroquis__zona { fill:var(--glass-bg-strong); stroke:var(--glass-border); stroke-width:.15; }
.minicroquis__zona--muro { fill:var(--text-soft); opacity:.55; stroke:none; }
.minicroquis__zona--pista { fill:var(--accent-soft); }
.minicroquis__zona--entrada { fill:var(--accent); opacity:.85; }
.minicroquis__zona--columna { fill:var(--text-soft); opacity:.35; }
.minicroquis__zona-txt { fill:var(--text-soft); text-anchor:middle; dominant-baseline:central; font-family:var(--font-sans); }
.minicroquis__mesa { fill:var(--glass-bg); stroke:var(--text-soft); stroke-width:.18; opacity:.8; }
.minicroquis__num { fill:var(--text-soft); text-anchor:middle; dominant-baseline:central; font-weight:500; }
.minicroquis__mesa.is-target { fill:var(--accent); stroke:var(--text); stroke-width:.3; opacity:1; }
.minicroquis__num.is-target { fill:var(--on-accent); font-weight:700; }
.minicroquis__zona-txt--entrada { fill:var(--accent); font-weight:700; letter-spacing:.02em; }
/* El contorno con el color del fondo separa el nombre de las mesas que pisa. */
.minicroquis__etiqueta { fill:var(--text); font-weight:700; text-anchor:middle; font-family:var(--font-serif); paint-order:stroke; stroke:var(--bg-base); stroke-width:.55; stroke-linejoin:round; }
.minicroquis__pulso { fill:none; stroke:var(--accent); stroke-width:.5; animation:minicroquisPulso 1.4s ease-out infinite; transform-box:fill-box; transform-origin:center; }
@keyframes minicroquisPulso { 0% { transform:scale(1); opacity:.9; } 100% { transform:scale(1.6); opacity:0; } }
@media (prefers-reduced-motion: reduce) { .minicroquis__pulso { animation:none; opacity:.6; } }
body.modo-puerta .minicroquis { max-width: 100%; }
/* En modo puerta el resultado ya es grande: el plano se queda en 38vh para que
   nombre, mesa y plano quepan juntos en la pantalla de un teléfono. */
body.modo-puerta .minicroquis__svg { max-height: 38vh; }
body.modo-puerta .minicroquis__pie { display: none; }
