/* ============================================================================
   illos.css — design tokens + the animation system
   ----------------------------------------------------------------------------
   Tailwind (loaded from the CDN) handles layout and spacing. This file owns
   the two things utility classes cannot express well: the brand's visual
   identity, and motion.

   Motion here is treated as a feature, not decoration:
     • Scroll reveals driven by IntersectionObserver (see assets/js/illos.js),
       so nothing animates until it is actually on screen.
     • Every effect is GPU-friendly — transform and opacity only, never
       width/top/left, which cause layout thrash on mid-range Android.
     • Every animation is disabled under prefers-reduced-motion. This is not
       optional politeness: motion sickness is real, and iOS/Android expose
       the setting prominently.
   ========================================================================== */

/* ---------------------------------------------------------------------------
   1. TOKENS
   ------------------------------------------------------------------------- */
:root {
  --gold:          #D4AF37;
  --gold-soft:     #E8CD70;
  --gold-deep:     #A8862A;
  --ink:           #0A0A0A;
  --ink-2:         #141414;
  --ink-3:         #1E1E1E;
  --line:          rgba(212, 175, 55, 0.18);
  --paper:         #FAF8F3;
  --muted:         #9A9A9A;

  --font-display:  'Cormorant Garamond', 'Playfair Display', Georgia, serif;
  --font-body:     'Poppins', system-ui, -apple-system, 'Segoe UI', sans-serif;

  --ease-out:      cubic-bezier(0.22, 1, 0.36, 1);
  --ease-in-out:   cubic-bezier(0.65, 0, 0.35, 1);
  --ease-spring:   cubic-bezier(0.34, 1.56, 0.64, 1);

  --nav-h:         76px;
}

/* ---------------------------------------------------------------------------
   2. BASE
   ------------------------------------------------------------------------- */
* { -webkit-tap-highlight-color: transparent; }

html { scroll-behavior: smooth; }
/* An in-page jump must not hide the target under the fixed navbar. */
html { scroll-padding-top: var(--nav-h); }

body {
  font-family: var(--font-body);
  background-color: var(--ink);
  color: #EDEDED;
  overflow-x: hidden;
  /* Stops iOS Safari inflating font sizes in landscape. */
  -webkit-text-size-adjust: 100%;
  text-rendering: optimizeLegibility;
}

h1, h2, h3, .display { font-family: var(--font-display); font-weight: 600; }

::selection { background: var(--gold); color: #000; }

/* Scrollbar — Chromium/WebKit, then Firefox. */
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: var(--ink-2); }
::-webkit-scrollbar-thumb {
  background: linear-gradient(var(--gold-deep), var(--gold));
  border-radius: 99px;
  border: 2px solid var(--ink-2);
}
::-webkit-scrollbar-thumb:hover { background: var(--gold-soft); }
* { scrollbar-width: thin; scrollbar-color: var(--gold-deep) var(--ink-2); }

/* Used by the category rail and mini-cart, which scroll but must look clean. */
.hide-scrollbar { -ms-overflow-style: none; scrollbar-width: none; }
.hide-scrollbar::-webkit-scrollbar { display: none; }

/* Visible keyboard focus. Removing outlines without a replacement makes a
   site unusable by keyboard, so this restores an on-brand one. */
:where(a, button, input, select, textarea, [tabindex]):focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 3px;
  border-radius: 4px;
}

/* ---------------------------------------------------------------------------
   3. ANIMATED BACKGROUND  —  "Golden Ember Drift"
   ---------------------------------------------------------------------------
   The site is dark-only, so the background is doing real work: on a flat black
   page every section boundary looks like a seam. These layers keep the black
   alive without ever competing with the food photography.

   Seven layers, all pure CSS — no canvas, no JS, no image requests:

     .bg-stage    the fixed container; owns the base ink gradient, which is
                  warmer at the top so the page is never a dead flat black
     .bg-orbs     three large gold light pools, each on its OWN path and its
                  own duration. Three separate loops of different lengths never
                  line back up, so the motion never looks like a short GIF
     .bg-beams    a very slow conic sweep — a light turning across the room
     .bg-aurora   the original drifting pools, kept as the mid-tone wash
     .bg-mesh     a faint grid, panning, that gives the black some depth
     .bg-embers   slow rising sparks — the movement the eye actually catches
     .bg-grain    a film-grain veil that stops the gradients banding
     .bg-vignette darkened edges so content in the middle stays the focus

   Everything animates on transform / opacity / background-position only, so
   the compositor handles it on the GPU and the main thread stays free for
   scrolling. Nothing here paints above z-index -1 and nothing takes pointer
   events, so no layer can ever intercept a tap on a button.
   ------------------------------------------------------------------------- */
.bg-stage {
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  overflow: hidden;
  /* Static on purpose. Animating a gradient on a full-viewport element means
     repainting the entire screen every frame; the orbs and beams below give
     the same impression using transforms, which the GPU handles for free. */
  background:
    radial-gradient(120% 90% at 50% -10%, #16130B 0%, transparent 58%),
    linear-gradient(175deg, #0C0B08 0%, #0A0A0A 46%, #08070A 100%);
}

/* --- Orbs: the main sense of movement -------------------------------------- */
.bg-orbs { position: absolute; inset: 0; }

.bg-orbs i {
  position: absolute;
  display: block;
  border-radius: 50%;
  filter: blur(70px);
  will-change: transform;
  opacity: 0.55;
}

.bg-orbs i:nth-child(1) {
  width: 46vw; height: 46vw;
  top: -8%; left: -6%;
  background: radial-gradient(circle, rgba(212,175,55,0.30), transparent 68%);
  animation: orb-a 38s var(--ease-in-out) infinite alternate;
}
.bg-orbs i:nth-child(2) {
  width: 40vw; height: 40vw;
  top: 34%; right: -10%; left: auto;
  background: radial-gradient(circle, rgba(168,134,42,0.26), transparent 68%);
  animation: orb-b 47s var(--ease-in-out) infinite alternate;
}
.bg-orbs i:nth-child(3) {
  width: 52vw; height: 52vw;
  bottom: -18%; left: 22%;
  background: radial-gradient(circle, rgba(232,205,112,0.18), transparent 70%);
  animation: orb-c 59s var(--ease-in-out) infinite alternate;
}

/* Different distances AND different durations — the three never resynchronise. */
@keyframes orb-a {
  0%   { transform: translate3d(0, 0, 0) scale(1); }
  50%  { transform: translate3d(14vw, 9vh, 0) scale(1.16); }
  100% { transform: translate3d(5vw, 20vh, 0) scale(0.94); }
}
@keyframes orb-b {
  0%   { transform: translate3d(0, 0, 0) scale(1.04); }
  50%  { transform: translate3d(-16vw, -11vh, 0) scale(0.9); }
  100% { transform: translate3d(-6vw, 12vh, 0) scale(1.2); }
}
@keyframes orb-c {
  0%   { transform: translate3d(0, 0, 0) scale(0.96); }
  50%  { transform: translate3d(11vw, -14vh, 0) scale(1.18); }
  100% { transform: translate3d(-9vw, -5vh, 0) scale(1.02); }
}

/* --- Beams: a slow turning light ------------------------------------------- */
.bg-beams {
  position: absolute;
  top: 50%; left: 50%;
  width: 165vmax; height: 165vmax;
  margin: -82.5vmax 0 0 -82.5vmax;
  background: conic-gradient(
    from 0deg,
    transparent 0deg,
    rgba(212,175,55,0.075) 18deg,
    transparent 46deg,
    transparent 150deg,
    rgba(232,205,112,0.055) 176deg,
    transparent 210deg,
    transparent 300deg,
    rgba(168,134,42,0.06) 326deg,
    transparent 356deg
  );
  /* Softened at the centre, faded at the rim — otherwise it reads as a pie chart. */
  mask-image: radial-gradient(circle, transparent 4%, #000 34%, transparent 76%);
  -webkit-mask-image: radial-gradient(circle, transparent 4%, #000 34%, transparent 76%);
  filter: blur(26px);
  animation: beams-turn 120s linear infinite;
  will-change: transform;
}

@keyframes beams-turn {
  to { transform: rotate(360deg); }
}

/* --- Aurora: the original mid-tone wash, kept ------------------------------ */
.bg-aurora {
  position: absolute;
  inset: -20%;
  background:
    radial-gradient(38% 44% at 18% 22%, rgba(212, 175, 55, 0.13), transparent 62%),
    radial-gradient(32% 38% at 82% 30%, rgba(168, 134, 42, 0.11), transparent 60%),
    radial-gradient(44% 46% at 50% 88%, rgba(232, 205, 112, 0.08), transparent 66%);
  filter: blur(18px);
  animation: aurora-drift 34s var(--ease-in-out) infinite alternate;
  will-change: transform;
}

@keyframes aurora-drift {
  0%   { transform: translate3d(0, 0, 0) scale(1); }
  50%  { transform: translate3d(-3%, 2.5%, 0) scale(1.09); }
  100% { transform: translate3d(2.5%, -2%, 0) scale(1.04); }
}

/* --- Mesh: panning grid ---------------------------------------------------- */
.bg-mesh {
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(rgba(212, 175, 55, 0.042) 1px, transparent 1px),
    linear-gradient(90deg, rgba(212, 175, 55, 0.042) 1px, transparent 1px);
  background-size: 68px 68px;
  /* Fades the grid out toward the edges so it never looks like a table. */
  mask-image: radial-gradient(circle at 50% 40%, #000 10%, transparent 76%);
  -webkit-mask-image: radial-gradient(circle at 50% 40%, #000 10%, transparent 76%);
  animation: mesh-pan 60s linear infinite;
}

@keyframes mesh-pan {
  to { background-position: 68px 68px, 68px 68px; }
}

/* --- Embers: slow rising sparks -------------------------------------------- */
/* Each <i> carries its own --x (start column), --dur, --delay, --size and
   --drift from the markup, so eighteen spans give eighteen distinct paths from
   one keyframe. Writing them as one animation keeps the CSS short and lets the
   compositor run every one of them off the main thread. */
.bg-embers { position: absolute; inset: 0; overflow: hidden; }

.bg-embers i {
  position: absolute;
  bottom: -6vh;
  left: var(--x, 50%);
  width: var(--size, 3px);
  height: var(--size, 3px);
  border-radius: 50%;
  background: var(--gold-soft);
  box-shadow: 0 0 6px rgba(212, 175, 55, 0.85);
  opacity: 0;
  animation: ember-rise var(--dur, 22s) linear var(--delay, 0s) infinite;
  will-change: transform, opacity;
}

@keyframes ember-rise {
  0%   { transform: translate3d(0, 0, 0) scale(0.6);                  opacity: 0; }
  8%   {                                                              opacity: 0.85; }
  50%  { transform: translate3d(var(--drift, 3vw), -55vh, 0) scale(1); opacity: 0.6; }
  85%  {                                                              opacity: 0.25; }
  100% { transform: translate3d(calc(var(--drift, 3vw) * -0.6), -112vh, 0) scale(0.5); opacity: 0; }
}

/* --- Grain + vignette ------------------------------------------------------ */
.bg-grain {
  position: absolute;
  inset: -150%;
  opacity: 0.032;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='180' height='180'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/></filter><rect width='180' height='180' filter='url(%23n)'/></svg>");
  animation: grain-shift 700ms steps(4) infinite;
}

@keyframes grain-shift {
  0%   { transform: translate(0, 0); }
  25%  { transform: translate(-2%, 1.5%); }
  50%  { transform: translate(1.5%, -1%); }
  75%  { transform: translate(-1%, -1.5%); }
  100% { transform: translate(0, 0); }
}

.bg-vignette {
  position: absolute;
  inset: 0;
  background: radial-gradient(120% 80% at 50% 40%, transparent 42%, rgba(0,0,0,0.55) 100%);
}

/* ---------------------------------------------------------------------------
   4. SCROLL REVEALS
   ---------------------------------------------------------------------------
   Add data-reveal to any element. illos.js adds .is-visible when it scrolls
   into view. data-reveal-delay="200" staggers it by 200ms.

   The starting state is only applied when JS is present (html.js), so if a
   script fails to load the content is visible rather than permanently blank —
   this is why the old AOS-based About page went empty for some users.
   ------------------------------------------------------------------------- */
.js [data-reveal] {
  opacity: 0;
  transition:
    opacity 800ms var(--ease-out),
    transform 800ms var(--ease-out),
    filter 800ms var(--ease-out);
  will-change: opacity, transform;
}

.js [data-reveal="up"]      { transform: translate3d(0, 38px, 0); }
.js [data-reveal="down"]    { transform: translate3d(0, -30px, 0); }
.js [data-reveal="left"]    { transform: translate3d(-48px, 0, 0); }
.js [data-reveal="right"]   { transform: translate3d(48px, 0, 0); }
.js [data-reveal="zoom"]    { transform: scale(0.9); }
.js [data-reveal="fade"]    { transform: none; }
.js [data-reveal="blur"]    { filter: blur(10px); transform: scale(1.03); }
.js [data-reveal="tilt"]    { transform: perspective(1000px) rotateX(-11deg) translate3d(0, 34px, 0); }

.js [data-reveal].is-visible {
  opacity: 1;
  transform: none;
  filter: none;
}

/* Reveal every direct child in sequence: <div data-reveal-group> */
.js [data-reveal-group] > * {
  opacity: 0;
  transform: translate3d(0, 26px, 0);
  transition: opacity 640ms var(--ease-out), transform 640ms var(--ease-out);
}
.js [data-reveal-group].is-visible > * { opacity: 1; transform: none; }
.js [data-reveal-group].is-visible > *:nth-child(1)  { transition-delay:  40ms; }
.js [data-reveal-group].is-visible > *:nth-child(2)  { transition-delay: 100ms; }
.js [data-reveal-group].is-visible > *:nth-child(3)  { transition-delay: 160ms; }
.js [data-reveal-group].is-visible > *:nth-child(4)  { transition-delay: 220ms; }
.js [data-reveal-group].is-visible > *:nth-child(5)  { transition-delay: 280ms; }
.js [data-reveal-group].is-visible > *:nth-child(6)  { transition-delay: 340ms; }
.js [data-reveal-group].is-visible > *:nth-child(7)  { transition-delay: 400ms; }
.js [data-reveal-group].is-visible > *:nth-child(8)  { transition-delay: 460ms; }
.js [data-reveal-group].is-visible > *:nth-child(n+9){ transition-delay: 520ms; }

/* ---------------------------------------------------------------------------
   5. TEXT EFFECTS
   ------------------------------------------------------------------------- */

/* Gold gradient text with a slow shimmer sweep. */
.text-gold-shimmer {
  background: linear-gradient(
    100deg,
    var(--gold-deep) 0%, var(--gold) 22%, #FFF6D8 42%,
    var(--gold) 60%, var(--gold-deep) 100%
  );
  background-size: 260% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
  animation: shimmer-sweep 7s linear infinite;
}

@keyframes shimmer-sweep {
  0%   { background-position: 180% 0; }
  100% { background-position: -80% 0; }
}

/* A gold hairline that grows out from the centre under a heading. */
.rule-gold {
  position: relative;
  display: inline-block;
  padding-bottom: 16px;
}
.rule-gold::after {
  content: '';
  position: absolute;
  left: 50%;
  bottom: 0;
  width: 0;
  height: 2px;
  background: linear-gradient(90deg, transparent, var(--gold), transparent);
  transform: translateX(-50%);
  transition: width 900ms var(--ease-out) 200ms;
}
.rule-gold.is-visible::after,
.is-visible .rule-gold::after { width: 128px; }

/* Letters rise into place one after another. Spans are built by illos.js. */
.split-lift > span {
  display: inline-block;
  opacity: 0;
  transform: translate3d(0, 0.7em, 0) rotate(4deg);
  transition: opacity 620ms var(--ease-out), transform 620ms var(--ease-spring);
}
.split-lift.is-visible > span { opacity: 1; transform: none; }

/* ---------------------------------------------------------------------------
   6. INTERACTIVE PIECES
   ------------------------------------------------------------------------- */

/* Gold button with a light sweep on hover. */
.btn-gold {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  background: linear-gradient(135deg, var(--gold) 0%, var(--gold-soft) 52%, var(--gold-deep) 100%);
  color: #100D04;
  font-weight: 600;
  letter-spacing: 0.02em;
  transition: transform 320ms var(--ease-spring), box-shadow 320ms var(--ease-out);
}
.btn-gold::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(115deg, transparent 32%, rgba(255,255,255,0.6) 50%, transparent 68%);
  transform: translateX(-110%);
  transition: transform 720ms var(--ease-out);
}
.btn-gold:hover { transform: translateY(-2px); box-shadow: 0 14px 34px -10px rgba(212,175,55,0.6); }
.btn-gold:hover::before { transform: translateX(110%); }
.btn-gold:active { transform: translateY(0) scale(0.985); }

/* Outline button that fills from the bottom. */
.btn-outline-gold {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  border: 1px solid var(--gold);
  color: var(--gold);
  font-weight: 500;
  transition: color 300ms var(--ease-out), transform 300ms var(--ease-spring);
}
.btn-outline-gold::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--gold);
  transform: translateY(101%);
  transition: transform 380ms var(--ease-out);
}
.btn-outline-gold:hover { color: #100D04; transform: translateY(-2px); }
.btn-outline-gold:hover::before { transform: translateY(0); }

/* Dish / content card: lifts, gains a gold edge, image pushes in slightly. */
.card-lift {
  transition:
    transform 480ms var(--ease-out),
    box-shadow 480ms var(--ease-out),
    border-color 480ms var(--ease-out);
  will-change: transform;
}
.card-lift:hover {
  transform: translateY(-8px);
  border-color: rgba(212, 175, 55, 0.55);
  box-shadow: 0 26px 52px -18px rgba(0,0,0,0.85), 0 0 0 1px rgba(212,175,55,0.22);
}
.card-lift .card-media { overflow: hidden; }
.card-lift .card-media img {
  transition: transform 760ms var(--ease-out), filter 500ms var(--ease-out);
  will-change: transform;
}
.card-lift:hover .card-media img { transform: scale(1.08); filter: brightness(1.06); }

/* A gold sheen that travels across a card on hover. */
.sheen { position: relative; overflow: hidden; }
.sheen::after {
  content: '';
  position: absolute;
  top: 0;
  left: -75%;
  width: 50%;
  height: 100%;
  background: linear-gradient(90deg, transparent, rgba(212,175,55,0.18), transparent);
  transform: skewX(-22deg);
  transition: left 780ms var(--ease-out);
  pointer-events: none;
}
.sheen:hover::after { left: 125%; }

/* Category pill for the menu rail. */
.pill {
  position: relative;
  white-space: nowrap;
  border: 1px solid rgba(212, 175, 55, 0.3);
  color: #D8D8D8;
  background: rgba(255, 255, 255, 0.03);
  transition:
    color 260ms var(--ease-out),
    border-color 260ms var(--ease-out),
    background-color 260ms var(--ease-out),
    transform 260ms var(--ease-spring);
}
.pill:hover { color: var(--gold); border-color: var(--gold); transform: translateY(-2px); }
.pill.active {
  color: #100D04;
  background: linear-gradient(135deg, var(--gold), var(--gold-soft));
  border-color: var(--gold);
  font-weight: 600;
  box-shadow: 0 8px 22px -8px rgba(212,175,55,0.65);
}

/* Underline that grows in from the left — navbar links. */
.link-underline { position: relative; }
.link-underline::after {
  content: '';
  position: absolute;
  left: 0;
  bottom: -5px;
  width: 100%;
  height: 1.5px;
  background: var(--gold);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 360ms var(--ease-out);
}
.link-underline:hover::after,
.link-underline[aria-current="page"]::after { transform: scaleX(1); }

/* ---------------------------------------------------------------------------
   7. HERO
   ------------------------------------------------------------------------- */
.hero-stage {
  position: relative;
  width: 100%;
  height: 100vh;
  /* Dynamic viewport height, so mobile browser chrome does not crop the hero. */
  height: 100dvh;
  overflow: hidden;
  background: #000;
}

.hero-stage video,
.hero-stage .hero-fallback {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Slow push-in gives a still-ish video some life. */
  animation: hero-push 26s var(--ease-in-out) infinite alternate;
}

@keyframes hero-push {
  from { transform: scale(1); }
  to   { transform: scale(1.07); }
}

.hero-veil {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(to bottom, rgba(0,0,0,0.62) 0%, rgba(0,0,0,0.34) 42%, rgba(10,10,10,0.96) 100%),
    radial-gradient(70% 60% at 50% 45%, transparent 30%, rgba(0,0,0,0.5) 100%);
}

.hero-body {
  position: relative;
  z-index: 2;
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 0 1.25rem;
}

/* The little bobbing scroll cue. */
.scroll-cue {
  position: absolute;
  left: 50%;
  bottom: 30px;
  transform: translateX(-50%);
  z-index: 3;
  animation: cue-bob 2.3s var(--ease-in-out) infinite;
}
@keyframes cue-bob {
  0%, 100% { transform: translateX(-50%) translateY(0);    opacity: 0.85; }
  50%      { transform: translateX(-50%) translateY(11px); opacity: 0.35; }
}

@media (max-width: 768px) {
  .hero-stage { height: 68vh; height: 68dvh; }
}

/* ---------------------------------------------------------------------------
   8. TIMELINE  (the Our Story page)
   ---------------------------------------------------------------------------
   Same left/right alternating shape as the original, but the spine now draws
   itself as you scroll (--spine is set by illos.js) instead of just sitting
   there, and each card animates in from its own side.
   ------------------------------------------------------------------------- */
.timeline { position: relative; padding: 12px 0 40px; }

/* The dim full-length track. */
.timeline::before {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  width: 2px;
  margin-left: -1px;
  background: rgba(212, 175, 55, 0.16);
}

/* The bright section that fills as you scroll. */
.timeline::after {
  content: '';
  position: absolute;
  top: 0;
  left: 50%;
  width: 2px;
  margin-left: -1px;
  height: var(--spine, 0%);
  background: linear-gradient(180deg, var(--gold-soft), var(--gold), var(--gold-deep));
  box-shadow: 0 0 16px rgba(212, 175, 55, 0.7);
  transition: height 180ms linear;
}

.tl-item {
  position: relative;
  width: 50%;
  padding: 0 42px 56px;
  box-sizing: border-box;
}
.tl-item.left  { left: 0; text-align: right; }
.tl-item.right { left: 50%; text-align: left; }

/* The node on the spine. */
.tl-item::after {
  content: '';
  position: absolute;
  top: 26px;
  width: 15px;
  height: 15px;
  border-radius: 50%;
  background: var(--ink);
  border: 2px solid var(--gold);
  z-index: 2;
  transition: transform 460ms var(--ease-spring), box-shadow 460ms var(--ease-out), background-color 460ms;
}
.tl-item.left::after  { right: -8.5px; }
.tl-item.right::after { left: -8.5px; }

.tl-item.is-visible::after {
  background: var(--gold);
  transform: scale(1.42);
  box-shadow: 0 0 0 6px rgba(212, 175, 55, 0.16), 0 0 20px rgba(212, 175, 55, 0.85);
}

.tl-card {
  background: linear-gradient(155deg, rgba(30,30,30,0.94), rgba(14,14,14,0.94));
  border: 1px solid var(--line);
  border-radius: 16px;
  padding: 24px 26px;
  backdrop-filter: blur(6px);
  transition: transform 520ms var(--ease-out), border-color 420ms, box-shadow 420ms;
}
.tl-card:hover {
  transform: translateY(-6px);
  border-color: rgba(212, 175, 55, 0.5);
  box-shadow: 0 24px 48px -20px rgba(0,0,0,0.9);
}

.tl-year {
  font-family: var(--font-display);
  font-size: 1.7rem;
  font-weight: 600;
  line-height: 1.1;
  color: var(--gold);
}
.tl-title {
  font-size: 0.94rem;
  font-weight: 500;
  color: #C9C9C9;
  margin-top: 3px;
}
.tl-copy {
  font-size: 0.9rem;
  line-height: 1.72;
  color: #A8A8A8;
  margin-top: 12px;
}

.tl-media {
  margin-top: 16px;
  border-radius: 12px;
  overflow: hidden;
  border: 1px solid rgba(212, 175, 55, 0.14);
  aspect-ratio: 16 / 10;
  background: var(--ink-3);
}
.tl-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 900ms var(--ease-out);
}
.tl-card:hover .tl-media img { transform: scale(1.07); }

/* Single column on tablet and phone, spine moved to the left edge. */
@media (max-width: 860px) {
  .timeline::before,
  .timeline::after { left: 21px; }

  .tl-item {
    width: 100%;
    left: 0 !important;
    text-align: left !important;
    padding: 0 0 40px 54px;
  }
  .tl-item::after {
    left: 14px !important;
    right: auto !important;
    top: 22px;
  }
  .tl-year { font-size: 1.45rem; }
}

/* ---------------------------------------------------------------------------
   9. MINI CART
   ------------------------------------------------------------------------- */
.cart-drawer {
  position: fixed;
  top: 0;
  right: 0;
  height: 100%;
  height: 100dvh;
  width: 100%;
  max-width: 400px;
  z-index: 1200;
  background: linear-gradient(180deg, var(--ink-2), var(--ink));
  border-left: 1px solid var(--line);
  box-shadow: -24px 0 60px -20px rgba(0,0,0,0.9);
  transform: translateX(100%);
  transition: transform 440ms var(--ease-out);
  display: flex;
  flex-direction: column;
}
.cart-drawer.open { transform: translateX(0); }

.cart-scrim {
  position: fixed;
  inset: 0;
  z-index: 1150;
  background: rgba(0,0,0,0.66);
  backdrop-filter: blur(3px);
  opacity: 0;
  visibility: hidden;
  transition: opacity 380ms var(--ease-out), visibility 380ms;
}
.cart-scrim.open { opacity: 1; visibility: visible; }

/* Rows slide in one after another when the drawer opens. */
.cart-drawer.open .cart-row {
  animation: row-in 420ms var(--ease-out) backwards;
}
.cart-drawer.open .cart-row:nth-child(1) { animation-delay:  60ms; }
.cart-drawer.open .cart-row:nth-child(2) { animation-delay: 110ms; }
.cart-drawer.open .cart-row:nth-child(3) { animation-delay: 160ms; }
.cart-drawer.open .cart-row:nth-child(4) { animation-delay: 210ms; }
.cart-drawer.open .cart-row:nth-child(n+5) { animation-delay: 260ms; }

@keyframes row-in {
  from { opacity: 0; transform: translateX(26px); }
  to   { opacity: 1; transform: none; }
}

/* The badge pops when the count changes. */
.badge-pop { animation: badge-pop 520ms var(--ease-spring); }
@keyframes badge-pop {
  0%   { transform: scale(1); }
  35%  { transform: scale(1.55); }
  100% { transform: scale(1); }
}

/* ---------------------------------------------------------------------------
   10. MODAL
   ------------------------------------------------------------------------- */
.modal-shell {
  position: fixed;
  inset: 0;
  z-index: 1300;
  display: none;
  align-items: center;
  justify-content: center;
  padding: 1rem;
}
.modal-shell.open { display: flex; }

.modal-scrim {
  position: absolute;
  inset: 0;
  background: rgba(0,0,0,0.78);
  backdrop-filter: blur(5px);
  animation: fade-in 280ms var(--ease-out);
}

.modal-card {
  position: relative;
  z-index: 1;
  width: 100%;
  max-height: 90vh;
  max-height: 90dvh;
  overflow-y: auto;
  background: linear-gradient(160deg, var(--ink-3), var(--ink));
  border: 1px solid var(--line);
  border-radius: 20px;
  animation: modal-in 420ms var(--ease-spring);
}

@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes modal-in {
  from { opacity: 0; transform: translateY(26px) scale(0.955); }
  to   { opacity: 1; transform: none; }
}

/* Size chips inside the dish modal. */
.size-chip {
  cursor: pointer;
  border: 1px solid rgba(212,175,55,0.3);
  color: #DADADA;
  transition: all 240ms var(--ease-out);
}
.size-chip:hover { border-color: var(--gold); color: var(--gold); transform: translateY(-2px); }
.size-chip.selected {
  background: linear-gradient(135deg, var(--gold), var(--gold-soft));
  border-color: var(--gold);
  color: #100D04;
  font-weight: 600;
  box-shadow: 0 8px 20px -8px rgba(212,175,55,0.65);
}

/* ---------------------------------------------------------------------------
   11. MARQUEE  (Features + Our Brands rails)
   ---------------------------------------------------------------------------
   Replaces the Swiper dependency. The track holds the list twice, and the
   animation moves it exactly -50%, so the loop is seamless with no JS.
   ------------------------------------------------------------------------- */
.marquee { overflow: hidden; position: relative; }
.marquee::before,
.marquee::after {
  content: '';
  position: absolute;
  top: 0;
  width: 90px;
  height: 100%;
  z-index: 2;
  pointer-events: none;
}
.marquee::before { left: 0;  background: linear-gradient(90deg, var(--ink), transparent); }
.marquee::after  { right: 0; background: linear-gradient(270deg, var(--ink), transparent); }

.marquee-track {
  display: flex;
  align-items: center;
  gap: 2.6rem;
  width: max-content;
  animation: marquee-run var(--marquee-speed, 42s) linear infinite;
}
.marquee:hover .marquee-track { animation-play-state: paused; }
.marquee-track.reverse { animation-direction: reverse; }

@keyframes marquee-run {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}

/* Logo colour and hover are defined once in section 20 ("FEATURES — in
   colour"). The greyscale treatment that used to live here has been removed
   rather than left to be overridden further down, so there is only one place
   that decides how these look. */

/* ---------------------------------------------------------------------------
   12. LOADING STATES
   ------------------------------------------------------------------------- */
.skeleton {
  background: linear-gradient(90deg, var(--ink-3) 25%, #2A2A2A 50%, var(--ink-3) 75%);
  background-size: 200% 100%;
  animation: skeleton-run 1.4s ease-in-out infinite;
  border-radius: 8px;
}
@keyframes skeleton-run {
  from { background-position: 200% 0; }
  to   { background-position: -200% 0; }
}

.spinner {
  width: 42px;
  height: 42px;
  border: 3px solid rgba(212, 175, 55, 0.2);
  border-top-color: var(--gold);
  border-radius: 50%;
  animation: spin 800ms linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* Full-screen veil while a payment redirect is in flight. */
.busy-veil {
  position: fixed;
  inset: 0;
  z-index: 2000;
  display: none;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1.2rem;
  background: rgba(6, 6, 6, 0.9);
  backdrop-filter: blur(6px);
}
.busy-veil.open { display: flex; animation: fade-in 240ms var(--ease-out); }

/* ---------------------------------------------------------------------------
   13. TOASTS
   ------------------------------------------------------------------------- */
.toast-stack {
  position: fixed;
  bottom: 22px;
  right: 22px;
  z-index: 2100;
  display: flex;
  flex-direction: column;
  gap: 10px;
  max-width: min(360px, calc(100vw - 44px));
}
.toast {
  display: flex;
  align-items: flex-start;
  gap: 11px;
  padding: 14px 16px;
  border-radius: 12px;
  border: 1px solid var(--line);
  background: linear-gradient(140deg, var(--ink-3), var(--ink-2));
  box-shadow: 0 18px 40px -14px rgba(0,0,0,0.9);
  font-size: 0.875rem;
  color: #E8E8E8;
  animation: toast-in 420ms var(--ease-spring);
}
.toast.leaving { animation: toast-out 300ms var(--ease-out) forwards; }
.toast.ok    { border-left: 3px solid #34D399; }
.toast.error { border-left: 3px solid #F87171; }
.toast.info  { border-left: 3px solid var(--gold); }

@keyframes toast-in  { from { opacity: 0; transform: translateX(60px) scale(0.94); } to { opacity: 1; transform: none; } }
@keyframes toast-out { to   { opacity: 0; transform: translateX(60px) scale(0.94); } }

/* ---------------------------------------------------------------------------
   14. AD POPUP
   ------------------------------------------------------------------------- */
.ad-shell {
  position: fixed;
  inset: 0;
  z-index: 1400;
  display: none;
  align-items: center;
  justify-content: center;
  padding: 1.25rem;
  background: rgba(0,0,0,0.82);
  backdrop-filter: blur(5px);
}
.ad-shell.open { display: flex; animation: fade-in 400ms var(--ease-out); }
.ad-frame {
  position: relative;
  max-width: 560px;
  width: 100%;
  animation: ad-in 620ms var(--ease-spring);
}
@keyframes ad-in {
  from { opacity: 0; transform: translateY(40px) scale(0.9); }
  to   { opacity: 1; transform: none; }
}

/* ---------------------------------------------------------------------------
   15. UTILITIES
   ------------------------------------------------------------------------- */
.glass {
  background: rgba(20, 20, 20, 0.72);
  backdrop-filter: blur(14px) saturate(150%);
  -webkit-backdrop-filter: blur(14px) saturate(150%);
  border: 1px solid var(--line);
}

.hairline { border-top: 1px solid var(--line); }

.float-slow { animation: float-slow 6.5s var(--ease-in-out) infinite; }
@keyframes float-slow {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-13px); }
}

.pulse-ring { position: relative; }
.pulse-ring::before {
  content: '';
  position: absolute;
  inset: -5px;
  border-radius: inherit;
  border: 1.5px solid var(--gold);
  animation: pulse-ring 2.1s var(--ease-out) infinite;
}
@keyframes pulse-ring {
  0%   { opacity: 0.85; transform: scale(0.94); }
  100% { opacity: 0;    transform: scale(1.28); }
}

/* Screen-reader-only text that stays keyboard reachable. */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ---------------------------------------------------------------------------
   16. PRINT  (admin uses this for order slips)
   ------------------------------------------------------------------------- */
@media print {
  body { background: #fff !important; color: #000 !important; }
  .bg-stage, .no-print, nav, footer, .cart-drawer, .cart-scrim { display: none !important; }
  * { animation: none !important; transition: none !important; box-shadow: none !important; }
  a[href]::after { content: ''; }
}

/* ---------------------------------------------------------------------------
   17. REDUCED MOTION
   ---------------------------------------------------------------------------
   One block that neutralises everything above for anyone who has asked their
   OS for less movement. Content still appears — only the motion stops.
   ------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }

  html { scroll-behavior: auto; }

  .js [data-reveal],
  .js [data-reveal-group] > *,
  .split-lift > span {
    opacity: 1 !important;
    transform: none !important;
    filter: none !important;
  }

  .bg-aurora, .bg-grain, .bg-mesh, .bg-beams { animation: none !important; }
  .bg-orbs i { animation: none !important; }
  .bg-embers { display: none !important; }
  .hero-stage video, .hero-stage .hero-fallback { animation: none !important; transform: none !important; }
  .marquee-track { animation: none !important; }
  .rule-gold::after { width: 128px !important; }
  .scroll-cue { display: none; }
}

/* ============================================================================
   18. MENU CARD — whole photo, and every size priced
   ----------------------------------------------------------------------------
   Two corrections to match the live site:

   1. The photo is no longer cropped. object-fit:cover filled the frame by
      slicing the edges off, which cut the ends off wide party trays — the
      worst possible thing to crop on a food menu. object-fit:contain shows the
      entire image; the tinted panel behind it absorbs the leftover space so
      the grid still lines up.

   2. Every size and its price is listed (Lite / Half / Full), rather than a
      single "from ₱840".
   ========================================================================== */

.dish-photo {
  width: 100%;
  aspect-ratio: 4 / 3;
  display: block;
  object-fit: contain;          /* whole picture, never cropped */
  object-position: center;
  background: var(--ink-3);
  padding: 6px;
  transition: transform 620ms var(--ease-out);
}

/* A blurred copy of the same photo fills the empty space beside a tall or
   narrow image, so the card never shows bare grey bars. */
.dish-media {
  position: relative;
  overflow: hidden;
  background: var(--ink-3);
}
.dish-media::before {
  content: '';
  position: absolute;
  inset: 0;
  background-image: var(--dish-bg);
  background-size: cover;
  background-position: center;
  filter: blur(22px) saturate(1.25) brightness(0.55);
  transform: scale(1.25);
  opacity: 0.5;
  z-index: 0;
}
.dish-media .dish-photo { position: relative; z-index: 1; background: transparent; }

.card-lift:hover .dish-photo { transform: scale(1.045); }

/* Size + price rows on the card. */
.size-line {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  padding: 3px 0;
  font-size: 0.8rem;
}
.size-line + .size-line { border-top: 1px dashed rgba(212, 175, 55, 0.16); }
.size-line .size-name  { color: var(--muted); letter-spacing: 0.02em; }
.size-line .size-price { color: var(--gold); font-weight: 600; font-variant-numeric: tabular-nums; }

/* Allergen line vs package line — visually distinct so they are not confused. */
.dish-allergens {
  display: inline-block;
  font-size: 0.65rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  font-weight: 600;
  color: #C98A2E;
  background: rgba(201, 138, 46, 0.12);
  border: 1px solid rgba(201, 138, 46, 0.28);
  border-radius: 999px;
  padding: 3px 9px;
}

.dish-package {
  font-size: 0.76rem;
  line-height: 1.6;
  color: var(--muted);
  display: -webkit-box;
  -webkit-line-clamp: 4;        /* keeps every card the same height */
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.dish-package .pkg-item { display: block; }
.dish-package .pkg-item::before { content: '· '; color: var(--gold); }

/* ============================================================================
   19. FEATURES — in colour
   ----------------------------------------------------------------------------
   The press logos were forced to greyscale. They are brand marks and read far
   better in their real colours, so the filter is gone; only a slight
   transparency remains, lifting to full on hover.
   ========================================================================== */

.marquee img {
  filter: none;
  opacity: 0.92;
  transition: transform 380ms var(--ease-spring), opacity 380ms var(--ease-out);
}
.marquee a:hover img { transform: scale(1.1); opacity: 1; filter: none; }

/* A few press logos are black-on-transparent and vanish against the ink. A soft
   white plate behind each one keeps them readable without washing out the
   colour. (This used to be forked per theme; the site is dark-only now.) */
.marquee a {
  background: rgba(255, 255, 255, 0.94);
  border-radius: 12px;
  padding: 10px 14px;
  display: block;
  transition: background-color 320ms var(--ease-out), transform 320ms var(--ease-spring);
}
.marquee a:hover {
  background: #FFFFFF;
  transform: translateY(-3px);
}

/* ============================================================================
   20. MOBILE & LOW-END DEVICE PERFORMANCE
   ----------------------------------------------------------------------------
   The animated background is the expensive part: three stacked layers, one of
   them a large blur, repainting continuously. On a mid-range Android that is
   the difference between smooth scrolling and visible stutter.

   Below 1024px the blur is reduced and the grain layer — the most costly and
   least noticeable of the three — is dropped entirely. Below 768px the aurora
   stops animating at all and becomes a static gradient, which looks nearly
   identical on a small screen and costs nothing to maintain.
   ========================================================================== */

@media (max-width: 1023px) {
  .bg-grain { display: none; }
  .bg-aurora { filter: blur(10px); animation-duration: 48s; }
  /* A 70px blur on a 46vw circle is the single most expensive thing on the
     page. Halving it is invisible at this size and costs a fraction to paint. */
  .bg-orbs i { filter: blur(44px); }
  .bg-beams  { filter: blur(16px); animation-duration: 160s; }
  .bg-embers i:nth-child(n+11) { display: none; }   /* 18 sparks -> 10 */
  .glass { backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px); }
}

@media (max-width: 767px) {
  /* Static background: no continuous repaint while the user scrolls. The orbs
     and embers stay — they are the movement worth keeping — but the layers
     that repaint the WHOLE viewport every frame are frozen. */
  .bg-aurora { animation: none; filter: blur(8px); }
  .bg-mesh   { animation: none; background-size: 54px 54px; }
  .bg-beams  { display: none; }
  .bg-orbs i { filter: blur(34px); opacity: 0.45; }
  .bg-embers i:nth-child(n+7) { display: none; }    /* 10 sparks -> 6 */

  /* The hero's slow zoom forces the compositor to re-rasterise a video frame
     every tick. Not worth it on a phone. */
  .hero-stage video,
  .hero-stage .hero-fallback { animation: none; transform: none; }

  /* Shorter, simpler reveals — long transforms feel sluggish on a small screen. */
  .js [data-reveal] { transition-duration: 480ms; }
  .js [data-reveal="up"]    { transform: translate3d(0, 22px, 0); }
  .js [data-reveal="left"],
  .js [data-reveal="right"] { transform: translate3d(0, 22px, 0); }
  .js [data-reveal="blur"]  { filter: none; transform: translate3d(0, 22px, 0); }
  .js [data-reveal="tilt"]  { transform: translate3d(0, 22px, 0); }

  /* Hover effects do nothing on touch and only cost paint time. */
  .card-lift:hover { transform: none; box-shadow: none; }
  .sheen::after    { display: none; }

  .marquee-track { animation-duration: 30s; }
}

/* Touch devices: give every control a finger-sized target.
   44px is Apple's minimum and Google's recommendation; below that people
   mis-tap, which on a checkout page means a lost order. */
@media (hover: none) and (pointer: coarse) {
  .a-btn,
  .btn-gold,
  .btn-outline-gold,
  .pill,
  .size-chip,
  .admin-link,
  button:not(.expand-btn),
  select,
  [role="tab"] {
    min-height: 44px;
  }

  .a-btn-sm { min-height: 38px; }

  /* iOS zooms the page in when a focused field's font is under 16px. Setting
     every input to 16px stops that jarring auto-zoom on the checkout form. */
  input, select, textarea { font-size: 16px !important; }

  /* Nothing should depend on hover being available. */
  .card-lift:hover,
  .a-card:hover,
  .a-btn:hover { transform: none; }
}

/* Very small phones: the reCAPTCHA box is a fixed 304px and cannot be resized
   with CSS, so it is scaled down instead. Without this it overflows the card
   and pushes the submit button off the screen. */
.recaptcha-wrap {
  display: flex;
  justify-content: center;
  min-height: 78px;
}
@media (max-width: 360px) {
  .recaptcha-wrap { transform: scale(0.86); transform-origin: center; min-height: 68px; }
}

/* Respect a data-saver setting: drop the decorative layers entirely. */
@media (prefers-reduced-data: reduce) {
  .bg-aurora, .bg-grain, .bg-mesh, .bg-beams, .bg-embers, .bg-orbs { display: none; }
}

/* Tablets: the dish grid reads better at three columns than four. */
@media (min-width: 768px) and (max-width: 1279px) {
  .dish-package { -webkit-line-clamp: 3; }
}

/* ============================================================================
   21. OUR BRANDS — the plates, shown whole
   ----------------------------------------------------------------------------
   The old cards used a square photo with object-fit:cover, which cropped a
   wide hexagonal plate into a square and sliced the ends off every mark. These
   cards do the opposite: a fixed 5:3 stage with object-fit:contain, so the
   plate is shown ENTIRE at every card width, and the artwork itself is a
   trimmed transparent PNG so it fills that stage rather than floating in a
   field of white.

   Nothing here sets a background behind the mark. Rosa, Patisserie and Home
   Buffet carry their own cream plate; Party Trays, Group and Privè are dark
   plates that read against the card. Adding a plate colour would put a box
   around the ones that already have one.
   ========================================================================== */

.brand-grid {
  display: grid;
  gap: 1.25rem;
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
@media (min-width: 640px)  { .brand-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 1024px) { .brand-grid { grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 1.5rem; } }

.brand-card {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: 1.35rem 1rem 1.5rem;
  border-radius: 1.15rem;
  overflow: hidden;
  isolation: isolate;
  border: 1px solid var(--line);
  background: linear-gradient(165deg, rgba(32,32,32,0.88), rgba(13,13,13,0.94));
  transition:
    transform 480ms var(--ease-out),
    border-color 480ms var(--ease-out),
    box-shadow 480ms var(--ease-out);
  will-change: transform;
}
.brand-card:hover,
.brand-card:focus-visible {
  transform: translateY(-9px);
  border-color: rgba(212, 175, 55, 0.55);
  box-shadow: 0 28px 54px -20px rgba(0,0,0,0.9), 0 0 0 1px rgba(212,175,55,0.22);
}

/* Decorative layers. Both are absolutely positioned and z-indexed BELOW the
   content, so neither can ever overlap or clip the mark. */
.brand-halo {
  position: absolute;
  inset: -30% 10% auto 10%;
  height: 78%;
  z-index: 0;
  pointer-events: none;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgba(212,175,55,0.30), transparent 72%);
  opacity: 0;
  transform: scale(0.7);
  transition: opacity 620ms var(--ease-out), transform 620ms var(--ease-out);
}
.brand-card:hover .brand-halo,
.brand-card:focus-visible .brand-halo { opacity: 1; transform: scale(1); }

.brand-sheen {
  position: absolute;
  top: 0;
  left: -75%;
  width: 50%;
  height: 100%;
  z-index: 0;
  pointer-events: none;
  background: linear-gradient(90deg, transparent, rgba(212,175,55,0.16), transparent);
  transform: skewX(-22deg);
  transition: left 820ms var(--ease-out);
}
.brand-card:hover .brand-sheen { left: 125%; }

/* THE STAGE. aspect-ratio fixes the height so every card lines up, and the
   mark is capped on BOTH axes so a wide plate and a tall plate are each shown
   whole inside it. width/height:auto is what stops the browser stretching one
   axis to the box. */
.brand-plate {
  position: relative;
  z-index: 1;
  display: grid;
  place-items: center;
  width: 100%;
  aspect-ratio: 5 / 3;
  padding: 0.35rem;
  margin-bottom: 1rem;
}
.brand-mark {
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  object-fit: contain;
  filter: drop-shadow(0 10px 22px rgba(0,0,0,0.55));
  transition: transform 640ms var(--ease-out), filter 480ms var(--ease-out);
}
.brand-card:hover .brand-mark {
  transform: scale(1.07);
  filter: drop-shadow(0 14px 30px rgba(0,0,0,0.7)) brightness(1.05);
}

.brand-body {
  position: relative;
  z-index: 1;
  display: block;
}
.brand-name {
  display: block;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.18rem;
  line-height: 1.25;
  color: var(--gold);
  margin-bottom: 0.3rem;
}
.brand-tagline {
  display: block;
  font-size: 0.78rem;
  line-height: 1.55;
  letter-spacing: 0.02em;
  color: var(--muted);
}

/* ============================================================================
   22. LIGHTBOX — the shared full-size viewer
   ----------------------------------------------------------------------------
   Used by venues.php, prive-menu.php and (when flyers are present)
   party-trays-menu.php. One dialog per page, reused for every image.

   The frame is a three-row grid — stage / caption / nothing — with the stage
   given the leftover height via minmax(0, 1fr). minmax(0, …) rather than a
   bare 1fr is load-bearing: a grid row's default minimum is min-content, and a
   2000px-tall menu page would push the row past the viewport and shove the
   caption off the bottom of the screen.
   ========================================================================== */

.lightbox {
  position: fixed;
  inset: 0;
  z-index: 1200;
  display: grid;
  /* THE ROW AND COLUMN ARE DECLARED EXPLICITLY, and this is load-bearing.
     With `place-items:center` alone the implicit row is auto-sized, which
     makes the frame's containing block INDEFINITE — so `height:100%` on the
     frame silently falls back to auto, the rows size to the image's natural
     1498px, and a portrait menu page runs off the bottom of the screen taking
     the caption with it. Caught by rendering; no static check sees it.
     minmax(0, 1fr) gives a definite height AND lets the row shrink below its
     content, which a bare 1fr will not do. */
  grid-template-rows: minmax(0, 1fr);
  grid-template-columns: minmax(0, 1fr);
  place-items: center;
  padding: clamp(0.75rem, 3vw, 2.25rem);
  opacity: 0;
  visibility: hidden;
  transition: opacity 320ms var(--ease-out), visibility 0s linear 320ms;
}
.lightbox.open {
  opacity: 1;
  visibility: visible;
  transition: opacity 320ms var(--ease-out), visibility 0s;
}

.lightbox__scrim {
  position: absolute;
  inset: 0;
  background: rgba(6, 6, 6, 0.93);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}

.lightbox__frame {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-rows: minmax(0, 1fr) auto;
  gap: 0.85rem;
  width: min(100%, 1080px);
  height: 100%;
  max-height: 100%;
  transform: scale(0.965) translateY(10px);
  transition: transform 420ms var(--ease-spring);
}
.lightbox.open .lightbox__frame { transform: none; }

/* FLEX, NOT GRID, and this is the second half of the same trap.
   As a grid, the image is a grid item whose `max-height:100%` resolves against
   its own grid area — and that area is sized BY the item, so the percentage is
   circular and the browser drops it. The 1415x2000 page then took its natural
   1271px height inside an 843px stage and hung off the bottom of the screen.
   In a flex container with a definite height the percentage resolves against
   the container, and the image is capped properly on both axes. */
.lightbox__stage {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 0;               /* pairs with minmax(0,1fr) above */
}

.lightbox__img {
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  object-fit: contain;         /* the page is never cropped */
  border-radius: 0.9rem;
  border: 1px solid rgba(212, 175, 55, 0.28);
  box-shadow: 0 40px 90px -30px rgba(0,0,0,0.95);
  background: var(--ink-2);
  transition: opacity 220ms var(--ease-out);
}
.lightbox.is-loading .lightbox__img { opacity: 0.25; }

/* Only visible while the next file is decoding, so a slow connection shows a
   spinner rather than the PREVIOUS image under the NEW caption. */
.lightbox__spinner {
  position: absolute;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  border: 2px solid rgba(212, 175, 55, 0.25);
  border-top-color: var(--gold);
  opacity: 0;
  pointer-events: none;
  animation: spin 780ms linear infinite;
  transition: opacity 200ms var(--ease-out);
}
.lightbox.is-loading .lightbox__spinner { opacity: 1; }

.lightbox__cap {
  text-align: center;
  padding: 0 3.25rem;
  line-height: 1.4;
}
.lightbox__title {
  display: block;
  font-family: var(--font-display);
  font-size: 1.4rem;
  font-weight: 600;
  color: var(--gold);
}
.lightbox__meta {
  display: block;
  font-size: 0.76rem;
  letter-spacing: 0.04em;
  color: #C9C9C9;
  margin-top: 0.15rem;
}
.lightbox__count {
  display: block;
  font-size: 0.68rem;
  letter-spacing: 0.16em;
  color: #7C7C7C;
  margin-top: 0.35rem;
  font-variant-numeric: tabular-nums;
}

.lightbox__nav,
.lightbox__x {
  position: absolute;
  z-index: 2;
  display: grid;
  place-items: center;
  border-radius: 999px;
  color: #EDEDED;
  background: rgba(18, 18, 18, 0.82);
  border: 1px solid rgba(212, 175, 55, 0.34);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  transition: color 260ms var(--ease-out), border-color 260ms var(--ease-out),
              background-color 260ms var(--ease-out), transform 260ms var(--ease-spring);
}
.lightbox__nav:hover,
.lightbox__x:hover { color: var(--gold); border-color: var(--gold); transform: scale(1.08); }

.lightbox__nav { top: 50%; width: 48px; height: 48px; margin-top: -24px; }
.lightbox__nav--prev { left: -4px; }
.lightbox__nav--next { right: -4px; }

.lightbox__x { top: -2px; right: -2px; width: 42px; height: 42px; }

/* A tall portrait page wants every vertical pixel it can get. */
.lightbox--tall .lightbox__frame { width: min(100%, 900px); }

/* ============================================================================
   23. OUR VENUES
   ========================================================================== */

.venue-hero {
  position: relative;
  overflow: hidden;
  min-height: 66vh;
  min-height: 66dvh;
  display: grid;
  place-items: center;
}
.venue-hero__shot {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  animation: hero-push 34s var(--ease-in-out) infinite alternate;
}
.venue-hero__body {
  position: relative;
  z-index: 2;
  text-align: center;
  padding: 6.5rem 1.25rem 4.5rem;
  max-width: 44rem;
}

/* --- filter rail --- */
.venue-filter,
.prive-filter {
  display: flex;
  gap: 0.6rem;
  overflow-x: auto;
  padding: 0.3rem 0.25rem 0.9rem;
  margin-bottom: 2.25rem;
  scroll-behavior: smooth;
  justify-content: flex-start;
}
@media (min-width: 900px) {
  .venue-filter,
  .prive-filter { justify-content: center; flex-wrap: wrap; overflow-x: visible; }
}
.venue-chip,
.prive-chip {
  flex: 0 0 auto;
  padding: 0.6rem 1.15rem;
  border-radius: 999px;
  font-size: 0.82rem;
}
.venue-chip__n,
.prive-chip__n {
  margin-left: 0.4rem;
  font-size: 0.68rem;
  opacity: 0.62;
  font-variant-numeric: tabular-nums;
}

/* --- grid --- */
.venue-grid {
  display: grid;
  gap: 1.5rem;
  grid-template-columns: minmax(0, 1fr);
}
@media (min-width: 700px)  { .venue-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1120px) { .venue-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

.venue-card {
  display: flex;
  flex-direction: column;
  border-radius: 1.15rem;
  overflow: hidden;
  border: 1px solid var(--line);
  background: linear-gradient(170deg, rgba(30,30,30,0.86), rgba(12,12,12,0.94));
  transition: transform 480ms var(--ease-out), border-color 480ms var(--ease-out),
              box-shadow 480ms var(--ease-out);
}
.venue-card:hover {
  transform: translateY(-7px);
  border-color: rgba(212, 175, 55, 0.5);
  box-shadow: 0 28px 54px -22px rgba(0,0,0,0.9);
}
/* The filter sets .hidden on the element. display:flex above would otherwise
   outrank the user-agent [hidden] rule and the card would stay on screen. */
.venue-card[hidden] { display: none !important; }

/* --- media: the flyer, whole --- */
.venue-media {
  position: relative;
  display: block;
  width: 100%;
  aspect-ratio: 4 / 5;
  overflow: hidden;
  background: var(--ink-3);
  border: 0;
  padding: 0;
  cursor: zoom-in;
}
/* Blurred copy of the same flyer, filling whatever the contained image leaves
   over, so there are never bare grey bars beside it. */
.venue-shot {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center;
  filter: blur(26px) saturate(1.3) brightness(0.5);
  transform: scale(1.3);
  opacity: 0.55;
  transition: background-image 400ms var(--ease-out);
}
.venue-stack { position: absolute; inset: 0; }
.venue-flyer {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;          /* NEVER cropped */
  object-position: center;
  opacity: 0;
  transition: opacity 900ms var(--ease-in-out), transform 760ms var(--ease-out);
}
.venue-flyer.is-active { opacity: 1; }
.venue-card:hover .venue-flyer.is-active { transform: scale(1.035); }

.venue-zoom {
  position: absolute;
  top: 0.7rem;
  right: 0.7rem;
  width: 34px;
  height: 34px;
  display: grid;
  place-items: center;
  border-radius: 999px;
  color: var(--gold);
  background: rgba(10, 10, 10, 0.68);
  border: 1px solid rgba(212, 175, 55, 0.34);
  opacity: 0;
  transform: scale(0.8);
  transition: opacity 320ms var(--ease-out), transform 320ms var(--ease-spring);
}
.venue-card:hover .venue-zoom,
.venue-media:focus-visible .venue-zoom { opacity: 1; transform: none; }

.venue-dots {
  position: absolute;
  left: 50%;
  bottom: 0.7rem;
  transform: translateX(-50%);
  display: flex;
  gap: 6px;
}
.venue-dots i {
  width: 6px;
  height: 6px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.32);
  transition: background-color 400ms var(--ease-out), width 400ms var(--ease-out);
}
.venue-dots i.is-active { background: var(--gold); width: 18px; }

/* --- body --- */
.venue-body { display: flex; flex-direction: column; flex: 1; padding: 1.35rem 1.25rem 1.4rem; }
.venue-place {
  font-size: 0.64rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--gold);
  margin-bottom: 0.45rem;
}
.venue-name {
  font-family: var(--font-display);
  font-size: 1.6rem;
  font-weight: 600;
  line-height: 1.15;
  color: #F1F1F1;
  margin-bottom: 0.6rem;
}
.venue-pax {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  align-self: flex-start;
  font-size: 0.7rem;
  letter-spacing: 0.05em;
  color: var(--gold);
  background: rgba(212, 175, 55, 0.1);
  border: 1px solid rgba(212, 175, 55, 0.28);
  border-radius: 999px;
  padding: 0.3rem 0.7rem;
  margin-bottom: 0.85rem;
}
.venue-copy { font-size: 0.82rem; line-height: 1.7; color: var(--muted); margin-bottom: 1rem; }

.venue-tags { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-bottom: 1.2rem; }
.venue-tags span {
  font-size: 0.64rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #B9B9B9;
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 999px;
  padding: 0.28rem 0.6rem;
}

.venue-actions { display: flex; gap: 0.6rem; margin-top: auto; }
.venue-more {
  flex: 0 0 auto;
  padding: 0 1.05rem;
  border-radius: 0.75rem;
  font-size: 0.72rem;
  letter-spacing: 0.04em;
  color: var(--muted);
  border: 1px solid var(--line);
  transition: color 280ms var(--ease-out), border-color 280ms var(--ease-out);
}
.venue-more:hover { color: var(--gold); border-color: var(--gold); }

/* --- enquiry panel (also used by prive-menu.php) --- */
.venue-cta {
  display: grid;
  gap: 2rem;
  align-items: center;
  padding: clamp(1.6rem, 4vw, 2.75rem);
  border-radius: 1.35rem;
  border: 1px solid var(--line);
  background:
    radial-gradient(120% 140% at 0% 0%, rgba(212,175,55,0.1), transparent 58%),
    linear-gradient(160deg, rgba(30,30,30,0.9), rgba(12,12,12,0.95));
}
@media (min-width: 900px) { .venue-cta { grid-template-columns: 1.1fr 1fr; gap: 3rem; } }

.venue-cta__list { display: grid; gap: 0.65rem; }
.venue-phone {
  display: flex;
  align-items: center;
  gap: 0.85rem;
  padding: 0.85rem 1rem;
  border-radius: 0.9rem;
  border: 1px solid var(--line);
  background: rgba(255, 255, 255, 0.025);
  transition: border-color 280ms var(--ease-out), background-color 280ms var(--ease-out),
              transform 280ms var(--ease-spring);
}
.venue-phone:hover { border-color: var(--gold); background: rgba(212,175,55,0.07); transform: translateX(4px); }
.venue-phone__icon {
  flex: 0 0 auto;
  width: 38px;
  height: 38px;
  display: grid;
  place-items: center;
  border-radius: 999px;
  color: var(--gold);
  border: 1px solid rgba(212, 175, 55, 0.32);
}
.venue-phone__n {
  display: block;
  font-size: 0.95rem;
  font-weight: 600;
  color: #EDEDED;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
}
.venue-phone__name { display: block; font-size: 0.7rem; letter-spacing: 0.14em; text-transform: uppercase; color: var(--gold); }

/* ============================================================================
   24. PRIVÈ CATERING MENU
   ----------------------------------------------------------------------------
   Privè's plate is navy and gold rather than the site's black and gold, so
   this page borrows a navy wash for its hero and its rate list. It is a tint
   on top of the existing palette, not a second theme — every token below still
   resolves to the same --gold.
   ========================================================================== */

.prive-scope { --navy: #16233F; --navy-soft: #1E3055; }

.prive-hero {
  position: relative;
  overflow: hidden;
  min-height: 62vh;
  min-height: 62dvh;
  display: grid;
  place-items: center;
}
.prive-hero__wash {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(90% 70% at 50% 0%,  rgba(30, 48, 85, 0.85), transparent 68%),
    radial-gradient(70% 60% at 80% 100%, rgba(212, 175, 55, 0.13), transparent 66%),
    linear-gradient(180deg, rgba(10,10,10,0.2), var(--ink) 92%);
  animation: prive-wash 26s var(--ease-in-out) infinite alternate;
}
@keyframes prive-wash {
  from { transform: scale(1)    translateY(0); }
  to   { transform: scale(1.14) translateY(-2%); }
}
.prive-hero__body {
  position: relative;
  z-index: 2;
  text-align: center;
  padding: 6.5rem 1.25rem 4.5rem;
  max-width: 46rem;
}
.prive-eyebrow { color: var(--gold); }
.prive-hero__tag {
  font-size: clamp(1.15rem, 3vw, 1.6rem);
  font-style: italic;
  letter-spacing: 0.04em;
  color: #D9E0EE;
}

/* --- rate list --- */
.rate-list { display: grid; gap: 0.15rem; list-style: none; padding: 0; margin: 0 auto; max-width: 46rem; counter-reset: none; }
.rate-open {
  display: grid;
  grid-template-columns: auto 1fr auto auto;
  align-items: baseline;
  gap: 0.55rem;
  width: 100%;
  text-align: left;
  padding: 0.85rem 0.9rem;
  border-radius: 0.7rem;
  border: 1px solid transparent;
  transition: background-color 280ms var(--ease-out), border-color 280ms var(--ease-out),
              transform 280ms var(--ease-out);
}
.rate-open:hover {
  background: rgba(212, 175, 55, 0.06);
  border-color: rgba(212, 175, 55, 0.26);
  transform: translateX(4px);
}
.rate-name { font-family: var(--font-display); font-size: 1.28rem; font-weight: 600; color: #F0F0F0; }
.rate-note {
  display: block;
  font-family: var(--font-body);
  font-style: normal;
  font-size: 0.66rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
  margin-top: 0.1rem;
}
/* A dotted leader, the way a printed menu sets a price against a dish. */
.rate-rule {
  align-self: center;
  height: 1px;
  min-width: 1.5rem;
  background-image: linear-gradient(to right, rgba(212,175,55,0.42) 40%, transparent 0%);
  background-size: 7px 1px;
  background-repeat: repeat-x;
}
.rate-price { font-size: 1.05rem; font-weight: 600; color: var(--gold); font-variant-numeric: tabular-nums; }
.rate-unit  { font-size: 0.68rem; letter-spacing: 0.08em; color: var(--muted); }

.rate-foot {
  max-width: 46rem;
  margin: 1.75rem auto 0;
  text-align: center;
  font-size: 0.76rem;
  line-height: 1.75;
  color: var(--muted);
}

/* --- inclusions --- */
.prive-inclusions {
  display: grid;
  gap: 1.75rem;
  padding: clamp(1.6rem, 4vw, 2.6rem);
  border-radius: 1.35rem;
  border: 1px solid var(--line);
  background:
    radial-gradient(110% 130% at 100% 0%, rgba(30, 48, 85, 0.55), transparent 60%),
    linear-gradient(160deg, rgba(28,28,28,0.9), rgba(12,12,12,0.95));
}
@media (min-width: 860px) { .prive-inclusions { grid-template-columns: 1fr 1.15fr; gap: 2.75rem; align-items: center; } }
.prive-inclusions__list { display: grid; gap: 0.7rem; }
.prive-inclusions__list li {
  display: flex;
  align-items: flex-start;
  gap: 0.65rem;
  font-size: 0.88rem;
  line-height: 1.55;
  color: #DCDCDC;
}
.prive-inclusions__list svg { flex: 0 0 auto; margin-top: 0.22rem; color: var(--gold); }

/* --- the pages --- */
.prive-grid {
  display: grid;
  gap: 1.35rem;
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
@media (min-width: 720px)  { .prive-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 1100px) { .prive-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

.prive-page {
  display: flex;
  flex-direction: column;
  text-align: left;
  border: 0;
  padding: 0;
  background: none;
  cursor: zoom-in;
}
/* Same trap as .venue-card: display:flex would outrank the [hidden] default. */
.prive-page[hidden] { display: none !important; }

.prive-page__frame {
  position: relative;
  display: block;
  width: 100%;
  aspect-ratio: 1415 / 2000;    /* the printed page's own proportions */
  overflow: hidden;
  border-radius: 0.95rem;
  border: 1px solid var(--line);
  background: var(--ink-3);
  transition: transform 480ms var(--ease-out), border-color 480ms var(--ease-out),
              box-shadow 480ms var(--ease-out);
}
.prive-page:hover .prive-page__frame,
.prive-page:focus-visible .prive-page__frame {
  transform: translateY(-7px);
  border-color: rgba(212, 175, 55, 0.55);
  box-shadow: 0 26px 50px -20px rgba(0,0,0,0.9);
}
.prive-page__wash {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center;
  filter: blur(24px) brightness(0.55);
  transform: scale(1.3);
  opacity: 0.5;
}
.prive-page__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;          /* the whole sheet, never cropped */
  transition: transform 700ms var(--ease-out);
}
.prive-page:hover .prive-page__img { transform: scale(1.04); }

.prive-page__no {
  position: absolute;
  top: 0.55rem;
  left: 0.55rem;
  font-size: 0.62rem;
  letter-spacing: 0.14em;
  font-variant-numeric: tabular-nums;
  color: var(--gold);
  background: rgba(10, 10, 10, 0.7);
  border: 1px solid rgba(212, 175, 55, 0.3);
  border-radius: 999px;
  padding: 0.2rem 0.5rem;
}
.prive-page__zoom {
  position: absolute;
  top: 0.55rem;
  right: 0.55rem;
  width: 32px;
  height: 32px;
  display: grid;
  place-items: center;
  border-radius: 999px;
  color: var(--gold);
  background: rgba(10, 10, 10, 0.68);
  border: 1px solid rgba(212, 175, 55, 0.3);
  opacity: 0;
  transform: scale(0.8);
  transition: opacity 320ms var(--ease-out), transform 320ms var(--ease-spring);
}
.prive-page:hover .prive-page__zoom,
.prive-page:focus-visible .prive-page__zoom { opacity: 1; transform: none; }

.prive-page__meta { display: block; padding: 0.75rem 0.2rem 0; }
.prive-page__title {
  display: block;
  font-family: var(--font-display);
  font-size: 1.05rem;
  font-weight: 600;
  color: #EDEDED;
  line-height: 1.2;
}
.prive-page__rate {
  display: block;
  font-size: 0.7rem;
  letter-spacing: 0.05em;
  color: var(--gold);
  margin-top: 0.15rem;
  font-variant-numeric: tabular-nums;
}

/* ============================================================================
   25. PARTY TRAYS MENU — hero only
   ----------------------------------------------------------------------------
   Everything below the hero is the dish grid, which already has its styling in
   section 18 and is shared with the homepage.
   ========================================================================== */

.tray-hero {
  position: relative;
  overflow: hidden;
  min-height: 60vh;
  min-height: 60dvh;
  display: grid;
  place-items: center;
}
.tray-hero__shot {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  animation: hero-push 32s var(--ease-in-out) infinite alternate;
}
.tray-hero__body {
  position: relative;
  z-index: 2;
  text-align: center;
  padding: 6.5rem 1.25rem 4.5rem;
  max-width: 46rem;
}
.tray-hero__tag {
  font-size: clamp(1.1rem, 3vw, 1.55rem);
  font-style: italic;
  letter-spacing: 0.04em;
  color: #E4D6AE;
}

/* ============================================================================
   26. SECTIONS 21-25 ON SMALL SCREENS AND UNDER REDUCED MOTION
   ----------------------------------------------------------------------------
   This block is LAST in the file on purpose. Everything in sections 21-25 is
   declared above it at equal specificity, so source order decides — putting
   these overrides anywhere earlier would silently lose. Any future tweak to
   the new components belongs ABOVE this line.
   ========================================================================== */

@media (max-width: 767px) {
  /* Five brand plates at two columns is already tight; drop the stage a little
     so the taglines are not pushed below the fold on every card. */
  .brand-card  { padding: 1.05rem 0.75rem 1.15rem; }
  .brand-plate { aspect-ratio: 16 / 9; margin-bottom: 0.75rem; }
  .brand-name  { font-size: 1rem; }
  .brand-tagline { font-size: 0.72rem; }

  /* The hero art zoom repaints a full-screen bitmap every tick. Not worth it
     on a phone — the same call section 20 already makes for the video hero. */
  .venue-hero__shot,
  .tray-hero__shot { animation: none; }
  .prive-hero__wash { animation: none; }

  .venue-name  { font-size: 1.35rem; }
  .venue-media { aspect-ratio: 3 / 4; }

  .rate-open  { grid-template-columns: 1fr auto; padding: 0.7rem 0.5rem; row-gap: 0.1rem; }
  .rate-rule  { display: none; }
  .rate-name  { font-size: 1.08rem; }
  .rate-unit  { grid-column: 2; text-align: right; }

  .prive-page__meta  { padding-top: 0.55rem; }
  .prive-page__title { font-size: 0.9rem; }
  .prive-page__rate  { font-size: 0.65rem; }

  /* The arrows sat over the image edges on a narrow screen and covered the
     artwork. Move them under the caption as a proper pair of buttons. */
  .lightbox__frame { grid-template-rows: minmax(0, 1fr) auto; }
  .lightbox__cap   { padding: 0 3rem; }
  .lightbox__nav   { top: auto; bottom: 0; margin-top: 0; width: 42px; height: 42px; }
  .lightbox__nav--prev { left: 0.35rem; }
  .lightbox__nav--next { right: 0.35rem; }
  .lightbox__title { font-size: 1.15rem; }
}

/* Hover effects do nothing on a touch screen and only cost paint time, so the
   zoom badges are simply always visible there instead. */
@media (hover: none) and (pointer: coarse) {
  .venue-zoom,
  .prive-page__zoom { opacity: 1; transform: none; }

  .brand-card:hover  { transform: none; box-shadow: none; }
  .venue-card:hover  { transform: none; box-shadow: none; }
  .prive-page:hover .prive-page__frame { transform: none; box-shadow: none; }
  .venue-phone:hover { transform: none; }
  .rate-open:hover   { transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .venue-hero__shot,
  .tray-hero__shot,
  .prive-hero__wash,
  .lightbox__spinner { animation: none !important; }

  .brand-halo,
  .brand-sheen { display: none; }

  .venue-flyer { transition: none; }
  /* With the cross-fade off, only the first photograph is ever shown, so the
     dots would otherwise sit there implying a control that does nothing. */
  .venue-dots  { display: none; }

  .lightbox__frame { transform: none; transition: none; }
}
