/* ==========================================================================
   Zaiqa London — Design System v2
   An editorial, cinematic language for a 30+ year Whitechapel halal kitchen.
   Type: Bodoni Moda (display, high-contrast editorial serif) + Public Sans (UI/body).
   Palette: near-black ground, oxblood accent, warm parchment for reading sections,
   brass used only as a hairline — never a fill.
   ========================================================================== */
:root{
  --ink:#15110D;
  --ink-2:#1C1610;
  --ink-3:#0F0C09;
  --maroon:#6E1423;
  --maroon-bright:#8C1B2E;
  --maroon-deep:#450C16;
  --brass:#A9895B;
  --brass-dim:#7C6644;
  --paper:#F5EFE3;
  --paper-dim:#EBE1CC;
  --paper-line:#DBCBA9;
  --text-dark:#241C15;
  --text-mid:#6E6151;
  --text-on-dark:#F1E9D9;
  --text-on-dark-mid:#B4A891;
  --line-on-dark:rgba(233,220,192,0.14);
  --line-on-dark-strong:rgba(233,220,192,0.24);

  --maxw:1240px;
  --r:2px;
  --shadow-card:0 24px 60px rgba(8,6,4,0.35);

  --font-head:'Bodoni Moda',serif;
  --font-body:'Public Sans',sans-serif;

  --sp-1:4px; --sp-2:8px; --sp-3:12px; --sp-4:16px; --sp-5:24px;
  --sp-6:32px; --sp-7:48px; --sp-8:72px; --sp-9:112px; --sp-10:160px;

  --ease-out:cubic-bezier(.23,1,.32,1);
  --ease-in-out:cubic-bezier(.77,0,.175,1);
  --dur-fast:160ms; --dur-base:280ms; --dur-slow:900ms;

  --shadow-maroon:0 14px 34px rgba(110,20,35,0.38);

  /* jaali lattice tile — shared by .fired-zone--jaali and the header */
  --jaali-svg:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='78' height='78' viewBox='0 0 78 78'%3E%3Cg fill='none' stroke='%23A9895B' stroke-width='1'%3E%3Ccircle cx='0' cy='0' r='28'/%3E%3Ccircle cx='78' cy='0' r='28'/%3E%3Ccircle cx='0' cy='78' r='28'/%3E%3Ccircle cx='78' cy='78' r='28'/%3E%3Crect x='19' y='19' width='40' height='40'/%3E%3Crect x='19' y='19' width='40' height='40' transform='rotate(45 39 39)'/%3E%3C/g%3E%3C/svg%3E");
}

*,*::before,*::after{box-sizing:border-box;}
*{margin:0;padding:0;}
html{scroll-behavior:smooth;overflow-x:clip;overflow-y:visible;}
body{
  background:var(--ink); color:var(--text-on-dark);
  font-family:var(--font-body); font-size:16px; line-height:1.65;
  -webkit-font-smoothing:antialiased;
  /* overflow-x:hidden here would turn body into a scroll container and break
     position:sticky on every descendant (header, menu subnav) in all major
     browsers; overflow:clip prevents the same horizontal-bleed scrollbar
     without creating that scroll container. overflow-y is set explicitly
     (not left to the implicit default) on both this and html above, so no
     browser can decide on its own to pair the x-axis clip with any y-axis
     clipping — vertical content, like the hero wordmark, is guaranteed
     unclipped here regardless of how any given engine resolves the
     unspecified case. */
  overflow-x:clip;overflow-y:visible;
}
img{max-width:100%;display:block;}
a{color:inherit;text-decoration:none;}

/* browser surfaces — themed, not left as browser defaults */
::selection{background:var(--maroon-bright);color:var(--text-on-dark);}
.on-paper ::selection{background:var(--maroon);color:var(--paper);}
::-webkit-scrollbar{width:11px;height:11px;}
::-webkit-scrollbar-track{background:var(--ink-3);}
::-webkit-scrollbar-thumb{background:var(--brass-dim);border:2px solid var(--ink-3);border-radius:8px;}
::-webkit-scrollbar-thumb:hover{background:var(--brass);}
html{scrollbar-color:var(--brass-dim) var(--ink-3);scrollbar-width:thin;}
ul{list-style:none;}
button{font-family:inherit;background:none;border:none;cursor:pointer;}
input,select,textarea{font-family:inherit;}

h1,h2,h3,h4{
  font-family:var(--font-head); font-weight:500; line-height:1.08;
  color:inherit; letter-spacing:-0.005em;
}
h1{font-size:clamp(40px,6.6vw,80px); font-weight:500; letter-spacing:-0.02em;}
h2{font-size:clamp(30px,4.4vw,52px);}
h3{font-size:24px;font-weight:500;}
h4{font-size:18px;font-weight:600;font-family:var(--font-body);}
em,i{font-style:italic;}
h1 em,h1 i,h2 em,h2 i{line-height:1.14;padding-bottom:0.08em;display:inline-block;}
p{margin:0 0 16px;color:var(--text-on-dark-mid);max-width:56ch;}
.on-paper p{color:var(--text-mid);}

.accent{color:var(--maroon-bright);font-style:italic;}
.on-paper .accent{color:var(--maroon);}
/* the hero's payoff word gets real scale and its own weight — not just a
   color change on the same type size, which is what read as "basic" */
.hero-inner h1 .accent{
  font-size:1.14em;font-weight:600;letter-spacing:-0.01em;
  display:inline-block;line-height:1;padding-bottom:0.06em;
}

.container{max-width:var(--maxw);margin:0 auto;padding:0 28px;}
.container--wide{max-width:1440px;}
.section{padding:var(--sp-9) 0;}
.section--tight{padding:var(--sp-7) 0;}
.on-paper{background:var(--paper);color:var(--text-dark);}
.on-paper p{color:var(--text-mid);}

.eyebrow{
  display:inline-block;font-family:var(--font-body);font-weight:600;font-size:12px;
  letter-spacing:0.2em;text-transform:uppercase;color:var(--brass);margin-bottom:var(--sp-3);
}
.on-paper .eyebrow{color:var(--maroon);}

/* skip link */
.skip-link{
  position:absolute;left:-999px;top:auto;background:var(--ink-3);color:var(--brass);
  padding:14px 22px;z-index:1000;font-weight:600;
}
.skip-link:focus{left:0;top:0;}

a:focus-visible,button:focus-visible,input:focus-visible,select:focus-visible,textarea:focus-visible,summary:focus-visible{
  outline:2px solid var(--brass);outline-offset:3px;
}

/* ==========================================================================
   Buttons — sharp, editorial, no shape mixing
   ========================================================================== */
.btn{
  position:relative;display:inline-flex;align-items:center;justify-content:center;gap:14px;
  font-family:var(--font-body);font-weight:600;font-size:13px;letter-spacing:0.08em;text-transform:uppercase;
  padding:17px 22px 17px 30px;border-radius:var(--r);min-height:50px;border:1.5px solid transparent;
  transition:transform var(--dur-base) var(--ease-out), background-color var(--dur-base) var(--ease-out), color var(--dur-base) var(--ease-out), border-color var(--dur-base) var(--ease-out), box-shadow var(--dur-base) var(--ease-out);
  white-space:nowrap;
}
.btn:not(.btn-block)::after{
  content:"";width:26px;height:26px;border-radius:50%;flex-shrink:0;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23F1E9D9' stroke-width='1.6'%3E%3Cpath d='M6 12h12M13 6l6 6-6 6'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:center;background-size:13px;
  transition:transform var(--dur-base) var(--ease-out), background-color var(--dur-base) var(--ease-out);
}
.btn-primary::after{background-color:rgba(241,233,217,0.16);}
.btn-outline::after{
  background-color:rgba(241,233,217,0.06);
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23F1E9D9' stroke-width='1.6'%3E%3Cpath d='M6 12h12M13 6l6 6-6 6'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:center;background-size:13px;
}
.on-paper .btn-outline::after{
  background-color:rgba(36,28,21,0.06);
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23241C15' stroke-width='1.6'%3E%3Cpath d='M6 12h12M13 6l6 6-6 6'/%3E%3C/svg%3E");
}
.btn:hover:not(.btn-block)::after{transform:translateX(3px);}
.btn:active{transform:scale(0.97);}

/* ---- The sheen. A single band of light that crosses the face of the button
   on hover and leaves — the thing that separates a button that was styled
   from a button that was designed. `isolation:isolate` makes this element a
   stacking context, which pins the z-index:-1 pseudo above the button's own
   background but still beneath its label, so the light passes UNDER the
   text rather than washing over it. Slow (0.8s) and eased out, because a
   fast sheen reads as a glitch; a slow one reads as material. */
.btn{overflow:hidden;isolation:isolate;}
.btn::before{
  content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;
  background:linear-gradient(105deg,transparent 32%,rgba(241,233,217,0.17) 50%,transparent 68%);
  transform:translateX(-130%);
  transition:transform .8s var(--ease-out);
}
.btn:hover::before{transform:translateX(130%);}
@media (prefers-reduced-motion:reduce){
  .btn::before{display:none;}
}

/* Primary: oxblood with a brass hairline set INSIDE the fill rather than a
   border around it — the rule reads as an inlay on the surface, not as an
   outline drawn around a shape. It tightens on hover instead of changing
   colour, which is what keeps the press feeling like one material. */
.btn-primary{
  background:var(--maroon);border-color:var(--maroon);color:var(--text-on-dark);
  box-shadow:inset 0 0 0 1px rgba(169,137,91,0.30);
}
.btn-primary:hover{
  background:var(--maroon-bright);border-color:var(--maroon-bright);
  box-shadow:var(--shadow-maroon),inset 0 0 0 1px rgba(169,137,91,0.58);
  transform:translateY(-2px);
}
.btn-primary:hover::after{background-color:rgba(169,137,91,0.40);}
.btn-primary:active{transform:translateY(-2px) scale(0.97);}

/* Outline: brass hairline at rest, and on hover a brass wash wipes in from
   the left and STAYS for as long as you're over it — the opposite gesture
   to the primary's pass-through sheen, so the two buttons sitting side by
   side in the hero read as a pair rather than as duplicates. */
.btn-outline{background:transparent;border-color:rgba(169,137,91,0.42);color:var(--text-on-dark);}
.btn-outline::before{
  background:linear-gradient(90deg,rgba(169,137,91,0.20) 0%,rgba(169,137,91,0.05) 100%);
  transform:translateX(-101%);
  transition:transform .55s var(--ease-out);
}
.btn-outline:hover::before{transform:translateX(0);}
.btn-outline:hover{border-color:var(--brass);transform:translateY(-2px);}
.btn-outline:hover::after{background-color:rgba(169,137,91,0.30);}
.on-paper .btn-outline{border-color:var(--paper-line);color:var(--text-dark);}
.on-paper .btn-outline::before{background:linear-gradient(90deg,rgba(110,20,35,0.10) 0%,rgba(110,20,35,0.03) 100%);}
.on-paper .btn-outline:hover{border-color:var(--text-dark);}
.btn-sm{padding:12px 16px 12px 20px;font-size:12px;min-height:44px;}
.btn-sm::after{width:22px;height:22px;background-size:11px;}
.btn-block{width:100%;padding:17px 30px;}

/* ---- Download variant. The base .btn::after paints a right-facing arrow,
   which reads as "go somewhere else" — wrong for a file that lands in your
   downloads folder. Swap the glyph for a tray arrow so the icon matches the
   action; everything else about the button is inherited untouched. */
.btn-download:not(.btn-block)::after{
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23F1E9D9' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 4v10M8 11l4 4 4-4M5 19h14'/%3E%3C/svg%3E");
}
.on-paper .btn-download:not(.btn-block)::after{
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23241C15' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 4v10M8 11l4 4 4-4M5 19h14'/%3E%3C/svg%3E");
}
.btn-download:hover:not(.btn-block)::after{transform:translateY(2px);}
.menu-download{margin:26px 0 0;}
.menu-download .btn{white-space:normal;}
.menu-download-label{display:flex;flex-direction:column;align-items:flex-start;line-height:1.15;}
.menu-download-meta{
  font-size:10px;letter-spacing:0.14em;opacity:0.62;
  margin-top:3px;font-weight:500;
}

/* ==========================================================================
   Header / Nav
   ========================================================================== */
.site-header{
  position:sticky;top:0;z-index:100;background:transparent;
  border-bottom:1px solid transparent;
  transition:background-color var(--dur-base) var(--ease-out),border-color var(--dur-base) var(--ease-out);
}
/* The solid bar (::before) and the jaali lattice laid over it (::after) are
   pseudo-elements rather than the header's own background, so the lattice
   can be masked on its own. It's strongest at the left edge and dissolves
   across the bar, gone before the right-hand buttons — the same motif
   as the homepage's fired zones, used as a signature rather than a fill.
   Both are locked on at all times, over the hero included, so the bar
   never changes or animates as the page scrolls. z-index:-1 keeps them
   under the nav but inside the header's own stacking context
   (sticky + z-index:100). */
.site-header::before,
.site-header::after{
  content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;
}
.site-header::before{
  background:var(--ink);border-bottom:1px solid var(--line-on-dark);
  -webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);
}
.site-header::after{
  background-image:var(--jaali-svg);background-size:58px 58px;background-position:0 50%;
  -webkit-mask-image:linear-gradient(90deg,#000 0%,rgba(0,0,0,0.55) 30%,rgba(0,0,0,0.15) 58%,transparent 80%);
  mask-image:linear-gradient(90deg,#000 0%,rgba(0,0,0,0.55) 30%,rgba(0,0,0,0.15) 58%,transparent 80%);
}
.site-header::after{opacity:0.22;}

/* ---- Hide-on-down / show-on-up.
   Scrolling down retires the header entirely so the photography gets the
   whole viewport back; scrolling up brings it straight back, already solid,
   so the nav is never more than a flick away. The asymmetry is deliberate:
   leaving is slower and eased out (it should feel like it's getting out of
   the way), returning is fast and near-linear (it should feel summoned).

   Desktop only, and not optional. Below 900px `.main-nav` is
   `position:fixed` INSIDE this element — and a transform on an ancestor
   makes fixed descendants resolve against that ancestor instead of the
   viewport, which would drag the open mobile menu up off the screen with
   the header.

   This now runs on phones too, where a retreating header matters most —
   small screens have the least room to spare. The fixed-descendant hazard
   is handled rather than avoided: the :has() rule below hard-guarantees the
   header carries NO transform whenever the menu is open, so the menu can
   never be dragged anywhere, and main.js clears the hidden state before it
   opens the menu as a second line of defence. `transform:none` does not
   create a containing block, so fixed positioning behaves normally again
   the moment the guard applies. */
.site-header{
  transition:background-color var(--dur-base) var(--ease-out),
             border-color var(--dur-base) var(--ease-out),
             transform 420ms var(--ease-out);
}
.site-header.is-hidden{
  transform:translateY(-100%);
}
.site-header.is-returning,
.site-header.is-hidden.is-returning{
  transition:background-color var(--dur-base) var(--ease-out),
             border-color var(--dur-base) var(--ease-out),
             transform 200ms cubic-bezier(.2,.7,.3,1);
}
/* THE GUARD — menu open means no transform, no exceptions. */
.site-header:has(.main-nav.is-open),
.site-header:has(.main-nav.is-open).is-hidden{
  transform:none;
}
/* Never animate the header away for anyone who asked for less motion —
   it just stays put and keeps its existing solid-on-scroll behaviour. */
@media (prefers-reduced-motion:reduce){
  .site-header,.site-header.is-hidden{transform:none;transition:background-color var(--dur-base) linear,border-color var(--dur-base) linear;}
}
.header-inner{
  display:flex;align-items:center;justify-content:space-between;gap:20px;
  max-width:1440px;margin:0 auto;padding:20px 28px;
}
.brand{display:flex;flex-direction:column;line-height:1;}
.brand .word{font-family:var(--font-head);font-style:italic;font-weight:500;font-size:26px;color:var(--text-on-dark);}
.brand .sub{font-family:var(--font-body);font-size:9.5px;letter-spacing:0.24em;text-transform:uppercase;color:var(--text-on-dark-mid);margin-top:5px;}

.main-nav{display:flex;align-items:center;gap:4px;}
.main-nav a{
  position:relative;font-size:12.5px;font-weight:600;letter-spacing:0.06em;text-transform:uppercase;
  color:var(--text-on-dark-mid);padding:10px 15px;transition:color var(--dur-fast) var(--ease-out);
}
.main-nav a:hover,.main-nav a.is-active{color:var(--text-on-dark);}
.main-nav a::after{
  content:"";position:absolute;left:15px;right:15px;bottom:5px;height:1px;background:var(--brass);
  transform:scaleX(0);transform-origin:left;transition:transform var(--dur-base) var(--ease-out);
}
.main-nav a:hover::after,.main-nav a.is-active::after{transform:scaleX(1);}

.header-actions{display:flex;align-items:center;gap:14px;}
.header-actions .btn{padding:12px 20px;gap:0;}
.header-actions .btn::after{display:none;}
.header-actions .btn-label-full{display:inline;}
.nav-toggle{
  display:none;width:44px;height:44px;align-items:center;justify-content:center;
  border:1px solid var(--line-on-dark-strong);color:var(--text-on-dark);
}
.nav-toggle svg{width:20px;height:20px;}

/* Order — a delivery-platform picker pinned top-right, since "order now"
   is the highest-value action on the site and deserves the strongest
   (filled) button; Call is demoted to outline to make room for it. */
.order-menu{position:relative;}
.order-dropdown{
  position:absolute;top:calc(100% + 10px);right:0;min-width:172px;
  background:var(--ink-3);border:1px solid var(--line-on-dark-strong);
  box-shadow:0 24px 48px -16px rgba(0,0,0,0.65);padding:6px;
  opacity:0;visibility:hidden;transform:translateY(-6px);
  transition:opacity var(--dur-fast) var(--ease-out),transform var(--dur-fast) var(--ease-out),visibility 0s linear var(--dur-fast);
  z-index:200;
}
.order-menu.is-open .order-dropdown{
  opacity:1;visibility:visible;transform:none;
  transition:opacity var(--dur-fast) var(--ease-out),transform var(--dur-fast) var(--ease-out);
}
.order-dropdown a{
  display:block;padding:12px 14px;font-size:12.5px;font-weight:600;letter-spacing:0.05em;
  text-transform:uppercase;color:var(--text-on-dark-mid);transition:color var(--dur-fast) var(--ease-out),background-color var(--dur-fast) var(--ease-out);
}
.order-dropdown a:hover{color:var(--text-on-dark);background:rgba(241,233,217,0.07);}

.call-btn{display:inline-flex;align-items:center;gap:8px;}
.call-btn svg{width:16px;height:16px;flex-shrink:0;}

@media (max-width:900px){
  .main-nav{
    position:fixed;inset:var(--header-h,91px) 0 0 0;background:var(--ink);
    flex-direction:column;align-items:stretch;padding:var(--sp-5);gap:0;
    transform:translateY(-14px);opacity:0;visibility:hidden;pointer-events:none;
    transition:opacity var(--dur-base) var(--ease-out),transform var(--dur-base) var(--ease-out),visibility 0s linear var(--dur-base);
    overflow-y:auto;z-index:150;
  }
  .main-nav.is-open{transform:translateY(0);opacity:1;visibility:visible;pointer-events:auto;transition:opacity var(--dur-base) var(--ease-out),transform var(--dur-base) var(--ease-out);}
  .main-nav a{font-size:19px;padding:20px 8px;border-bottom:1px solid var(--line-on-dark);font-family:var(--font-head);font-style:italic;text-transform:none;letter-spacing:0;}
  .main-nav a::after{display:none;}
  .nav-toggle{display:inline-flex;}
  /* phones/tablets: a shorter fade, so the lattice stays behind the logo
     and clears well before the Order/Call/menu buttons */
  .site-header::after{
    -webkit-mask-image:linear-gradient(90deg,#000 0%,rgba(0,0,0,0.4) 35%,transparent 60%);
    mask-image:linear-gradient(90deg,#000 0%,rgba(0,0,0,0.4) 35%,transparent 60%);
  }
  /* the page behind the open menu shouldn't scroll under the visitor's thumb */
  html.nav-open{overflow:hidden;}
}

/* Below ~400px, Order + Call + the hamburger no longer fit as three
   labelled buttons — Call drops to a phone icon only, since Order is the
   priority action here and the number is still in the footer/Visit page. */
@media (max-width:400px){
  .header-actions{gap:8px;}
  .call-btn .btn-label-full{display:none;}
  .call-btn{padding:12px;}
  .call-btn svg{width:18px;height:18px;}
}

/* ==========================================================================
   Hero — full-bleed cinematic
   ========================================================================== */
/* overflow:hidden lives on .hero-media below, NOT here. This box holds both
   the background video AND the hero text — clipping overflow at this level
   was cutting the wordmark's own letters whenever the text stack ran even
   slightly taller than the box (any wide-but-short window, or a bigger
   swash letter). The zoom animation that actually needs clipping only ever
   lives inside .hero-media, so that's the only place overflow:hidden
   belongs; text here can now never be cut off by this section. */
.hero{position:relative;color:var(--text-on-dark);min-height:100vh;display:flex;align-items:flex-end;}
.hero-media{position:absolute;inset:0;z-index:-2;overflow:hidden;}
.hero-media img,.hero-media video{width:100%;height:100%;object-fit:cover;}
.hero-media img{animation:kenburns 15s var(--ease-in-out) infinite alternate;filter:contrast(1.1) saturate(1.15);}
/* video already has the same grade baked in during encoding — a live CSS filter on a
   continuously-decoding video forces the browser to reprocess it on every frame, which
   was a real, constant cost (not just during the scroll-reveal animation) and a
   meaningful contributor to scroll jank, worse on desktop where the source video is
   larger. Baking it into the file removes that cost entirely. */
/* the hero video already carries its own camera push-in and street motion — stacking the CSS
   Ken Burns zoom on top reads as jittery, so it's disabled for this element specifically */
.hero-media video.hero-video{animation:none;}
.hero-media .hero-video-fallback{display:none;}
@keyframes kenburns{from{transform:scale(1);}to{transform:scale(1.1);}}
/* THE SCRIM. The storefront footage is bright and busy exactly where the
   headline sits — warm window light, orange signage, moving reflections —
   and cream type over that was washing out. Deepened on all three layers:
   a stronger, wider pool under the text block itself, a heavier mid-stop so
   the copy never sits on raw footage, and a darker base.

   Built as gradients rather than a flat overlay on purpose: a uniform
   dim would kill the video, where a pool concentrated behind the words
   keeps the storefront bright everywhere it isn't competing with text. */
.hero-media::after{
  content:"";position:absolute;inset:0;
  background:
    radial-gradient(ellipse 1150px 760px at 6% 84%, rgba(15,12,9,0.90) 0%, rgba(15,12,9,0.55) 42%, rgba(15,12,9,0.12) 70%, transparent 84%),
    linear-gradient(180deg,rgba(15,12,9,0.30) 0%,rgba(15,12,9,0.62) 48%,rgba(15,12,9,0.92) 80%,var(--ink) 100%);
}
.page-hero .hero-media::after{
  background:
    radial-gradient(ellipse 1000px 700px at 10% 82%, rgba(15,12,9,0.78) 0%, rgba(15,12,9,0.35) 50%, transparent 78%),
    linear-gradient(180deg,rgba(15,12,9,0.48) 0%,rgba(15,12,9,0.70) 45%,rgba(15,12,9,0.94) 100%);
}
.hero-inner{padding:0 0 var(--sp-9);max-width:760px;}
.hero-inner h1,.page-hero .hero-inner h1{text-shadow:0 4px 30px rgba(0,0,0,0.5);}
.hero-inner .accent{text-shadow:0 4px 30px rgba(0,0,0,0.6);}
/* The smaller hero type had no shadow at all and was the hardest to read —
   a headline has enough mass to survive a busy background, 11px letter-
   spaced caps do not. Two shadows each: a tight one that gives the glyph
   edges a hard border against moving footage, and a wide soft one that
   darkens the area around the text without looking like a drop shadow. */
.hero .hero-kicker,
.hero .hero-tagline,
.hero .hero-meta,
.page-hero .lede{
  text-shadow:0 1px 2px rgba(0,0,0,0.9), 0 2px 8px rgba(0,0,0,0.8), 0 8px 30px rgba(0,0,0,0.65);
}
.hero .hero-tagline{color:#F3EADA;}
.hero .hero-meta{color:#CBBEA4;}
.hero .hero-kicker{color:#C9A96B;}
/* the panel layout on phones puts this type on solid --ink, where shadows
   would just be grime on a clean background */
@media (max-width:700px){
  .hero .hero-kicker,
  .hero .hero-tagline,
  .hero .hero-meta{text-shadow:none;}
}
.hero .lede{font-size:18px;max-width:460px;margin:var(--sp-4) 0 var(--sp-6);color:#E2D6BE;}
.hero-ctas{display:flex;flex-wrap:wrap;gap:14px;margin-bottom:var(--sp-7);}
/* A frosted glass pill rather than a plain border-top list — the same
   glass-panel language high-end hospitality sites use for an info/contact
   overlay, borrowed here for a small contained element instead of a full
   panel so it stays in keeping with an editorial page (no card grids). */
.hero-meta{
  display:inline-flex;flex-wrap:wrap;gap:24px;margin-top:var(--sp-5);
  padding:14px 26px;border-radius:999px;
  background:rgba(241,233,217,0.07);border:1px solid rgba(241,233,217,0.16);
  backdrop-filter:blur(14px) saturate(1.4);-webkit-backdrop-filter:blur(14px) saturate(1.4);
  font-size:12px;font-weight:600;letter-spacing:0.05em;text-transform:uppercase;color:var(--text-on-dark-mid);
}
.hero-meta strong{color:var(--text-on-dark);font-weight:600;}

/* ---- Hero wordmark — the "prestigious" masthead treatment: a slim
   letter-spaced kicker, a quiet lead-in line, then the brand name itself
   given real scale with a foil-gold gradient fill and a per-letter reveal.
   The goal is a page that opens on the name, not a paragraph of copy. ---- */
/* Both the kicker and the lead-in line sit directly over the storefront's
   own signage baked into the footage ("ZAIQA LONDON", "TANDOOR GRILL
   KARAHI") — real letters behind our letters, which no amount of text-
   shadow fixes because it's not a contrast problem, it's two different
   pieces of text occupying the same pixels. Same frosted-pill fix as
   .hero-meta: a small, tightly-hugging glass chip that lifts each line
   onto its own clean surface instead of fighting the sign for it. */
.hero .hero-kicker,
.hero .hero-wordmark-pre{
  background:rgba(15,12,9,0.5);border-radius:999px;
  backdrop-filter:blur(12px) saturate(1.3);-webkit-backdrop-filter:blur(12px) saturate(1.3);
}
.hero-kicker{
  display:inline-flex;align-items:center;gap:16px;
  font-family:var(--font-body);font-size:11.5px;font-weight:600;letter-spacing:0.34em;
  text-transform:uppercase;color:var(--brass);margin-bottom:var(--sp-6);
  padding:9px 18px 9px 14px;
}
.hero-kicker::before{content:"";width:24px;height:1px;background:var(--brass-dim);flex-shrink:0;}
.hero-wordmark{margin-bottom:var(--sp-6);}
.hero-wordmark-pre{
  display:inline-block;font-family:var(--font-body);font-weight:400;font-size:clamp(15px,1.7vw,19px);
  letter-spacing:0.05em;color:var(--text-on-dark-mid);margin-bottom:6px;
  padding:5px 16px;
}
.hero-wordmark-brand{
  --brand-grad:linear-gradient(100deg,#E9CFA0 0%,#F8ECCE 20%,#C9A25E 42%,#F3E4B4 58%,#B4874A 80%,#E7CB98 100%);
  display:block;font-family:var(--font-head);font-style:italic;font-weight:500;
  /* sized by width AND height, not width alone — a wide-but-short window
     (a completely normal 1440x700 laptop screen, or a taller one with the
     browser zoomed out) has plenty of vw to give a huge font-size here even
     though there's very little vertical room, and the hero clips overflow
     to mask its Ken Burns zoom — so an over-tall wordmark got its top
     sheared off by that clip. min() caps it by whichever axis is tighter. */
  font-size:clamp(56px,min(15vw,20vh),200px);
  /* generous leading + extra headroom on top specifically — the swash "Z"
     below is deliberately taller than the line's own cap-height, so the box
     needs more spare room above the text than below it, whatever the exact
     font metrics do at this scale. Tight leading here is what caused
     letters to render partly outside their line box before. */
  line-height:1.3;padding:0.3em 0 0.12em;letter-spacing:-0.01em;
}
/* background-clip:text only paints an element's OWN text runs — set on the
   parent it does nothing, because the parent's text is these nested <span>
   letters, not text of the parent itself. Each letter gets the same gradient
   at a large background-size with a per-letter offset, so the five slices
   line up into one continuous sweep instead of five identical fills. */
.hero-wordmark-brand .ch{
  display:inline-block;opacity:0;transform:translateY(0.3em);
  background:var(--brand-grad);background-size:600% 100%;
  /* per-letter offset lines the five slices up into one continuous sweep;
     --shimmer rides on top of that and is what the foil glint animates
     (registered via @property further down, or this would not interpolate) */
  background-position:calc(var(--i,0) * 25% + var(--shimmer,0%)) 0;
  -webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;color:transparent;
  text-shadow:0 10px 40px rgba(0,0,0,0.55);
  animation:heroLetterIn .9s var(--ease-out) forwards;
  animation-delay:calc(var(--i,0) * 75ms + .4s);
  /* THE PAINT BOX — why the swash Z and the i's tittle were losing their tops.
     `background-clip:text` paints the gradient only where it overlaps this
     span's own background box (content + padding). The glyphs here are
     italic Bodoni at display size: the swash Z's flourish and the dot on
     the i both rise ABOVE the box that line-height gives them. That ink had
     no gradient behind it to show through, so it simply wasn't painted —
     which reads as a clean horizontal cut, not as a missing letter. It was
     never an overflow or clipping problem; nothing here has overflow:hidden.

     The fix is to enlarge the paint box, not the type. Padding grows the
     background box in every direction; the matching negative margin pulls
     the layout back by exactly the same amount, so letter positions,
     spacing and the wordmark's own height are all completely unchanged.
     Values are in em, so they scale with each letter's own font-size — the
     Z gets proportionally more headroom than the lowercase, automatically,
     at every clamp() size from 56px to 200px. */
  padding:0.5em 0.14em 0.34em;
  margin:-0.5em -0.14em -0.34em;
}
/* the opening letter set larger than the rest — a dropped/raised swash
   capital, the way a wordmark logotype would treat it, rather than trying
   to match the lowercase letters exactly. Sitting on the same baseline
   (the default for inline-block text content) means it reads as one
   deliberate letterform, not a mistake — and the extra top padding above
   gives its taller cap plenty of room, so this can't clip either. */
.hero-wordmark-brand .ch.is-swash{font-size:1.32em;}
/* opacity + rise only — no clip-path here. Clipping a gradient-filled glyph
   to its own line box is what caused the "q" descender and the "Z"/"i" cap
   height to render cut off in the first place; a plain fade avoids that
   whole class of bug while still reading as a considered entrance. */
@keyframes heroLetterIn{to{opacity:1;transform:translateY(0);}}
.hero-tagline{
  font-family:var(--font-head);font-style:italic;font-weight:400;
  font-size:clamp(18px,2vw,22px);line-height:1.4;color:var(--text-on-dark);max-width:440px;
  margin:var(--sp-5) 0 var(--sp-6);
}
@media (max-width:700px){
  .hero-wordmark-brand{font-size:clamp(50px,min(20vw,20vh),120px);}
}
/* short windows generally (landscape phones, a browser zoomed out, a small
   laptop panel) — trims the vertical rhythm around the wordmark so the
   whole stack has less chance of ever needing more height than the hero
   actually has, on top of the width+height-aware font-size above. */
@media (max-height:640px){
  .hero-kicker{margin-bottom:14px;}
  .hero-wordmark{margin-bottom:14px;}
  .hero-tagline{margin:10px 0 20px;}
  .hero-ctas{margin-bottom:24px;}
  .hero-inner{padding-bottom:var(--sp-6);}
}
@media (prefers-reduced-motion:reduce){
  .hero-wordmark-brand .ch{opacity:1;transform:none;clip-path:none;animation:none;}
}

.page-hero{position:relative;color:var(--text-on-dark);padding:calc(var(--sp-9) + 40px) 0 var(--sp-8);overflow:hidden;min-height:60vh;display:flex;align-items:flex-end;}
.page-hero .hero-media{position:absolute;inset:0;z-index:-2;}
.page-hero .hero-inner{max-width:620px;padding:0;}

@media (max-width:700px){
  /* The video's landscape framing (~16:9) was being forced to fill a 100vh portrait
     container via object-fit:cover, which meant cropping away most of its width —
     the storefront sign was losing its edges, showing only the center. Below this
     width the video gets its own natural-ratio block instead of a forced full-bleed
     crop, and the headline moves into a solid panel underneath it rather than
     overlaying the video, so nothing needs cropping to stay legible or readable.
     Scoped to .hero specifically (not .page-hero, which every other page uses and
     is a different, shorter layout that doesn't have this crop problem). */
  .hero{min-height:0;display:block;}
  /* Square, not the footage's native 16:9: at 16:9 the hero was a ~210px
     strip on a phone and read as small. The storefront sign spans the middle
     ~51% of the frame's width, and a square crop of the 720x402 phone clip
     keeps ~56%, so the whole "ZAIQA LONDON" sign still fits — the video is
     ~75% taller for the cost of the empty pavement at either side. Capped at
     70svh so a short landscape-ish phone still sees the headline below it. */
  .hero .hero-media{position:relative;inset:auto;aspect-ratio:1/1;max-height:70svh;z-index:0;}
  .hero .hero-media video,.hero .hero-media img{object-position:49% 50%;}
  .hero .hero-media::after{display:none;}
  .hero .hero-inner{
    position:relative;background:var(--ink);
    padding:var(--sp-7) 28px var(--sp-8);
  }
  .hero .hero-inner h1,.hero .hero-inner .accent{text-shadow:none;}
}

@media (prefers-reduced-motion:reduce){
  .hero-media img,.hero-media video{animation:none;}
}

/* ---- Hero exit — scroll-scrubbed, not triggered.
   Every other reveal on this site is trigger-once: an observer fires, a
   class lands, a transition plays on its own clock. This one is different
   on purpose. It is bound to the scroll position itself, so the wordmark
   doesn't "play an exit animation" — it is dragged out of the frame by the
   scroll, 1:1, and comes straight back if the user scrolls up. That
   reversibility is the whole effect; a triggered animation cannot do it.

   Scale + blur + fade together rather than a plain fade: shrinking and
   defocusing at the same time reads as the camera pulling focus off the
   masthead and onto the page, which is depth. A fade alone just reads as
   a disappearing div.

   `scroll(root block)` with an explicit range keeps it predictable — the
   dissolve now runs from 25vh of scroll to 220vh, well over two screens'
   worth (widened from an original 10–75vh, which finished within a single
   scroll gesture and took the CTAs with it before they could be read).
   Starting at 25vh rather than 0 means the first nudge of the wheel does
   nothing at all: no twitch on a trackpad's idle drift. */
@keyframes heroExit{
  from{transform:scale(1);filter:blur(0px);opacity:1;}
  to{transform:scale(.88);filter:blur(16px);opacity:0;}
}
/* The two buttons and the info chip are not decoration — they are the only
   two things on this page a visitor is actually meant to click, and the
   dissolve above was taking them with it on the first inch of scroll,
   leaving them legible for roughly nobody. They get their own curve:
   dead flat (no blur, no fade, full size) for the whole first screen, so
   they stay perfectly crisp and clickable for as long as they are on it,
   and only then drop away — timed to finish as they leave the viewport,
   so the exit is something you see happen rather than something you find
   has already happened. */
@keyframes heroActionsExit{
  0%,55%{transform:scale(1);filter:blur(0px);opacity:1;}
  100%{transform:scale(.94);filter:blur(10px);opacity:0;}
}
/* Desktop only — below 700px the hero is a different layout entirely
   (natural-ratio video block, text in its own solid panel underneath),
   where there is nothing to dissolve over and the effect makes no sense. */
@media (min-width:701px) and (prefers-reduced-motion:no-preference){
  @supports (animation-timeline:scroll()){
    /* Inner heroes on the other five pages carry no CTAs, so the whole
       block can still dissolve as one. On the home hero the animation moves
       down onto .hero-caption — a filter on .hero-inner would blur the
       buttons too, and no child can undo an ancestor's blur. */
    .page-hero .hero-inner,
    .hero:not(.page-hero) .hero-caption{
      animation:heroExit linear both;
      animation-timeline:scroll(root block);
      animation-range:25vh 220vh;
      /* transform-origin low and left, anchored to where the wordmark
         actually sits in the frame, so it recedes into its own corner
         instead of drifting toward the middle of an empty viewport. */
      transform-origin:12% 78%;
      will-change:transform,filter,opacity;
    }
    /* the caption is now the top two-thirds of the block it used to be, so
       its own corner sits lower within it */
    .hero:not(.page-hero) .hero-caption{transform-origin:10% 88%;}

    .hero:not(.page-hero) .hero-ctas,
    .hero:not(.page-hero) .hero-meta{
      animation:heroActionsExit linear both;
      animation-timeline:scroll(root block);
      /* 25vh–98vh, holding flat to 55% of it: completely untouched until
         ~65vh of scroll — by which point the buttons have reached the top
         of the screen and are sliding under the header — then dissolving
         over the last stretch so the exit is visible on the way out rather
         than happening while they are still the thing you are reading. */
      animation-range:25vh 98vh;
      transform-origin:10% 50%;
      will-change:transform,filter,opacity;
    }
  }
}

/* ==========================================================================
   Editorial feature rows (replaces card grids)
   ========================================================================== */
.feature{display:grid;gap:var(--sp-8);align-items:center;}
.feature--split{grid-template-columns:1.05fr 0.95fr;}
.feature--split.is-reverse .feature-media,.feature--split.is-reverse .fired-frame{order:2;}
.feature--split.is-reverse .feature-text{order:1;}
@media (max-width:860px){
  .feature--split{grid-template-columns:1fr;gap:var(--sp-6);}
  .feature--split.is-reverse .feature-media,.feature--split.is-reverse .fired-frame,.feature--split.is-reverse .feature-text{order:initial;}
}
/* Media height cut ~25%. Reduced via aspect-ratio rather than max-width on
   purpose: these sit inside .fired-frame, whose offset rule and corner
   brackets are positioned against the frame's own edges, so narrowing the
   media would have left the brass frame hanging around empty space. Cutting
   the height keeps frame and media locked together, and object-fit:cover
   re-crops the footage to suit. 4/5 → 4/3.75 and 16/10 → 16/7.5 are both
   exactly a quarter off the rendered height. */
.feature-media{
  position:relative;overflow:hidden;aspect-ratio:4/3.75;
  box-shadow:
    inset 0 0 0 1px rgba(169,137,91,0.32),
    0 36px 64px -30px rgba(0,0,0,0.6),
    0 10px 22px -14px rgba(0,0,0,0.5);
}
.feature-media.is-wide{aspect-ratio:16/7.5;}
.feature-media img,.feature-media video{width:100%;height:100%;object-fit:cover;transition:transform 1.4s var(--ease-out);}
.feature-media img{filter:contrast(1.1) saturate(1.15);}
.feature:hover .feature-media img,.feature:hover .feature-media video{transform:scale(1.045);}
/* ---- Numbered rows: media and text converge from opposite sides.
   Scroll-scrubbed, the same mechanic as the hero exit — the row is dragged
   into place by the scroll itself and slides back out if you scroll up,
   rather than playing a one-shot entrance. `view()` rather than `scroll()`
   here because each row needs its own timeline anchored to its own position
   in the page, not to the document's total scroll.

   Both halves share one range, so they land together — that simultaneity is
   what makes the row read as a composition assembling rather than as two
   separate elements that happen to animate. The direction follows the
   layout: on a normal row the media sits left and enters from the left; on
   .is-reverse the sides swap, so each half always arrives from its own edge
   rather than crossing over the other.

   Desktop only — at ≤860px .feature--split collapses to one column, where
   there are no left and right halves to converge. */
@keyframes rowFromLeft{from{transform:translateX(-10vw);opacity:0;}to{transform:none;opacity:1;}}
@keyframes rowFromRight{from{transform:translateX(10vw);opacity:0;}to{transform:none;opacity:1;}}

@media (min-width:861px) and (prefers-reduced-motion:no-preference){
  @supports (animation-timeline:view()){
    .feature--split > .fired-frame,
    .feature--split > .feature-media,
    .feature--split > .feature-text{
      animation-timeline:view();
      animation-range:entry 5% entry 90%;
      animation-fill-mode:both;
      animation-timing-function:linear;
    }
    .feature--split > .fired-frame,
    .feature--split > .feature-media{animation-name:rowFromLeft;}
    .feature--split > .feature-text{animation-name:rowFromRight;}
    .feature--split.is-reverse > .fired-frame,
    .feature--split.is-reverse > .feature-media{animation-name:rowFromRight;}
    .feature--split.is-reverse > .feature-text{animation-name:rowFromLeft;}

    /* One gesture per object. The media inside these frames still carries
       .reveal-clip, whose wipe would otherwise fire at the same moment as
       the slide — a frame sliding in while the picture inside it wipes open
       is two competing entrances on one element. The slide wins here; the
       clip wipe still runs everywhere this block doesn't apply (mobile,
       reduced motion, browsers without scroll timelines). */
    .feature--split > .fired-frame .reveal-clip,
    .feature--split > .feature-media.reveal-clip{clip-path:none;transform:none;}
  }
}

.feature-text .num{font-family:var(--font-head);font-style:italic;font-size:15px;color:var(--brass);display:block;margin-bottom:var(--sp-3);}
.feature-text h3{font-size:clamp(26px,3vw,36px);margin-bottom:var(--sp-4);}
.feature-text p{margin-bottom:var(--sp-4);}
.feature-text .link{
  font-size:12.5px;font-weight:700;letter-spacing:0.08em;text-transform:uppercase;color:var(--text-on-dark);
  display:inline-flex;align-items:center;gap:8px;border-bottom:1px solid var(--brass-dim);padding-bottom:4px;
  transition:border-color var(--dur-base) var(--ease-out),color var(--dur-base) var(--ease-out),transform var(--dur-base) var(--ease-out);
}
.on-paper .feature-text .link{color:var(--text-dark);}
.feature-text .link:hover{border-color:var(--maroon-bright);color:var(--maroon-bright);transform:translateX(3px);}

/* "Fired" zone — Tandoor + Grill together, treated as one continuous canvas
   rather than two sections each painting their own background (which is what
   was creating the hard seam / "filled in with a bucket tool" look). One
   gradient spans the whole wrapper's height, so the color genuinely flows
   from the first section into the second instead of cutting off and
   restarting at the section boundary. No border line between them anymore —
   the flowing color itself is what marks the zone, not a drawn rule. */
.fired-zone{position:relative;}
.fired-zone::before{
  content:"";position:absolute;inset:0;z-index:0;pointer-events:none;
  background:
    radial-gradient(ellipse 1300px 1100px at 10% 8%, rgba(169,137,91,0.16) 0%, transparent 55%),
    radial-gradient(ellipse 1300px 1100px at 90% 55%, rgba(110,20,35,0.18) 0%, transparent 55%),
    radial-gradient(ellipse 1300px 1100px at 15% 95%, rgba(169,137,91,0.13) 0%, transparent 55%),
    linear-gradient(180deg, #171310 0%, #15110d 100%);
  /* fades the background to nothing at its own top and bottom edge, so it
     dissolves into the plain --ink of the sections above and below instead
     of cutting off hard against them. Lives on a dedicated pseudo-element
     behind the content, not on .fired-zone itself — masking the wrapper
     directly would fade its children (the video, text, buttons) too. */
  -webkit-mask-image:linear-gradient(180deg, transparent 0, #000 60px, #000 calc(100% - 60px), transparent 100%);
  mask-image:linear-gradient(180deg, transparent 0, #000 60px, #000 calc(100% - 60px), transparent 100%);
}
.fired-zone > *{position:relative;z-index:1;}

/* ---- Jaali lattice.
   A pierced-screen motif of the kind cut into sandstone across Mughal
   architecture: interlocking rings with an eight-pointed khatam star at
   each junction, drawn here as two squares at 45° to each other, which is
   how the figure is actually constructed. Geometric rather than floral —
   a paisley or a mandala would have pulled this toward takeaway-menu
   territory, which is exactly the look the rest of this redesign was
   built to get away from.

   Delivered as an inline SVG data-URI, so it adds a pattern to the page
   without adding a request. It tiles seamlessly because the four corner
   circles are quarters that complete against their neighbours.

   Kept deliberately faint. It should register as texture in the surface —
   something you notice on the second look — not as wallpaper behind the
   food. It rides on ::after so the existing gradient stack on ::before is
   untouched, and carries the same top/bottom mask so it dissolves into the
   plain --ink above and below instead of stopping at a hard edge. */
.fired-zone--jaali::after{
  content:"";position:absolute;inset:0;z-index:0;pointer-events:none;
  background-image:var(--jaali-svg);
  background-size:78px 78px;
  background-repeat:repeat;
  opacity:0.13;
  -webkit-mask-image:linear-gradient(180deg, transparent 0, #000 120px, #000 calc(100% - 120px), transparent 100%);
  mask-image:linear-gradient(180deg, transparent 0, #000 120px, #000 calc(100% - 120px), transparent 100%);
}
@media (max-width:700px){
  /* smaller tile so the motif still reads as a lattice on a narrow screen
     rather than as a few oversized fragments */
  .fired-zone--jaali::after{background-size:58px 58px;opacity:0.10;}
}

.fired-zone .feature-media,
.fired-zone .story-mosaic figure,
.fired-zone .map-embed{
  box-shadow:
    inset 0 0 0 1px rgba(169,137,91,0.28),
    0 40px 70px -28px rgba(0,0,0,0.75);
}
/* the frame: an offset outer rule standing away from the media's edge, with
   corner brackets — a restrained gallery-mount device. Lives on a wrapper,
   not .feature-media itself, since that box needs overflow:hidden to clip
   its video/image content and would clip these pseudo-elements too. */
.fired-zone .fired-frame,.story-intro .fired-frame{position:relative;margin:14px;}
.fired-zone .fired-frame::after,.story-intro .fired-frame::after{
  content:"";position:absolute;inset:-14px;pointer-events:none;
  border:1px solid rgba(169,137,91,0.35);
}
.fired-zone .fired-frame::before,.story-intro .fired-frame::before{
  content:"";position:absolute;inset:-14px;pointer-events:none;z-index:1;
  --bl:22px;
  background:
    linear-gradient(var(--brass) 0 0) 0 0/2px var(--bl) no-repeat,
    linear-gradient(var(--brass) 0 0) 0 0/var(--bl) 2px no-repeat,
    linear-gradient(var(--brass) 0 0) 100% 0/2px var(--bl) no-repeat,
    linear-gradient(var(--brass) 0 0) 100% 0/var(--bl) 2px no-repeat,
    linear-gradient(var(--brass) 0 0) 0 100%/2px var(--bl) no-repeat,
    linear-gradient(var(--brass) 0 0) 0 100%/var(--bl) 2px no-repeat,
    linear-gradient(var(--brass) 0 0) 100% 100%/2px var(--bl) no-repeat,
    linear-gradient(var(--brass) 0 0) 100% 100%/var(--bl) 2px no-repeat;
  background-position:top left,top left,top right,top right,bottom left,bottom left,bottom right,bottom right;
}
@media (max-width:700px){
  .fired-zone .fired-frame,.story-intro .fired-frame{margin:8px;}
  .fired-zone .fired-frame::after,.fired-zone .fired-frame::before,
  .story-intro .fired-frame::after,.story-intro .fired-frame::before{inset:-8px;}
}

/* Homepage "Our Story" intro — text left, dining-room photo right in the
   same brass gallery-mount frame used by the feature rows below it */
.story-intro{display:grid;grid-template-columns:7fr 5fr;gap:var(--sp-8);align-items:center;}
.story-intro .statement{max-width:none;}
.story-intro-media{
  margin:0;aspect-ratio:4/5;overflow:hidden;
  box-shadow:inset 0 0 0 1px rgba(169,137,91,0.28),0 40px 70px -28px rgba(0,0,0,0.75);
}
.story-intro-media img{
  width:100%;height:100%;object-fit:cover;object-position:62% 50%;
  filter:contrast(1.05) saturate(1.1);transition:transform 1.4s var(--ease-out);
}
.story-intro-frame:hover .story-intro-media img{transform:scale(1.04);}
@media (max-width:960px){
  .story-intro{grid-template-columns:1fr;gap:var(--sp-7);}
  .story-intro-media{aspect-ratio:4/3;}
}

/* full-bleed captioned image, used as a rhythm-break between feature rows */
.bleed-figure{
  position:relative;overflow:hidden;aspect-ratio:21/9;
  box-shadow:
    inset 0 0 0 1px rgba(169,137,91,0.32),
    0 40px 70px -32px rgba(0,0,0,0.6);
}
.bleed-figure img,.bleed-figure video{width:100%;height:100%;object-fit:cover;}
.bleed-figure img{filter:contrast(1.1) saturate(1.15);}
@media (max-width:700px){.bleed-figure{aspect-ratio:4/5;}}

/* the storefront shot on About is the one bleed-figure where the whole
   building actually matters — the default 21:9 band was cropping enough
   off the top and bottom that the front of the shop wasn't fully in frame.
   The source photo is ~2400x1340 (close to 16:9), so matching that ratio
   here shows the full building instead of a slice of it. */
.bleed-figure.hero-storefront-figure{aspect-ratio:16/9;}
@media (max-width:700px){.bleed-figure.hero-storefront-figure{aspect-ratio:4/5;}}

/* menu-page photo/video breaks — the source assets are portrait/native-ratio
   originals (e.g. 1400x2087) which, applied straight as aspect-ratio, made
   each break nearly a full screen tall. Capped to a shorter cinematic band
   with a max-height so they read as a pause between categories, not a wall. */
.menu-bleed-figure{aspect-ratio:21/9;max-height:420px;margin-bottom:var(--sp-6);}
@media (max-width:700px){.menu-bleed-figure{aspect-ratio:16/10;max-height:280px;}}

/* for a portrait photo too small to stretch across the band without going
   soft (e.g. the 477x640 lamb karahi): the photo sits whole and sharp in the
   middle, and a blurred, darkened copy of itself (--fig-bg) fills the sides */
.menu-bleed-figure--contain{background:var(--ink);}
.menu-bleed-figure--contain::before{
  content:"";position:absolute;inset:-40px;
  background:var(--fig-bg) center/cover no-repeat;
  filter:blur(28px) brightness(0.45) saturate(1.2);
}
.menu-bleed-figure--contain img{position:relative;object-fit:contain;}
.menu-bleed-figure--contain figcaption{z-index:1;}

/* grill-slow-motion: the bottom third of the frame is a stained steel ledge
   (from ~68% down, right side). Framing the band higher keeps it on the
   flames and skewers and leaves the ledge out of view at every breakpoint. */
.menu-bleed-figure--grill video{object-position:50% 40%;}
/* same clip behind the menu's CTA band — on phones that band is taller than
   the clip is wide, so cover shows its full height; scaling 1.5x from the top
   pushes the lower third (the ledge) out of the box */
.cta-band .cta-media--grill video{object-position:50% 45%;transform:scale(1.5);transform-origin:50% 0;}

/* story-grill clip (homepage 01 + Our Story mosaic): the grill's stained
   front lip sits in the bottom-left corner, below a line from ~75% down at
   the left edge. Scaling 1.3x from near the top-right keeps only the top
   ~77% of the frame, so the lip never enters the box at any container
   ratio, while the flames and meat stay centred. Hover keeps its gentle
   push-in on top of the crop. */
video.crop-grill-lip{transform:scale(1.3);transform-origin:70% 0;}
.feature:hover video.crop-grill-lip,
.story-mosaic figure:hover video.crop-grill-lip{transform:scale(1.36);}

.bleed-figure figcaption{
  position:absolute;left:28px;bottom:22px;color:var(--text-on-dark);
  font-family:var(--font-head);font-style:italic;font-size:19px;
  text-shadow:0 2px 18px rgba(0,0,0,0.6);
}

/* ==========================================================================
   Full-bleed video (the "Straight from the tandoor" moment)
   ========================================================================== */

/* Same autoplay/loop pattern as every other video on the site (karahi,
   story-grill, etc.), which is why this is reliable: it's picked up by the
   generic IntersectionObserver play/pause system in js/main.js like any
   other video[autoplay] element, nothing bespoke. */
/* Full size, deliberately. This one was briefly cut to 60vh along with the
   feature media and it was wrong: this is a wide platter shot that needs the
   height to hold its framing — at 60vh object-fit:cover was slicing the top
   and bottom off the plate. The height cut applies to the numbered feature
   rows only; this stays as the page's one full-scale moment. */
.bleed-video{position:relative;width:100%;height:80vh;max-height:720px;overflow:hidden;background:var(--ink);}
.bleed-video-el{width:100%;height:100%;object-fit:cover;filter:contrast(1.1) saturate(1.15);display:block;}
.pin-caption{
  position:absolute;left:28px;bottom:22px;color:var(--text-on-dark);
  font-family:var(--font-head);font-style:italic;font-size:19px;
  text-shadow:0 2px 18px rgba(0,0,0,0.6);margin:0;
}

@media (max-width:700px){
  .bleed-video{height:auto;aspect-ratio:4/5;}
}

/* pull quote / statement block */
.statement{max-width:900px;}
.statement h2{font-weight:400;}
.statement h2 em{color:var(--brass);}

/* asymmetric two column, generous whitespace variant used sparingly */
.split{display:grid;grid-template-columns:5fr 6fr;gap:var(--sp-9);align-items:start;}
@media (max-width:860px){.split{grid-template-columns:1fr;gap:var(--sp-6);}}
.split.is-narrow{grid-template-columns:4fr 7fr;}
@media (max-width:860px){.split.is-narrow{grid-template-columns:1fr;}}

/* overlapping composition (hero of Our Story) */
.overlap{position:relative;}
.overlap .overlap-behind{width:78%;}
.overlap .overlap-front{
  position:absolute;right:-6%;bottom:-10%;width:52%;border:6px solid var(--ink);box-shadow:var(--shadow-card);
}
@media (max-width:760px){
  .overlap{padding-bottom:26%;}
  .overlap .overlap-behind{width:100%;}
  .overlap .overlap-front{width:58%;right:0;bottom:-14%;}
}

/* ==========================================================================
   Story / rotating gallery
   ========================================================================== */
.story-media{position:relative;overflow:hidden;aspect-ratio:4/5.2;box-shadow:var(--shadow-card),inset 0 0 0 1px rgba(169,137,91,0.28);}
@media (max-width:860px){.story-media{aspect-ratio:4/5;}}
.story-media img,.story-media video{width:100%;height:100%;object-fit:cover;display:block;}
.story-carousel{background:var(--ink-2);}
.story-carousel .story-slide{position:absolute;inset:0;opacity:0;transition:opacity 900ms var(--ease-out);}
.story-carousel .story-slide.is-active{opacity:1;z-index:1;}
.story-carousel::after{
  content:"";position:absolute;left:0;right:0;bottom:0;height:90px;z-index:1;pointer-events:none;
  background:linear-gradient(to top, rgba(15,12,9,0.6), transparent);
}
.story-dots{position:absolute;left:0;right:0;bottom:18px;z-index:2;display:flex;justify-content:center;gap:8px;}
.story-dots button{
  position:relative;width:6px;height:6px;border-radius:50%;background:rgba(241,233,217,0.4);
  border:none;padding:0;cursor:pointer;transition:background var(--dur-base) var(--ease-out),transform var(--dur-base) var(--ease-out);
}
.story-dots button::before{
  content:"";position:absolute;top:50%;left:50%;width:44px;height:44px;transform:translate(-50%,-50%);
}
.story-dots button:hover{background:rgba(241,233,217,0.7);}
.story-dots button.is-active{background:var(--brass);transform:scale(1.4);}
@media (prefers-reduced-motion:reduce){.story-carousel .story-slide{transition:none;}}

.gallery-head{max-width:640px;margin:0 auto var(--sp-7);text-align:center;}
.gallery-head .eyebrow{display:block;}

/* ---- Homepage dish coverflow — a stack of cards where the active one
   sits large and centred, its neighbours peeking in half-scale either
   side, dimmed. Distance from the active card ("delta", set as inline
   custom properties by js/main.js) drives everything: position, scale,
   opacity, brightness. Clicking a peeking card, an arrow or a dot all
   just change which index is "0" and the transition does the rest. ---- */
/* The row breaks out of the 1240px container to span up to 1440px (or the
   full viewport on smaller screens), so the second ring of cards reaches
   out towards the page edges. margin-left rather than a transform does the
   centring, because .reveal-clip already animates this element's transform. */
.dish-coverflow-wrap{
  position:relative;display:flex;align-items:center;justify-content:center;gap:20px;
  width:min(1440px,100vw);margin-left:calc(50% - min(720px,50vw));padding:0 28px;
}
/* the outer cards dissolve into the page instead of stopping at a hard edge */
.dish-coverflow{
  position:relative;flex:1;height:540px;
  -webkit-mask-image:linear-gradient(90deg,transparent 0,#000 16%,#000 84%,transparent 100%);
  mask-image:linear-gradient(90deg,transparent 0,#000 16%,#000 84%,transparent 100%);
}
.dish-card{
  position:absolute;top:50%;left:50%;width:315px;aspect-ratio:3/4;
  transform:translate(-50%,-50%) translateX(var(--dx,0%)) scale(var(--s,1));
  opacity:var(--op,0);z-index:var(--z,1);filter:brightness(var(--b,1));
  transition:transform .65s var(--ease-out),opacity .65s var(--ease-out),filter .65s var(--ease-out);
  border-radius:18px;overflow:hidden;box-shadow:0 30px 70px -24px rgba(0,0,0,0.7);cursor:pointer;
}
.dish-card img,.dish-card video{width:100%;height:100%;object-fit:cover;display:block;}
.dish-card::after{
  content:"";position:absolute;inset:0;
  background:linear-gradient(to top, rgba(15,12,9,0.75) 0%, transparent 48%);
}
.dish-card-label{
  position:absolute;left:20px;bottom:16px;z-index:1;
  font-family:var(--font-head);font-style:italic;font-weight:500;font-size:24px;color:var(--text-on-dark);
  text-shadow:0 2px 14px rgba(0,0,0,0.5);
}
@media (max-width:1000px){
  .dish-coverflow{height:440px;}
  .dish-card{width:255px;}
}
@media (max-width:700px){
  .dish-coverflow-wrap{padding:0 12px;}
  .dish-coverflow{
    height:340px;
    -webkit-mask-image:linear-gradient(90deg,transparent 0,#000 14%,#000 86%,transparent 100%);
    mask-image:linear-gradient(90deg,transparent 0,#000 14%,#000 86%,transparent 100%);
  }
  .dish-card{width:200px;}
  .dish-card-label{font-size:20px;}
}
@media (max-width:460px){
  .dish-coverflow{height:290px;}
  .dish-card{width:170px;}
}

.gallery-arrow{
  flex-shrink:0;width:52px;height:52px;border-radius:50%;
  display:flex;align-items:center;justify-content:center;
  border:1px solid var(--line-on-dark-strong);color:var(--text-on-dark);background:rgba(241,233,217,0.04);
  transition:background-color var(--dur-base) var(--ease-out),border-color var(--dur-base) var(--ease-out),transform var(--dur-fast) var(--ease-out);
}
.gallery-arrow svg{width:20px;height:20px;}
.gallery-arrow:hover{background:var(--brass);border-color:var(--brass);color:var(--ink);transform:scale(1.06);}
.gallery-arrow:active{transform:scale(0.96);}
@media (max-width:600px){
  .dish-coverflow-wrap{gap:6px;}
  .gallery-arrow{width:38px;height:38px;}
  .gallery-arrow svg{width:15px;height:15px;}
}

.dish-dots{display:flex;justify-content:center;gap:8px;margin-top:var(--sp-6);}
.dish-dots button{
  position:relative;width:6px;height:6px;border-radius:50%;background:rgba(241,233,217,0.35);
  border:none;padding:0;cursor:pointer;transition:background var(--dur-base) var(--ease-out),transform var(--dur-base) var(--ease-out);
}
.dish-dots button::before{content:"";position:absolute;top:50%;left:50%;width:40px;height:40px;transform:translate(-50%,-50%);}
.dish-dots button:hover{background:rgba(241,233,217,0.7);}
.dish-dots button.is-active{background:var(--brass);transform:scale(1.5);}

@media (prefers-reduced-motion:reduce){.dish-card{transition:opacity .3s linear;}}

/* asymmetric editorial gallery — diptych + triptych, no fixed row-heights so it degrades cleanly */
.story-mosaic-top{display:grid;grid-template-columns:7fr 5fr;gap:var(--sp-5);align-items:stretch;}
.story-mosaic-top .wide{aspect-ratio:4/3;}
.story-mosaic-top .tall{aspect-ratio:3/4;}
.story-mosaic-bottom{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--sp-5);margin-top:var(--sp-5);}
.story-mosaic-bottom figure{aspect-ratio:1/1;}
.story-mosaic figure{position:relative;overflow:hidden;margin:0;box-shadow:inset 0 0 0 1px rgba(169,137,91,0.28);}
.story-mosaic img,.story-mosaic video{width:100%;height:100%;object-fit:cover;display:block;transition:transform 1.4s var(--ease-out);}
.story-mosaic img{filter:contrast(1.1) saturate(1.15);}
.story-mosaic figure:hover img,.story-mosaic figure:hover video{transform:scale(1.045);}
@media (max-width:760px){
  .story-mosaic-top{grid-template-columns:1fr;}
  .story-mosaic-top .wide,.story-mosaic-top .tall{aspect-ratio:4/3;}
  .story-mosaic-bottom{grid-template-columns:1fr 1fr;}
  .story-mosaic-bottom figure:last-child{grid-column:1/-1;aspect-ratio:16/9;}
}

/* editorial pull-quote — a second-read moment inside a long statement block */
.pull-quote{
  font-family:var(--font-head);font-style:italic;font-weight:500;
  font-size:clamp(24px,3vw,34px);line-height:1.35;color:var(--maroon-bright);
  max-width:640px;margin:var(--sp-6) 0;padding-left:var(--sp-5);
  border-left:1px solid var(--line-on-dark);
}
/* on paper-toned (light) sections, e.g. About's story block, the ink-dark
   defaults above lose contrast against --paper — swap to the deeper maroon
   and paper-toned rule used on light grounds elsewhere */
.on-paper .pull-quote{color:var(--maroon);border-left-color:var(--paper-line);}

.fact-row{display:flex;flex-wrap:wrap;gap:6px 20px;padding:16px 0;border-bottom:1px solid var(--line-on-dark);}
.on-paper .fact-row{border-color:var(--paper-line);}
.fact-row dt{font-size:11.5px;font-weight:700;letter-spacing:0.1em;text-transform:uppercase;color:var(--text-on-dark-mid);width:120px;flex-shrink:0;}
.on-paper .fact-row dt{color:var(--text-mid);}
.fact-row dd{font-size:15.5px;}
.fact-row dd a:hover{color:var(--brass);}
.on-paper .fact-row dd a:hover{color:var(--maroon);}

.map-embed{overflow:hidden;border:1px solid var(--line-on-dark);height:420px;filter:grayscale(0.3) contrast(1.05);}
.on-paper .map-embed{border-color:var(--paper-line);}
.map-embed iframe{width:100%;height:100%;border:0;display:block;}

.text-links{display:flex;gap:20px;flex-wrap:wrap;margin-top:var(--sp-5);}
.text-links a{
  display:inline-block;font-size:12.5px;font-weight:700;letter-spacing:0.06em;text-transform:uppercase;
  border-bottom:1px solid var(--line-on-dark-strong);padding-bottom:4px;
  transition:border-color var(--dur-base) var(--ease-out),color var(--dur-base) var(--ease-out),transform var(--dur-base) var(--ease-out);
}
.text-links a:hover{border-color:var(--brass);color:var(--brass);transform:translateY(-2px);}
.on-paper .text-links a{border-color:var(--paper-line);}
.on-paper .text-links a:hover{border-color:var(--maroon);color:var(--maroon);}

/* event gallery — asymmetric, not equal grid */
/* ---- Event mosaic — five images, five entrance directions.
   `overflow:clip` on the grid is what makes the horizontal slides safe: a
   tile translating in from off its own edge would otherwise push the
   document wider and create a horizontal scrollbar. Clipping at the grid
   means each tile emerges from behind the gallery's edge instead, which is
   also the better-looking version of the effect. `clip` rather than
   `hidden` so it never becomes a scroll container.

   Because it is clipped, this is the one place on the site where sideways
   motion is safe on a phone too — so mobile keeps all five directions
   rather than being flattened to a vertical rise. */
.event-gallery--mosaic{
  display:grid;grid-template-columns:repeat(6,1fr);gap:var(--sp-5);
  overflow:clip;
}
.event-gallery--mosaic figure{margin:0;overflow:hidden;position:relative;}
.event-gallery--mosaic img{width:100%;height:100%;object-fit:cover;display:block;}
.eg-room{grid-column:span 4;aspect-ratio:16/10;}
.eg-cake{grid-column:span 2;aspect-ratio:3/4;}
.eg-window,.eg-stage,.eg-fountain{grid-column:span 2;aspect-ratio:4/3;}
@media (max-width:860px){
  .event-gallery--mosaic{grid-template-columns:repeat(2,1fr);}
  .eg-room{grid-column:span 2;aspect-ratio:16/9;}
  .eg-cake{grid-column:span 1;}
  .eg-window,.eg-stage,.eg-fountain{grid-column:span 1;}
}
@media (max-width:560px){
  .event-gallery--mosaic{grid-template-columns:1fr;gap:var(--sp-4);}
  .eg-room,.eg-cake,.eg-window,.eg-stage,.eg-fountain{grid-column:span 1;aspect-ratio:4/3;}
  .eg-cake{aspect-ratio:3/4;}
}

@keyframes egFromLeft  {from{transform:translateX(-10vw);opacity:0;}to{transform:none;opacity:1;}}
@keyframes egFromRight {from{transform:translateX(10vw); opacity:0;}to{transform:none;opacity:1;}}
@keyframes egFromTop   {from{transform:translateY(-80px);opacity:0;}to{transform:none;opacity:1;}}
@keyframes egFromBottom{from{transform:translateY(80px); opacity:0;}to{transform:none;opacity:1;}}
@keyframes egFromCorner{from{transform:translate(8vw,70px);opacity:0;}to{transform:none;opacity:1;}}

@media (prefers-reduced-motion:no-preference){
  @supports (animation-timeline:view()){
    .event-gallery--mosaic figure{
      animation-timeline:view();
      animation-range:entry 0% entry 70%;
      animation-fill-mode:both;
      animation-timing-function:linear;
    }
    .eg-room    {animation-name:egFromLeft;}
    .eg-cake    {animation-name:egFromRight;}
    .eg-window  {animation-name:egFromBottom;}
    .eg-stage   {animation-name:egFromTop;}
    .eg-fountain{animation-name:egFromCorner;}
    /* the tiles carry their own entrance now — the shared .reveal fade
       underneath would just be a second, slower copy of the same idea */
    .event-gallery--mosaic figure.reveal{opacity:1;transform:none;}
  }
}

.event-gallery{display:grid;grid-template-columns:1.3fr 1fr;gap:var(--sp-5);}
@media (max-width:700px){.event-gallery{grid-template-columns:1fr;}}
.event-gallery figure{margin:0;overflow:hidden;position:relative;}
.event-gallery img{width:100%;height:100%;object-fit:cover;display:block;}
.event-gallery .tall{aspect-ratio:3/4;}
.event-gallery .short{aspect-ratio:1/1;}

/* occasions list — replaces 3 equal icon cards */
.occasion-list{border-top:1px solid var(--line-on-dark);}
.occasion{
  display:grid;grid-template-columns:180px 1fr;gap:var(--sp-6);padding:var(--sp-6) 0;border-bottom:1px solid var(--line-on-dark);
}
@media (max-width:700px){.occasion{grid-template-columns:1fr;gap:var(--sp-2);}}
.occasion .label{font-family:var(--font-head);font-style:italic;font-size:20px;color:var(--brass);}
.occasion h3{margin-bottom:8px;}
.occasion p{margin-bottom:0;}

/* ==========================================================================
   Menu page
   ========================================================================== */
/* Pinned directly under the (always-visible) header. --header-h is the
   header's real measured height, kept current by main.js — it's ~84px on
   desktop but ~91px on phones, and the old hard-coded 73px tucked the
   subnav's top edge under the header on every screen size. */
.menu-subnav{
  position:sticky;top:var(--header-h,84px);z-index:40;background:var(--paper);border-bottom:1px solid var(--paper-line);
  overflow-x:auto;-webkit-overflow-scrolling:touch;
}
.menu-subnav .row{display:flex;gap:2px;padding:0 28px;max-width:1440px;margin:0 auto;width:max-content;min-width:100%;}
.menu-subnav a{
  flex-shrink:0;font-size:12px;font-weight:600;letter-spacing:0.06em;text-transform:uppercase;padding:18px 16px;
  color:var(--text-mid);border-bottom:2px solid transparent;white-space:nowrap;
}
.menu-subnav a:hover{color:var(--text-dark);}
.menu-subnav a.is-active{color:var(--maroon);border-color:var(--maroon);}
.menu-wrap{background:var(--paper);}

.menu-category{padding:var(--sp-8) 0;border-bottom:1px solid var(--paper-line);scroll-margin-top:150px;}
.menu-category:last-child{border-bottom:none;}
.menu-cat-head{margin-bottom:var(--sp-6);max-width:640px;}
.menu-cat-head p{max-width:520px;}
.menu-cat-head-row{display:flex;align-items:flex-end;justify-content:space-between;gap:16px;flex-wrap:wrap;margin-bottom:var(--sp-6);}
.menu-cat-head-row .menu-cat-head{margin-bottom:0;}
.price-cols{display:flex;gap:26px;font-size:11px;font-weight:700;letter-spacing:0.08em;text-transform:uppercase;color:var(--text-mid);padding-bottom:4px;}

.menu-list{display:grid;grid-template-columns:1fr 1fr;gap:0 var(--sp-7);}
@media (max-width:700px){.menu-list{grid-template-columns:1fr;}}
.menu-item{display:flex;align-items:baseline;gap:10px;padding:15px 0;border-bottom:1px solid var(--paper-line);}
.menu-item-body{display:flex;flex-direction:column;flex:1;min-width:0;}
.menu-item-name{font-family:var(--font-head);font-size:17.5px;font-weight:500;color:var(--text-dark);}
.menu-item-desc{font-size:13.5px;color:var(--text-mid);margin-top:3px;}
.menu-item-price{font-family:var(--font-head);font-weight:500;font-size:17px;color:var(--maroon);white-space:nowrap;font-variant-numeric:tabular-nums;}
.menu-item-price-split{display:flex;gap:16px;flex-shrink:0;}
.menu-item-price-split span{font-family:var(--font-head);font-weight:500;font-size:15px;color:var(--maroon);white-space:nowrap;width:52px;text-align:right;font-variant-numeric:tabular-nums;}
.menu-item-tags{display:flex;gap:8px;margin-top:6px;flex-wrap:wrap;}
.tag{font-size:9.5px;font-weight:700;letter-spacing:0.07em;text-transform:uppercase;color:var(--maroon);padding:2px 0;}
.tag::before{content:"";}
.tag.veg{color:#3E6B3A;}
.menu-subhead{font-family:var(--font-head);font-style:italic;font-size:21px;color:var(--maroon);margin:var(--sp-7) 0 var(--sp-4);}
.menu-subhead:first-child{margin-top:0;}
.menu-note{text-align:center;font-size:13px;color:var(--text-mid);margin:var(--sp-6) 0 0;}

/* ==========================================================================
   FAQ accordion — editorial, no icon buttons
   ========================================================================== */
.accordion{border-top:1px solid var(--line-on-dark);}
.on-paper .accordion{border-color:var(--paper-line);}
.accordion-item{border-bottom:1px solid var(--line-on-dark);}
.on-paper .accordion-item{border-color:var(--paper-line);}
.accordion-q{
  width:100%;display:flex;align-items:center;justify-content:space-between;gap:24px;
  padding:26px 2px;text-align:left;font-family:var(--font-head);font-weight:500;font-size:20px;color:var(--text-on-dark);
  transition:transform var(--dur-fast) var(--ease-out),opacity var(--dur-fast) var(--ease-out);
}
.accordion-q:active{transform:scale(0.99);opacity:0.85;}
.on-paper .accordion-q{color:var(--text-dark);}
.accordion-q .ind{font-family:var(--font-body);font-size:20px;font-weight:300;color:var(--brass);flex-shrink:0;transition:transform var(--dur-base) var(--ease-in-out);}
.accordion-item.is-open .accordion-q .ind{transform:rotate(45deg);}
.accordion-a{max-height:0;overflow:hidden;transition:max-height var(--dur-base) var(--ease-in-out);}
.accordion-a-inner{padding:0 2px var(--sp-5);font-size:15.5px;color:var(--text-on-dark-mid);max-width:640px;}
.on-paper .accordion-a-inner{color:var(--text-mid);}
.accordion-a-inner a{font-weight:700;border-bottom:1px solid currentColor;}

/* ==========================================================================
   Forms
   ========================================================================== */
.form-grid{display:grid;grid-template-columns:1fr 1fr;gap:var(--sp-5) var(--sp-6);}
@media (max-width:600px){.form-grid{grid-template-columns:1fr;}}
.field{display:flex;flex-direction:column;gap:8px;margin-bottom:var(--sp-5);}
.field.full{grid-column:1/-1;}
.field label{font-size:11.5px;font-weight:700;letter-spacing:0.06em;text-transform:uppercase;color:var(--text-on-dark-mid);}
.on-paper .field label{color:var(--text-mid);}
.field input,.field select,.field textarea{
  border:none;border-bottom:1.5px solid var(--line-on-dark-strong);padding:12px 2px;font-size:16px;
  background:transparent;color:var(--text-on-dark);
}
.on-paper .field input,.on-paper .field select,.on-paper .field textarea{border-color:var(--paper-line);color:var(--text-dark);}
.field input:focus,.field select:focus,.field textarea:focus{border-color:var(--brass);outline:none;}
.on-paper .field input:focus,.on-paper .field select:focus,.on-paper .field textarea:focus{border-color:var(--maroon);}
.form-note{font-size:13px;color:var(--text-on-dark-mid);margin-top:14px;min-height:18px;}
.on-paper .form-note{color:var(--text-mid);}
.form-note.success{color:var(--brass);font-weight:700;}
.on-paper .form-note.success{color:var(--maroon);}
.visually-hidden{position:absolute!important;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0;}

/* ==========================================================================
   Word-mask heading reveal — .split-heading (main.js wraps each word in a
   clipping mask + inner span, mirroring the hero wordmark's per-letter
   treatment but at word granularity for body headings).

   Word-level rather than per-letter or per-line on purpose: per-letter is
   too busy at heading size outside the one hero masthead it's reserved for,
   and per-line would need re-measuring every time a resize changes where
   text wraps. Masking by word sidesteps both — no remeasuring, and at 2-5
   words a heading still reads as one considered, staggered arrival rather
   than confetti. */
.split-word{display:inline-block;overflow:hidden;vertical-align:top;}
.split-word-inner{
  display:inline-block;transform:translateY(112%);opacity:0;
  transition:transform .85s var(--ease-out),opacity .7s var(--ease-out);
  transition-delay:calc(var(--i,0) * 45ms);
}
.split-heading.is-visible .split-word-inner{transform:translateY(0);opacity:1;}
@media (prefers-reduced-motion:reduce){
  .split-word-inner{transform:none;opacity:1;transition:none;}
}

/* ==========================================================================
   CTA banner
   ========================================================================== */
.cta-band{position:relative;background:var(--maroon-deep);padding:var(--sp-8) 0;text-align:center;overflow:hidden;}
.cta-band .cta-media{position:absolute;inset:0;z-index:0;}
.cta-band .cta-media img,.cta-band .cta-media video{width:100%;height:100%;object-fit:cover;}
.cta-band .cta-media::after{content:"";position:absolute;inset:0;background:linear-gradient(160deg,rgba(69,12,22,0.94),rgba(30,7,11,0.9));}
.cta-band .container{position:relative;z-index:1;}
.cta-band h2{color:var(--text-on-dark);margin-bottom:16px;font-weight:400;}
.cta-band p{color:var(--text-on-dark-mid);max-width:480px;margin:0 auto 28px;}
.cta-band .row{display:flex;gap:14px;justify-content:center;flex-wrap:wrap;}

/* ==========================================================================
   Footer
   ========================================================================== */
.site-footer{background:var(--ink-3);color:var(--text-on-dark);padding:var(--sp-8) 0 var(--sp-5);border-top:1px solid var(--line-on-dark);}
.footer-grid{display:grid;grid-template-columns:1.5fr 1fr 1fr 1fr;gap:var(--sp-6);margin-bottom:var(--sp-7);}
@media (max-width:820px){.footer-grid{grid-template-columns:1fr 1fr;}}
@media (max-width:520px){.footer-grid{grid-template-columns:1fr;}}
.footer-brand .word{font-family:var(--font-head);font-style:italic;font-size:26px;color:var(--text-on-dark);margin-bottom:12px;display:block;}
.footer-brand p{color:var(--text-on-dark-mid);max-width:280px;}
.footer-col h4{font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:0.14em;color:var(--brass);margin-bottom:var(--sp-4);}
.footer-col a{display:block;color:var(--text-on-dark-mid);font-size:14px;margin-bottom:11px;transition:color var(--dur-fast);}
.footer-col a:hover{color:var(--text-on-dark);}
.footer-bottom{
  border-top:1px solid var(--line-on-dark);padding-top:var(--sp-5);
  display:flex;justify-content:space-between;flex-wrap:wrap;gap:10px;font-size:12px;color:var(--text-on-dark-mid);
}
.footer-bottom a{transition:color var(--dur-fast);}
.footer-bottom a:hover{color:var(--text-on-dark);}
.footer-legal{display:flex;flex-wrap:wrap;gap:6px 20px;}
.footer-legal a{border-bottom:1px solid var(--line-on-dark-strong);}

/* ==========================================================================
   Legal page (privacy.html) — long-form reading on paper
   ========================================================================== */
.legal{max-width:760px;}
.legal-updated{font-size:13px;letter-spacing:0.04em;margin-bottom:var(--sp-6);}
.legal h2{
  font-size:clamp(24px,2.8vw,32px);color:var(--text-dark);
  margin:var(--sp-7) 0 var(--sp-4);scroll-margin-top:110px;
}
.legal p,.legal li{font-size:15.5px;color:var(--text-mid);max-width:68ch;}
.legal ul{list-style:disc;padding-left:22px;margin:0 0 var(--sp-4);}
.legal li{margin-bottom:10px;padding-left:4px;}
.legal li::marker{color:var(--maroon);}
.legal strong{color:var(--text-dark);font-weight:600;}
.legal a{color:var(--maroon);font-weight:600;border-bottom:1px solid currentColor;}
.legal a:hover{color:var(--maroon-bright);}

/* privacy line above form submit buttons */
.form-privacy{font-size:12.5px;margin:0 0 var(--sp-4);max-width:none;}
.form-privacy a{border-bottom:1px solid currentColor;}

/* click-to-load map placeholder (contact.html) — Google's iframe, and its
   cookies, only arrive after the visitor asks for the map */
.map-consent{
  height:100%;display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:var(--sp-4);padding:var(--sp-6);text-align:center;background:var(--ink-2);
}
.map-consent p{font-size:13.5px;max-width:34ch;margin:0;}
.map-consent p a,.map-consent-link{border-bottom:1px solid currentColor;}
.map-consent-link{font-size:13px;color:var(--text-on-dark-mid);}
.map-consent-link:hover{color:var(--text-on-dark);}

/* allergen notice at the top of the menu */
.allergen-notice{
  margin:var(--sp-7) 0 0;padding:var(--sp-5) var(--sp-5) var(--sp-4);
  border:1px solid var(--paper-line);border-left:3px solid var(--maroon);
  background:var(--paper-dim);scroll-margin-top:150px;
}
.allergen-notice strong{display:block;font-size:15px;color:var(--text-dark);margin-bottom:6px;}
.allergen-notice p{font-size:14.5px;max-width:78ch;}
.allergen-notice a{color:var(--maroon);font-weight:700;border-bottom:1px solid currentColor;}

/* ==========================================================================
   Scroll reveal
   ========================================================================== */
.reveal{opacity:0;transform:translateY(28px);transition:opacity .9s var(--ease-out),transform .9s var(--ease-out);transition-delay:var(--d,0s);}
.reveal.is-visible{opacity:1;transform:none;}
.reveal-fade{opacity:0;transition:opacity 1s var(--ease-out);transition-delay:var(--d,0s);}
.reveal-fade.is-visible{opacity:1;}

/* image reveal — a fade + gentle scale-settle, same mechanism as .reveal.
   This used to animate clip-path (a literal wipe), but that transition was
   unreliable — it would sometimes get stuck at its clipped starting state
   even after the is-visible class was confirmed present, hiding the dish
   gallery and the About page's storefront photo entirely. opacity/transform
   are the two properties every browser composites cheaply and consistently,
   which is exactly why .reveal already used them — this now does too.
   will-change is applied only while the element is about to animate and
   removed right after, so the browser isn't asked to keep a permanent extra
   layer for every reveal element on the page. */
.reveal-clip{
  opacity:0;transform:scale(1.03);
  transition:opacity 1.1s var(--ease-out),transform 1.1s var(--ease-out);
  transition-delay:var(--d,0s);
}
.reveal-clip.is-visible{opacity:1;transform:none;}

/* ==========================================================================
   Reviews band
   ==========================================================================
   Thirty years of goodwill that the site was not spending. Deliberately
   restrained: a score, a link out, and the words of two real customers.
   No star-rating JSON-LD — marking up a rating you collected from Google
   and re-publishing it as your own structured data is against Google's
   guidelines and risks a manual action, so the proof here is visual and
   links back to the source instead. */
.reviews-grid{
  display:grid;grid-template-columns:0.85fr 1fr 1fr;gap:var(--sp-6);align-items:start;
}
@media (max-width:860px){.reviews-grid{grid-template-columns:1fr;gap:var(--sp-5);}}

.review-score{display:flex;flex-direction:column;gap:6px;}
.review-score .score{
  font-family:var(--font-head);font-style:italic;font-weight:500;
  font-size:clamp(52px,6vw,76px);line-height:1;color:var(--text-on-dark);
}
.review-score .score-meta{font-size:13px;color:var(--text-on-dark-mid);letter-spacing:0.02em;}
.review-score .score-link{
  margin-top:8px;font-size:12px;font-weight:600;letter-spacing:0.08em;text-transform:uppercase;
  color:var(--brass);border-bottom:1px solid rgba(169,137,91,0.4);align-self:flex-start;padding-bottom:3px;
  transition:color var(--dur-fast) var(--ease-out),border-color var(--dur-fast) var(--ease-out);
}
.review-score .score-link:hover{color:var(--text-on-dark);border-color:var(--text-on-dark);}

/* five stars, filled to --pct — one element, no icon font, no images */
.stars{
  position:relative;display:inline-block;font-size:17px;letter-spacing:4px;
  color:rgba(169,137,91,0.28);line-height:1;
}
.stars::before{content:"★★★★★";}
.stars::after{
  content:"★★★★★";position:absolute;left:0;top:0;
  width:var(--pct,88%);overflow:hidden;white-space:nowrap;color:var(--brass);
}

.review{margin:0;display:flex;flex-direction:column;gap:var(--sp-4);}
.review p{
  font-family:var(--font-head);font-style:italic;font-weight:400;
  font-size:clamp(17px,1.5vw,20px);line-height:1.55;color:var(--text-on-dark);margin:0;
}
.review cite{
  font-family:var(--font-body);font-style:normal;font-size:11.5px;font-weight:600;
  letter-spacing:0.16em;text-transform:uppercase;color:var(--text-on-dark-mid);
}
.review cite::before{content:"";display:block;width:26px;height:1px;background:var(--brass-dim);margin-bottom:12px;}

/* fixed, pointer-events-none grain — never attached to a scrolling container */
.grain{position:fixed;inset:0;z-index:2;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' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ==========================================================================
   Mobile motion — the same language, rewritten for a portrait screen
   ==========================================================================
   Phones were getting none of the scroll motion: every scrubbed effect was
   gated to desktop because the desktop geometry didn't survive the drop to
   one column. Rather than shipping a phone with no motion at all, these are
   the same ideas re-choreographed for vertical.

   The one rule that governs all of it: NOTHING TRANSLATES HORIZONTALLY ON
   MOBILE. On a phone the feature rows are full-bleed single-column blocks,
   so any x-offset pushes past the viewport edge and creates a horizontal
   scrollbar — the single most common way a "responsive" page feels broken.
   The convergence becomes a vertical rise with a stagger instead, which
   reads as the same considered arrival without the risk.
   ========================================================================== */
@keyframes rowRise{
  from{transform:translateY(38px);opacity:0;}
  to{transform:none;opacity:1;}
}
/* a slow push-in on the hero footage as it leaves — replaces the desktop
   dissolve, which needs a full-bleed background to dissolve over and has
   nothing to work with in the phone's stacked layout */
@keyframes heroFootagePush{
  from{transform:scale(1.002);}
  to{transform:scale(1.13);}
}

@media (max-width:860px) and (prefers-reduced-motion:no-preference){
  @supports (animation-timeline:view()){
    .feature--split > .fired-frame,
    .feature--split > .feature-media,
    .feature--split > .feature-text{
      animation:rowRise linear both;
      animation-timeline:view();
      animation-range:entry 0% entry 62%;
    }
    /* text trails the image slightly — the picture arrives, then the words
       settle under it. Same stagger the desktop rows get from sharing a
       range; here it has to be built by hand because they're not side by
       side any more. */
    .feature--split > .feature-text{animation-range:entry 12% entry 76%;}

    /* the clip wipe would double up with the rise, same as on desktop */
    .feature--split > .fired-frame .reveal-clip,
    .feature--split > .feature-media.reveal-clip{clip-path:none;transform:none;}
  }
}

@media (max-width:700px) and (prefers-reduced-motion:no-preference){
  @supports (animation-timeline:view()){
    /* Scoped to the video INSIDE .hero-media, never the container: the
       container is what clips, so scaling it would spill the footage over
       the page rather than push into it. Overrides the deliberate
       `animation:none` on .hero-video, which exists to stop the CSS Ken
       Burns stacking on the video's own camera move — this replaces that
       zoom rather than adding to it, and only while the hero is leaving. */
    .hero .hero-media video,
    .hero .hero-media img.hero-video-fallback{
      animation:heroFootagePush linear both;
      animation-timeline:view();
      animation-range:exit 0% exit 100%;
    }
  }
}

/* ==========================================================================
   Read-progress hairline
   ==========================================================================
   A brass thread across the very top that fills as the page is read. It is
   the cheapest possible signal that someone sweated the details — and it is
   genuinely useful on the menu, which is long. Driven entirely by the
   scroll timeline, so there is no scroll listener and no JS in the loop at
   all; the element is created once in main.js the same way .grain is, so
   every page gets it without touching six HTML files. */
.scroll-progress{
  position:fixed;top:0;left:0;right:0;height:2px;z-index:300;
  pointer-events:none;transform:scaleX(0);transform-origin:0 50%;
  background:linear-gradient(90deg,var(--brass-dim) 0%,var(--brass) 55%,#E7CB98 100%);
}
@keyframes progressFill{from{transform:scaleX(0);}to{transform:scaleX(1);}}
@supports (animation-timeline:scroll()){
  @media (prefers-reduced-motion:no-preference){
    .scroll-progress{
      animation:progressFill linear both;
      animation-timeline:scroll(root block);
    }
  }
}
/* Without scroll-timeline support the bar would sit permanently empty and
   read as a broken element, so it is removed entirely rather than left. */
@supports not (animation-timeline:scroll()){
  .scroll-progress{display:none;}
}

/* ==========================================================================
   Wordmark foil sweep
   ==========================================================================
   One slow glint travelling across the gold, once, after the letters have
   finished arriving — the way light moves over foil stamping when you tilt
   a menu card. Deliberately NOT a loop: a permanent shimmer reads as a
   web-banner effect and costs a repaint forever, where a single pass reads
   as a material property of the logotype.

   --shimmer has to be registered with @property, because a plain custom
   property is an untyped string and would jump between keyframes instead of
   interpolating. Registering it as a <percentage> makes it animatable. */
@property --shimmer{
  syntax:'<percentage>';
  inherits:true;
  initial-value:0%;
}
/* The glint travels across and SETTLES BACK to 0%. That return matters: the
   per-letter offsets were tuned to line the five gradient slices into one
   continuous sweep, so ending anywhere else would leave the wordmark
   permanently mis-registered — a one-way animation would have quietly
   broken the logotype it was meant to flatter. */
@keyframes foilSweep{
  0%{--shimmer:0%;}
  55%{--shimmer:-120%;}
  100%{--shimmer:0%;}
}
@media (prefers-reduced-motion:no-preference){
  .hero-wordmark-brand{
    animation:foilSweep 2.6s var(--ease-in-out) 1.5s 1 both;
  }
}

/* ==========================================================================
   Ghost numerals
   ==========================================================================
   The oversized outlined figure sitting behind each feature row — the
   device an editorial spread uses to number a series without a heading.
   Outline only (text-stroke, no fill) and very low contrast, so it reads as
   watermark rather than as content competing with the headline.

   Hidden below 860px: in one column it would sit on top of the copy
   instead of beside it, and there is no spare horizontal room to bleed it
   into. The small brass .num label carries the numbering there. */
.feature-text{position:relative;}
@media (min-width:861px){
  .feature-text[data-num]::before{
    content:attr(data-num);
    position:absolute;z-index:-1;pointer-events:none;
    top:-0.42em;left:-0.16em;
    font-family:var(--font-head);font-style:italic;font-weight:500;
    font-size:clamp(130px,13vw,210px);line-height:1;
    color:transparent;
    -webkit-text-stroke:1px rgba(169,137,91,0.16);
    text-stroke:1px rgba(169,137,91,0.16);
  }
  .feature--split.is-reverse .feature-text[data-num]::before{
    left:auto;right:-0.16em;
  }
}

/* ==========================================================================
   Hero scroll cue
   ==========================================================================
   A hairline that fills downward on a loop, with the invitation set beside
   it. Present because the hero is a full viewport of video with the payoff
   below it — without a cue, a first-time visitor on a big screen has no
   signal there is more page. It lives outside .hero-inner so the hero's
   scroll dissolve doesn't drag it around, and fades on its own as soon as
   the page moves. */
.scroll-cue{
  /* Fixed to the VIEWPORT, not to .hero. Two things push a hero-anchored cue
     below the fold: the hero is min-height:100vh but its content can grow it
     taller, and the sticky header occupies flow space above it, so the
     hero's own 100vh already starts ~87px down. Fixed sidesteps both, and
     costs nothing here because the cue retires within 18vh of scroll — it
     is never a floating element competing with the page. */
  position:fixed;left:50%;bottom:26px;transform:translateX(-50%);
  display:flex;flex-direction:column;align-items:center;gap:10px;
  font-family:var(--font-body);font-size:9.5px;font-weight:600;
  letter-spacing:0.32em;text-transform:uppercase;color:var(--text-on-dark-mid);
  pointer-events:none;z-index:1;
}
.scroll-cue-line{
  width:1px;height:46px;background:var(--line-on-dark-strong);
  position:relative;overflow:hidden;
}
.scroll-cue-line::after{
  content:"";position:absolute;inset:0;background:var(--brass);
  transform:translateY(-100%);
  animation:cueTravel 2.4s var(--ease-in-out) infinite;
}
@keyframes cueTravel{
  0%{transform:translateY(-100%);}
  60%{transform:translateY(100%);}
  100%{transform:translateY(100%);}
}
/* the cue has done its job the instant the page moves */
@keyframes cueRetire{to{opacity:0;}}
@supports (animation-timeline:scroll()){
  @media (prefers-reduced-motion:no-preference){
    .scroll-cue{
      animation:cueRetire linear both;
      animation-timeline:scroll(root block);
      animation-range:0 18vh;
    }
  }
}
/* no room for it in the phone's stacked hero, and nothing to scroll over */
@media (max-width:700px){
  .scroll-cue{display:none;}
}
@media (prefers-reduced-motion:reduce){
  .scroll-cue-line::after{animation:none;transform:translateY(0);}
}

@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto;}
  *{animation-duration:0.001ms!important;transition-duration:0.001ms!important;}
  .reveal,.reveal-fade,.reveal-clip{opacity:1;transform:none;clip-path:none;filter:none;}
  .scroll-progress{display:none;}
}
