    @font-face {
      font-family: 'Lovely Mess';
      src: url('assets/fonts/LovelyMess.ttf') format('truetype'),
           url('assets/fonts/LovelyMess.otf') format('opentype');
      font-weight: 400;
      font-style: normal;
      font-display: swap;
    }

    :root {
      --pink-strong: #ffa9a8;
      --pink-soft:   #ffd8d9;
      --peach:       #ffe4cf;
      --red:         #ce1616;
      --orange:      #ff6d28;
      --wine:        #580703;
      --green:       #036d3e;
      --ink:         #1c1815;
      --paper:       #fff;

      --serif: 'Lora', Georgia, 'Times New Roman', serif;
      --script: 'Lovely Mess', 'Caveat Brush', 'Brush Script MT', cursive;

      /* Responsive sizing knobs. The media queries at the end of the file
         reassign these; padding / gap / title size are calc()'d from them.
         app.js then layers the per-panel --fit-* factors on top so every
         panel fits exactly one viewport (see "Fit each panel" in app.js). */
      /* Fluid breathing room: grows with the viewport's smaller axis so on
         a laptop the "frame" feels generous and on mobile stays compact.
         Hero shares the same vertical rhythm as every other panel so the
         "see you in burgos baby" block sits dead-centre.
         Tightened ~20% over the previous defaults so a big script title
         and its supporting info both fit one viewport more comfortably. */
      --panel-pad-y:      clamp(36px, 8vmin, 110px);
      --panel-pad-x:      clamp(20px, 4vmin, 72px);
      --panel-gap:        clamp(20px, 3.4vmin, 48px);
      --script-size:      clamp(96px, 25vmin, 160px);
      --script-leading:   0.95;
      --content-width:    min(92vw, clamp(420px, 76vmin, 880px));
      /* Two fluid sizes for every support text. They share the same vmin
         scale so body and caption grow together; on a tiny mobile they
         settle at the floor (14/11 px), on a tall laptop they reach
         the ceiling (22/16 px). */
      --body-size:        18px;
      --caption-size:     clamp(11px, 1.6vmin, 16px);
      --header-size:      22px;

      /* Default accent for components that live outside a panel
         (e.g. the RSVP modal). Each panel overrides this from its own
         script colour below, so CTAs, deadline pills and links match
         the dominant tone of the panel they live in. */
      --accent:           var(--wine);

      /* Shared design language tokens — every card uses the same radius,
         padding and shadow; every pill uses the same radius and the same
         padding scale; every link uses the same bottom-border treatment.
         Component rules below reference these so the system stays
         consistent — change one knob, change every card / pill at once. */
      --card-radius:      8px;
      --card-pad:         16px 18px;
      --card-shadow:      none;
      --card-shadow-lift: none;
      --pill-radius:      999px;
      --pill-pad-lg:      14px 28px;    /* primary CTA            */
      --pill-pad-md:      11px 22px;    /* default chip / button  */
      --pill-pad-sm:      7px 14px;     /* tag badge              */
      --link-underline:   1px solid currentColor;
    }
    /* Móvil: reducimos cuerpo/header un punto para que respire mejor en
       pantallas estrechas. */
    @media (max-width: 600px) {
      :root {
        --body-size:      16px;
        --header-size:    20px;
      }
    }

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

    html, body {
      margin: 0;
      padding: 0;
      background: var(--pink-strong);
      color: var(--ink);
      font-family: var(--serif);
      -webkit-font-smoothing: antialiased;
      -webkit-text-size-adjust: 100%;
    }

    /* iOS Safari fix: <main> es el contenedor de scroll, no <html>.
       html/body/main usan 100lvh (large viewport height) que junto con
       viewport-fit=cover hace que el contenido se EXTIENDA bajo las
       toolbars de iOS Safari. Como esas barras son translúcidas en iOS
       15+, ven el color del panel detrás → SIN franjas de color que
       choquen. El contenido se centra en el área segura via padding
       con env(safe-area-inset-*). */
    html, body {
      height: 100lvh;
      margin: 0;
      overflow: hidden;
      overscroll-behavior: none;
    }
    main {
      height: 100lvh;
      width: 100%;
      overflow-x: hidden;
      overflow-y: scroll;
      scroll-snap-type: y mandatory;
      scroll-behavior: smooth;
      -webkit-overflow-scrolling: touch;
      scrollbar-width: none;
    }
    main::-webkit-scrollbar { display: none; }

    /* Each panel snaps to top and fills the FULL viewport including
       under the status bar / URL bar (gracias a viewport-fit=cover +
       100lvh). El padding interno respeta los safe-area-insets para
       que el contenido no se oculte tras las toolbars.

       El truco `calc(100lvh - 100svh)` en padding-bottom suma el alto
       que ocupa la URL bar de iOS Safari cuando está visible. Cuando
       la URL bar se oculta al scrollear, esa diferencia es 0 y el
       padding vuelve al mínimo. Así el contenido nunca queda cortado
       por la URL bar.

       `contain: layout paint` aísla cada panel: cambios dentro de uno
       (countdown ticking, palabras levitando) no provocan repaint del
       resto, eliminando parpadeos cruzados en iOS Safari. */
    .panel {
      scroll-snap-align: start;
      scroll-snap-stop: always;
      height: 100lvh;
      min-height: 100lvh;
      contain: layout paint;
      width: 100%;
      padding-top:
        calc(var(--panel-pad-y) + env(safe-area-inset-top, 0px));
      padding-right: var(--panel-pad-x);
      padding-bottom:
        calc(var(--panel-pad-y) + env(safe-area-inset-bottom, 0px) + (100lvh - 100svh));
      padding-left: var(--panel-pad-x);
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      gap: calc(var(--panel-gap) * var(--fit-space, 1));
      text-align: center;
      position: relative;
      overflow: hidden;
    }

    /* Content wrapper inserted by app.js around every panel's children, so
       the whole block can be measured and — as a last resort — uniformly
       scaled (--fit-all) to always fit one viewport. */
    .panel-fit {
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: calc(var(--panel-gap) * var(--fit-space, 1));
      width: 100%;
      max-width: var(--content-width);
      margin-inline: auto;
      flex: 0 0 auto;
      transform: scale(var(--fit-all, 1));
      transform-origin: center;
    }
    .hero .panel-fit { transform-origin: center; }

    /* Skip-to-content link — invisible until el usuario lo enfoca con Tab.
       Cumple WCAG 2.4.1 (bypass blocks) y permite a usuarios de teclado
       saltarse el botón flotante de menú. */
    .skip-link {
      position: absolute;
      top: -100px;
      left: 50%;
      transform: translateX(-50%);
      background: var(--ink);
      color: var(--paper);
      padding: 10px 16px;
      border-radius: var(--card-radius, 8px);
      font-family: var(--serif);
      font-weight: 600;
      font-size: 14px;
      text-decoration: none;
      z-index: 100;
      transition: top 0.18s ease;
    }
    .skip-link:focus,
    .skip-link:focus-visible {
      top: 12px;
      outline: 2px solid var(--paper);
      outline-offset: 2px;
    }

    /* Scroll hint flotante — flecha SVG en rojo de marca, círculo blanco
       de fondo para máximo contraste sobre cualquier color del hero.
       Decorativo (aria-hidden). Se muestra con .is-visible vía JS. */
    .scroll-hint {
      position: fixed;
      bottom: calc(24px + env(safe-area-inset-bottom, 0px));
      left: 50%;
      transform: translate(-50%, 8px);
      display: flex;
      align-items: center;
      justify-content: center;
      width: 40px;
      height: 40px;
      color: var(--red);
      opacity: 0;
      pointer-events: none;
      transition: opacity 0.45s ease, transform 0.45s ease;
      z-index: 40;
    }
    .scroll-hint.is-visible {
      opacity: 1;
      transform: translate(-50%, 0);
    }
    .scroll-hint__arrow {
      display: block;
      animation: scroll-hint-bounce 1.4s ease-in-out infinite;
    }
    @keyframes scroll-hint-bounce {
      0%, 100% { transform: translateY(0); }
      50%      { transform: translateY(6px); }
    }
    @media (prefers-reduced-motion: reduce) {
      .scroll-hint__arrow { animation: none; }
    }

    /* Reduced-motion: red de seguridad global. Las @media específicas más
       abajo desactivan las animaciones de panel y .script__word; aquí
       acortamos el resto (drawer, modal, hovers) a 0.01ms para que sigan
       funcionando técnicamente pero sin movimiento perceptible. */
    @media (prefers-reduced-motion: reduce) {
      *,
      *::before,
      *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
      }
    }

    /* Floating menu button (top right, fixed so it lives on every panel). */
    .menu {
      position: fixed;
      top: 24px;
      right: 20px;
      width: 56px;
      height: 56px;
      border: 0;
      background: transparent;
      padding: 0;
      cursor: pointer;
      z-index: 50;
      transition: transform 0.25s ease;
    }
    .menu img { width: 100%; height: 100%; display: block; transition: opacity 0.2s ease; }
    .menu:focus-visible { outline: 2px solid var(--ink); outline-offset: 4px; border-radius: 50%; }
    .menu[aria-expanded="true"] { transform: rotate(90deg); }
    .menu[aria-expanded="true"] img { opacity: 0; }
    .menu::after {
      content: "";
      position: absolute;
      inset: 14px;
      background:
        linear-gradient(var(--paper), var(--paper)) center/100% 2px no-repeat,
        linear-gradient(var(--paper), var(--paper)) center/100% 2px no-repeat;
      background-position: center 10px, center 18px;
      opacity: 0;
      transition: opacity 0.2s ease 0.05s;
      pointer-events: none;
    }
    .menu[aria-expanded="true"]::after { opacity: 1; }

    /* Drawer */
    .menu-drawer {
      position: fixed;
      top: 0;
      right: 0;
      bottom: 0;
      width: min(86vw, 340px);
      background: var(--wine);
      color: var(--paper);
      z-index: 40;
      padding: 96px 28px 32px;
      transform: translateX(100%);
      transition: transform 0.35s cubic-bezier(0.22, 0.9, 0.3, 1);
      box-shadow: -16px 0 48px rgba(0,0,0,0.25);
      display: flex;
      flex-direction: column;
      gap: 24px;
      visibility: hidden;
      /* En móvil estrecho/corto el contenido del drawer puede ser más
         alto que la pantalla — habilitamos scroll interno. */
      overflow-y: auto;
      -webkit-overflow-scrolling: touch;
      overscroll-behavior: contain;
    }
    .menu-drawer.is-open {
      transform: translateX(0);
      visibility: visible;
    }
    .menu-drawer__list {
      list-style: none;
      margin: 0;
      padding: 0;
      display: flex;
      flex-direction: column;
      gap: 18px;
    }
    .menu-drawer__list a {
      font-family: var(--script);
      font-size: 40px;
      line-height: 0.95;
      color: var(--paper);
      text-decoration: none;
      display: inline-block;
      transform-origin: left center;
      transform: rotate(-2deg);
      transition: color 0.2s ease, transform 0.2s ease;
    }
    .menu-drawer__list a:hover,
    .menu-drawer__list a:focus-visible {
      color: var(--orange);
      transform: rotate(-2deg) translateX(4px);
      outline: none;
    }
    .menu-drawer__footer {
      margin-top: auto;
      font-family: var(--serif);
      font-size: var(--body-size);
      font-weight: 500;
      line-height: 1.5;
      display: flex;
      flex-direction: column;
      gap: 20px;
    }
    .menu-drawer__couple,
    .menu-drawer__contact { margin: 0; }
    .menu-drawer__couple strong { font-weight: 700; }
    .menu-drawer__heading {
      display: inline-block;
      margin-bottom: 4px;
      font-weight: 700;
      letter-spacing: 0.06em;
      text-transform: uppercase;
      font-size: var(--caption-size);
      opacity: 0.85;
    }
    .menu-drawer__footer a {
      color: inherit;
      text-decoration: underline;
      text-underline-offset: 3px;
    }

    /* Backdrop — sin blur (estilo limpio). */
    .menu-backdrop {
      position: fixed;
      inset: 0;
      background: rgba(0,0,0,0.45);
      z-index: 30;
      opacity: 0;
      visibility: hidden;
      transition: opacity 0.25s ease, visibility 0s linear 0.25s;
    }
    .menu-backdrop.is-open {
      opacity: 1;
      visibility: visible;
      transition: opacity 0.25s ease, visibility 0s linear 0s;
    }

    body.menu-open { overflow: hidden; touch-action: none; }

    /* Colour variants */
    /* --panel-bg expone el color de fondo del panel como variable para
       que los botones outline puedan usarlo al invertir en hover
       (texto pasa al color del fondo, no a blanco fijo). */
    .bg-pink   { background: var(--pink-strong); --panel-bg: var(--pink-strong); }
    .bg-blush  { background: var(--pink-soft);   --panel-bg: var(--pink-soft); }
    .bg-peach  { background: var(--peach);       --panel-bg: var(--peach); }
    .bg-paper  { background: var(--paper);       --panel-bg: var(--paper); }
    .bg-wine   { background: var(--wine); color: var(--paper); --panel-bg: var(--wine); }

    /* Per-panel accent — derived from the script colour inside each panel.
       Components further down (.rsvp__cta, .deadline, .link-arrow, etc.)
       read var(--accent) so they automatically match the panel's vibe. */
    .panel:has(.script.red)         { --accent: var(--red); }
    .panel:has(.script.wine)        { --accent: var(--wine); }
    .panel:has(.script.orange)      { --accent: var(--orange); }
    .panel:has(.script.green)       { --accent: var(--green); }
    .panel.hero                     { --accent: var(--red); }
    /* Wine-background panels (EAT.BEBER.) need a lighter accent on top
       of dark bg, so the orange script also drives the accent. */
    .panel.bg-wine                  { --accent: var(--orange); }

    /* Information-heavy panels (those carrying a list, schedule, agenda,
       hotel/place cards, IBAN block, venue links) keep the *same* big
       script size as every other panel — what changes is body text and
       gap, which shrink a touch so the cards and info fit. If something
       still overflows on a given viewport, the panel-fit JS scales it
       smoothly via the --fit-* variables. */
    .panel:has(.schedule),
    .panel:has(.agenda),
    .panel:has(.hotels),
    .panel:has(.places),
    .panel:has(.iban),
    .panel:has(.venue-links) {
      --panel-gap: clamp(12px, 2.2vmin, 28px);
      /* --body-size se queda en el valor global (20px). Si los paneles
         densos no caben tras este cambio, panel-fit (JS) reduce gaps y
         escala el bloque proporcionalmente para que entre. */
    }

    /* Typography */
    .eyebrow {
      font-family: var(--serif);
      font-weight: 700;
      font-size: var(--header-size);
      line-height: 1.2;
      letter-spacing: 0.02em;
      color: var(--accent);
    }
    /* Subtitle line — sigue el mismo patrón que el subtítulo del hero:
       mayúsculas en mayúsculas reales (text-transform) y peso normal,
       mismo tamaño que la línea principal para que la cabecera entera
       lea como una unidad tipográfica. */
    .eyebrow .light {
      display: block;
      font-weight: 400;
      font-size: var(--header-size);
      text-transform: uppercase;
      letter-spacing: 0.02em;
      margin-top: 6px;
      color: var(--ink);
    }

    .body-copy {
      font-family: var(--serif);
      font-weight: 500;
      font-size: var(--body-size);
      line-height: 1.4;
      max-width: 52ch;
    }
    /* En paneles con cards (alojamiento), un poco más ancho aún para
       que cosas como "Miranda de Ebro:" no caigan a una línea suelta. */
    .panel:has(.hotels) .body-copy { max-width: 60ch; }
    /* Negritas dentro del cuerpo (strong) heredan el accent del panel. */
    .body-copy strong {
      font-weight: 700;
      color: var(--accent);
    }
    .body-copy p { margin: 0; }
    .body-copy p + p { margin-top: 0.2em; }
    /* Em-dash separador cuando el body-copy sigue a la agenda — marca la
       transición de "lo concreto" (horas) al "texto de apoyo". El
       margen negativo de arriba acerca el conjunto al schedule.
       También se usa entre body-copy y la lista de hoteles, y entre los
       botones venue-links y el body-copy cuando viven juntos. */
    .schedule + .body-copy::before,
    .body-copy + .hotels::before,
    .venue-links + .body-copy::before {
      content: "—";
      display: block;
      text-align: center;
      font-family: var(--serif);
      font-size: var(--header-size);
      line-height: 1;
      color: var(--accent);
      margin: -12px 0 6px;
      font-weight: 400;
    }

    .script {
      font-family: var(--script);
      font-weight: 400;
      font-style: normal;
      color: var(--red);
      font-size: calc(var(--script-size) * var(--fit-title, 1));
      line-height: var(--script-leading);
      letter-spacing: 0.005em;
      transform: rotate(-2.8deg);
      max-width: 100%;
      word-break: break-word;
      hyphens: none;
    }
    .script.wine   { color: var(--wine); }
    .script.orange { color: var(--orange); }
    .script.green  { color: var(--green); }
    .script.red    { color: var(--red); }

    /* Hero ------------------------------------------------------------- */
    .hero {
      /* Same symmetric vertical padding as every other panel; the content
         is centred, so equal top and bottom keeps the title and the closing
         line at the same distance from the edges. */
      justify-content: center;
      gap: calc(var(--panel-gap) * var(--fit-space, 1));
    }
    .hero__title {
      font-weight: 700;
      font-size: var(--header-size);
      line-height: 1.2;
      max-width: 44ch;
      color: var(--accent);
    }
    .hero__title-main {
      display: block;
      animation: hero-title-fall 0.7s 0.1s both cubic-bezier(0.22, 1, 0.36, 1);
    }
    .hero__title small,
    .hero__title-sub {
      display: block;
      font-weight: 400;
      font-size: var(--header-size);
      line-height: 1.4;
      margin-top: 6px;
      color: var(--ink);
      animation: hero-fade-up 0.6s 0.45s both ease-out;
    }
    .hero__art {
      display: flex;
      flex-direction: column;
      align-items: center;
      position: relative;
    }
    .hero__art img.illustration {
      width: calc(clamp(80px, 22vmin, 280px) * var(--fit-gfx, 1));
      aspect-ratio: 104.898 / 224.6;
      height: auto;
      display: block;
      flex-shrink: 0;
      object-fit: contain;
      transform-origin: 50% 14%;
      animation:
        hero-cup-drop  1.2s 0.65s both cubic-bezier(0.22, 1, 0.36, 1),
        hero-cup-swing 5s   1.85s ease-in-out infinite;
    }
    .hero__script {
      position: relative;
      margin-top: calc(18px * var(--fit-space, 1));
      transform: rotate(-3deg);
      color: var(--red);
      font-family: var(--script);
      font-size: calc(var(--script-size) * var(--fit-title, 1));
      line-height: var(--script-leading);
      text-align: center;
      max-width: 100%;
    }
    .hero__script .line {
      display: block;
      opacity: 0;
      transform-origin: 50% 80%;
      animation: hero-line-pop 0.55s both cubic-bezier(0.22, 1.6, 0.36, 1);
    }
    .hero__script .line-1 { animation-delay: 1.55s; }
    .hero__script .line-2 { animation-delay: 1.80s; }
    .hero__script .line-3 { animation-delay: 2.05s; }
    .hero__script .arrow {
      position: absolute;
      right: -38px;
      bottom: 4px;
      width: 32px;
      height: 28.6px;
      aspect-ratio: 30.6241 / 27.3898;
      object-fit: contain;
      flex-shrink: 0;
      transform: rotate(2deg);
      opacity: 0;
      animation:
        hero-arrow-twinkle 0.6s 2.35s both cubic-bezier(0.22, 1.6, 0.36, 1),
        hero-arrow-pulse   2.4s 3.05s ease-in-out infinite;
    }
    .hero__closing {
      font-family: var(--serif);
      font-weight: 400;
      font-size: var(--body-size);
      line-height: 1.4;
      max-width: 44ch;
      animation: hero-fade-up 0.7s 2.55s both ease-out;
    }

    /* Hero entrance choreography ---------------------------------------- */
    @keyframes hero-title-fall {
      0%   { opacity: 0; transform: translateY(-18px); }
      100% { opacity: 1; transform: translateY(0); }
    }
    @keyframes hero-fade-up {
      0%   { opacity: 0; transform: translateY(10px); }
      100% { opacity: 1; transform: translateY(0); }
    }
    @keyframes hero-cup-drop {
      0%   { opacity: 0; transform: translateY(-120px) rotate(-32deg); }
      55%  { opacity: 1; transform: translateY(8px)    rotate(14deg);  }
      78%  {              transform: translateY(-3px)  rotate(-7deg);  }
      100% { opacity: 1; transform: translateY(0)     rotate(-2deg);  }
    }
    @keyframes hero-cup-swing {
      0%, 100% { transform: rotate(-2deg); }
      50%      { transform: rotate(2deg);  }
    }
    @keyframes hero-line-pop {
      0%   { opacity: 0; transform: scale(0.7) translateY(14px); }
      55%  { opacity: 1; transform: scale(1.08) translateY(-2px); }
      100% { opacity: 1; transform: scale(1) translateY(0); }
    }
    @keyframes hero-arrow-twinkle {
      0%   { opacity: 0; transform: scale(0) rotate(-90deg); }
      60%  { opacity: 1; transform: scale(1.25) rotate(12deg); }
      100% { opacity: 1; transform: scale(1) rotate(2deg); }
    }
    @keyframes hero-arrow-pulse {
      0%, 100% { transform: scale(1) rotate(2deg); }
      50%      { transform: scale(1.15) rotate(-6deg); }
    }

    @media (prefers-reduced-motion: reduce) {
      .hero__title-main,
      .hero__title small, .hero__title-sub,
      .hero__art img.illustration,
      .hero__script .line,
      .hero__script .arrow,
      .hero__closing {
        animation: none !important;
        opacity: 1 !important;
        transform: none !important;
      }
    }

    /* Reveal on scroll for the rest of the panels --------------------- */
    .panel:not(.hero) .eyebrow,
    .panel:not(.hero) .body-copy,
    .panel:not(.hero) .script__word,
    .panel:not(.hero) .link-arrow,
    .panel:not(.hero) .venue-links,
    .panel:not(.hero) .rsvp__cta,
    .panel:not(.hero) .schedule,
    .panel:not(.hero) .agenda,
    .panel:not(.hero) .hotels,
    .panel:not(.hero) .places,
    .panel:not(.hero) .bus-note,
    .panel:not(.hero) .deadline,
    .panel:not(.hero) .contact-line,
    .panel:not(.hero) .forever-countdown,
    .panel:not(.hero) .hits__caption {
      opacity: 0;
    }

    .panel.is-active .eyebrow {
      animation: rev-down 0.6s 0.10s cubic-bezier(0.22, 1, 0.36, 1) both;
    }
    /* El titular contenedor (.script) ya no anima de entrada — cada
       palabra (.script__word) tiene su propio fade-in + levitar. */
    .panel.is-active .body-copy {
      animation: rev-up 0.65s 0.55s cubic-bezier(0.22, 1, 0.36, 1) both;
    }
    .panel.is-active .schedule,
    .panel.is-active .agenda,
    .panel.is-active .hotels,
    .panel.is-active .places,
    .panel.is-active .bus-note {
      animation: rev-up 0.7s 0.70s cubic-bezier(0.22, 1, 0.36, 1) both;
    }
    .panel.is-active .link-arrow,
    .panel.is-active .venue-links,
    .panel.is-active .rsvp__cta,
    .panel.is-active .deadline,
    .panel.is-active .contact-line,
    .panel.is-active .forever-countdown,
    .panel.is-active .hits__caption {
      animation: rev-up 0.6s 0.85s ease-out both;
    }

    /* Cada palabra del titular aparece con su propio "pop" festivo,
       y luego sigue levitando con un offset distinto. La cadencia (
       --in-delay) la fija el JS por palabra y por panel. */
    .panel.is-active .script__word {
      animation:
        script-word-in 0.6s var(--in-delay, 0s) cubic-bezier(0.22, 1.6, 0.36, 1) both,
        script-word-float 8s calc(var(--in-delay, 0s) + 1.8s) ease-in-out infinite;
    }

    @keyframes rev-down {
      0%   { opacity: 0; transform: translateY(-14px); }
      100% { opacity: 1; transform: translateY(0); }
    }
    @keyframes rev-up {
      0%   { opacity: 0; transform: translateY(16px); }
      100% { opacity: 1; transform: translateY(0); }
    }
    @keyframes rev-fade {
      0%   { opacity: 0; }
      100% { opacity: 1; }
    }
    @keyframes rev-script {
      0%   { opacity: 0; transform: translateY(24px) rotate(-2.8deg) scale(0.82); }
      60%  { opacity: 1; transform: translateY(-4px) rotate(-2.8deg) scale(1.06); }
      100% { opacity: 1; transform: translateY(0)    rotate(-2.8deg) scale(1); }
    }
    /* Palabras de los titulares — empiezan invisibles, hacen un pop
       festivo de entrada (scale + bounce sutil) cuando el panel se
       activa, y luego flotan en vertical (sin rotación, que daba
       sensación de "letras tambaleantes"). */
    .script__word {
      display: inline-block;
      will-change: transform, opacity;
    }
    @keyframes script-word-in {
      0%   { opacity: 0; transform: translateY(22px) scale(0.85); }
      55%  { opacity: 1; transform: translateY(-4px) scale(1.06); }
      100% { opacity: 1; transform: translateY(0)    scale(1); }
    }
    @keyframes script-word-float {
      0%, 100% { transform: translateY(0); }
      50%      { transform: translateY(-5px); }
    }
    @media (prefers-reduced-motion: reduce) {
      .panel.is-active .script__word { animation: none; opacity: 1; }
    }

    @media (prefers-reduced-motion: reduce) {
      .panel:not(.hero) .eyebrow,
      .panel:not(.hero) .body-copy,
      .panel:not(.hero) .script__word,
      .panel:not(.hero) .link-arrow,
      .panel:not(.hero) .rsvp__cta,
      .panel:not(.hero) .schedule,
      .panel:not(.hero) .agenda,
      .panel:not(.hero) .hotels,
      .panel:not(.hero) .places,
      .panel:not(.hero) .venue-links,
      .panel:not(.hero) .bus-note,
      .panel:not(.hero) .deadline,
      .panel:not(.hero) .contact-line,
      .panel:not(.hero) .forever-countdown,
      .panel:not(.hero) .hits__caption {
        animation: none !important;
        opacity: 1 !important;
      }
    }

    /* (Legacy .lugar__image / .sabado__image / .help__image / .rsvp__image
       eliminados — pertenecían al diseño anterior y los PNG asociados se
       quitaron de /assets/.) */

    /* Inline link system — everything that's a link inside body text or
       venue blocks shares the same underline treatment. Buttons and pills
       opt out with their own rules. */
    .link-arrow,
    .venue-links a,
    .hotel-card a,
    .contact-line a {
      font-family: var(--serif);
      color: inherit;
      text-decoration: underline;
      text-decoration-thickness: 1px;
      text-underline-offset: 3px;
      transition: opacity 0.18s ease;
    }
    .link-arrow {
      font-weight: 500;
      font-size: var(--body-size);
      color: var(--accent);
    }
    .link-arrow:hover,
    .venue-links a:hover,
    .hotel-card a:not(.hotel-card__photo):hover,
    .contact-line a:hover { opacity: 0.7; }
    /* La foto del hotel (wrapper <a>) NO debe cambiar al pasar el cursor. */
    .hotel-card__photo:hover { opacity: 1; }

    /* RSVP CTA --------------------------------------------------------- */
    .rsvp__cta {
      display: inline-block;
      font-family: var(--serif);
      font-weight: 700;
      font-size: var(--body-size);
      letter-spacing: 0.04em;
      text-transform: uppercase;
      color: var(--paper);
      background: var(--accent);
      padding: var(--pill-pad-lg);
      border-radius: var(--pill-radius);
      text-decoration: none;
      transition: transform 0.15s ease, background 0.2s ease, box-shadow 0.2s ease;
      border: 0;
      cursor: pointer;
    }
    @media (hover: hover) {
      .rsvp__cta:hover {
        background: color-mix(in oklab, var(--accent) 80%, black);
      }
    }
    .rsvp__cta:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; }

    /* Schedule (time list inside day panels) */
    .schedule {
      list-style: none;
      margin: 0;
      padding: 0;
      display: flex;
      flex-direction: column;
      gap: 18px;
      font-family: var(--serif);
      font-weight: 500;
      font-size: var(--body-size);
      line-height: 1.35;
      color: var(--ink);
      max-width: 44ch;
      width: 100%;
      text-align: center;
    }
    .schedule li {
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 4px;
    }
    .schedule .t {
      font-weight: 700;
      font-variant-numeric: tabular-nums;
      letter-spacing: 0.04em;
      color: var(--accent);
      font-size: 1.05em;
    }
    .schedule .t--soft {
      font-weight: 500;
      font-style: normal;
      letter-spacing: 0;
      opacity: 0.7;
    }
    /* En el panel bg-wine TODO el cuerpo (eyebrow sub, schedule, body-copy)
       va en paper porque el ink no contrasta sobre el fondo wine. */
    .panel.bg-wine .schedule,
    .panel.bg-wine .body-copy,
    .panel.bg-wine .eyebrow .light {
      color: var(--paper);
    }
    /* Subtítulo bajo un acto (p.ej. nombre del restaurante).
       Mismo tamaño y peso que body-copy + schedule — coherencia visual. */
    .schedule-sub {
      display: inline-block;
      font-size: 1em;
      color: var(--ink);
    }
    .panel.bg-wine .schedule-sub { color: var(--paper); }

    /* (.agenda / .agenda__* / .bus-note — eliminados: pertenecían al
       diseño anterior de Sábado y ya no se usan.) */

    /* Hotels (Alojamiento) — horizontal swipe on mobile, centred side-by-side
       on wider screens. Padding-inline aligns the first card with the
       container's centre so it doesn't read as left-anchored. */
    .hotels {
      display: flex;
      flex-direction: row;
      gap: 12px;
      width: 100%;
      max-width: 100%;
      overflow-x: auto;
      overflow-y: visible;
      scroll-snap-type: x mandatory;
      -webkit-overflow-scrolling: touch;
      scrollbar-width: none;
      padding: 4px 6%;
    }
    .hotels::-webkit-scrollbar { display: none; }
    .hotel-card {
      flex: 0 0 88%;
      max-width: 320px;
      scroll-snap-align: center;
      position: relative;
      border: 0;
      border-radius: var(--card-radius);
      padding: 16px 20px 20px;
      text-align: center;
      background: var(--accent);
      color: var(--paper);
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 8px;
      box-shadow: var(--card-shadow);
      overflow: hidden;
      transition: transform 0.25s cubic-bezier(0.22, 1, 0.36, 1),
                  box-shadow 0.25s ease;
    }
    @media (min-width: 600px) {
      .hotels {
        overflow: visible;
        scroll-snap-type: none;
        max-width: 560px;
        gap: 14px;
        padding: 0;
        justify-content: center;
      }
      .hotel-card {
        flex: 1 1 0;
        max-width: none;
      }
    }
    .hotel-card p.hotel-card__name {
      font-family: var(--serif);
      font-weight: 800;
      font-size: clamp(14px, 1.85vmin, 17px);
      letter-spacing: 0.005em;
      color: var(--paper);
      margin: 0;
      padding-bottom: 8px;
      line-height: 1.2;
      position: relative;
      opacity: 1;
    }
    /* Hairline under the name — sutil sobre el fondo accent. */
    .hotel-card__name::after {
      content: "";
      display: block;
      width: 28px;
      height: 1px;
      background: var(--paper);
      opacity: 0.55;
      margin: 10px auto 0;
    }
    .hotel-card p {
      font-family: var(--serif);
      font-weight: 500;
      font-size: clamp(13px, 1.6vmin, 16px);
      line-height: 1.4;
      margin: 0;
      color: var(--paper);
    }
    /* Web line subtler than phone line. */
    .hotel-card p:last-child {
      font-size: clamp(12px, 1.4vmin, 14px);
      opacity: 0.85;
    }
    .hotel-card a { color: var(--paper); text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 2px; }

    /* Venue links (web + map under each location name) */
    .venue-links {
      display: flex;
      flex-direction: column;
      gap: 10px;
      align-items: center;
      flex-wrap: wrap;
      justify-content: center;
    }
    /* A partir de tablet ambos botones en la misma línea. */
    @media (min-width: 600px) {
      .venue-links {
        flex-direction: row;
        gap: 14px;
      }
    }
    /* Píldora outline: hereda el accent del panel como borde + texto.
       En hover invierte (fondo accent, texto paper). Override del grupo
       inline-link (que aplicaba subrayado a .venue-links a). */
    .venue-links a {
      display: inline-flex;
      align-items: center;
      gap: 6px;
      font-weight: 700;
      font-size: var(--body-size);
      color: var(--accent);
      background: transparent;
      border: 2px solid currentColor;
      padding: var(--pill-pad-md);
      border-radius: var(--pill-radius);
      text-decoration: none;
      transition: background 0.2s ease, color 0.2s ease, transform 0.2s ease;
    }
    /* Hover solo en dispositivos con ratón. En táctil (iOS Safari) el
       :hover se queda "stuck" tras el primer tap y requiere segundo tap
       para el click → se rompe la UX. */
    @media (hover: hover) {
      .venue-links a:hover {
        background: var(--accent);
        color: var(--panel-bg, var(--paper));
        border-color: var(--accent);
        opacity: 1;
        transform: translateY(-1px);
      }
    }
    /* touch-action: manipulation elimina el delay de 300ms en iOS Safari
       y previene comportamientos raros con doble-tap. Aplicado a todos
       los botones/enlaces táctiles. */
    .venue-links a,
    .hotel-card .hotel-card__link a,
    .hotel-card .hotel-card__phone a,
    .rsvp__cta,
    .add-person,
    .iban__number,
    .menu,
    .menu-drawer__list a,
    .rsvp-dialog__close,
    .person-block__remove,
    .event-option,
    .menu-option,
    .skip-link,
    .scroll-hint,
    a[href] {
      touch-action: manipulation;
      -webkit-tap-highlight-color: transparent;
    }
    .venue-links a:focus-visible {
      outline: 2px solid var(--accent);
      outline-offset: 3px;
    }
    /* Icono pequeño dentro de botones (a la izquierda del texto). */
    .btn-icon {
      width: 18px;
      height: 18px;
      flex-shrink: 0;
    }

    /* Places (Alrededores) — horizontal swipe on mobile, 2×2 grid on wider
       screens. Same snap pattern as hotels; padding-inline centres the
       first card. */
    .places {
      display: flex;
      flex-direction: row;
      gap: 10px;
      width: 100%;
      max-width: 100%;
      overflow-x: auto;
      overflow-y: visible;
      scroll-snap-type: x mandatory;
      -webkit-overflow-scrolling: touch;
      scrollbar-width: none;
      padding: 4px 19%;
    }
    .places::-webkit-scrollbar { display: none; }
    .place-card {
      flex: 0 0 62%;
      max-width: 220px;
      scroll-snap-align: center;
    }
    /* From 600px up: 2×2 grid as fallback for narrow desktops/tablets. */
    @media (min-width: 600px) {
      .places {
        display: grid;
        grid-template-columns: 1fr 1fr;
        gap: 12px;
        max-width: 48ch;
        overflow: visible;
        scroll-snap-type: none;
        padding: 0;
        justify-content: center;
      }
      .place-card {
        flex: initial;
        max-width: none;
      }
    }

    /* From 900px up: a single row of 4 — matches the hotels' "one line"
       layout for full design consistency on desktop. */
    @media (min-width: 900px) {
      .places {
        display: flex;
        flex-direction: row;
        gap: 12px;
        max-width: 100%;
        justify-content: center;
      }
      .place-card {
        flex: 1 1 0;
        min-width: 0;
        max-width: 220px;
      }
    }
    .place-card {
      position: relative;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: flex-start;
      gap: 6px;
      text-decoration: none;
      border: 0;
      border-radius: var(--card-radius);
      padding: 14px 12px 18px;
      background: var(--accent);
      text-align: center;
      transition: transform 0.25s cubic-bezier(0.22, 1, 0.36, 1),
                  box-shadow 0.25s ease;
      color: var(--paper);
      box-shadow: var(--card-shadow);
      min-height: 200px;
      overflow: hidden;
    }
    .place-card:hover {
      transform: translateY(-3px);
      box-shadow: var(--card-shadow-lift);
    }
    .place-card:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

    /* Image zone at the top of every card. By default it shows a soft
       accent-tinted gradient as placeholder; drop a real photo via the
       data-img attribute by adding to assets/ and the image fills it.
       The CSS rule with [data-img] sets the background-image from the
       attribute so you don't need inline styles. */
    .card__image {
      width: calc(100% + 40px);     /* extend flush past card horizontal padding */
      margin: -16px -20px 12px;
      height: 90px;
      /* Placeholder con dos tonos del accent — sutil si la foto no carga. */
      background: linear-gradient(
        135deg,
        color-mix(in oklab, var(--accent) 60%, black),
        color-mix(in oklab, var(--accent) 90%, white)
      );
      background-size: cover;
      background-position: center;
      flex-shrink: 0;
    }
    .place-card .card__image {
      width: calc(100% + 24px);
      margin: -14px -12px 12px;
      height: 84px;
    }
    .place-card__name {
      font-family: var(--serif);
      font-weight: 800;
      font-size: clamp(14px, 1.85vmin, 17px);
      letter-spacing: 0.005em;
      color: var(--paper);
      margin: 0;
      line-height: 1.2;
      text-wrap: balance;
      padding-bottom: 8px;
      white-space: nowrap;
    }
    /* Hairline under the name — sutil sobre el fondo accent. */
    .place-card__name::after {
      content: "";
      display: block;
      width: 24px;
      height: 1px;
      background: var(--paper);
      opacity: 0.55;
      margin: 8px auto 0;
    }
    .place-card__tag {
      font-family: var(--serif);
      font-style: normal;
      font-size: clamp(12px, 1.4vmin, 14px);
      margin: 0;
      opacity: 0.85;
      line-height: 1.3;
      color: var(--paper);
    }

    /* ────────────────────────────────────────────────────────────────────────
       Accordion strips (hotels + places). Override the older row layouts: now
       the cards stack vertically as horizontal franjas. On hover-capable
       devices we collapse everything except the title; hover/focus opens the
       franja, revealing the image and the contact / tag details. Touch
       devices (no hover) keep the cards always expanded so the info is one
       glance away — no extra tap needed.
       ──────────────────────────────────────────────────────────────────────── */
    .hotels,
    .places {
      display: flex;
      flex-direction: column;
      gap: 8px;
      width: 100%;
      max-width: 460px;
      margin: 0 auto;
      padding: 0;
      overflow: visible;
      scroll-snap-type: none;
    }
    .hotel-card,
    .place-card {
      width: 100%;
      max-width: none;
      flex: 0 0 auto;
      min-height: 56px;
      padding: 16px 20px;
      gap: 6px;
      scroll-snap-align: none;
      position: relative;
      isolation: isolate;        /* contain z-index stacking */
      overflow: hidden;
    }
    .place-card { padding: 16px 16px; }

    /* The photo becomes the franja's background: positioned absolutely
       behind everything, covering the full card. The accent-coloured scrim
       (::before) above it preserves contrast so the white title and details
       stay legible on top of any photograph. */
    .hotel-card .card__image,
    .place-card .card__image {
      position: absolute;
      inset: 0;
      width: 100%;
      height: 100%;
      margin: 0;
      z-index: 0;
      filter: saturate(0.9);
      transition: filter 0.4s ease;
    }
    .hotel-card::before,
    .place-card::before {
      content: "";
      position: absolute;
      inset: 0;
      background: linear-gradient(
        180deg,
        color-mix(in oklab, var(--accent) 55%, transparent) 0%,
        color-mix(in oklab, var(--accent) 88%, transparent) 100%
      );
      z-index: 1;
      pointer-events: none;
      transition: background 0.3s ease;
    }
    /* Everything that isn't the photo backdrop must sit above the scrim. */
    .hotel-card > *:not(.card__image),
    .place-card > *:not(.card__image) {
      position: relative;
      z-index: 2;
    }


    /* No-hover / touch devices: keep cards always expanded (no surprise UX). */
    @media (hover: none) {
      .hotel-card,
      .place-card {
        padding: 16px 20px 18px;
      }
    }

    /* ── Hover-capable devices: franja collapsed, expand on hover/focus. ── */
    @media (hover: hover) and (pointer: fine) {
      /* Hotel contact lines (phone, web) collapsed. */
      .hotel-card > p:not(.hotel-card__name) {
        max-height: 0;
        opacity: 0;
        margin: 0;
        overflow: hidden;
        transition: max-height 0.35s cubic-bezier(0.22, 1, 0.36, 1),
                    opacity 0.2s ease,
                    margin 0.35s ease;
      }
      /* Place tag (italic subtitle) collapsed. */
      .place-card .place-card__tag {
        max-height: 0;
        opacity: 0;
        margin: 0;
        overflow: hidden;
        transition: max-height 0.35s cubic-bezier(0.22, 1, 0.36, 1),
                    opacity 0.2s ease,
                    margin 0.35s ease;
      }
      /* Decorative hairline under the name fades out. */
      .hotel-card__name::after,
      .place-card__name::after {
        opacity: 0;
        transition: opacity 0.25s ease;
      }
      /* Name sits tight inside the strip when collapsed. */
      .hotel-card p.hotel-card__name,
      .place-card__name {
        padding-bottom: 0;
        transition: padding-bottom 0.3s ease;
      }

      /* ── Expanded state ── */
      /* On hover the photo brightens and the scrim lightens so the
         image reads more clearly while the strip is open. */
      .hotel-card:hover .card__image,
      .hotel-card:focus-within .card__image,
      .place-card:hover .card__image,
      .place-card:focus-within .card__image {
        filter: saturate(1.05);
      }
      .hotel-card:hover::before,
      .hotel-card:focus-within::before,
      .place-card:hover::before,
      .place-card:focus-within::before {
        background: linear-gradient(
          180deg,
          color-mix(in oklab, var(--accent) 35%, transparent) 0%,
          color-mix(in oklab, var(--accent) 80%, transparent) 100%
        );
      }
      .hotel-card:hover > p:not(.hotel-card__name),
      .hotel-card:focus-within > p:not(.hotel-card__name) {
        max-height: 40px;
        opacity: 1;
        margin-top: 4px;
      }
      .place-card:hover .place-card__tag,
      .place-card:focus-within .place-card__tag {
        max-height: 40px;
        opacity: 1;
        margin-top: 4px;
      }
      .hotel-card:hover .hotel-card__name::after,
      .hotel-card:focus-within .hotel-card__name::after,
      .place-card:hover .place-card__name::after,
      .place-card:focus-within .place-card__name::after {
        opacity: 0.55;
      }
      .hotel-card:hover p.hotel-card__name,
      .hotel-card:focus-within p.hotel-card__name,
      .place-card:hover .place-card__name,
      .place-card:focus-within .place-card__name {
        padding-bottom: 8px;
      }
    }

    /* ════════════════════════════════════════════════════════════════════
       HOTEL CARDS — estilo AirBnB.
       Las reglas de arriba (franjas con foto-fondo + scrim accent) se
       sobreescriben aquí: foto rectangular arriba con bordes redondeados,
       texto debajo en columna, sin overlays. Se prefiere reset explícito
       a `!important` para que la cascade siga limpia.
       ════════════════════════════════════════════════════════════════════ */
    /* Móvil: slider horizontal con scroll-snap.
       Tablet+ : dos cards lado a lado, sin scroll. */
    .hotels {
      display: flex;
      flex-direction: row;
      gap: 16px;
      width: 100%;
      max-width: 100%;
      margin: 0;
      padding: 4px 16px;
      overflow-x: auto;
      overflow-y: visible;
      scroll-snap-type: x mandatory;
      -webkit-overflow-scrolling: touch;
      scrollbar-width: none;
    }
    .hotels::-webkit-scrollbar { display: none; }
    @media (min-width: 600px) {
      .hotels {
        max-width: 620px;
        margin: 0 auto;
        gap: 22px;
        padding: 0;
        overflow: visible;
        scroll-snap-type: none;
        align-items: flex-start;
      }
    }
    .hotel-card {
      flex: 0 0 82%;        /* móvil: ocupa ~82% del ancho para mostrar
                               un trozo de la siguiente y sugerir scroll */
      width: 82%;
      max-width: 360px;
      min-height: 0;
      scroll-snap-align: center;
      display: flex;
      flex-direction: column;
      align-items: stretch;
      text-align: left;
      gap: 6px;
      padding: 0;
      border: 0;
      border-radius: 0;
      background: transparent;
      color: var(--ink);
      box-shadow: none;
      overflow: visible;
      isolation: auto;
      position: relative;
      transition: transform 0.25s cubic-bezier(0.22, 1, 0.36, 1);
    }
    @media (min-width: 600px) {
      .hotel-card {
        flex: 1 1 0;       /* tablet+ row: comparten ancho */
        width: auto;
        max-width: none;
      }
    }
    .hotel-card:focus-within { outline: none; }
    /* Mata todos los hover-effects legacy de la franja-accordion: nada
       cambia al pasar el cursor sobre la tarjeta de hotel. */
    .hotel-card,
    .hotel-card:hover,
    .hotel-card:focus-within {
      transform: none !important;
    }
    .hotel-card:hover .card__image,
    .hotel-card:focus-within .card__image {
      filter: none !important;
      transform: none !important;
      background-size: cover !important;
      opacity: 1;
    }
    .hotel-card:hover::before,
    .hotel-card:focus-within::before,
    .hotel-card:hover .hotel-card__name::after,
    .hotel-card:focus-within .hotel-card__name::after {
      background: transparent;
      opacity: 1;
    }
    .hotel-card:hover > p:not(.hotel-card__name),
    .hotel-card:focus-within > p:not(.hotel-card__name) {
      max-height: none;
      opacity: 1;
      margin-top: 0;
    }
    /* Anula el scrim accent: */
    .hotel-card::before { content: none; }
    .hotel-card > *:not(.card__image) {
      position: static;
      z-index: auto;
    }
    /* La foto va envuelta en un <a> que abre la web del hotel.
       Sin hover (ni opacity, ni zoom, ni filter). */
    .hotel-card__photo {
      display: block;
      text-decoration: none;
      border-radius: var(--card-radius);
      overflow: hidden;
    }
    .hotel-card__photo:hover,
    .hotel-card__photo:focus-within,
    .hotel-card__photo:hover .card__image,
    .hotel-card__photo:focus-within .card__image {
      opacity: 1 !important;
      transform: none !important;
      filter: none !important;
      background-size: cover !important;
    }
    .hotel-card__photo:focus-visible {
      outline: 2px solid var(--accent);
      outline-offset: 3px;
    }
    /* Foto: bloque relativo arriba, rectangular y apaisado.
       Mata TODA transición / animación / filtro en la tarjeta para evitar
       cualquier parpadeo al pasar el cursor por encima. */
    .hotel-card .card__image {
      position: relative;
      inset: auto;
      width: 100%;
      aspect-ratio: 16 / 10;
      height: auto;
      margin: 0 0 10px;
      border-radius: var(--card-radius);
      background-size: cover;
      background-position: center;
      filter: none !important;
      z-index: auto;
      transition: none !important;
      animation: none !important;
    }
    .hotel-card,
    .hotel-card *,
    .hotel-card__photo,
    .hotel-card__photo * {
      transition: none !important;
      animation: none !important;
    }
    .hotel-card:hover .card__image,
    .hotel-card:focus-within .card__image,
    .hotel-card__photo:hover .card__image,
    .hotel-card__photo:focus-within .card__image,
    .hotel-card__photo:hover,
    .hotel-card__photo:focus-within {
      filter: none !important;
      transform: none !important;
      opacity: 1 !important;
      background-size: cover !important;
    }
    /* Override fuerte sobre el accordion legacy: que el teléfono y la
       web siempre se vean (no collapse al hover-out). */
    .hotels .hotel-card > p:not(.hotel-card__name),
    .hotels .hotel-card > p.hotel-card__name,
    .hotel-card > p {
      margin: 0;
      padding: 0;
      max-height: none;
      opacity: 1;
      overflow: visible;
      text-align: left;
      transition: none;
      font-family: var(--serif);
      font-size: var(--body-size);
      line-height: 1.4;
      color: var(--ink);
      font-weight: 500;
    }
    .hotels .hotel-card > p.hotel-card__name {
      font-weight: 800;
      font-size: clamp(17px, 2.05vmin, 20px);
      margin-top: 2px;
    }
    .hotel-card__name::after { content: none; }
    .hotel-card p:last-child {
      font-size: clamp(13px, 1.5vmin, 15px);
      opacity: 0.7;
    }
    .hotel-card a {
      color: var(--accent);
      text-decoration: underline;
      text-decoration-thickness: 1px;
      text-underline-offset: 2px;
    }

    /* ════════════════════════════════════════════════════════════════════
       HOTELES — diseño tipográfico sin foto. Resetea las iteraciones
       anteriores (franjas con foto-fondo + slider AirBnB) y deja un par
       de bloques de texto centrados, alineados con el resto de paneles.
       ════════════════════════════════════════════════════════════════════ */
    .hotels {
      display: flex;
      flex-direction: column;
      align-items: center;
      /* gap entre tarjetas se aplica como margin sobre la segunda+ para
         que el `::before` con el em-dash quede pegado a la primera
         tarjeta (gap empuja a TODOS los hijos, incluido el dash). */
      gap: 0;
      width: 100%;
      max-width: 460px;
      margin: 0 auto;
      padding: 0;
      overflow: visible;
      scroll-snap-type: none;
    }
    .hotels .hotel-card + .hotel-card {
      margin-top: 32px;
    }
    /* Reset duro de iteraciones anteriores. */
    .hotel-card {
      flex: 0 0 auto;
      width: 100%;
      max-width: 320px;
      min-height: 0;
      scroll-snap-align: none;
      display: flex;
      flex-direction: column;
      align-items: center;
      text-align: center;
      gap: 6px;
      padding: 0;
      border: 0;
      border-radius: 0;
      background: transparent;
      color: var(--ink);
      box-shadow: none;
      overflow: visible;
      isolation: auto;
      position: relative;
      transition: none;
    }
    .hotel-card::before { content: none; }
    .hotel-card .card__image,
    .hotel-card .hotel-card__photo { display: none !important; }
    .hotel-card p {
      margin: 0;
      padding: 0;
      max-height: none;
      opacity: 1;
      overflow: visible;
      text-align: center;
      transition: none;
      font-family: var(--serif);
      font-size: var(--body-size);
      line-height: 1.45;
      color: var(--ink);
      font-weight: 500;
    }
    .hotels .hotel-card > p.hotel-card__name {
      font-weight: 800;
      font-size: clamp(18px, 2.2vmin, 22px);
      margin-bottom: 4px;
      color: var(--accent);
    }
    /* Teléfono: subrayado discreto en color ink, mismo patrón que los
       enlaces inline del resto del sitio. */
    .hotel-card .hotel-card__phone a {
      color: var(--ink);
      text-decoration: underline;
      text-decoration-thickness: 1px;
      text-underline-offset: 3px;
      transition: opacity 0.18s ease;
    }
    .hotel-card .hotel-card__phone a:hover { opacity: 0.65; }
    /* "Más información" — mismo botón outline tipo píldora que usa
       .venue-links a ("Cómo llegar" / "Más información" en lugar y
       domingo). Hereda el accent del panel; hover invierte. */
    .hotels .hotel-card > p.hotel-card__link {
      margin-top: 16px;
    }
    .hotel-card .hotel-card__link a {
      display: inline-flex;
      align-items: center;
      gap: 6px;
      font-family: var(--serif);
      font-weight: 700;
      font-size: var(--body-size);
      color: var(--accent);
      background: transparent;
      border: 2px solid currentColor;
      padding: var(--pill-pad-md);
      border-radius: var(--pill-radius);
      text-decoration: none;
      transition: background 0.2s ease, color 0.2s ease, transform 0.2s ease;
    }
    @media (hover: hover) {
      .hotel-card .hotel-card__link a:hover {
        background: var(--accent);
        color: var(--panel-bg, var(--paper));
        border-color: var(--accent);
        opacity: 1;
        transform: translateY(-1px);
      }
    }
    .hotel-card .hotel-card__link a:focus-visible {
      outline: 2px solid var(--accent);
      outline-offset: 3px;
    }

    /* RSVP deadline pill — inherits the panel's accent. */
    .deadline {
      display: inline-block;
      font-family: var(--serif);
      font-weight: 700;
      font-size: var(--caption-size);
      letter-spacing: 0.16em;
      text-transform: uppercase;
      color: var(--paper);
      background: var(--accent);
      padding: var(--pill-pad-sm);
      border: 0;
      border-radius: var(--pill-radius);
      transition: background 0.2s ease;
    }

    /* Cuenta atrás textual del cierre — usa los mismos selectores
       [data-cd] que el chip antiguo, así countdown.js la rellena solo. */
    .forever-countdown {
      font-family: var(--serif);
      font-weight: 500;
      font-size: var(--body-size);
      line-height: 1.5;
      text-align: center;
      color: var(--ink);
      /* Desktop / tablet ancha: una sola línea. En móvil bajamos el bloque
         con label arriba + nums compactos abajo via .cd-short / .cd-long. */
      max-width: none;
      white-space: nowrap;
      margin: 0;
    }
    @media (max-width: 600px) {
      .forever-countdown {
        white-space: normal;
      }
    }
    .forever-countdown__num {
      font-weight: 800;
      color: var(--ink);
      font-variant-numeric: tabular-nums;
    }
    .forever-countdown__label {
      margin-right: 6px;
    }
    /* Por defecto (desktop, tablet ancha): formato largo "62 días, 21 horas…"
       en la misma línea que "Nos vemos en:". */
    .forever-countdown .cd-short { display: none; }
    .forever-countdown .cd-long  { display: inline; }
    /* Móvil: compactamos a "62 d  21 h  57 m  45 s" para no romper la
       línea con un solo bloque legible. */
    @media (max-width: 600px) {
      .forever-countdown .cd-long  { display: none; }
      .forever-countdown .cd-short { display: inline; }
      .forever-countdown__label    { display: block; margin: 0 0 6px; }
    }

    /* Contact line — texto oscuro como el resto, nunca accent (el verde del
       RSVP, por ejemplo, no era legible). Mismo body-size que body-copy. */
    .contact-line {
      font-family: var(--serif);
      font-weight: 500;
      font-size: var(--body-size);
      line-height: 1.5;
      text-align: center;
      color: var(--ink);
    }
    .contact-line a {
      color: var(--accent);
      text-decoration: underline;
      text-underline-offset: 3px;
    }
    /* Móvil: 3 líneas (¿Duda? / Ángela / Miguel). Desktop: 1 línea con
       separadores · entre cada bloque. Los <br class="br-mobile">
       y el <span class="contact-line__sep"> intercambian visibilidad
       según breakpoint. */
    .contact-line .br-mobile { display: inline; }
    .contact-line .contact-line__sep { display: none; }
    @media (min-width: 600px) {
      .contact-line .br-mobile { display: none; }
      .contact-line .contact-line__sep { display: inline; }
    }

    /* IBAN block (Help us) — light & airy, not a chunky button. */
    .iban {
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 10px;
      max-width: 420px;
      width: 100%;
    }
    .iban__label {
      font-family: var(--serif);
      font-weight: 700;
      font-size: var(--body-size);
      letter-spacing: 0.01em;
      color: var(--accent);
      margin: 0;
    }
    .iban__number {
      position: relative;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      gap: clamp(8px, 1.8vmin, 16px);
      font-family: 'Lora', Georgia, serif;
      font-variant-numeric: tabular-nums;
      font-weight: 700;
      font-size: clamp(11px, 1.55vmin, 17px);
      letter-spacing: 0.06em;
      color: var(--accent);
      background: var(--paper);
      border: 0;
      padding: 16px clamp(24px, 6vmin, 60px);
      border-radius: var(--pill-radius);
      cursor: pointer;
      box-shadow: none;
      transition: background 0.18s ease, transform 0.15s ease;
      max-width: 100%;
    }
    .iban__value { white-space: nowrap; }
    .iban__copy {
      width: 22px;
      height: 22px;
      flex-shrink: 0;
      opacity: 0.85;
    }
    .iban__number:hover {
      background: var(--paper);
    }
    .iban__number:active { transform: translateY(1px); }
    .iban__number:focus-visible { outline: 2px solid var(--wine); outline-offset: 3px; }

    /* Status hint sits BELOW the button so the IBAN keeps a single line. */
    .iban__hint {
      font-family: var(--serif);
      font-weight: 700;
      font-size: var(--caption-size);
      letter-spacing: 0.14em;
      text-transform: uppercase;
      color: var(--wine);
      opacity: 0.7;
      transition: color 0.2s ease, opacity 0.2s ease;
      min-height: 14px;
      pointer-events: none;
    }
    .iban__hint.is-visible {
      opacity: 1;
      color: var(--green);
    }
    .iban__number.is-copied {
      background: var(--wine);
      color: var(--paper);
      border-color: var(--wine);
    }
    .iban__holders {
      font-family: var(--serif);
      font-weight: 500;
      font-size: var(--body-size);
      line-height: 1.45;
      color: var(--ink);
      margin: 6px 0 0;
      opacity: 1;
      text-align: center;
    }
    .iban__holders-label {
      font-weight: 700;
      color: var(--accent);
    }

    /* Reveal animation for the IBAN block */
    .panel:not(.hero) .iban { opacity: 0; }
    .panel.is-active .iban {
      animation: rev-up 0.6s 0.75s cubic-bezier(0.22, 1, 0.36, 1) both;
    }

    /* RSVP — modal dialog */
    /* Mobile-first: the modal takes the whole screen (no rounded corners,
       no tiny margins) so the form feels like its own moment instead of a
       cramped tooltip on top of the page. From 700px and up it collapses
       back into a centred card with generous padding and shadow. */
    .rsvp-dialog {
      /* Hereda el accent del panel RSVP (script.green) para todo el modal. */
      --accent: var(--green);
      border: 0;
      padding: 0;
      margin: 0;
      background: var(--peach);
      color: var(--ink);
      width: 100vw;
      height: 100dvh;
      max-width: 100vw;
      max-height: 100dvh;
      border-radius: 0;
      overflow: hidden;
      box-shadow: none;
    }
    .rsvp-dialog::backdrop {
      background: rgba(28, 24, 21, 0.55);
    }
    .rsvp-dialog[open] {
      animation: dialog-in 0.32s cubic-bezier(0.22, 1, 0.36, 1);
    }
    @keyframes dialog-in {
      from { opacity: 0; transform: translateY(20px) scale(0.97); }
      to   { opacity: 1; transform: translateY(0) scale(1); }
    }

    /* Toggle entre vista de form y vista de éxito. El form va por
       defecto, success se enseña cuando el dialog tiene
       data-state="success" (lo setea el JS al enviar OK). */
    .rsvp-dialog__success { display: none; }
    .rsvp-dialog[data-state="success"] .rsvp-form,
    .rsvp-dialog[data-state="success"] .rsvp-dialog__form-script,
    .rsvp-dialog[data-state="success"] .rsvp-dialog__form-intro {
      display: none;
    }
    .rsvp-dialog[data-state="success"] .rsvp-dialog__success {
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 12px;
      padding: 12px 4px 24px;
      animation: rsvp-success-in 0.5s cubic-bezier(0.22, 1.2, 0.36, 1) both;
    }
    .rsvp-dialog__success-sub {
      font-family: var(--serif);
      font-weight: 500;
      font-size: var(--body-size);
      color: var(--ink);
      opacity: 0.75;
      text-align: center;
      max-width: 32ch;
      margin: 0;
      line-height: 1.45;
    }
    @keyframes rsvp-success-in {
      from { opacity: 0; transform: translateY(12px); }
      to   { opacity: 1; transform: translateY(0); }
    }
    @media (prefers-reduced-motion: reduce) {
      .rsvp-dialog[data-state="success"] .rsvp-dialog__success { animation: none; }
    }

    .rsvp-dialog__inner {
      padding: 52px 24px 24px;
      padding-bottom: calc(24px + env(safe-area-inset-bottom, 0px));
      max-height: 100dvh;
      overflow-y: auto;
      overscroll-behavior: contain;
      /* Reserva siempre el carril del scrollbar — evita el salto horizontal
         del contenido cuando la barra aparece/desaparece. */
      scrollbar-gutter: stable;
      position: relative;
      /* Scrollbar de marca — fina, en verde accent del modal, con
         padding visual respecto al borde redondeado del modal. Mantiene
         la accesibilidad (afordancia visible) sin romper la estética. */
      scrollbar-width: thin;                                       /* Firefox */
      scrollbar-color: color-mix(in oklab, var(--accent) 55%, transparent) transparent;
    }
    .rsvp-dialog__inner::-webkit-scrollbar {
      width: 8px;
    }
    .rsvp-dialog__inner::-webkit-scrollbar-track {
      background: transparent;
      margin: 8px 0;        /* respira con los bordes redondeados del modal */
    }
    .rsvp-dialog__inner::-webkit-scrollbar-thumb {
      background: color-mix(in oklab, var(--accent) 55%, transparent);
      border-radius: 999px;
      border: 2px solid transparent;
      background-clip: padding-box;       /* el borde transparente "encoge" el thumb */
    }
    .rsvp-dialog__inner::-webkit-scrollbar-thumb:hover {
      background: color-mix(in oklab, var(--accent) 85%, transparent);
      background-clip: padding-box;
    }

    @media (min-width: 700px) {
      .rsvp-dialog {
        margin: auto;
        width: calc(100% - 40px);
        max-width: 640px;
        height: auto;
        max-height: calc(100dvh - 40px);
        border-radius: 28px;
        box-shadow: none;
      }
      .rsvp-dialog__inner {
        padding: 48px 40px 40px;
        max-height: calc(100dvh - 40px);
      }
    }

    /* Script title — same vocabulary as the panel scripts. Proportional to
       the modal (not poster-sized) and slightly tilted to mimic
       hand-writing. */
    /* Eyebrow del modal — mismo patrón que los paneles, centrado. */
    .rsvp-dialog__heading {
      text-align: center;
      margin: 0;
    }
    /* Script title del modal — misma fuente y verde que los .script verde
       del sitio, pero proporcionado al modal (no tamaño poster). */
    .rsvp-dialog__script {
      text-align: center;
      margin: 24px 0 32px;
      font-size: clamp(56px, 14vmin, 88px);
      line-height: 0.95;
      transform: rotate(-2deg);
    }
    @media (min-width: 700px) {
      .rsvp-dialog__script {
        font-size: clamp(38px, 5vmin, 60px);
        margin: 32px 0 40px;
      }
    }
    /* Subtítulo bajo el script del modal. */
    .rsvp-dialog__intro {
      text-align: center;
      max-width: 460px;
      margin: -16px auto 24px;
      font-family: var(--serif);
      font-weight: 500;
      font-size: var(--body-size);
      line-height: 1.45;
      color: var(--ink);
    }
    @media (min-width: 700px) {
      .rsvp-dialog__intro {
        margin: -20px auto 32px;
      }
    }

    /* Close × — círculo blanco con × dibujada por CSS (dos diagonales),
       garantiza centrado perfecto sin depender de métricas de fuente. */
    .rsvp-dialog__close {
      position: absolute;
      top: 16px;
      right: 16px;
      width: 44px;
      height: 44px;
      border-radius: 50%;
      border: 0;
      background: var(--paper);
      font-size: 0;          /* oculta la × de texto */
      line-height: 0;
      color: var(--accent);
      cursor: pointer;
      padding: 0;
      box-shadow: none;
      transition: background 0.18s ease;
    }
    .rsvp-dialog__close::before,
    .rsvp-dialog__close::after {
      content: "";
      position: absolute;
      top: 50%;
      left: 50%;
      width: 16px;
      height: 2px;
      background: currentColor;
      border-radius: 1px;
    }
    .rsvp-dialog__close::before { transform: translate(-50%, -50%) rotate(45deg); }
    .rsvp-dialog__close::after  { transform: translate(-50%, -50%) rotate(-45deg); }
    .rsvp-dialog__close:hover {
      background: var(--accent);
      color: var(--paper);
    }
    .rsvp-dialog__close:focus-visible {
      outline: 2px solid var(--accent);
      outline-offset: 2px;
    }

    .rsvp-form {
      width: 100%;
      max-width: 460px;       /* readable column even in a 640 desktop card */
      margin: 0 auto;
      display: flex;
      flex-direction: column;
      gap: 26px;
      text-align: left;
    }

    .people-list {
      display: flex;
      flex-direction: column;
      gap: 14px;
    }

    /* Person card (inside the modal): same card system as hotels/places,
       just a different fill (cream) so it reads as a "name tag" against
       the peach modal bg. */
    /* Person card — sin caja. Sólo se pinta una línea verde ENTRE
       bloques cuando hay más de una persona (border-top en bloques
       a partir del segundo). Si hay una sola persona, no se ve línea. */
    .person-block {
      position: relative;
      border: 0;
      border-radius: 0;
      padding: 0;
      background: transparent;
      display: flex;
      flex-direction: column;
      gap: 14px;
      box-shadow: none;
    }
    .people-list .person-block + .person-block {
      margin-top: 8px;
      padding-top: 32px;
      border-top: 1px solid color-mix(in oklab, var(--accent) 55%, transparent);
    }
    /* La primera persona no puede eliminarse → ocultamos su × */
    .people-list .person-block:first-child .person-block__remove {
      display: none;
    }
    /* "Persona N" label is hidden, and the head wrapper is absolutely
       positioned in the corner so the × never pushes the rest of the card
       down — every person card has the same height regardless of whether
       it has a remove button or not. */
    .person-block__head {
      position: absolute;
      top: 28px;
      right: 0;
      display: flex;
      justify-content: flex-end;
      align-items: center;
      margin: 0;
      z-index: 1;
    }
    .person-block__title {
      display: none;
    }
    /* × quitar persona — círculo verde con × blanco (dos diagonales
       CSS), compacto y perfectamente centrado. */
    .person-block__remove {
      position: relative;
      border: 0;
      background: var(--accent);
      color: var(--paper);
      width: 24px;
      height: 24px;
      border-radius: 50%;
      font-size: 0;
      line-height: 0;
      padding: 0;
      cursor: pointer;
      opacity: 1;
      transition: background 0.18s ease, color 0.18s ease;
    }
    .person-block__remove:hover {
      background: color-mix(in oklab, var(--accent) 80%, black);
    }
    .person-block__remove:focus-visible {
      outline: 2px solid var(--accent);
      outline-offset: 2px;
    }
    .person-block__remove::before,
    .person-block__remove::after {
      content: "";
      position: absolute;
      top: 50%;
      left: 50%;
      width: 10px;
      height: 2px;
      background: currentColor;
      border-radius: 1px;
    }
    .person-block__remove::before { transform: translate(-50%, -50%) rotate(45deg); }
    .person-block__remove::after  { transform: translate(-50%, -50%) rotate(-45deg); }
    .person-block .row { gap: 14px; }

    /* + Añadir persona: píldora compacta, centrada, NO full-width. El
       contraste de anchos contra los inputs (que ocupan todo el ancho del
       form) la hace destacar y se lee como acción discreta pero clara.
       Borde fino accent + fondo blanco; al hover invierte (fondo accent,
       texto blanco) para feedback explícito. */
    .add-person {
      align-self: center;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      gap: 6px;
      width: auto;
      text-align: center;
      border: 1px solid var(--accent);
      background: var(--paper);
      color: var(--accent);
      font-family: var(--serif);
      font-weight: 700;
      font-size: 13px;
      letter-spacing: 0.14em;
      text-transform: uppercase;
      padding: 12px 22px;
      border-radius: var(--pill-radius);
      cursor: pointer;
      text-decoration: none;
      transition: background 0.18s ease, color 0.18s ease, border-color 0.18s ease;
    }
    .add-person::before {
      content: "+";
      font-size: 16px;
      line-height: 1;
      font-weight: 700;
      letter-spacing: 0;
      margin-top: -1px;
    }
    @media (hover: hover) {
      .add-person:hover {
        background: var(--accent);
        color: var(--paper);
        border-color: var(--accent);
      }
    }
    .add-person:active { transform: translateY(1px); }
    .add-person:focus-visible {
      outline: 2px solid var(--ink);
      outline-offset: 3px;
    }

    .rsvp-form .field {
      display: flex;
      flex-direction: column;
      gap: 8px;
    }

    /* Labels: estilo de formulario convencional. Usa los mismos tokens
       de tamaño que el resto del sitio. */
    .rsvp-form label {
      font-family: var(--serif);
      font-weight: 600;
      font-size: var(--caption-size);
      letter-spacing: 0;
      text-transform: none;
      color: var(--ink);
    }
    .rsvp-form label .hint {
      font-weight: 400;
      font-style: normal;
      letter-spacing: 0;
      text-transform: none;
      opacity: 1;
      color: var(--ink);
      margin-left: 4px;
      font-size: var(--caption-size);
    }

    /* Inputs y textarea — UI plana: fondo blanco sólido, sin bordes
       grises. Solo el focus pinta un inset accent. */
    .rsvp-form input[type="text"],
    .rsvp-form input[type="tel"],
    .rsvp-form input:not([type]),
    .rsvp-form select,
    .rsvp-form textarea {
      font-family: var(--serif);
      font-weight: 500;
      font-size: var(--body-size);
      color: var(--ink);
      background: var(--paper);
      border: 0;
      border-radius: var(--card-radius);
      padding: 12px 16px;
      width: 100%;
      box-shadow: none;
      transition: box-shadow 0.2s ease;
    }
    .rsvp-form textarea {
      min-height: 72px;
      resize: vertical;
      line-height: 1.4;
    }
    .rsvp-form input:focus,
    .rsvp-form textarea:focus,
    .rsvp-form select:focus {
      outline: 2px solid var(--accent);
      outline-offset: -2px;
      box-shadow: none;
    }
    /* Validación inline — se activa solo tras la primera interacción
       de la persona (data-touched) para no marcar en rojo el primer
       render del modal. */
    .rsvp-form input[data-touched]:invalid,
    .rsvp-form textarea[data-touched]:invalid,
    .rsvp-form select[data-touched]:invalid {
      outline: 2px solid var(--red);
      outline-offset: -2px;
    }
    .rsvp-form .field {
      position: relative;
    }
    .rsvp-form .field-error {
      display: none;
      margin-top: 6px;
      font-family: var(--serif);
      font-weight: 500;
      font-size: var(--caption-size);
      color: var(--red);
    }
    .rsvp-form .field:has([data-touched]:invalid) > .field-error {
      display: block;
    }
    /* Errores inline para grupos sin input (eventos, captcha). Se activan
       desde JS añadiendo `is-shown`. */
    .rsvp-form .field-error.is-shown {
      display: block;
    }
    .rsvp-form__captcha {
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 0;
    }
    .rsvp-form__captcha .field-error {
      text-align: center;
    }
    .rsvp-form input::placeholder,
    .rsvp-form textarea::placeholder {
      color: rgba(28, 24, 21, 0.30);
      font-weight: 400;
    }

    /* Menú (Adulto / Infantil / Bebé) — 3 chips lado a lado. */
    .menu-options {
      display: flex;
      gap: 6px;
      width: 100%;
    }
    .menu-option {
      flex: 1 1 0;
      display: flex;
      align-items: center;
      justify-content: center;
      padding: 12px 8px;
      background: var(--paper);
      color: var(--ink);
      border-radius: var(--card-radius);
      cursor: pointer;
      font-family: var(--serif);
      font-weight: 500;
      font-size: var(--body-size);
      text-align: center;
      transition: background 0.15s ease, color 0.15s ease;
    }
    .menu-option input { position: absolute; opacity: 0; pointer-events: none; }
    .menu-option:hover:not(:has(input:checked)) {
      background: #fff6ee;
    }
    .menu-option:has(input:checked) {
      background: var(--accent);
      color: var(--paper);
      font-weight: 600;
    }
    .menu-option:has(input:checked):hover {
      background: color-mix(in oklab, var(--accent) 85%, black);
    }
    .menu-option:focus-within {
      outline: 2px solid var(--accent);
      outline-offset: 2px;
    }

    /* Fieldset (¿A qué eventos venís?) — reset y label estilo
       convencional. */
    .rsvp-form__fieldset {
      border: 0;
      padding: 0;
      margin: 0;
    }
    .rsvp-form__fieldset > legend {
      padding: 0;
      margin-bottom: 8px;
      font-family: var(--serif);
      font-weight: 600;
      font-size: var(--caption-size);
      color: var(--ink);
    }
    .rsvp-form__fieldset > legend .hint {
      font-weight: 400;
      font-size: var(--caption-size);
      opacity: 0.55;
      margin-left: 6px;
    }

    /* Event option chips — white pills, wine when checked. */
    /* Eventos (¿A qué venís?) — multi-select estilo botón, mismo
       lenguaje visual que los chips de Menú. La palomita ✓ aparece a la
       izquierda cuando está marcado. */
    .event-options {
      display: flex;
      flex-direction: column;
      gap: 8px;
    }
    .event-option {
      display: flex;
      align-items: center;
      justify-content: flex-start;
      gap: 12px;
      padding: 14px 16px;
      background: var(--paper);
      color: var(--ink);
      border-radius: var(--card-radius);
      cursor: pointer;
      font-family: var(--serif);
      font-weight: 500;
      font-size: var(--body-size);
      transition: background 0.15s ease, color 0.15s ease;
    }
    .event-option::before {
      content: "";
      width: 18px;
      height: 18px;
      border-radius: 4px;
      flex-shrink: 0;
      background: rgba(28, 24, 21, 0.08);
    }
    .event-option input { position: absolute; opacity: 0; pointer-events: none; }
    .event-option:hover:not(:has(input:checked)) {
      background: #fff6ee;
    }
    .event-option:has(input:checked) {
      background: var(--accent);
      color: var(--paper);
      font-weight: 600;
    }
    .event-option:has(input:checked):hover {
      background: color-mix(in oklab, var(--accent) 85%, black);
    }
    .event-option:has(input:checked)::before {
      /* Check geométrico (dos trazos rectos) sobre fondo blanco. */
      background:
        var(--paper)
        url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 18' fill='none'%3E%3Cpath d='M4 9.5l3.2 3.2L14 6' stroke='%23036d3e' stroke-width='2.4' stroke-linecap='square' stroke-linejoin='miter'/%3E%3C/svg%3E")
        center/72% no-repeat;
    }
    .event-option:focus-within {
      outline: 2px solid var(--accent);
      outline-offset: 2px;
    }

    /* 2-col row inside a person card (menu + alérgenos). Uses CSS grid
       with display:contents on the inner .field so both labels share
       a row and both inputs share another — even if one label wraps to
       2 lines, the inputs stay aligned at the bottom. */
    .rsvp-form .row {
      display: grid;
      grid-template-columns: 1fr 1fr;
      grid-template-rows: auto auto;
      gap: 8px 14px;
    }
    .rsvp-form .row > .field {
      display: contents;
    }
    .rsvp-form .row > .field > label {
      grid-row: 1;
      align-self: end;
    }
    .rsvp-form .row > .field > input,
    .rsvp-form .row > .field > select,
    .rsvp-form .row > .field > textarea {
      grid-row: 2;
    }
    .rsvp-form .row > .field:nth-child(1) > label,
    .rsvp-form .row > .field:nth-child(1) > input,
    .rsvp-form .row > .field:nth-child(1) > select,
    .rsvp-form .row > .field:nth-child(1) > textarea {
      grid-column: 1;
    }
    .rsvp-form .row > .field:nth-child(2) > label,
    .rsvp-form .row > .field:nth-child(2) > input,
    .rsvp-form .row > .field:nth-child(2) > select,
    .rsvp-form .row > .field:nth-child(2) > textarea {
      grid-column: 2;
    }

    /* Submit — pill verde. */
    .rsvp-form .submit-wrap {
      display: flex;
      justify-content: stretch;
      margin-top: 8px;
    }
    .rsvp-form .submit-wrap .rsvp__cta {
      width: 100%;
      padding: 18px 32px;
      font-size: var(--body-size);
      letter-spacing: 0.16em;
      box-shadow: none;
    }
    @media (hover: hover) {
      .rsvp-form .submit-wrap .rsvp__cta:hover {
        background: color-mix(in oklab, var(--accent) 80%, black);
        box-shadow: none;
      }
    }

    /* Deadline note (inline-styled <p> direct child of form). */
    /* Deadline note al pie del modal — mismo tamaño y peso que el resto,
       sin cursiva, sin opacidad. */
    .rsvp-form__deadline {
      margin: 16px 0 0;
      text-align: center;
      font-family: var(--serif);
      font-weight: 500;
      font-size: var(--body-size);
      color: var(--ink);
    }

    .rsvp-form__status {
      text-align: center;
      font-family: var(--serif);
      font-weight: 500;
      font-size: var(--body-size);
      color: var(--green);
      margin: 0;
    }
    .rsvp-form__status:empty {
      display: none;
    }
    .rsvp-form__status[data-state="error"] { color: var(--red); }

    /* Greatest hits ---------------------------------------------------- */
    .hits {
      justify-content: flex-end;
      /* Padding inferior dinámico: 48px base + safe-area-inset-bottom
         (notch/home indicator) + calc(100lvh - 100svh) (URL bar de
         iOS Safari cuando está visible). Sin esto, el caption queda
         oculto bajo la URL bar porque hits usa justify-content: flex-end
         y empuja todo al fondo. */
      padding-bottom:
        calc(48px + env(safe-area-inset-bottom, 0px) + (100lvh - 100svh));
      color: var(--paper);
      background-color: #2a1a16;
      --panel-bg: #2a1a16;
    }
    .hits .script {
      color: var(--orange);
      position: relative;
      z-index: 20;
    }
    /* Texto de apoyo sobre el overlay — paper translúcido, centrado,
       debajo del título "los greatest hits.". Una sola línea. */
    .hits__caption {
      position: relative;
      z-index: 20;
      margin: 8px auto 0;
      max-width: none;
      white-space: nowrap;
      text-align: center;
      font-family: var(--serif);
      font-weight: 500;
      font-size: var(--body-size);
      line-height: 1.45;
      color: var(--paper);
      opacity: 0.9;
    }
    /* En móvil muy estrecho dejamos que se ajuste para no salirse. */
    @media (max-width: 420px) {
      .hits__caption {
        white-space: normal;
        max-width: 32ch;
        padding: 0 16px;
      }
    }

    /* Deck = lienzo donde se acumulan las polaroids. */
    .hits__deck {
      position: absolute;
      inset: 0;
      z-index: 1;
      pointer-events: none;
    }
    /* Cada polaroid es una foto cuadrada con marco blanco, sombra
       profunda y rotación leve. Posición y rotación las asigna JS al
       crearla (random dentro de zonas distribuidas). Entran con un
       scale + opacidad para dar sensación de "ploj" sobre la mesa. */
    .hits__photo {
      position: absolute;
      width: min(78vmin, 440px);
      aspect-ratio: 1 / 1;
      background-size: cover;
      background-position: center;
      background-repeat: no-repeat;
      background-color: #444;
      border-radius: 4px;
      box-shadow:
        0 0 0 11px white,
        0 0 0 12px rgba(0, 0, 0, 0.08),
        0 22px 42px rgba(0, 0, 0, 0.6),
        0 10px 20px rgba(0, 0, 0, 0.35);
      opacity: 0;
      transform: translate(-50%, -50%) rotate(var(--rot, 0deg)) scale(0.5);
      transition: opacity 600ms ease,
                  transform 700ms cubic-bezier(0.22, 1.4, 0.36, 1);
      will-change: opacity, transform;
    }
    .hits__photo.is-in {
      opacity: 1;
      transform: translate(-50%, -50%) rotate(var(--rot, 0deg)) scale(1);
    }
    /* Salida suave: encoge y desvanece. */
    .hits__photo.is-out {
      opacity: 0;
      transform: translate(-50%, -50%) rotate(var(--rot, 0deg)) scale(0.7);
    }

    /* El overlay-gradient se queda solo en el bottom para sustentar el
       título "los greatest hits." y el caption — el resto del panel es
       fondo oscuro sólido (efecto "mesa"). */
    .hits__overlay {
      position: absolute;
      inset: auto 0 0 0;
      height: 40%;
      background: linear-gradient(
        180deg,
        rgba(42, 26, 22, 0)   0%,
        rgba(42, 26, 22, 0.7) 60%,
        rgba(42, 26, 22, 0.95) 100%
      );
      z-index: 11;
      pointer-events: none;
    }

    /* 3 slides en bucle de 15 s — cada una visible ~4 s con cross-fade. */
    @keyframes hits-cross {
      0%   { opacity: 0; }
      5%   { opacity: 1; }
      33%  { opacity: 1; }
      38%  { opacity: 0; }
      100% { opacity: 0; }
    }

    @media (prefers-reduced-motion: reduce) {
      .hits__slide { animation: none; }
      .hits__slide.is-1 { opacity: 1; }
      .hits__slide.is-2,
      .hits__slide.is-3 { display: none; }
    }

    /* Reduced motion --------------------------------------------------- */
    @media (prefers-reduced-motion: reduce) {
      html { scroll-behavior: auto; }
    }

    /* ------------------------------------------------------------------ *
     * Responsive sizing. These media queries only reassign the sizing
     * knobs declared in :root — the real padding / gap / title size is
     * calc()'d from them, and app.js layers the per-panel --fit-* factors
     * on top so each panel always fits one viewport.
     *
     * The min-width block is FIRST on purpose: on a screen that is wide
     * *and* short (e.g. a 1280x720 laptop) the max-height blocks below
     * come later in the cascade and win, so the titles stay compact.
     * ------------------------------------------------------------------ */

    /* Larger screens — keep the column readable. */
    @media (min-width: 720px) {
      /* All sizing tokens now scale via vmin in :root; no overrides needed.
         Body / hero text max-widths are already in ch units. */
    }

    /* Short screens — laptops at 720px tall, landscape phones, iPhone SE… */
    @media (max-height: 720px) {
      :root {
        --panel-pad-y:      clamp(36px, 7vmin, 72px);
        --panel-gap:        clamp(20px, 3vmin, 32px);
        --script-size:      clamp(72px, 18vmin, 120px);
        --script-leading:   0.85;
      }
    }
    @media (max-height: 560px) {
      :root {
        --panel-pad-y:      clamp(24px, 5vmin, 40px);
        --panel-gap:        clamp(16px, 2.5vmin, 24px);
        --script-size:      clamp(36px, 9vmin, 52px);
        --script-leading:   0.82;
      }
    }
