@layer components {

/* Nutrition Facts Modal */
.nutrition-modal {
  width: 100%;
  max-width: min(760px, 92vw);
  max-height: 88vh;
  margin: auto;
  padding: 0;
  border: none;
  border-radius: 20px;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.25);
  /* Resting/closed appearance. Open and close now share this one
     duration/easing (see .nutrition-modal[open] below), so there's a
     single transition per element instead of a separate one per
     direction — JS drives the actual close via .is-closing and only
     calls the real .close() once it's done, so by the time this bare
     rule re-applies, opacity/transform are already at these values. */
  opacity: 0;
  transform: scale(0.96) translateY(10px);
  transition: opacity 0.3s ease, transform 0.3s ease;
}

.nutrition-modal[open] {
  opacity: 1;
  transform: none;
}

/* Desktop only: give the modal its own vertical scroll. On desktop the JS
   locks the page while the modal is open (see app.js), so if a product's
   facts ever exceed the modal's max-height, they scroll *inside* the modal
   rather than being trapped by the page lock. The mobile bottom sheet is
   deliberately excluded — it shares the page's scroll to reveal its height. */
@media (min-width: 701px) {
  .nutrition-modal {
    overflow: hidden auto;
  }
}

/* The starting point for the *entry* transition specifically — without
   this, the dialog would just snap straight to the [open] state above. */
@starting-style {
  .nutrition-modal[open] {
    opacity: 0;
    transform: scale(0.96) translateY(10px);
  }
}

/* JS-driven close (see app.js): Safari doesn't reliably honor an
   allow-discrete exit transition for a <dialog> on its own — it can drop
   straight to display:none regardless of the declared duration. So JS
   adds this class first, waits for the transition above to actually
   finish, and only then calls the real .close(). */
.nutrition-modal[open].is-closing {
  opacity: 0;
  transform: scale(0.96) translateY(10px);
}

.nutrition-modal::backdrop {
  background: rgba(0, 0, 0, 0);
  transition: background-color 0.3s ease;
}

.nutrition-modal[open]::backdrop {
  background: rgba(0, 0, 0, 0.55);
}

.nutrition-modal[open].is-closing::backdrop {
  background: rgba(0, 0, 0, 0);
}

@starting-style {
  .nutrition-modal[open]::backdrop {
    background: rgba(0, 0, 0, 0);
  }
}

.nutrition-modal__inner {
  position: relative;
  padding: 1.5rem;
}

/* Title + close share a centered flex row (matches the flyer modal's header),
   so the X lines up with the title instead of floating above it. */
.nutrition-modal__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 1.25rem;
}

.nutrition-modal__close {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 24px;
  height: 24px;
  padding: 0;
  border: none;
  background: none;
  color: var(--brand-primary);
  cursor: pointer;
  transition: opacity 0.15s ease;
}

.nutrition-modal__close:hover {
  opacity: 0.7;
}

.nutrition-modal__close-icon {
  display: block;
  width: 100%;
  height: 100%;
}

.nutrition-modal__title {
  color: var(--brand-primary);
  font-size: 1.75rem;
  font-weight: 500;
  /* Spacing now lives on .nutrition-modal__header — the old right margin
     (to clear the absolutely-positioned close) and bottom margin are gone. */
  margin: 0;
}

.nutrition-modal__media {
  height: 250px;
  margin-bottom: 1.5rem;
  overflow: hidden;
  border-radius: 10px;
  border: 1.5px solid rgba(0, 0, 0, 0.02);
  filter:
    drop-shadow(rgba(0, 0, 0, 0.06) 2px 4px 6px)
    drop-shadow(rgba(0, 0, 0, 0.03) 1px 2px 3px);
  /* Force a stable GPU layer so iOS WebKit doesn't drop this rounded,
     filtered image when the sheet scrolls ("image vanishes on scroll"). */
  transform: translateZ(0);
}

/* A fixed container height (rather than an aspect-ratio range) keeps the
   crop identical at every viewport width — see the object-position rule
   below, which is tuned against this exact box shape. */
.nutrition-modal__media img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.nutrition-modal__media img[src*="products-sheilas-sandwich-bread"] {
  object-position: center 40%;
}

.nutrition-modal__columns {
  display: grid;
  grid-template-columns: minmax(0, 280px) minmax(0, 1fr);
  align-items: start;
  gap: 1.75rem;
}

.nutrition-modal__side {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}

@media (max-width: 700px) {
  .nutrition-modal {
    /* svh = the SMALL viewport height (toolbars shown). iOS Safari's `vh`
       measures the *large* viewport, so 92vh there ≈ the whole visible area
       when the toolbar is up — the sheet's top slid under the status bar.
       svh is always relative to the visible area, keeping the top gap real.
       The vh line is a fallback for browsers without svh support. */
    max-height: 92vh;
    max-height: 92svh;
    max-width: 100%;
    width: 100%;
    margin: 0;
    position: fixed;
    inset: auto 0 0 0;
    border-radius: 20px 20px 0 0;
    /* Scroll the (tall) facts INSIDE the sheet, like the flyer modal, which
       renders correctly on iOS. Without this the mobile nutrition modal has
       no scroll container of its own, so on iOS WebKit its content spills
       (Safari opens it mis-positioned) and the rounded image repaints away
       on scroll. overscroll-behavior: contain stops the scroll chaining to
       the page behind (the background isn't locked on mobile). */
    overflow: hidden auto;
    overscroll-behavior: contain;
    /* Apple-style bottom sheet: slide up from off-screen instead of the
       desktop fade+scale. No opacity fade here — only the backdrop dims;
       the sheet itself just translates, like an iOS action sheet. Open
       and close share this one duration now — see the desktop rule above
       for why that removed the need for a separate [open] override here. */
    opacity: 1;
    transform: translateY(100%);
    transition: transform 0.6s cubic-bezier(0.32, 0.72, 0, 1);
  }

  /* JS-driven close override — see the desktop .is-closing rule for why.
     Also re-assert opacity: 1 here: the desktop .is-closing rule sets
     opacity: 0, and since opacity isn't in this breakpoint's transition
     list, that would snap the sheet invisible instantly — making the
     0.6s slide-down play out on an already-hidden element. The mobile
     sheet only translates; it never fades. */
  .nutrition-modal[open].is-closing {
    opacity: 1;
    transform: translateY(100%);
  }

  @starting-style {
    .nutrition-modal[open] {
      transform: translateY(100%);
    }
  }

  .nutrition-modal__title {
    font-size: 1.4rem;
  }

  .nutrition-modal__columns {
    grid-template-columns: 1fr;
  }

  .nutrition-label {
    max-width: 340px;
    margin: 0 auto;
  }
}

}
