:root { color-scheme: light; }
.dark { color-scheme: dark; }
body { -webkit-font-smoothing: antialiased; }

/* ══════════════════════════════════════════════════════════════════════════
   IMAGES
   ══════════════════════════════════════════════════════════════════════════ */

/* Every image from `imgTag` carries data-cover unless it asked for contain.
   This says how the picture behaves inside its box — and nothing about how big
   that box is.

   The distinction matters, and getting it wrong is what broke the menu cards:
   an earlier version of this rule also set `width:100%; height:100%`. An
   attribute selector out-specifies a class, so `height:100%` beat the `h-52`
   on the card image; 100% of a parent with no height of its own resolves to
   `auto`, and every card grew to whatever height its photograph happened to
   have. The fix is not a more specific rule — it is for this rule to stop
   having an opinion about size. The box is the layout's business. */
img[data-cover] {
  display: block;
  object-fit: cover;
  object-position: center;
}

/* The lightbox and anything else that opts out. A photo the guest opened on
   purpose should be shown whole, not cropped to a tidy rectangle. */
img.object-contain {
  object-fit: contain;
}

/* ── The picture box on a card ──────────────────────────────────────────────
   Written as real CSS rather than as Tailwind utilities, deliberately.

   Tailwind is loaded from the Play CDN, which generates its rules by watching
   the DOM for class names. Dish cards are built in JavaScript and inserted
   after the page has loaded, so every utility on them depends on that observer
   firing before the paint anyone is looking at. For colour and spacing, losing
   that race costs a moment of plain text. For height it costs the layout: the
   image falls back to its intrinsic size and each card becomes as tall as
   whatever photograph the kitchen happened to upload.

   The height of every dish photo is not a thing to leave to a moving part. One
   class, one number, in a stylesheet the browser has before any card exists.

   `--card-media-height` is the only number to change if these should be taller
   or shorter. */
:root { --card-media-height: 14rem; }        /* 224px */

.media-box {
  position: relative;
  display: block;
  width: 100%;
  height: var(--card-media-height);
  overflow: hidden;
  /* The card is a flex column; without this a long description can squeeze the
     picture, which is the same bug wearing a different hat. */
  flex: 0 0 auto;
}

/* Out of the flow, so the image cannot contribute its own height no matter
   what `object-fit` is doing. This is the property that actually guarantees a
   constant card — object-fit only decides how the picture sits in a box that
   has already been sized. */
.media-box > img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}

/* ── The picture box in the dish dialog ─────────────────────────────────────
   Stacked on a phone: a fixed band, so the photograph cannot push the price
   and the allergens below the fold — which is what the guest opened this for.

   Side by side from 768px: the image column matches the text column exactly,
   whatever the text turns out to be, with a floor so a one-line dish does not
   produce a letterbox. */
.dialog-media {
  position: relative;
  width: 100%;
  height: 16rem;
  overflow: hidden;
}

.dialog-media > img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}

@media (min-width: 768px) {
  .dialog-media {
    /* `height: auto`, not `100%`. The dialog body is a two-column grid and a
       grid item stretches to its row by default, so the box already has the
       text column's height; asking for 100% of a height that is being derived
       from this box's own row is the kind of circular sizing browsers resolve
       differently. Let stretch do it, and keep a floor for short dishes. */
    height: auto;
    min-height: 26rem;
  }
}

/* ── The gallery strip on a phone ───────────────────────────────────────────
   The mosaic is right on a laptop and wrong on a 390px screen, where two
   columns of interiors are a column of postage stamps. A phone gets a strip
   that scrolls sideways under the thumb instead.

   Real CSS for the same reason as `.media-box` above: the cells are built in
   JavaScript, and the whole layout — direction, snapping, cell width — would
   otherwise depend on the Play CDN's observer winning a race against the paint.
   Losing it here does not cost a moment of plain text; it costs a vertical
   stack of full-width photographs.

   The class is applied to `#galleryGrid` in place of the grid utilities, so the
   two layouts never both apply. */
.gallery-strip {
  display: flex;
  /* The cells get their height from `aspect-ratio` below; stretching them to
     the row would be a height derived from a height derived from itself. */
  align-items: flex-start;
  gap: 1rem;
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  padding-bottom: .5rem;

  /* Bleeds to both screen edges while the first cell still lines up with the
     heading above — a strip that stops short of the edge reads as a clipped
     grid rather than as something to swipe. The values mirror the section's
     own `px-5 sm:px-6`, and they are logical properties, so Arabic gets the
     mirror image without a second rule. */
  margin-inline: -1.25rem;
  padding-inline: 1.25rem;

  /* A scrollbar under a row of photographs is noise; the snap points and the
     cut-off cell at the edge already say "this moves". */
  scrollbar-width: none;
}

.gallery-strip::-webkit-scrollbar { display: none; }

.gallery-strip > * {
  position: relative;
  overflow: hidden;
  flex: 0 0 auto;
  /* Just under the full width, so a sliver of the next photograph is always
     showing. That sliver is the affordance — it is what tells a thumb there is
     more without a caption saying so. */
  width: 78vw;
  max-width: 22rem;
  aspect-ratio: 4 / 3;
  scroll-snap-align: center;
}

/* Same reasoning as `.media-box > img`: out of the flow, so the photograph
   fills the cell it was given instead of deciding how tall that cell is. */
.gallery-strip > * > img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}

@media (min-width: 640px) {
  .gallery-strip { margin-inline: -1.5rem; padding-inline: 1.5rem; }
}

/* ── The reviews strip on a phone ───────────────────────────────────────────
   Same idea, different cargo. The grid collapses to one column on a phone, so
   forty approved reviews become forty screens of scrolling between the guest
   and the reservation form. Sideways, it is one screen however many there are.

   Wider cells than the gallery's: a photograph reads at any size, a paragraph
   does not, and a card narrower than about 300px starts breaking sentences
   into three words a line. */
.reviews-strip {
  display: flex;
  gap: 1.25rem;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;

  /* Room for the cards' hover lift and shadow, which would otherwise be
     clipped by the scroll container. */
  padding-block: .5rem;

  margin-inline: -1.25rem;
  padding-inline: 1.25rem;
  scrollbar-width: none;
}

.reviews-strip::-webkit-scrollbar { display: none; }

.reviews-strip > * {
  flex: 0 0 auto;
  width: 85vw;
  max-width: 24rem;
  scroll-snap-align: center;
  /* Every card as tall as the tallest, so the row has one baseline instead of
     a ragged edge that moves as you swipe. A flex container stretches its
     children by default; this only says so out loud, because the cards are
     `flex flex-col` and it is the property their inner layout depends on. */
  align-self: stretch;
}

@media (min-width: 640px) {
  .reviews-strip { margin-inline: -1.5rem; padding-inline: 1.5rem; }
}

/* ══════════════════════════════════════════════════════════════════════════
   MOTION & SURFACES
   ══════════════════════════════════════════════════════════════════════════ */

/* Scroll reveal */
.reveal { opacity: 0; transform: translateY(28px); transition: opacity .7s cubic-bezier(.22,1,.36,1), transform .7s cubic-bezier(.22,1,.36,1); }
.reveal.is-visible { opacity: 1; transform: none; }

/* Glass */
.glass { backdrop-filter: saturate(180%) blur(16px); -webkit-backdrop-filter: saturate(180%) blur(16px); }

/* Hairline divider with gradient */
.hairline { background-image: linear-gradient(90deg, transparent, rgba(200,136,44,.55), transparent); height:1px; }

/* Skeleton */
.skel { position:relative; overflow:hidden; background:rgba(120,120,130,.14); }
.skel::after { content:''; position:absolute; inset:0; transform:translateX(-100%);
  background:linear-gradient(90deg,transparent,rgba(255,255,255,.18),transparent); animation:shimmer 1.6s infinite; }
@keyframes shimmer { 100% { transform: translateX(100%); } }

/* Modal */
dialog::backdrop { background: rgba(6,6,8,.72); backdrop-filter: blur(6px); }
dialog[open] { animation: modalIn .28s cubic-bezier(.22,1,.36,1); }
@keyframes modalIn { from { opacity:0; transform: translateY(12px) scale(.98); } }

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: .001ms !important; transition-duration: .001ms !important; }
  .reveal { opacity:1; transform:none; }
  .slide { transition: opacity .3s ease; }
}
