/* ========================================
   KEBAB STATION KUMEU
   Carved over fire, served fast.
   Charcoal & ember — cinematic, artisanal, fast-casual
   Typography: Sora (display) + Manrope (body)
   ======================================== */

:root {
  --bg-base: #14100e;
  --bg-alt: #1a1614;
  --bg-deep: #0d0a09;
  --bg-card-1: rgba(40, 30, 23, 0.6);
  --bg-card-2: rgba(22, 16, 12, 0.6);
  --bg-card-1-hover: rgba(50, 30, 18, 0.68);
  --bg-card-2-hover: rgba(28, 16, 10, 0.68);

  --ember: #e8531f;
  --ember-deep: #c0431f;
  --ember-light: #f4b13a;
  --gold: #f0a72e;
  --green: #3bd17a;
  --ember-soft: rgba(232, 83, 31, 0.14);

  --text-cream: #f5ede0;
  --text-muted: #cbbdb0;
  --text-faint: #b7a89a;
  --text-dim: #9c8e80;
  --text-ghost: #7a6a5a;

  --border: rgba(245, 237, 224, 0.1);
  --border-strong: rgba(245, 237, 224, 0.16);

  --font-display: "Sora", -apple-system, BlinkMacSystemFont, sans-serif;
  --font-body: "Manrope", -apple-system, BlinkMacSystemFont, "Segoe UI",
    sans-serif;

  --space-xs: 0.5rem;
  --space-sm: 1rem;
  --space-md: 1.5rem;
  --space-lg: 2.5rem;
  --space-xl: 4rem;
  --space-2xl: 6rem;
  --space-3xl: 8rem;

  --radius-sm: 12px;
  --radius-md: 18px;
  --radius-lg: 26px;
  --radius-full: 99px;

  --shadow-sm: 0 2px 14px rgba(0, 0, 0, 0.35);
  --shadow-md: 0 16px 40px rgba(0, 0, 0, 0.45);
  --shadow-lg: 0 30px 80px rgba(0, 0, 0, 0.55);
  --glow-ember: 0 14px 34px rgba(232, 83, 31, 0.38);

  --ease: cubic-bezier(0.25, 0.46, 0.45, 0.94);
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-plastic: cubic-bezier(0.22, 1.4, 0.36, 1);
  --duration: 0.35s;
  --duration-fast: 0.09s;
  --duration-slow: 0.7s;
}

/* ── Reset ── */
*,
*::before,
*::after {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
}

body {
  font-family: var(--font-body);
  font-weight: 400;
  font-size: 1rem;
  line-height: 1.7;
  color: var(--text-faint);
  background: var(--bg-base);
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
}

img,
video {
  display: block;
  max-width: 100%;
  height: auto;
}
a {
  color: inherit;
  text-decoration: none;
}
button {
  font: inherit;
  cursor: pointer;
  border: none;
  background: none;
  color: inherit;
}
ul {
  list-style: none;
}
::selection {
  background: var(--ember);
  color: var(--bg-deep);
}

.container {
  width: 100%;
  max-width: 1280px;
  margin: 0 auto;
  padding: 0 clamp(18px, 5vw, 40px);
}

/* ── Preloader ── */
.preloader {
  position: fixed;
  inset: 0;
  z-index: 3000;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg-base);
  opacity: 1;
  transition: opacity var(--duration-slow) var(--ease-out);
}

.preloader.is-hidden {
  opacity: 0;
  pointer-events: none;
}

.preloader__mark {
  position: relative;
  width: 64px;
  height: 64px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.preloader__logo {
  width: 38px;
  height: 38px;
  object-fit: contain;
}

.preloader__ring {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  border: 2.5px solid var(--border-strong);
  border-top-color: var(--ember);
  animation: preloader-spin 0.85s linear infinite;
}

@keyframes preloader-spin {
  to {
    transform: rotate(360deg);
  }
}

@media (prefers-reduced-motion: reduce) {
  .preloader {
    transition: none;
  }
  .preloader__ring {
    animation: none;
    border-top-color: var(--border-strong);
    opacity: 0.6;
  }
}

/* ── Scroll Progress Bar ── */
.scroll-progress {
  position: fixed;
  top: 0;
  left: 0;
  height: 3px;
  background: linear-gradient(90deg, var(--ember), var(--gold));
  z-index: 1100;
  width: 0%;
}

/* Native scroll-driven animation where supported — this runs on the
   compositor instead of recalculating a width in JS on every scroll
   event (main.js skips its own handler when this matches). Browsers
   without the API keep the JS path, so behaviour is identical either
   way; only which thread does the work changes. */
@supports (animation-timeline: scroll()) {
  .scroll-progress {
    width: 100%;
    transform-origin: 0 50%;
    animation: scroll-progress-grow linear both;
    animation-timeline: scroll(root block);
  }

  @keyframes scroll-progress-grow {
    from {
      transform: scaleX(0);
    }
    to {
      transform: scaleX(1);
    }
  }
}

/* ── Ambient embers ──
   Fixed (not tied to scroll), so they drift continuously the full height
   of the viewport on every section. Kept near the left/right edges rather
   than the centered content column so they never cross over text or
   photos — purely atmospheric, reinforcing the fire/ember identity beyond
   just the hero. z-index only needs to clear normal in-flow content
   (<main> has no explicit stacking), so a low positive value is enough;
   it still sits well under the header (1000) and progress bar (1100). */
.ember-field {
  position: fixed;
  inset: 0;
  z-index: 2;
  overflow: hidden;
  pointer-events: none;
}

.ember {
  position: absolute;
  bottom: -5%;
  border-radius: 50%;
  opacity: 0;
  /* Two independent animations: the slow climb (organic, multi-point drift
     rather than a single straight line) and a fast brightness flicker layered
     on top — real embers don't glow at a constant intensity, they pulse as
     they tumble through the air. Keeping flicker on `filter` rather than
     `opacity` avoids the two animations fighting over the same property
     (the later-listed animation would just win outright and cancel the
     rise's own fade envelope). */
  animation: ember-rise var(--ember-duration, 20s) ease-in-out infinite,
    ember-flicker var(--flicker-duration, 0.5s) ease-in-out infinite;
}

@keyframes ember-rise {
  0% {
    transform: translate(0, 0) scale(0.4);
    opacity: 0;
  }
  9% {
    opacity: 0.85;
    transform: translate(calc(var(--ember-drift, 18px) * 0.2), -9vh) scale(1);
  }
  23% {
    transform: translate(calc(var(--ember-drift, 18px) * -0.25), -23vh) scale(0.9);
    opacity: 0.6;
  }
  39% {
    transform: translate(calc(var(--ember-drift, 18px) * 0.65), -39vh) scale(1.05);
    opacity: 0.75;
  }
  55% {
    transform: translate(var(--ember-drift, 18px), -58vh) scale(0.8);
    opacity: 0.48;
  }
  73% {
    transform: translate(calc(var(--ember-drift, 18px) * -0.45), -78vh) scale(0.6);
    opacity: 0.28;
  }
  89% {
    transform: translate(calc(var(--ember-drift, 18px) * -1.1), -98vh) scale(0.4);
    opacity: 0.12;
  }
  100% {
    transform: translate(calc(var(--ember-drift, 18px) * -1.5), -112vh) scale(0.15);
    opacity: 0;
  }
}

@keyframes ember-flicker {
  0%,
  100% {
    filter: brightness(1);
  }
  35% {
    filter: brightness(1.5);
  }
  60% {
    filter: brightness(0.8);
  }
  82% {
    filter: brightness(1.3);
  }
}

.ember--1 {
  left: 3%;
  width: 3px;
  height: 3px;
  background: var(--ember-light);
  box-shadow: 0 0 4px var(--ember-light), 0 0 8px var(--ember);
  --ember-drift: 14px;
  --ember-duration: 19s;
  --flicker-duration: 0.42s;
  animation-delay: -2s, -0.1s;
}
.ember--2 {
  left: 7%;
  width: 2px;
  height: 2px;
  background: var(--gold);
  box-shadow: 0 0 3px var(--gold), 0 0 6px var(--ember);
  --ember-drift: -20px;
  --ember-duration: 23s;
  --flicker-duration: 0.55s;
  animation-delay: -9s, -0.3s;
}
.ember--3 {
  left: 93%;
  width: 4px;
  height: 4px;
  background: var(--ember);
  box-shadow: 0 0 5px var(--ember), 0 0 10px var(--ember-deep);
  --ember-drift: -16px;
  --ember-duration: 21s;
  --flicker-duration: 0.48s;
  animation-delay: -14s, -0.05s;
}
.ember--4 {
  left: 96%;
  width: 2px;
  height: 2px;
  background: var(--ember-light);
  box-shadow: 0 0 3px var(--ember-light), 0 0 6px var(--ember);
  --ember-drift: 22px;
  --ember-duration: 17s;
  --flicker-duration: 0.6s;
  animation-delay: -5s, -0.2s;
}
.ember--5 {
  left: 12%;
  width: 3px;
  height: 3px;
  background: var(--gold);
  box-shadow: 0 0 4px var(--gold), 0 0 8px var(--ember-deep);
  --ember-drift: -12px;
  --ember-duration: 25s;
  --flicker-duration: 0.38s;
  animation-delay: -18s, -0.4s;
}
.ember--6 {
  left: 88%;
  width: 3px;
  height: 3px;
  background: var(--ember);
  box-shadow: 0 0 4px var(--ember), 0 0 8px var(--ember-deep);
  --ember-drift: 18px;
  --ember-duration: 20s;
  --flicker-duration: 0.52s;
  animation-delay: -11s, -0.15s;
}

.scroll-glow {
  position: fixed;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  mix-blend-mode: screen;
  background: radial-gradient(
    70vw 55vh at 50% var(--glow-y, 15%),
    rgba(232, 83, 31, var(--glow-strength, 0.06)),
    transparent 65%
  );
}

@media (prefers-reduced-motion: reduce) {
  .scroll-glow {
    display: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .ember-field {
    display: none;
  }
}

/* ── Section labels ── */
.section-tag {
  font-family: var(--font-body);
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ember);
  margin-bottom: var(--space-sm);
}

.section-title {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: clamp(2.1rem, 4.4vw, 3.6rem);
  line-height: 1.04;
  letter-spacing: -0.02em;
  color: var(--text-cream);
}

/* ── Icon system ──
   One shared line-icon language (stroke, currentColor) for every food/UI
   glyph on the site — replaces the emoji + mismatched icon packs that used
   to be scattered across menu items, the builder, and combo cards. Defs
   live in the inline <svg class="icon-sprite"> sprite at the top of <body>. */
.icon {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
  flex: none;
}

/* ── Buttons ── */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 0.95rem 1.9rem;
  border-radius: var(--radius-full);
  border: 1px solid transparent;
  font-family: var(--font-body);
  font-size: 0.95rem;
  font-weight: 700;
  position: relative;
  overflow: hidden;
  transform: perspective(500px) rotateX(0deg) rotateY(0deg) scale(1);
  transition: transform var(--duration-slow) var(--ease-plastic),
    background var(--duration) var(--ease),
    border-color var(--duration) var(--ease), color var(--duration) var(--ease);
  white-space: nowrap;
}

/* Plasticity contact point: a dark dent right under the finger/cursor,
   paired with a light bulge on the opposite side (material displaced
   away from the press). Position/strength driven by --px-frac/--py-frac/
   --pf, set from pointer data in main.js. */
.btn::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: radial-gradient(
      circle at calc(var(--px-frac, 0.5) * 100%) calc(var(--py-frac, 0.5) * 100%),
      rgba(8, 5, 4, 0.8),
      rgba(8, 5, 4, 0.35) 28%,
      transparent 50%
    ),
    radial-gradient(
      circle at calc((1 - var(--px-frac, 0.5)) * 100%) calc((1 - var(--py-frac, 0.5)) * 100%),
      rgba(255, 255, 255, 0.4),
      transparent 42%
    );
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--duration-slow) var(--ease-out);
}

.btn:focus-visible {
  outline: 2px solid var(--ember-light);
  outline-offset: 3px;
}
.btn--block {
  display: flex;
  width: 100%;
}

.btn--ember {
  background: linear-gradient(145deg, var(--ember), var(--ember-deep));
  color: #fff;
  box-shadow: var(--glow-ember);
}
.btn--ember:hover {
  transform: translateY(-3px);
}

.btn--ghost {
  background: rgba(245, 237, 224, 0.06);
  border-color: var(--border-strong);
  color: var(--text-cream);
}
.btn--ghost:hover {
  background: rgba(245, 237, 224, 0.12);
}

.btn--outline {
  border-color: rgba(232, 83, 31, 0.4);
  background: rgba(232, 83, 31, 0.08);
  color: #f3a578;
}
.btn--outline:hover {
  background: rgba(232, 83, 31, 0.18);
}


/* Pressed state: tilts toward the press point and compresses, force
   scaling everything via --pf (0–1). Fast, un-eased tracking while held
   so it reads as 1:1 with the pointer; release (base .btn transition
   above) is the slow overshoot settle. */
.btn.is-pressed {
  transition: transform var(--duration-fast) linear,
    background var(--duration) var(--ease),
    border-color var(--duration) var(--ease), color var(--duration) var(--ease);
  transform: perspective(500px)
    rotateX(calc((0.5 - var(--py-frac, 0.5)) * var(--pf, 0) * 18deg))
    rotateY(calc((var(--px-frac, 0.5) - 0.5) * var(--pf, 0) * 18deg))
    scale(calc(1 - var(--pf, 0) * 0.1));
}
.btn.is-pressed::after {
  opacity: calc(0.3 + var(--pf, 0) * 0.6);
  transition: opacity var(--duration-fast) linear;
}
.btn--ember.is-pressed {
  box-shadow: 0 calc(14px - var(--pf, 0) * 10px) calc(34px - var(--pf, 0) * 20px)
    rgba(232, 83, 31, calc(0.38 - var(--pf, 0) * 0.14));
}

/* Call-to-order confirm ring: repurposes the same ::after as the plasticity
   dent above (only one is ever showing at a time — main.js clears this
   class again once the animation's done, handing ::after back). */
.btn.is-confirming::after {
  background: radial-gradient(circle, rgba(255, 255, 255, 0.6), transparent 70%);
  opacity: 0.9;
  animation: cta-confirm-ring 0.55s var(--ease-out);
}

@keyframes cta-confirm-ring {
  0% {
    opacity: 0.85;
    transform: scale(0.35);
  }
  100% {
    opacity: 0;
    transform: scale(1.7);
  }
}

@media (prefers-reduced-motion: reduce) {
  .btn.is-confirming::after {
    animation: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .btn,
  .menu__tab {
    transition: background var(--duration) var(--ease),
      border-color var(--duration) var(--ease), color var(--duration) var(--ease);
  }
}

/* ========================================
   NAVIGATION
   ======================================== */
/* Note: the translucent blur lives on ::before (not on .site-header itself)
   because backdrop-filter on a position:fixed ancestor creates a new
   containing block, which would trap the fixed-position mobile nav overlay
   inside the header's box instead of the viewport. */
.site-header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 1000;
  transition: border-color var(--duration) var(--ease),
    transform var(--duration) var(--ease);
  border-bottom: 1px solid transparent;
}

/* The footer carries its own logo + tagline lockup right at its top edge.
   On short documents (mostly narrow/mobile widths, where the footer stacks
   into one tall column) that lockup can scroll up far enough to sit directly
   under this fixed header, reading as a confusing duplicate logo. Sliding
   the header off-screen just before that happens (toggled in main.js) avoids
   the collision without guessing a scroll-padding value that would need to
   vary with viewport height. */
.site-header.at-footer {
  transform: translateY(-100%);
}

.site-header::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: linear-gradient(
    to bottom,
    rgba(13, 10, 9, 0.82),
    rgba(13, 10, 9, 0.3)
  );
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  transition: background var(--duration) var(--ease);
}

.nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 84px;
}

.nav__logo {
  display: flex;
  align-items: center;
  gap: 12px;
  z-index: 1001;
  position: relative;
}

/* Grounds the mark with a soft ember glow so it reads as a deliberate
   lockup rather than a sticker floating in the header. */
.nav__logo::before {
  content: "";
  position: absolute;
  left: 11px;
  top: 50%;
  width: 84px;
  height: 84px;
  transform: translate(-50%, -50%);
  background: radial-gradient(
    circle,
    rgba(232, 83, 31, 0.28),
    transparent 68%
  );
  filter: blur(6px);
  pointer-events: none;
  z-index: -1;
}

.nav__logo-mark {
  flex: none;
  width: auto;
  height: 44px;
  pointer-events: none;
  filter: drop-shadow(0 6px 16px rgba(0, 0, 0, 0.45));
  transition: transform var(--duration-slow) var(--ease-plastic);
}

.nav__logo:hover .nav__logo-mark {
  transform: scale(1.05);
}

@media (prefers-reduced-motion: reduce) {
  .nav__logo-mark {
    transition: none;
  }
}

.nav__wordmark {
  font-family: var(--font-display);
  font-weight: 700;
  letter-spacing: 0.14em;
  font-size: 0.95rem;
  text-transform: uppercase;
  color: var(--text-cream);
}

.nav__wordmark span {
  color: var(--ember);
}

.nav__right {
  display: flex;
  align-items: center;
  gap: 1.5rem;
}

.nav__links {
  display: flex;
  align-items: center;
  gap: 2rem;
}






.nav__link {
  position: relative;
  font-size: 0.88rem;
  font-weight: 600;
  color: var(--text-muted);
  transition: color var(--duration) var(--ease);
}

.nav__link:hover {
  color: var(--text-cream);
}

/* Scroll-spy: whichever section is in view gets its nav link lit up —
   see js/main.js. The underline scales in from the center rather than
   just appearing, so it reads as a deliberate signal, not a glitch. */
.nav__link--active {
  color: var(--text-cream);
}

.nav__link--active::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -6px;
  height: 2px;
  border-radius: var(--radius-full);
  background: var(--ember);
  transform: scaleX(1);
  transform-origin: center;
  animation: nav-link-underline 0.35s var(--ease-out) both;
}

@keyframes nav-link-underline {
  from {
    transform: scaleX(0);
  }
  to {
    transform: scaleX(1);
  }
}

.nav__link--cta {
  padding: 0.7rem 1.4rem;
  border-radius: var(--radius-full);
  background: linear-gradient(145deg, var(--ember), var(--ember-deep));
  color: #fff;
  font-weight: 700;
  box-shadow: 0 10px 26px rgba(232, 83, 31, 0.35);
  transition: transform var(--duration) var(--ease);
}

.nav__link--cta:hover {
  transform: translateY(-2px);
  color: #fff;
}

.nav__toggle {
  display: none;
  flex-direction: column;
  gap: 5px;
  z-index: 1010;
  padding: 10px;
  width: 44px;
  height: 44px;
  align-items: center;
  justify-content: center;
  background: rgba(245, 237, 224, 0.06);
  border: 1px solid var(--border-strong);
  border-radius: 12px;
}

.nav__toggle-bar {
  display: block;
  width: 20px;
  height: 2px;
  background: var(--text-cream);
  border-radius: 2px;
  transition: all 0.3s var(--ease);
}

.nav__toggle.active .nav__toggle-bar:nth-child(1) {
  transform: rotate(45deg) translate(5px, 5px);
}
.nav__toggle.active .nav__toggle-bar:nth-child(2) {
  opacity: 0;
}
.nav__toggle.active .nav__toggle-bar:nth-child(3) {
  transform: rotate(-45deg) translate(5px, -5px);
}

/* ========================================
   HERO
   ======================================== */
/* Extra scroll runway for the pinned hero below — see js/hero.js. Height
   above 100vh, minus the 100vh the hero itself holds while stuck, is the
   distance scrubbing the donor's rotation takes — taller track, same
   rotation, just spread across more scrolling (slower). */
.hero-scroll-track {
  position: relative;
  height: 340vh;
}

.hero {
  background: var(--bg-base);
  padding-top: 84px;
  overflow: hidden;
  position: sticky;
  top: 0;
  min-height: 100vh;
  display: flex;
  align-items: center;
}

.hero__visual {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}

.hero__video {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover;
  object-position: center center;
}

.hero__video-scrim {
  position: absolute;
  inset: 0;
  z-index: 0;
  background: linear-gradient(
    to bottom,
    transparent 50%,
    rgba(13, 10, 9, 0.88) 100%
  );
  pointer-events: none;
}

/* Film-grain texture — cheap cinematic depth, generated inline (no image
   request). Static, not animated: a flickering grain reads as noisy/cheap;
   a still one just adds tooth to the gradient. */
.hero::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  opacity: 0.05;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 180px 180px;
}

.hero__inner {
  position: relative;
  z-index: 2;
  width: 100%;
}

.hero__copy {
  max-width: 620px;
  padding: var(--space-2xl) 0;
}

.hero__status {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 8px 16px;
  border-radius: var(--radius-full);
  background: rgba(245, 237, 224, 0.06);
  border: 1px solid var(--border-strong);
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--text-muted);
  margin-bottom: 1.6rem;
}

.hero__status-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--green);
  box-shadow: 0 0 10px var(--green);
}

.hero__title {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: clamp(2.7rem, 7vw, 5.4rem);
  line-height: 0.98;
  letter-spacing: -0.02em;
  color: var(--text-cream);
  margin-bottom: 1.4rem;
}

/* Entrance and the perpetual float are two separate animations run one at a
   time (never simultaneously on the same element) — js/hero.js swaps the
   "hero__title--float" class on the real animationend event once entrance
   finishes, rather than lining them up by matching delay/duration numbers.
   Two comma-separated animations both touching `transform` on the same
   element can hand off with a one-frame pop if their clocks drift even
   slightly; a class-swap driven by a real event can't drift. */
.hero__title > span {
  display: block;
  opacity: 0;
  animation: hero-word-in 0.85s cubic-bezier(0.22, 1, 0.36, 1) both;
}

.hero__title > span:nth-child(1) {
  animation-delay: 0.15s;
}
.hero__title > span:nth-child(2) {
  animation-delay: 0.38s;
}
.hero__title > span:nth-child(3) {
  animation-delay: 0.6s;
}

.hero__title > span.hero__title--float {
  /* explicit opacity: swapping the `animation` shorthand fully replaces
     hero-word-in's fill-mode:both, so its held opacity:1 goes with it —
     without this, the base rule's opacity:0 shows through and the line
     vanishes the instant it starts floating. */
  opacity: 1;
  animation: hero-word-float 4.5s ease-in-out infinite;
}

@media (prefers-reduced-motion: reduce) {
  /* animation: none alone would leave the line stuck at hero-word-in's
     opacity: 0 starting state — fill-mode: both is what's holding it
     there once the animation's gone, so opacity needs setting back
     explicitly, same as .hero__title--float already does above for the
     same reason. */
  .hero__title > span {
    opacity: 1;
    animation: none;
  }
  .hero__title > span.hero__title--float {
    animation: none;
  }
}

.hero__accent {
  position: relative;
  color: var(--ember);
  animation: ks-glow 3s ease-in-out infinite;
}

@media (prefers-reduced-motion: reduce) {
  .hero__accent {
    animation: none;
  }
}

/* Full-inset overlay so each spark's bottom/left % positions relative to
   the whole "fire" word box, not just the text baseline. */
.hero__spark-field {
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  overflow: visible;
}

.hero__spark {
  position: absolute;
  border-radius: 50%;
  font-style: normal;
  animation-name: hero-spark-rise;
  animation-timing-function: ease-out;
  animation-iteration-count: infinite;
}

.hero__spark--1 {
  bottom: 88%;
  left: 2%;
  width: 4px;
  height: 4px;
  background: #ffe840;
  box-shadow: 0 0 4px #ffe840, 0 0 8px #f09030;
  --spark-x: -44px;
  --spark-y: -28px;
  animation-duration: 1.6s;
  animation-delay: -0.2s;
}
.hero__spark--2 {
  bottom: 100%;
  left: 14%;
  width: 3px;
  height: 3px;
  background: #fff8e0;
  box-shadow: 0 0 3px #fff8e0, 0 0 6px #f08020;
  --spark-x: -26px;
  --spark-y: -54px;
  animation-duration: 1.2s;
  animation-delay: -0.9s;
}
.hero__spark--3 {
  bottom: 94%;
  left: 30%;
  width: 5px;
  height: 5px;
  background: #ffd020;
  box-shadow: 0 0 5px #ffd020, 0 0 10px #f06010;
  --spark-x: 16px;
  --spark-y: -64px;
  animation-duration: 1.8s;
  animation-delay: 0s;
}
.hero__spark--4 {
  bottom: 82%;
  left: 48%;
  width: 3px;
  height: 3px;
  background: #ffb030;
  box-shadow: 0 0 4px #ffb030, 0 0 7px #e84010;
  --spark-x: -32px;
  --spark-y: -38px;
  animation-duration: 1.1s;
  animation-delay: -0.55s;
}
.hero__spark--5 {
  bottom: 96%;
  left: 62%;
  width: 4px;
  height: 4px;
  background: #ffe040;
  box-shadow: 0 0 4px #ffe040, 0 0 8px #f07020;
  --spark-x: 48px;
  --spark-y: -25px;
  animation-duration: 1.4s;
  animation-delay: -1.1s;
}
.hero__spark--6 {
  bottom: 88%;
  left: 75%;
  width: 3px;
  height: 5px;
  background: #fff8e0;
  box-shadow: 0 0 3px #fff8e0, 0 0 7px #f09020;
  --spark-x: 28px;
  --spark-y: -52px;
  animation-duration: 1.3s;
  animation-delay: -0.35s;
}
.hero__spark--7 {
  bottom: 92%;
  left: 88%;
  width: 4px;
  height: 4px;
  background: #ffc030;
  box-shadow: 0 0 4px #ffc030, 0 0 9px #e85010;
  --spark-x: 52px;
  --spark-y: -20px;
  animation-duration: 1.5s;
  animation-delay: -0.75s;
}
.hero__spark--8 {
  bottom: 78%;
  left: 55%;
  width: 2px;
  height: 2px;
  background: #ffe840;
  box-shadow: 0 0 3px #ffe840, 0 0 6px #ffa020;
  --spark-x: 22px;
  --spark-y: -44px;
  animation-duration: 1s;
  animation-delay: -1.3s;
}

.hero__subtitle {
  max-width: 460px;
  font-size: clamp(1rem, 1.6vw, 1.15rem);
  line-height: 1.65;
  color: var(--text-faint);
  margin-bottom: 2.2rem;
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
}

.hero__scroll-hint {
  position: absolute;
  bottom: 26px;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  color: var(--text-dim);
  font-size: 0.7rem;
  letter-spacing: 0.2em;
  z-index: 2;
}

.hero__scroll-hint span {
  width: 1px;
  height: 34px;
  background: linear-gradient(var(--text-dim), transparent);
}

/* ========================================
   OUR STORY
   ======================================== */
.story {
  padding: var(--space-3xl) 0;
  background: var(--bg-base);
}

.story__grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-2xl);
  align-items: center;
}

/* Deliberately never transforms. At this element's size, tilting it
   directly used to visibly shift its own edges out from under a cursor
   sitting near the border — pointer hit-testing follows the transformed
   box, so that shift could drop the hover, snap the tilt back to flat,
   put the cursor back inside, and re-trigger it: a flicker loop, worse
   the longer the cursor held still near an edge. Splitting the hover
   target (this, stable) from the visual tilt (.story__image-frame,
   below) means the tilt can move however far it wants without ever
   moving the box hover is actually measured against. .menu-item and
   .combo-card don't need this same split — small enough that the same
   6deg max tilt shifts their edges only a couple of pixels, not enough
   to cross the cursor. */
.story__image {
  position: relative;
  aspect-ratio: 4 / 5;
}

.story__image-frame {
  position: absolute;
  inset: 0;
  /* Same tilt-motion language as .combo-card/.menu-item: transform itself
     lives on .reveal/.reveal.visible (this element is always also
     .reveal), but the transition needs to sit here regardless, since
     that's what actually smooths every --tilt-x/--tilt-y change coming
     from the pointermove/pointerleave handler in main.js — both the live
     cursor-tracking and the reset back to flat on hover-out. --tilt-x/
     --tilt-y themselves are set on .story__image (see main.js) and
     inherit down to here, same as --mx/--my below. */
  transition: transform 0.4s var(--ease-out);
}

@media (prefers-reduced-motion: reduce) {
  .story__image-frame {
    transition: none;
  }
}

/* Cursor-follow spotlight — same language as the combo-card/menu-item
   hover glow (see main.js, which tracks --mx/--my for this too, set on
   the stable .story__image above). Desktop/mouse only; harmless no-op
   elsewhere since the glow just never gets an opacity to show. */
.story__image-frame::before {
  content: "";
  position: absolute;
  inset: 0;
  /* Above the ::after top-fade (also z-index 2, painted later in source
     order) so the glow isn't dimmed under the darkened top of the photo. */
  z-index: 3;
  opacity: 0;
  border-radius: var(--radius-lg);
  background: radial-gradient(
    280px circle at var(--mx, 50%) var(--my, 50%),
    rgba(232, 83, 31, 0.16),
    transparent 70%
  );
  transition: opacity 0.4s var(--ease-out);
  pointer-events: none;
}

.story__image:hover .story__image-frame::before {
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  .story__image-frame::before {
    transition: none;
  }
}

.story__image-frame img {
  position: relative;
  z-index: 1;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: var(--radius-lg);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-lg);
  transition: border-color var(--duration) var(--ease);
}

.story__image:hover .story__image-frame img {
  border-color: rgba(232, 83, 31, 0.35);
}

.story__image-frame::after {
  content: "";
  position: absolute;
  z-index: 2;
  inset: 0;
  border-radius: var(--radius-lg);
  background: linear-gradient(to top, rgba(13, 10, 9, 0.4), transparent 45%);
}

.story__title {
  margin-bottom: 1.4rem;
}

.story__body {
  font-size: 1.05rem;
  line-height: 1.75;
  color: var(--text-faint);
  margin-bottom: 1.1rem;
}

.story__stats {
  display: grid;
  /* auto-fit so this reflows on its own content width rather than jumping
     to a single column at the same breakpoint the rest of the page does —
     three short stat pairs have room to stay in a row well past 768px. */
  grid-template-columns: repeat(auto-fit, minmax(96px, 1fr));
  gap: var(--space-md);
  margin-top: 1.8rem;
}

.story__stat-value {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 1.9rem;
  color: var(--gold);
  margin-bottom: 0.2rem;
}

.story__stat-label {
  font-size: 0.82rem;
  color: var(--text-dim);
}

/* ========================================
   CROWD FAVOURITES — marquee
   ======================================== */
.marquee {
  padding: 2rem 0 3.2rem;
  overflow: hidden;
  background: var(--bg-base);
}

.marquee__label {
  text-align: center;
  margin-bottom: 1.6rem;
}

.marquee__track {
  display: flex;
  gap: 16px;
  width: max-content;
  animation: ks-marquee 34s linear infinite;
}

@media (prefers-reduced-motion: reduce) {
  /* The pills are one set duplicated once, for a seamless loop back to
     0% — freezing here just shows that first, complete set normally,
     rather than cutting anything off mid-scroll. */
  .marquee__track {
    animation: none;
  }
}

.marquee__pill {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 24px;
  border-radius: var(--radius-full);
  background: linear-gradient(160deg, var(--bg-card-1), var(--bg-card-2));
  border: 1px solid var(--border);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.05rem;
  color: var(--text-cream);
  white-space: nowrap;
}

.marquee__pill .icon {
  width: 20px;
  height: 20px;
  color: var(--ember);
}
.marquee__pill span:last-child {
  color: var(--ember);
}

/* ========================================
   MENU
   ======================================== */
.menu {
  padding: var(--space-3xl) 0;
  background: var(--bg-alt);
}

.menu__header {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 1.5rem;
  flex-wrap: wrap;
  margin-bottom: 2.4rem;
}


.menu__tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 2.2rem;
}

.menu__tab {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  flex: 0 0 auto;
  padding: 9px 18px 9px 14px;
  border-radius: var(--radius-full);
  border: 1px solid var(--border-strong);
  background: rgba(245, 237, 224, 0.05);
  color: var(--text-muted);
  font-weight: 700;
  font-size: 0.88rem;
  white-space: nowrap;
  transition: all var(--duration) var(--ease);
}

.menu__tab-icon {
  width: 18px;
  height: 18px;
  flex: none;
  object-fit: contain;
}

.menu__tab:hover {
  border-color: var(--border-strong);
  color: var(--text-cream);
}

.menu__tab.active {
  background: linear-gradient(145deg, var(--ember), var(--ember-deep));
  color: #fff;
  border-color: transparent;
}

.menu__tab:focus-visible {
  outline: 2px solid var(--ember-light);
  outline-offset: 2px;
}

/* Below full desktop width the nine chips no longer fit one row; a single
   swipeable row (same treatment as phones, see the 768px block) beats a
   lonely second row of two chips. */
@media (max-width: 1199px) {
  .menu__tabs {
    flex-wrap: nowrap;
    overflow-x: auto;
    scroll-snap-type: x proximity;
    scrollbar-width: none;
    margin-left: calc(-1 * clamp(18px, 5vw, 40px));
    margin-right: calc(-1 * clamp(18px, 5vw, 40px));
    padding-left: clamp(18px, 5vw, 40px);
    padding-right: clamp(18px, 5vw, 40px);
  }
  .menu__tabs::-webkit-scrollbar {
    display: none;
  }
  .menu__tab {
    scroll-snap-align: start;
  }
}

/* Plasticity press reaction — same contact-point mechanic as .btn (see
   above): a dark dent under the press point paired with a light bulge
   opposite it, tilt/compression scaling with --pf. Dialled back a notch
   from .btn since tabs are a secondary, frequently-repeated control. */
.menu__tab {
  position: relative;
  overflow: hidden;
  transform: perspective(500px) rotateX(0deg) rotateY(0deg) scale(1);
  transition: background var(--duration) var(--ease),
    color var(--duration) var(--ease), border-color var(--duration) var(--ease),
    transform var(--duration-slow) var(--ease-plastic);
}
.menu__tab::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: radial-gradient(
      circle at calc(var(--px-frac, 0.5) * 100%) calc(var(--py-frac, 0.5) * 100%),
      rgba(8, 5, 4, 0.55),
      rgba(8, 5, 4, 0.22) 28%,
      transparent 50%
    ),
    radial-gradient(
      circle at calc((1 - var(--px-frac, 0.5)) * 100%) calc((1 - var(--py-frac, 0.5)) * 100%),
      rgba(255, 255, 255, 0.3),
      transparent 42%
    );
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--duration-slow) var(--ease-out);
}
.menu__tab.is-pressed {
  transition: background var(--duration) var(--ease),
    color var(--duration) var(--ease), border-color var(--duration) var(--ease),
    transform var(--duration-fast) linear;
  transform: perspective(500px)
    rotateX(calc((0.5 - var(--py-frac, 0.5)) * var(--pf, 0) * 14deg))
    rotateY(calc((var(--px-frac, 0.5) - 0.5) * var(--pf, 0) * 14deg))
    scale(calc(1 - var(--pf, 0) * 0.08));
}
.menu__tab.is-pressed::after {
  opacity: calc(0.28 + var(--pf, 0) * 0.55);
  transition: opacity var(--duration-fast) linear;
}

.menu__banner {
  position: relative;
  border-radius: var(--radius-lg);
  overflow: hidden;
  height: 500px;
  margin-bottom: 1.8rem;
  background: var(--bg-deep);
}

.menu__banner::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  background-image: var(--banner-bg);
  background-size: cover;
  background-position: center;
  filter: blur(26px) brightness(0.55) saturate(1.15);
  transform: scale(1.15);
}

.menu__banner img {
  position: relative;
  z-index: 1;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.menu__banner::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  background: linear-gradient(
    to top,
    rgba(13, 10, 9, 0.75) 0%,
    transparent 55%
  );
}

.menu__banner-caption {
  position: absolute;
  bottom: 28px;
  left: 32px;
  z-index: 3;
}

.menu__banner-eyebrow {
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.2em;
  color: rgba(245, 237, 224, 0.55);
  margin-bottom: 6px;
}

.menu__banner-title {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 2.1rem;
  color: #fff;
  letter-spacing: -0.01em;
}

.menu__panel {
  display: none;
}
.menu__panel.active {
  display: block;
  animation: fadeInUp 0.5s var(--ease-out);
}

@media (prefers-reduced-motion: reduce) {
  .menu__panel.active {
    animation: none;
  }
}

/* Each panel groups a few of the original, more specific categories under
   one broader tab (e.g. "Rice & Salad" holds Doner Rice, Doner Salad, and
   Shawarma) so the tab row stays short while every item keeps a clear,
   labeled subsection. */
.menu__group {
  margin-bottom: 2.4rem;
}
.menu__group:last-child {
  margin-bottom: 0;
}

.menu__group-title {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.05rem;
  color: var(--text-cream);
  padding-left: 14px;
  border-left: 3px solid var(--ember);
  margin-bottom: 1rem;
}

.menu__list {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  align-items: stretch;
  gap: 10px;
}

/* Desktop only: banner pinned beside the scrolling item list, rather than
   stacked above it. Selecting .menu__banner/.menu__list/.menu__group by
   direct-child instead of wrapping them in a new container keeps this a
   pure CSS layout change — no HTML restructuring across the nine panels.
   Below this width the panel stays the original stacked layout; pinning a
   banner while a short list scrolls past isn't worth it once there's no
   real scroll runway, and a fixed sticky photo can crowd a small screen. */
@media (min-width: 900px) {
  .menu__panel.active {
    display: grid;
    grid-template-columns: minmax(280px, 380px) 1fr;
    align-items: start;
    gap: 2.4rem;
  }

  .menu__panel.active > .menu__banner {
    grid-column: 1;
    grid-row: 1 / -1;
    position: sticky;
    top: 100px;
    margin-bottom: 0;
  }

  .menu__panel.active > .menu__list,
  .menu__panel.active > .menu__group {
    grid-column: 2;
  }
}

/* Beside the pinned banner on a tablet-width screen, two columns leave
   each card too narrow for a name, description and price side by side. */
@media (min-width: 900px) and (max-width: 1199px) {
  .menu__list {
    grid-template-columns: 1fr;
  }
}

.menu-item {
  position: relative;
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  column-gap: 20px;
  row-gap: 4px;
  padding: 18px 22px;
  /* Every card the same height regardless of content — a two-line name,
     one price line, or a stacked S/L price all fit within this, so
     nothing needs to stretch or leave a gap to line up with its row. */
  min-height: 96px;
  border-radius: var(--radius-md);
  background: linear-gradient(160deg, var(--bg-card-1), var(--bg-card-2));
  border: 1px solid var(--border);
  /* transform itself lives on .reveal/.reveal.visible (this card is always
     also .reveal) — see the comment there. */
  transition: border-color var(--duration) var(--ease),
    background var(--duration) var(--ease), transform 0.4s var(--ease-out);
}

.menu-item:hover {
  border-color: rgba(232, 83, 31, 0.35);
  background: linear-gradient(
    160deg,
    var(--bg-card-1-hover),
    var(--bg-card-2-hover)
  );
}

/* Cursor-follow spotlight + tilt, same language as the combo cards below —
   mouse-only (see main.js), a no-op elsewhere since the glow just never
   gets an opacity and --tilt-x/--tilt-y never leave their 0deg default. */
.menu-item::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  border-radius: inherit;
  opacity: 0;
  background: radial-gradient(
    220px circle at var(--mx, 50%) var(--my, 50%),
    rgba(232, 83, 31, 0.14),
    transparent 70%
  );
  transition: opacity 0.4s var(--ease-out);
  pointer-events: none;
}
.menu-item:hover::before {
  opacity: 1;
}
.menu-item > * {
  position: relative;
  z-index: 1;
}

@media (prefers-reduced-motion: reduce) {
  .menu-item {
    transition: border-color var(--duration) var(--ease),
      background var(--duration) var(--ease);
  }
  .menu-item::before {
    transition: none;
  }
}

.menu-item__head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}
.menu-item__icon {
  width: 20px;
  height: 20px;
  color: var(--ember);
}

.menu-item__name {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1rem;
  color: var(--text-cream);
  /* Capped at two lines so a handful of longer names (e.g. "Beef
     Camembert Burger") don't wrap to three and make their card taller
     than every other card's fixed min-height below. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.menu-item__badge {
  padding: 3px 8px;
  border-radius: var(--radius-full);
  background: rgba(59, 209, 122, 0.15);
  border: 1px solid rgba(59, 209, 122, 0.4);
  color: #7fe6a6;
  font-size: 0.62rem;
  font-weight: 700;
  letter-spacing: 0.06em;
}

.menu-item__price {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 1.25rem;
  color: var(--gold);
  white-space: nowrap;
  flex-shrink: 0;
}





/* Price spans both rows so it stays vertically centred beside the
   name + description pair, rather than aligning to the name alone. */
.menu-item__price {
  grid-column: 2;
  grid-row: 1 / span 2;
}

.menu-item__desc {
  grid-column: 1;
  font-size: 0.82rem;
  line-height: 1.45;
  color: var(--text-dim);
}

/* The one item worth steering an undecided customer towards — a warmer
   border and a gold tag, quieter than the ember used for actions. */
.menu-item--featured {
  border-color: rgba(240, 167, 46, 0.4);
}

.menu-item__tag {
  padding: 3px 9px;
  border-radius: var(--radius-full);
  background: rgba(240, 167, 46, 0.14);
  border: 1px solid rgba(240, 167, 46, 0.45);
  color: var(--gold);
  font-size: 0.62rem;
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  white-space: nowrap;
}

/* For items sold in two sizes (e.g. chips, wedges) — stacks S/L prices
   instead of a single figure, at a smaller scale so it doesn't outweigh
   the plain single-price items next to it in the grid. */
.menu-item__price--sizes {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 3px;
  flex-shrink: 0;
}

.menu-item__price-row {
  font-family: var(--font-body);
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--text-dim);
  white-space: nowrap;
}

.menu-item__price-row strong {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 1rem;
  color: var(--gold);
  margin-left: 3px;
}

.menu__note {
  text-align: center;
  margin-top: 2rem;
  font-size: 0.82rem;
  color: var(--text-dim);
}

/* ========================================
   COMBO DEALS
   ======================================== */
.combos {
  padding: var(--space-xl) 0;
  background: var(--bg-base);
}

.combos__header {
  margin-bottom: 1.6rem;
}
.combos__title {
  margin-top: 0.3rem;
}

/* Exactly three deals, so three equal columns across the full container —
   auto-fill left them bunched on the left with half the row empty. */
.combos__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
}

.combo-card {
  position: relative;
  border-radius: var(--radius-md);
  overflow: hidden;
  padding: 24px 24px 22px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  border: 1px solid var(--border);
  background: linear-gradient(
    145deg,
    rgba(42, 26, 14, 0.7),
    rgba(26, 14, 8, 0.7)
  );
  /* transform itself lives on .reveal/.reveal.visible (this card is always
     also .reveal) — see the comment there. */
  transition: transform 0.4s var(--ease-out);
}

@media (prefers-reduced-motion: reduce) {
  .combo-card {
    transition: none;
  }
}

/* Cursor-follow spotlight — a quiet nod to the plasticity buttons'
   pointer-reactive language, scaled down for a passive hover instead of a
   press. Desktop/mouse only (see main.js); harmless no-op elsewhere since
   the glow just never gets an opacity to show. */
.combo-card::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  opacity: 0;
  background: radial-gradient(
    260px circle at var(--mx, 50%) var(--my, 50%),
    rgba(232, 83, 31, 0.16),
    transparent 70%
  );
  transition: opacity 0.4s var(--ease-out);
  pointer-events: none;
}
.combo-card:hover::before {
  opacity: 1;
}
.combo-card > * {
  position: relative;
  z-index: 1;
}

@media (prefers-reduced-motion: reduce) {
  .combo-card::before {
    transition: none;
  }
}

.combo-card--popular {
  border-color: rgba(232, 83, 31, 0.35);
}

.combo-card__badge {
  position: absolute;
  top: 0;
  right: 0;
  padding: 8px 16px;
  background: linear-gradient(135deg, var(--ember), var(--ember-deep));
  border-radius: 0 var(--radius-lg) 0 16px;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 0.75rem;
  color: #fff;
  letter-spacing: 0.04em;
}

.combo-card__icon {
  display: flex;
  align-items: center;
  gap: 8px;
  color: var(--ember);
}
.combo-card__icon .icon {
  width: 30px;
  height: 30px;
}
.combo-card__icon--group .icon:first-child {
  width: 26px;
  height: 26px;
}
.combo-card__icon--group .icon--badge {
  width: 16px;
  height: 16px;
  color: var(--gold);
}

.combo-card__name {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 1.2rem;
  color: var(--text-cream);
}

.combo-card__desc {
  font-size: 0.86rem;
  line-height: 1.5;
  color: var(--text-dim);
}

.combo-card__price-row {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin-top: auto;
}

.combo-card__price {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 1.9rem;
  color: var(--gold);
}

.combo-card__price-note {
  font-size: 0.76rem;
  color: var(--text-dim);
}


/* ========================================
   BUILD YOUR KEBAB
   ======================================== */
.builder {
  padding: var(--space-3xl) 0;
  background: linear-gradient(
    180deg,
    transparent,
    rgba(232, 83, 31, 0.05) 30%,
    rgba(232, 83, 31, 0.05) 70%,
    transparent
  );
}

.builder__header {
  text-align: center;
  margin-bottom: 2.8rem;
}
.builder__title {
  margin-top: 0.4rem;
}

.builder__grid {
  display: grid;
  grid-template-columns: 1.3fr 0.8fr;
  gap: 28px;
  align-items: start;
}

/* A `1fr` track is `minmax(auto, 1fr)`, and that `auto` floor is the
   item's min-content width — which for the preview card includes its
   nowrap summary values ("Onion, Parsley, Tomato, Mixed Cabbage,
   Lettuce"). Picking four or five salads therefore pushed the track
   past the container and shoved the whole page sideways, worst on
   phones where the grid collapses to one column and has no slack.
   min-width:0 lets the track shrink so the ellipsis actually engages. */
.builder__grid > * {
  min-width: 0;
}

.builder__groups {
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.builder__group {
  border-radius: var(--radius-md);
  background: linear-gradient(160deg, var(--bg-card-1), var(--bg-card-2));
  border: 1px solid var(--border);
  padding: 18px 18px 20px;
}

.builder__group-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin-bottom: 14px;
  gap: 12px;
}

.builder__group-title {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.05rem;
  color: var(--text-cream);
}

.builder__group-hint {
  font-size: 0.75rem;
  color: var(--text-dim);
  font-weight: 600;
  white-space: nowrap;
}

.builder__options {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}

.builder__option {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 10px 16px;
  border-radius: var(--radius-full);
  border: 1.5px solid var(--border-strong);
  background: rgba(245, 237, 224, 0.04);
  color: var(--text-faint);
  font-weight: 600;
  font-size: 0.88rem;
  transition: all 0.18s var(--ease);
}

.builder__option-icon {
  width: 18px;
  height: 18px;
  color: var(--ember);
}

/* "Mixed" and "Super (double)" aren't dishes of their own — they're
   combinations of the meats already pictured elsewhere — so instead of a
   single icon they reuse those: two icons side by side for "Mixed", one
   icon plus a size badge for "Super". */
.builder__option-icon-pair {
  display: inline-flex;
  align-items: center;
}
.builder__option-icon-pair .builder__option-icon:last-child {
  margin-left: -6px;
}

.builder__option-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 1px 6px;
  border-radius: var(--radius-full);
  background: rgba(240, 167, 46, 0.16);
  border: 1px solid rgba(240, 167, 46, 0.45);
  color: var(--gold);
  font-size: 0.68rem;
  font-weight: 800;
}
/* Sauces are too visually similar to tell apart as pictograms (every
   squeeze bottle looks the same) — a colour swatch showing the sauce's
   actual colour is more honest and more scannable across eleven options. */
.builder__option-swatch {
  width: 14px;
  height: 14px;
  flex: none;
  border-radius: 50%;
  background: var(--swatch);
  border: 1px solid rgba(0, 0, 0, 0.25);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.15);
}
.builder__option-plus {
  font-size: 0.75rem;
  opacity: 0.85;
}

.builder__option:hover {
  border-color: rgba(232, 83, 31, 0.4);
}

.builder__option.is-active {
  background: var(--ember-soft);
  border-color: var(--ember);
  color: var(--text-cream);
}

.builder__option:focus-visible {
  outline: 2px solid var(--ember-light);
  outline-offset: 2px;
}

/* Falafel/Super are disabled on bases the real menu doesn't sell them on
   (e.g. Meat on Chips is only ever Chicken/Lamb/Mixed). */
.builder__option:disabled,
.builder__option.is-disabled {
  opacity: 0.35;
  cursor: not-allowed;
  pointer-events: none;
}

.builder__preview {
  position: sticky;
  top: 104px;
}

.builder__card {
  border-radius: var(--radius-lg);
  background: linear-gradient(
    160deg,
    rgba(45, 33, 24, 0.85),
    rgba(20, 14, 10, 0.9)
  );
  border: 1px solid var(--border-strong);
  padding: 24px;
  box-shadow: var(--shadow-lg);
}

.builder__card-head {
  margin-bottom: 16px;
}

.builder__eyebrow {
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ember-light);
  margin-bottom: 4px;
}

.builder__dish-title {
  font-family: var(--font-display);
  font-size: 1.5rem;
  font-weight: 800;
  color: var(--text-cream);
  line-height: 1.15;
  transition: opacity 0.2s var(--ease-out);
}

.builder__dish-subtitle {
  margin-top: 6px;
  font-size: 0.85rem;
  color: var(--text-muted);
  line-height: 1.4;
  transition: opacity 0.2s var(--ease-out);
}

/* Each summary row is a small card: an icon thumbnail, an uppercase
   category label over the picked value, and a "Change" link that jumps
   straight back to that step above instead of leaving the shopper to
   scroll and hunt for it. */
.builder__summary {
  margin-top: 18px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-height: 30px;
}

.builder__summary-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  background: rgba(245, 237, 224, 0.03);
  border: 1px solid var(--border);
}

.builder__summary-icon {
  flex: none;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  overflow: hidden;
  display: grid;
  place-items: center;
  background: rgba(240, 167, 46, 0.14);
}

.builder__summary-icon img {
  width: 18px;
  height: 18px;
}

.builder__summary-text {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.builder__summary-label {
  font-size: 0.66rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-dim);
}

.builder__summary-value {
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--text-cream);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.builder__summary-change {
  flex: none;
  font-size: 0.76rem;
  font-weight: 700;
  color: var(--ember-light);
  padding: 4px 6px;
  border-radius: var(--radius-sm);
  transition: color 0.15s var(--ease), background 0.15s var(--ease);
}

.builder__summary-change:hover,
.builder__summary-change:focus-visible {
  color: var(--text-cream);
  background: rgba(232, 83, 31, 0.18);
}

.builder__total-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: 18px;
  padding-top: 18px;
  border-top: 1px solid var(--border-strong);
  margin-bottom: 16px;
}

.builder__total-label {
  font-size: 0.88rem;
  color: var(--text-faint);
  font-weight: 600;
}

.builder__total {
  display: inline-block;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 1.9rem;
  color: var(--gold);
}

@keyframes builder-total-bump {
  0% {
    transform: scale(1);
    color: var(--gold);
  }
  40% {
    transform: scale(1.16);
    color: #ffd873;
  }
  100% {
    transform: scale(1);
    color: var(--gold);
  }
}

.builder__total.is-bumping {
  animation: builder-total-bump 0.5s var(--ease-out);
}

@media (prefers-reduced-motion: reduce) {
  .builder__dish-title,
  .builder__dish-subtitle {
    transition: none;
  }
  .builder__total.is-bumping {
    animation: none;
  }
}

/* ========================================
   STICKY MOBILE BUILDER TOTAL BAR
   ======================================== */
.builder__order-note {
  font-size: 0.78rem;
  line-height: 1.5;
  color: var(--text-dim);
  text-align: center;
  margin-bottom: 12px;
}

.builder__uber-btn {
  margin-top: 10px;
}

/* An inline <svg> with no width/height stretches to fill its flex line,
   so this needs an explicit size or it swallows the whole button. */
.builder__call-btn .icon {
  width: 18px;
  height: 18px;
}

.builder-mobile-bar {
  display: none;
}

@media (max-width: 768px) {
  .builder-mobile-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 14px;
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 998;
    padding: 12px clamp(16px, 5vw, 28px)
      calc(12px + env(safe-area-inset-bottom));
    background: linear-gradient(
      to top,
      rgba(13, 10, 9, 0.97),
      rgba(13, 10, 9, 0.85)
    );
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    border-top: 1px solid var(--border);
    transform: translateY(100%);
    transition: transform var(--duration-slow) var(--ease-plastic);
  }

  .builder-mobile-bar.is-visible {
    transform: translateY(0);
  }

  .builder-mobile-bar__total {
    display: flex;
    flex-direction: column;
    line-height: 1.15;
  }

  .builder-mobile-bar__label {
    font-size: 0.7rem;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--text-dim);
    font-weight: 700;
  }

  .builder-mobile-bar__amount {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 1.3rem;
    color: var(--gold);
  }

  .builder-mobile-bar .btn {
    flex: none;
    padding-left: 20px;
    padding-right: 20px;
  }

  /* Never stack the section-scoped bar on top of the site-wide one. */
  body.builder-bar-active .sticky-order {
    transform: translateY(100%) !important;
  }
}

@media (prefers-reduced-motion: reduce) {
  .builder-mobile-bar {
    transition: none;
  }
}

/* ========================================
   REVIEWS
   ======================================== */
.reviews {
  padding: var(--space-3xl) 0;
  background: var(--bg-alt);
}

.reviews__header {
  margin-bottom: 2.6rem;
}

/* Desktop: heading + Google link on the left, the card deck on the right,
   so the deck no longer floats alone in the middle of a wide, empty band. */
@media (min-width: 900px) {
  .reviews__layout {
    display: grid;
    grid-template-columns: 1fr minmax(380px, 460px);
    align-items: center;
    gap: var(--space-xl);
  }
  .reviews__header {
    margin-bottom: 0;
  }
}

.reviews__intro {
  max-width: 34ch;
  margin-top: var(--space-sm);
  font-size: 1.05rem;
  color: var(--text-muted);
}

.reviews__google {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  margin-top: var(--space-md);
  padding: 12px 20px;
  border-radius: var(--radius-full);
  border: 1px solid var(--border-strong);
  background: rgba(245, 237, 224, 0.05);
  color: var(--text-cream);
  font-weight: 700;
  font-size: 0.9rem;
  transition: border-color var(--duration) var(--ease),
    background var(--duration) var(--ease);
}
.reviews__google:hover {
  border-color: rgba(240, 167, 46, 0.5);
  background: rgba(240, 167, 46, 0.08);
}
.reviews__google:focus-visible {
  outline: 2px solid var(--ember-light);
  outline-offset: 2px;
}
.reviews__google-stars {
  color: var(--gold);
  letter-spacing: 2px;
}
.reviews__google-arrow {
  transition: transform var(--duration) var(--ease-out);
}
.reviews__google:hover .reviews__google-arrow {
  transform: translateX(4px);
}

@media (prefers-reduced-motion: reduce) {
  .reviews__google,
  .reviews__google-arrow {
    transition: none;
  }
}
.reviews__title {
  margin-top: 0.4rem;
}

.reviews__deck-wrap {
  display: flex;
  flex-direction: column;
  align-items: center;
  max-width: 100%;
  overflow-x: hidden;
}

.reviews__deck-hint {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 18px;
  color: var(--text-dim);
}

.reviews__deck-hint-label {
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
}

.reviews__deck-hint-arrow {
  font-size: 0.95rem;
  animation: reviews-hint-nudge 1.6s ease-in-out infinite;
}

@keyframes reviews-hint-nudge {
  0%,
  100% {
    transform: translateX(0);
  }
  50% {
    transform: translateX(6px);
  }
}

.reviews__deck {
  position: relative;
  /* The stacked cards behind the top one fan out via `translate` (see the
     nth-child rules below), up to 42px right / 24px down plus a bit more
     from the rotation's bounding-box growth. Reserving that space here
     keeps the fan inside the deck's own box instead of bleeding past the
     viewport edge on narrow screens. */
  width: calc(100% - 64px);
  max-width: 330px;
  /* A fixed height rather than aspect-ratio: how many lines the 6-line
     clamp below needs is a function of font metrics, not card width, so
     tying height to width left narrower (mobile) cards too short to fit
     a full 6 lines without clipping mid-line. */
  height: 300px;
}

.reviews__deck-controls {
  display: flex;
  gap: 14px;
  margin-top: 26px;
}

.reviews__deck-btn {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: 1px solid var(--border-strong);
  background: rgba(245, 237, 224, 0.05);
  color: var(--text-cream);
  font-size: 1.1rem;
  display: grid;
  place-items: center;
  transition: all var(--duration) var(--ease);
}

.reviews__deck-btn:hover {
  background: rgba(232, 83, 31, 0.16);
  border-color: rgba(232, 83, 31, 0.4);
  transform: translateY(-2px);
}

.review-card {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  border-radius: var(--radius-lg);
  background: linear-gradient(160deg, var(--bg-card-1), var(--bg-card-2)),
    var(--bg-deep);
  border: 1px solid var(--border);
  box-shadow: 0 24px 60px rgba(13, 10, 9, 0.5);
  padding: 24px;
  cursor: grab;
  /* pan-y (not none) — lets the browser handle a vertical drag as normal
     page scrolling, and only withholds horizontal panning, which is what
     the swipe-to-dismiss drag below actually needs to own. `none` here
     was swallowing vertical scroll gestures that started on the front
     card into a card-drag instead. */
  touch-action: pan-y;
  transition: transform 0.45s var(--ease-out), filter 0.45s var(--ease-out),
    opacity 0.45s var(--ease-out);
}

.review-card:active {
  cursor: grabbing;
}

.review-card.is-dragging {
  transition: none;
}

.reviews__deck .review-card:nth-child(1) {
  z-index: 50;
  transform: translate(0, 0) rotate(0deg);
  filter: brightness(1);
  pointer-events: auto;
}
.reviews__deck .review-card:nth-child(2) {
  z-index: 40;
  transform: translate(14px, 8px) rotate(5deg);
  filter: brightness(0.82);
  pointer-events: none;
}
.reviews__deck .review-card:nth-child(3) {
  z-index: 30;
  transform: translate(28px, 16px) rotate(9deg);
  filter: brightness(0.68);
  pointer-events: none;
}
.reviews__deck .review-card:nth-child(4) {
  z-index: 20;
  transform: translate(42px, 24px) rotate(13deg);
  filter: brightness(0.55);
  pointer-events: none;
}
.reviews__deck .review-card:nth-child(n + 5) {
  z-index: 10;
  opacity: 0;
  pointer-events: none;
}

.review-card__stars {
  color: var(--gold);
  font-size: 0.9rem;
  margin-bottom: 10px;
  letter-spacing: 2px;
  flex: none;
}

.review-card__text {
  position: relative;
  font-size: 0.88rem;
  line-height: 1.55;
  color: var(--text-muted);
  margin-bottom: 14px;
  flex: 1;
  /* How many lines a review needs varies a lot by card width (up to 11 on
     a narrow phone for the longest review, vs. 6-7 once the deck hits its
     330px max-width) — no single line-clamp fits every review at every
     width without either clipping the long ones or wasting space on the
     short ones. Scrolling the text itself, instead of clamping it, means
     every review is fully readable regardless of how long it is. */
  overflow-y: auto;
  overscroll-behavior: contain;
  user-select: none;
}

/* Only shown once js/reviews-deck.js confirms the text actually overflows
   (see updateScrollHints) — a fade that's always there would dim the last
   line of plenty of reviews that fit just fine. */
.review-card__text.has-more::after {
  content: '';
  position: sticky;
  display: block;
  left: 0;
  right: 0;
  bottom: 0;
  height: 22px;
  margin-top: -22px;
  background: linear-gradient(to bottom, transparent, var(--bg-card-2));
  pointer-events: none;
}

.review-card__footer {
  display: flex;
  align-items: center;
  gap: 10px;
  flex: none;
}

.review-card__avatar {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: linear-gradient(145deg, var(--ember), var(--ember-deep));
  display: grid;
  place-items: center;
  font-weight: 700;
  font-size: 0.9rem;
  color: #fff;
  flex-shrink: 0;
}

.review-card__author {
  font-weight: 700;
  font-size: 0.85rem;
  color: var(--text-cream);
}
.review-card__note {
  font-size: 0.7rem;
  color: var(--text-dim);
  font-style: italic;
  margin-top: 2px;
}

/* ========================================
   FIND US
   ======================================== */
.find-us {
  padding: var(--space-3xl) 0;
  background: var(--bg-base);
}

.find-us__grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 24px;
}

.find-us__map {
  position: relative;
  min-height: 380px;
  border-radius: var(--radius-lg);
  overflow: hidden;
  border: 1px solid var(--border);
  background: var(--bg-deep);
}

/* Google's embed only ships a light-mode map (no API key = no styling
   params), so we fake dark mode with a colour-invert filter — a standard
   technique for free embeds. Slight desaturation + contrast keeps the
   inverted greys from looking too blown-out next to the ember palette. */
.find-us__map iframe {
  display: block;
  width: 100%;
  height: 100%;
  min-height: 380px;
  filter: invert(92%) hue-rotate(180deg) contrast(88%) saturate(120%)
    brightness(0.95);
  position: relative;
  z-index: 1;
  /* The embed itself takes a beat to fetch and paint (a live Google page,
     not a static asset) — fading it in on 'load' (see main.js) instead of
     leaving it to pop in mid-fetch reads as intentional rather than slow. */
  opacity: 0;
  /* Invisible but still on top until it loads — without this it would
     swallow clicks meant for the fallback card's Google Maps link. */
  pointer-events: none;
  transition: opacity 0.5s var(--ease-out);
}

.find-us__map iframe.is-loaded {
  opacity: 1;
  pointer-events: auto;
}

@media (prefers-reduced-motion: reduce) {
  .find-us__map iframe {
    transition: none;
  }
}

/* Sits behind the iframe (see z-index above), so it shows during the load
   gap — and stays as a usable card if the embed is blocked or offline.
   The faint street grid is pure CSS: two repeating line gradients plus one
   wider "main road" band, so it costs no image request. */
.find-us__map-placeholder {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: var(--space-md);
  text-align: center;
  color: var(--text-ghost);
  background:
    linear-gradient(
      100deg,
      transparent 46%,
      rgba(245, 237, 224, 0.07) 46%,
      rgba(245, 237, 224, 0.07) 50%,
      transparent 50%
    ),
    repeating-linear-gradient(
      0deg,
      transparent 0 46px,
      rgba(245, 237, 224, 0.035) 46px 48px
    ),
    repeating-linear-gradient(
      90deg,
      transparent 0 62px,
      rgba(245, 237, 224, 0.035) 62px 64px
    ),
    var(--bg-deep);
}

.find-us__map-address {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 1.3rem;
  line-height: 1.25;
  color: var(--text-cream);
}
.find-us__map-address span {
  display: block;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.9rem;
  color: var(--text-muted);
}

.find-us__map-link {
  position: relative;
  z-index: 3;
  margin-top: 4px;
  padding: 8px 4px;
  font-weight: 700;
  font-size: 0.88rem;
  color: var(--ember-light);
}
.find-us__map-link:hover {
  color: var(--gold);
}
.find-us__map-link:focus-visible {
  outline: 2px solid var(--ember-light);
  outline-offset: 2px;
  border-radius: 4px;
}

.find-us__map-placeholder .icon {
  width: 36px;
  height: 36px;
  color: var(--ember);
  animation: find-us-pin-pulse 1.6s var(--ease) infinite;
}

@keyframes find-us-pin-pulse {
  0%,
  100% {
    opacity: 0.5;
    transform: scale(1);
  }
  50% {
    opacity: 1;
    transform: scale(1.08);
  }
}

@media (prefers-reduced-motion: reduce) {
  .find-us__map-placeholder .icon {
    animation: none;
  }
}

/* Soft ember vignette at the edges ties the map into the card system
   instead of it reading as a foreign embedded rectangle. Explicit z-index
   so it stays above the iframe (z-index: 1 above) regardless of DOM order. */
.find-us__map::after {
  content: "";
  position: absolute;
  z-index: 2;
  inset: 0;
  pointer-events: none;
  box-shadow: inset 0 0 60px 10px rgba(13, 10, 9, 0.55);
  background: radial-gradient(
    circle at 85% 15%,
    rgba(232, 83, 31, 0.12),
    transparent 55%
  );
}

.find-us__card {
  border-radius: var(--radius-lg);
  background: linear-gradient(160deg, var(--bg-card-1), var(--bg-card-2));
  border: 1px solid var(--border);
  padding: clamp(24px, 4vw, 40px);
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.find-us__title {
  margin-bottom: 1.6rem;
}

.find-us__details {
  display: flex;
  flex-direction: column;
  gap: 20px;
  margin-bottom: 1.8rem;
}

.find-us__detail {
  display: flex;
  gap: 14px;
  align-items: flex-start;
}

.find-us__icon {
  width: 22px;
  height: 22px;
  flex-shrink: 0;
  color: var(--ember);
  margin-top: 2px;
}

.find-us__detail-label {
  font-weight: 700;
  font-size: 1rem;
  color: var(--text-cream);
  margin-bottom: 3px;
}
.find-us__detail-value {
  color: var(--text-faint);
  font-size: 0.92rem;
  line-height: 1.5;
}
.find-us__detail-value a:hover {
  color: var(--ember);
}

.find-us__actions {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
}
.find-us__actions .btn {
  flex: 1;
}

/* ========================================
   FOOTER
   ======================================== */
.footer {
  background: var(--bg-deep);
  padding: var(--space-2xl) 0 var(--space-lg);
  border-top: 1px solid var(--border);
}

.footer__grid {
  display: grid;
  grid-template-columns: 1.4fr 1fr 1fr;
  gap: 36px;
  margin-bottom: 2.4rem;
}

.footer__logo {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 18px;
}
.footer__logo-mark {
  width: auto;
  height: 48px;
  flex: none;
  pointer-events: none;
}

.footer__wordmark {
  font-family: var(--font-display);
  font-weight: 700;
  letter-spacing: 0.14em;
  font-size: 0.9rem;
  text-transform: uppercase;
  color: var(--text-cream);
}

.footer__wordmark span {
  color: var(--ember);
}

.footer__tagline {
  color: var(--text-dim);
  font-size: 0.9rem;
  line-height: 1.6;
  max-width: 300px;
}

.footer__badges {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: var(--space-md);
}

.footer__badge {
  display: inline-flex;
  align-items: center;
  padding: 8px 16px;
  border-radius: var(--radius-full);
  font-size: 0.8rem;
  font-weight: 700;
}

.footer__badge--halal {
  background: rgba(59, 209, 122, 0.12);
  border: 1px solid rgba(59, 209, 122, 0.4);
  color: #7fe6a6;
  letter-spacing: 0.04em;
}

.footer__badge--link {
  border: 1px solid var(--border-strong);
  background: rgba(245, 237, 224, 0.05);
  color: var(--text-cream);
  transition: border-color var(--duration) var(--ease),
    background var(--duration) var(--ease);
}
.footer__badge--link:hover {
  border-color: rgba(232, 83, 31, 0.45);
  background: var(--ember-soft);
}
.footer__badge--link:focus-visible {
  outline: 2px solid var(--ember-light);
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
  .footer__badge--link {
    transition: none;
  }
}

.footer__heading {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 0.85rem;
  letter-spacing: 0.1em;
  margin-bottom: 16px;
  color: var(--text-muted);
}

.footer__col {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

/* padding (not just gap) so each link's own tap target is close to the
   44px touch-target minimum, not just the text's line-height */
.footer__col a,
.footer__col p {
  display: block;
  padding: 8px 0;
  font-size: 0.9rem;
  color: var(--text-dim);
  transition: color var(--duration) var(--ease);
}
.footer__col a:hover {
  color: var(--text-cream);
}

.footer__bottom {
  max-width: 1280px;
  margin: 0 auto;
  padding-top: 24px;
  border-top: 1px solid var(--border);
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 12px;
  font-size: 0.78rem;
  color: var(--text-dim);
}

.footer__bottom a {
  display: inline-block;
  font-weight: 800;
  color: var(--gold);
  text-decoration: underline;
  text-decoration-color: rgba(240, 167, 46, 0.4);
  text-underline-offset: 2px;
  transition: color var(--duration) var(--ease);
  /* Scaling it up (an earlier attempt) grew the text in place without
     reflowing "Site by " right before it — at the top of the pulse the
     two visually overlapped, reading like a stacking/z-index glitch. Same
     vertical-only idea as the hero H1 words' hero-word-float, but that
     animation's -7px suits a big heading word — proportionally huge on
     this much smaller footer text — so this is its own keyframe with a
     smaller rise instead, same 4.5s timing and easing, still layered
     with the same glow .hero__accent uses on "fire". */
  animation: footer-credit-float 4.5s ease-in-out infinite,
    ks-glow 3s ease-in-out infinite;
}

@keyframes footer-credit-float {
  0%,
  100% {
    transform: translateY(0);
  }
  50% {
    transform: translateY(-2px);
  }
}

@media (prefers-reduced-motion: reduce) {
  .footer__bottom a {
    animation: none;
  }
}

.footer__bottom a:hover {
  color: var(--ember-light);
}

/* ========================================
   SKIP LINK
   There are ~150 focusable elements on this page; without this a keyboard
   or screen-reader user tabs the entire nav before reaching any content.
   Off-screen until focused rather than display:none, which would take it
   out of the tab order and defeat the point.
   ======================================== */
.skip-link {
  /* fixed, not absolute: an absolutely positioned element nudged off the
     top sits at negative document coordinates, which is exactly the strip
     that rubber-band/elastic overscroll exposes on macOS trackpads and
     iOS Safari — so it would flash into view on an ordinary scroll. */
  position: fixed;
  top: 8px;
  left: 8px;
  z-index: 2000;
  padding: 12px 20px;
  border-radius: var(--radius-full);
  background: var(--ember);
  color: #fff;
  font-weight: 700;
  font-size: 0.9rem;
  /* Hidden by clipping rather than by being moved somewhere off-screen:
     there is no scroll position or overscroll state that can reveal a
     fully clipped box, and it stays in the tab order either way. */
  clip-path: inset(50%);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--duration) var(--ease-out);
}

.skip-link:focus {
  clip-path: none;
  opacity: 1;
  pointer-events: auto;
  outline: 2px solid var(--ember-light);
  outline-offset: 3px;
}

@media (prefers-reduced-motion: reduce) {
  .skip-link {
    transition: none;
  }
}

/* ========================================
   VIEW TRANSITIONS — menu tab panels
   Progressive enhancement: browsers without the API just hard-cut as
   before (see activateTab in main.js). Naming the panel container means
   only it crossfades, rather than the default root snapshot animating
   the whole page.
   ======================================== */
.menu__panels {
  view-transition-name: menu-panels;
}

::view-transition-old(menu-panels),
::view-transition-new(menu-panels) {
  animation-duration: 0.28s;
  animation-timing-function: var(--ease-out);
}

@media (prefers-reduced-motion: reduce) {
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) {
    animation: none !important;
  }
}

/* ========================================
   STICKY MOBILE ORDER BAR
   ======================================== */
.sticky-order {
  display: none;
}

@media (max-width: 768px) {
  .sticky-order {
    display: block;
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 999;
    padding: 12px clamp(16px, 5vw, 28px)
      calc(12px + env(safe-area-inset-bottom));
    background: linear-gradient(
      to top,
      rgba(13, 10, 9, 0.97),
      rgba(13, 10, 9, 0.82)
    );
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    border-top: 1px solid var(--border);
    transform: translateY(100%);
    transition: transform var(--duration-slow) var(--ease-plastic);
  }

  .sticky-order.is-visible {
    transform: translateY(0);
  }

  .sticky-order .icon {
    width: 20px;
    height: 20px;
  }

  /* Room so the bar never covers the last bit of page content. */
  body:has(.sticky-order) {
    scroll-padding-bottom: 84px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .sticky-order {
    transition: none;
  }
}

/* ========================================
   MOBILE SECTION JUMP BAR + BACK TO TOP
   Both are phone-only: on desktop the full nav is always visible, so
   neither has anything to add there.
   ======================================== */
.jump-bar,
.to-top {
  display: none;
}

@media (max-width: 768px) {
  .jump-bar {
    display: flex;
    gap: 8px;
    position: fixed;
    /* Sits directly under the fixed header (85px, constant across mobile
       widths) rather than at top:0, where the header's higher z-index
       would render straight over it. */
    top: 85px;
    left: 0;
    right: 0;
    z-index: 900;
    padding: 10px clamp(18px, 5vw, 40px);
    overflow-x: auto;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
    background: rgba(13, 10, 9, 0.94);
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    border-bottom: 1px solid var(--border);
    transform: translateY(-100%);
    transition: transform var(--duration-slow) var(--ease-plastic);
  }
  .jump-bar::-webkit-scrollbar {
    display: none;
  }
  .jump-bar.is-visible {
    transform: translateY(0);
  }

  /* The header slides away near the footer to avoid colliding with the
     footer's own logo; the jump bar has to travel with it or it would be
     left stranded against the top of the viewport. */
  body:has(.site-header.at-footer) .jump-bar {
    transform: translateY(calc(-100% - 85px));
  }

  .jump-bar__link {
    flex: 0 0 auto;
    padding: 7px 14px;
    border-radius: var(--radius-full);
    border: 1px solid var(--border-strong);
    background: rgba(245, 237, 224, 0.05);
    color: var(--text-muted);
    font-size: 0.8rem;
    font-weight: 600;
    white-space: nowrap;
  }
  .jump-bar__link.is-current {
    background: var(--ember-soft);
    border-color: var(--ember);
    color: var(--text-cream);
  }

  .to-top {
    display: flex;
    align-items: center;
    justify-content: center;
    position: fixed;
    right: clamp(16px, 5vw, 28px);
    /* Docked inside the sticky order bar's row (same side padding) rather than floating above it, where it sat over the right-hand
       column of whatever content was scrolling past. 58px bar button,
       12px bar padding: (58 - 42) / 2 + 12 = 20px. */
    bottom: calc(20px + env(safe-area-inset-bottom));
    z-index: 1000;
    width: 42px;
    height: 42px;
    border-radius: 50%;
    background: rgba(20, 16, 14, 0.92);
    border: 1px solid var(--border-strong);
    color: var(--text-cream);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    box-shadow: 0 8px 22px rgba(0, 0, 0, 0.45);
    opacity: 0;
    transform: translateY(10px) scale(0.9);
    pointer-events: none;
    transition: opacity var(--duration) var(--ease-out),
      transform var(--duration) var(--ease-plastic);
  }
  .to-top.is-visible {
    opacity: 1;
    transform: translateY(0) scale(1);
    pointer-events: auto;
  }
  .to-top .icon {
    width: 19px;
    height: 19px;
  }

  /* Make room in the order bar for the docked button beside it. */
  body:has(.to-top.is-visible) .sticky-order {
    padding-right: calc(clamp(16px, 5vw, 28px) + 52px);
  }

  /* The builder's own bar puts its Call button where this would dock. */
  body.builder-bar-active .to-top.is-visible {
    opacity: 0;
    pointer-events: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .jump-bar,
  .to-top {
    transition: none;
  }
}

/* ========================================
   ANIMATIONS
   ======================================== */
.fade-up {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity 0.7s var(--ease-out), transform 0.7s var(--ease-out);
}

.fade-up.visible {
  opacity: 1;
  transform: translateY(0);
}
.fade-up--d1 {
  transition-delay: 0.15s;
}
.fade-up--d2 {
  transition-delay: 0.3s;
}
.fade-up--d3 {
  transition-delay: 0.45s;
}

/* No transition here — the animated middle is owned by Motion's spring
   animate() in main.js. These two rules are just the before/after resting
   states (and the sole animation for prefers-reduced-motion / tab-switch
   instant-reveal paths, which set .visible without calling Motion at all).
   Must stay in sync with the y/scale values passed to animate() below —
   this is the frame that paints before Motion's spring takes over. */
/* --tilt-x/--tilt-y (set by the card spotlight/tilt handler in main.js,
   0deg everywhere else) live here rather than on .menu-item/.combo-card
   directly — those cards are always also .reveal, and a card's own
   `transform` declaration would just lose the cascade to this one on
   specificity (.reveal.visible is two classes) every time, leaving the
   tilt permanently dead once a card had finished revealing in. */
.reveal {
  opacity: 0;
  transform: translateY(40px) scale(0.96) perspective(900px)
    rotateX(var(--tilt-y, 0deg)) rotateY(var(--tilt-x, 0deg));
}

.reveal.visible {
  opacity: 1;
  transform: translateY(0) scale(1) perspective(900px)
    rotateX(var(--tilt-y, 0deg)) rotateY(var(--tilt-x, 0deg));
}

/* Stagger for these three now lives in main.js (staggerDelayFor), passed as
   Motion's `delay` option — transition-delay has no effect without a
   CSS transition, which .reveal no longer has. */

@keyframes fadeInUp {
  from {
    opacity: 0;
    transform: translateY(16px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes ks-marquee {
  to {
    transform: translateX(-50%);
  }
}

/* filter: drop-shadow() instead of text-shadow — text-shadow forces a full
   repaint of the glyphs on every animation frame; drop-shadow composites
   on the GPU like transform/opacity, so it doesn't fight the adjacent
   float animation for main-thread time. */
@keyframes ks-glow {
  0%,
  100% {
    filter: drop-shadow(0 0 12px rgba(232, 83, 31, 0.4));
  }
  50% {
    filter: drop-shadow(0 0 20px rgba(240, 167, 46, 0.6));
  }
}

@keyframes hero-word-in {
  from {
    opacity: 0;
    transform: translateY(20px) skewY(2deg);
  }
  to {
    opacity: 1;
    transform: translateY(0) skewY(0deg);
  }
}

@keyframes hero-word-float {
  0%,
  100% {
    transform: translateY(0);
  }
  50% {
    transform: translateY(-7px);
  }
}

@keyframes hero-spark-rise {
  0% {
    opacity: 1;
    transform: translate(0, 0) scale(1);
  }
  18% {
    opacity: 1;
  }
  100% {
    opacity: 0;
    transform: translate(var(--spark-x, 0px), var(--spark-y, -50px)) scale(0);
  }
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  html {
    scroll-behavior: auto;
  }
  .reveal,
  .fade-up,
  .hero__title > span {
    opacity: 1;
    transform: none;
  }
  .hero__spark {
    display: none;
  }
  .scroll-progress {
    display: none;
  }
}

/* ========================================
   RESPONSIVE — TABLET
   ======================================== */
@media (max-width: 1024px) {
  .nav__links {
    display: none;
  }
  .nav__toggle {
    display: flex;
  }

  .nav__links.open {
    display: flex;
    position: fixed;
    inset: 0;
    z-index: 1005;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    gap: var(--space-lg);
    background: rgba(13, 10, 9, 0.97);
    backdrop-filter: blur(20px);
    -webkit-backdrop-filter: blur(20px);
  }

  .nav__links.open .nav__link {
    display: block;
    padding: 8px 16px;
    font-size: 1.3rem;
  }

  .hero {
    text-align: center;
    justify-content: center;
  }
  .hero__copy {
    max-width: 100%;
    padding: var(--space-xl) 0 var(--space-2xl);
    margin: 0 auto;
  }
  .hero__actions {
    justify-content: center;
  }
  .hero__status {
    margin-left: auto;
    margin-right: auto;
  }

  .hero__visual {
    left: 0;
    width: 100%;
    max-width: none;
  }
  .hero__video {
    /* The spit sits around 72% across the source frame, and narrower
       viewports crop hard enough off both sides that a centred crop
       leaves barely any of it on screen. Biasing the crop right pulls
       the spit back into view (the image shifts left) while keeping
       enough dark surround for the headline to stay legible. */
    object-position: 65% 50%;
  }
  .hero__video-scrim {
    background: linear-gradient(
      to bottom,
      rgba(20, 16, 14, 0.4) 0%,
      rgba(13, 10, 9, 0.93) 100%
    );
  }

  .story__grid {
    grid-template-columns: 1fr;
    gap: var(--space-xl);
  }
  .story__image {
    aspect-ratio: 16 / 9;
  }

  .builder__grid {
    grid-template-columns: 1fr;
  }
  .builder__preview {
    position: static;
  }

  .find-us__grid {
    grid-template-columns: 1fr;
  }
  .footer__grid {
    grid-template-columns: 1fr 1fr;
    gap: var(--space-lg);
  }
}

/* ========================================
   RESPONSIVE — MOBILE
   ======================================== */
@media (max-width: 768px) {
  .hero__title {
    font-size: clamp(2.3rem, 11vw, 3.2rem);
  }
  .hero__actions {
    flex-direction: column;
    align-items: stretch;
    max-width: 300px;
    margin: 0 auto;
  }

  /* Zoomed out for phones specifically. `cover` is by definition the
     *smallest* scale that fills its box, so the only way to zoom out is
     to stop asking a 16:9 clip to fill a tall portrait screen — capping
     the height scales the frame down until the whole spit fits across
     the width. (The source is already a tight close-up, the meat spans
     nearly the full frame height, so this is about as wide as the shot
     can usefully go.) The bottom is faded out so the clip dissolves into
     the section rather than stopping at a hard horizontal edge. */
  .hero__visual {
    height: clamp(400px, 76vh, 660px);
    -webkit-mask-image: linear-gradient(
      to bottom,
      #000 0%,
      #000 72%,
      transparent 100%
    );
    mask-image: linear-gradient(to bottom, #000 0%, #000 72%, transparent 100%);
  }

  /* The tab row already scrolls sideways below 1200px (see the MENU
     section); phones only need it a little tighter to the content. */
  .menu__tabs {
    margin-bottom: 1.4rem;
  }

  /* Step accordion — see the matching block in js/builder.js. Scoped to
     a class that script adds, so with JS off the groups stay open and
     usable rather than collapsing shut with no way to reopen them. */
  body.builder-accordion .builder__group {
    padding: 0;
  }
  body.builder-accordion .builder__group-head {
    display: grid;
    /* title | hint | chevron. The chevron needs its own column: sharing
       one with the hint made the two overlap once the step was open and
       both sat in row 1 ("pick on" with an arrow through it). */
    grid-template-columns: 1fr auto auto;
    align-items: center;
    gap: 2px 12px;
    margin: 0;
    padding: 16px 18px;
    cursor: pointer;
  }
  body.builder-accordion .builder__group-hint {
    grid-column: 2;
    grid-row: 1;
  }
  body.builder-accordion .builder__group-value {
    grid-column: 1 / 3;
    grid-row: 2;
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--ember-light);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    /* Same reasoning as .builder__grid > * — keeps this nowrap string
       from setting a min-content floor on the header's own grid track. */
    min-width: 0;
  }
  /* An open step already shows its picks as highlighted chips, so
     repeating them in the header would just be noise. */
  body.builder-accordion
    .builder__group:not(.is-collapsed)
    .builder__group-value {
    display: none;
  }
  body.builder-accordion .builder__group-head::after {
    content: "";
    grid-column: 3;
    grid-row: 1 / -1;
    align-self: center;
    justify-self: end;
    width: 9px;
    height: 9px;
    border-right: 2px solid var(--text-dim);
    border-bottom: 2px solid var(--text-dim);
    transform: rotate(45deg) translateY(-3px);
    transition: transform var(--duration) var(--ease);
  }
  body.builder-accordion
    .builder__group:not(.is-collapsed)
    .builder__group-head::after {
    transform: rotate(-135deg) translateY(-3px);
  }
  body.builder-accordion .builder__group-head:focus-visible {
    outline: 2px solid var(--ember-light);
    outline-offset: -2px;
  }
  body.builder-accordion .builder__options {
    padding: 0 18px 18px;
  }
  body.builder-accordion .builder__group.is-collapsed .builder__options {
    display: none;
  }

  /* Shorter runway than desktop — the donor's rotation is the least
     valuable part of the page on a small screen, so it's still covered
     faster here even after the same slow-down. */
  .hero-scroll-track {
    height: 215vh;
  }

  .story__stats {
    gap: var(--space-sm);
    text-align: left;
  }
  /* At this 3-column width "In-house" wraps mid-word ("In-" / "house"),
     making that column noticeably taller than "100%" and "Daily" next to
     it. A touch smaller keeps every stat on one line. */
  .story__stat-value {
    font-size: 1.4rem;
  }

  .menu__header {
    text-align: center;
    justify-content: center;
  }
  .menu__banner {
    height: 260px;
  }
  .menu__banner-title {
    font-size: 1.5rem;
  }
  /* One row per dish on phones, price on the right — the way a printed
     menu reads. Two narrow columns wrapped names like "Souvlaki Chicken"
     mid-phrase and left no room for the descriptions. */
  .menu__list {
    grid-template-columns: 1fr;
    gap: 8px;
  }
  .menu-item {
    min-height: 0;
    column-gap: 14px;
    padding: 14px 16px;
  }
  .menu-item__name {
    font-size: 0.95rem;
  }
  .menu-item__desc {
    font-size: 0.78rem;
  }
  .menu-item__price {
    font-size: 1.1rem;
  }

  .combos__grid {
    grid-template-columns: 1fr;
  }

  .builder__group-head {
    flex-direction: column;
    align-items: flex-start;
    gap: 4px;
  }

  .find-us__actions {
    flex-direction: column;
  }

  /* The footer ran to 931px stacked — the Explore links alone took
     252px at one full-width row each. Laying them out as a wrapped
     row and tightening the surrounding space cuts that roughly in
     half without shrinking any tap target below the ~44px minimum. */
  /* Extra bottom clearance so the fixed sticky-order bar (~84px, see its
     own scroll-padding-bottom above) never sits over the last real
     content — a plain scroll to the bottom isn't scroll-padding's doing,
     that only affects anchor/scroll-snap targets. */
  .footer {
    padding: var(--space-xl) 0 calc(var(--space-lg) + 84px);
  }
  .footer__grid {
    grid-template-columns: 1fr;
    text-align: center;
    gap: 20px;
    margin-bottom: 1.4rem;
  }
  .footer__logo {
    justify-content: center;
  }
  .footer__tagline {
    margin-inline: auto;
  }
  .footer__badges {
    justify-content: center;
  }
  .footer__heading {
    margin-bottom: 6px;
  }

  /* Explore: a centred wrapped row instead of five stacked rows. */
  .footer__col {
    flex-direction: row;
    flex-wrap: wrap;
    justify-content: center;
    gap: 2px 18px;
  }
  .footer__col .footer__heading {
    flex: 0 0 100%;
  }

  /* Visit: these are static address lines rather than links, so they
     don't need a touch target — only the phone number does, and it
     keeps its full padding below. */
  .footer__col p {
    padding: 2px 0;
    flex: 0 0 100%;
  }
  .footer__col a {
    padding: 8px 0;
  }

  .footer__bottom {
    justify-content: center;
    text-align: center;
  }

  .story,
  .marquee,
  .menu,
  .builder,
  .reviews,
  .find-us {
    padding: var(--space-2xl) 0;
  }

  .combos {
    padding: var(--space-lg) 0;
  }
}

@media (max-width: 380px) {
  .section-title {
    font-size: 1.7rem;
  }
  .btn {
    padding: 0.8rem 1.5rem;
    font-size: 0.85rem;
  }
}

@media (max-width: 365px) {
  /* auto-fit's 2-col-plus-orphan fallback looks worse than a clean single
     column on genuinely tiny screens — 375px+ phones keep the row. */
  .story__stats {
    grid-template-columns: 1fr;
  }
}
