/*
 * Shared invitation viewport for every theme and entry point.
 * Guest links and catalogue previews are mobile-first, even in a desktop tab.
 * Do not apply to Studio, storefront, or other application pages.
 */
:root { --invitation-phone-width: 440px; }
html { overflow-x: clip; }
body { margin: 0; overflow-x: clip; }

/* A real phone uses all the available width; on laptops the invitation is
   centered within the same maximum width as a large-screen phone. */
body > #invitation {
  position: relative;
  width: 100%;
  max-width: var(--invitation-phone-width);
  min-height: 100dvh;
  margin-inline: auto;
  background: var(--paper, #faf7ef);
  box-sizing: border-box;
}

/* Opening scenes are position:fixed and otherwise escape the constrained
   invitation. Give them the same width and horizontal position as the card.
   This includes carved Haveli doors, Noor-e-Jahan gates and all 16 openings. */
body #invitation .opening-overlay,
body #invitation .cover {
  position: fixed;
  top: 0;
  bottom: 0;
  left: 50%;
  right: auto;
  width: min(100vw, var(--invitation-phone-width));
  max-width: var(--invitation-phone-width);
  height: 100dvh;
  transform: translateX(-50%);
  box-sizing: border-box;
}

/* Keep the same desktop frame during loading, opening and reading.
   The invitation scrolls inside the frame after Open or Skip. */
@media (min-width: 768px) {
  body > #invitation {
    position: fixed;
    inset: 0;
    width: min(100vw, var(--invitation-phone-width));
    height: min(900px, 100dvh);
    min-height: 0;
    max-height: 100dvh;
    margin: auto;
    overflow-x: hidden;
    overflow-y: auto;
    overscroll-behavior: contain;
    scroll-behavior: smooth;
  }

  body #invitation > .sound {
    bottom: max(24px, calc((100dvh - 900px) / 2 + 24px));
  }

  /* All 16 opening scenes fill exactly the capped invitation container.
     Keep their existing appearance and animations; only positioning changes. */
  body.sealed #invitation .opening-overlay,
  body.sealed #invitation .cover {
    position: absolute;
    inset: 0;
    width: 100%;
    max-width: 100%;
    height: 100%;
    max-height: 100%;
    transform: none;
  }

  /* Noor's gate and its 9:16 artboard must follow the container height, not
     100dvh, otherwise the artwork extends beyond the newly capped frame. */
  body.sealed #invitation .op-noor .nj-gateway {
    height: 100%;
  }
  body.sealed #invitation .op-noor .nj-artboard {
    width: max(100%, calc(min(900px, 100dvh) * 0.5625));
  }
}

/* Keep the music toggle over the invitation, not stranded at the far right
   side of a wide desktop monitor. */
body #invitation > .sound {
  right: max(16px, calc((100vw - var(--invitation-phone-width)) / 2 + 16px));
}

/* Preview markings must cover the actual invitation artwork, not the rails. */
body .bulawa-preview-watermark {
  left: 50%;
  right: auto;
  width: min(100vw, var(--invitation-phone-width));
  max-width: var(--invitation-phone-width);
  transform: translateX(-50%);
}
body .template-enquiry-bar {
  max-width: min(calc(100vw - 24px), calc(var(--invitation-phone-width) - 24px));
}

/* The photo lightbox can use the monitor as a dim backdrop, but its
   interactive content remains phone-width. */
body dialog.lightbox {
  width: min(100vw, var(--invitation-phone-width));
  max-width: var(--invitation-phone-width);
  margin-inline: auto;
}

@media (min-width: 480px) {
  html { background: #262923; }
  body { background: #262923 !important; }
  body > #invitation {
    box-shadow: 0 0 0 1px #c4b38b66, 0 14px 58px #0b150e55;
  }

}

@media (max-width: 479px) {
  /* No extra border, margins or artificial device chrome on real phones. */
  body > #invitation { width: 100%; box-shadow: none; }
}

/*
 * Memories gallery: the invitation remains phone-width even on desktops.
 * CSS viewport breakpoints must not turn its 440px inner gallery into the
 * desktop three-column grid. Keep the same two-photo composition everywhere.
 */
body > #invitation .gallery-grid {
  width: 100%;
  max-width: 100%;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
  justify-items: stretch;
}
body > #invitation .gallery-grid > button {
  display: block;
  width: 100%;
  min-width: 0;
  margin: 0;
  padding: 0;
}
body > #invitation .gallery-grid > button > img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 4 / 5;
  object-fit: cover;
}

/* Lock both the document and the fixed opening scene until the guest taps
   Open or Skip. Studio and catalogue previews follow the same rule. */
html:has(body.invitation-loading),
html:has(body.sealed){
  overflow:hidden!important;
  height:100%;
  overscroll-behavior:none;
}
body.invitation-loading,
body.sealed{
  overflow:hidden!important;
  height:100dvh;
  max-height:100dvh;
  overscroll-behavior:none;
}
body.invitation-loading > #invitation,
body.sealed > #invitation{
  max-height:100dvh;
  overflow:hidden;
}
body #invitation .opening-overlay{
  overflow:hidden;
  overscroll-behavior:none;
}
@media(max-height:520px){
  body #invitation .opening-overlay:not(.op-noor):not(.op-haveli){
    padding:22px 12px 14px;
  }
  body #invitation .opening-overlay:not(.op-noor):not(.op-haveli) .op-stage{
    height:160px;
  }
}

/* The first paint uses the same frame as the opening while data loads.
   These styles leave with invitation-loading on both success and failure. */
body.invitation-loading > #invitation {
  display: grid;
  place-items: center;
  background: var(--loading-background, #800020);
  color: var(--loading-text, #F8F4EC);
}
body.invitation-loading > #invitation > p {
  display: grid;
  justify-items: center;
  gap: 22px;
  margin: 0;
  max-width: 100%;
  box-sizing: border-box;
  font: 400 18px/1.6 Georgia, serif;
}
body.invitation-loading > #invitation > p::before {
  content: "";
  width: 32px;
  height: 32px;
  border: 1px solid color-mix(in srgb, var(--loading-accent, #C8A25D) 25%, transparent);
  border-top-color: var(--loading-accent, #C8A25D);
  border-radius: 50%;
  animation: invitation-loading-turn 1.4s linear infinite;
}
@keyframes invitation-loading-turn {
  to { transform: rotate(360deg); }
}
@media (prefers-reduced-motion: reduce) {
  body.invitation-loading > #invitation > p::before { animation: none; }
}

body .template-enquiry-bar{flex-wrap:wrap}
body .template-enquiry-bar label{display:flex;align-items:center;gap:8px;font:11px/1.5 Arial,sans-serif;max-width:100%}
body .template-enquiry-bar select{min-height:36px;max-width:100%;padding:6px;background:#fffdf7;color:#12382e;border:1px solid #c8a25d;border-radius:5px;font:11px Arial,sans-serif}

/* Content responds to the invitation width, never the desktop monitor.
   Containment stays on main so fixed opening/music controls retain their anchors. */
body > #invitation > main { container: invitation / inline-size; min-width:0; width:100%; }
body #invitation .topbar { padding:12px 16px; gap:8px; }
body #invitation .photo-selection-grid { grid-template-columns:repeat(2,minmax(0,1fr)); }
