/* ==========================================================================
   The Bunhouse Café — thebunhousecafe.com
   "Nocturne & Amber": deep midnight navy, molten amber, hairline gold.

   WHY THIS IS HAND-WRITTEN CSS AND NOT TAILWIND.
   The site's own security policy (web/public/_headers) is
   `script-src 'self'; style-src 'self'; font-src 'self'` — no CDN, nothing
   inline. The design was handed over as a Tailwind-CDN page with an inline
   config block, inline <style>, and style="" attributes; every one of those
   is refused by that header. Loosening the policy to run the mockup as-is
   would mean allowing third-party script onto the same origin that serves
   the ordering pages, where a signed-in customer's session cookie lives.
   So the look is reproduced here instead, and the policy stays shut.

   The two typefaces are served from ./fonts, for the same reason and one
   more: a Google Fonts request tells Google who is reading the menu.

   As on the ordering app, every element gets a class. There are no inline
   styles anywhere in index.html — not as a convention, but because the
   browser would drop them.
   ========================================================================== */

/* ---- 1. Typefaces -------------------------------------------------------- */

@font-face {
  font-family: 'Playfair Display';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('fonts/playfair-display-latin.woff2') format('woff2');
}
@font-face {
  font-family: 'Plus Jakarta Sans';
  font-style: normal;
  font-weight: 200 800;
  font-display: swap;
  src: url('fonts/plus-jakarta-sans-latin.woff2') format('woff2');
}

/* ---- 2. Tokens ----------------------------------------------------------
   THE PALETTE IS THE EMBLEM'S, NOT THE DESIGN FILE'S.

   The design file ("Nocturne & Amber") specified midnight navy. The café's
   emblem has no blue in it at all: cream (#fef7ed), deep olive, and a warm
   gold (#c9a169) on the word CAFÉ and the little hearts. A navy site would
   have been a second brand, and the ordering app on order.thebunhousecafe.com
   is already built in the olive — a customer pressing "Order Online" would
   have walked from one company into another.

   So the design file's STRUCTURE is kept — a dark, candlelit canvas with one
   warm metal glowing on it — and its hues are replaced by the emblem's. The
   dark is now a deep olive night rather than navy, and the amber is the
   brand's roasted gold.

   EVERY COLOUR BELOW IS DEFINED ONCE. The three that get used at a dozen
   opacities are kept as bare RGB components so the rest of the sheet can say
   rgb(var(--gold-rgb) / 0.3) instead of repeating a literal. Changing the
   brand is changing these lines and nothing else.                           */

:root {
  /* Bare components, for the colours that are used at many opacities. */
  --gold-rgb: 196 152 89;   /* #c49859 — the emblem's gold                   */
  --glow-rgb: 232 189 126;  /* #e8bd7e — the lit edge of it                  */
  --card-rgb: 29 40 23;     /* #1d2817 — the card, for translucent panels    */
  --deep-rgb: 13 19 9;      /* #0d1309 — the floor, for overlays & vignettes */

  /* Canvas, ascending. Depth here is tonal, not shadowed. */
  --surface-lowest:   #0d1309;
  --surface:          #141c10;
  --surface-low:      #1a2415;
  --surface-card:     #1d2817;
  --surface-container:#212d1a;
  --surface-high:     #2c3a23;
  --surface-elevated: #26331d;
  --surface-overlay:  rgb(var(--deep-rgb) / 0.85);

  /* Gold, the one thing that glows. */
  --primary:          #e8bd7e;
  --primary-container:#c49859;
  --on-primary:       #2b1c06;
  --secondary:        #d9b76a;
  --gold-light:       #f0d9ad;
  --gold-border:      rgb(var(--gold-rgb) / 0.30);
  --gold-glow:        rgb(var(--gold-rgb) / 0.18);

  /* Veg and non-veg. Green and red are what every menu in India uses and what
     people look for first, so they stay green and red and are NOT folded into
     the brand palette — this is the one place where being on-brand would cost
     somebody the one fact they came to the page for. Both are lifted bright
     enough to separate cleanly from an olive background. */
  --veg:              #7fe3a0;
  --veg-soft:         rgb(127 227 160 / 0.12);
  --non-veg:          #ffb0a8;
  --non-veg-soft:     rgb(255 176 168 / 0.12);
  --egg:              #ffd98a;
  --egg-soft:         rgb(255 217 138 / 0.12);

  /* Warm ivory, never a blue-white: the emblem is printed on cream. */
  --text-primary:     #f8f5ec;
  --on-background:    #e3e1d2;
  --text-muted:       #a6ab94;   /* 7.5:1 on the canvas */
  --hairline:         rgb(255 255 255 / 0.07);

  --serif: 'Playfair Display', Georgia, 'Times New Roman', serif;
  --sans:  'Plus Jakarta Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;

  --r-sm: 0.25rem;
  --r:    0.5rem;
  --r-md: 0.75rem;
  --r-xl: 1.5rem;
  --r-2xl: 1.75rem;
  --r-full: 9999px;

  /* 1280px, as the design file's grid model specifies. */
  --measure: 80rem;
  --gutter: 1.5rem;
  --gutter-mobile: 1rem;

  --bar-h: 5rem;
}

/* ---- 3. Reset ----------------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  /* Every in-page link lands under the fixed header rather than beneath it. */
  scroll-padding-top: calc(var(--bar-h) + 1rem);
  -webkit-text-size-adjust: 100%;
}
/* Somebody who has asked their system for less movement gets none of it —
   including the scroll easing, which is motion they did not ask for. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
}

body {
  margin: 0;
  font-family: var(--sans);
  font-size: 0.9375rem;
  line-height: 1.6;
  color: var(--on-background);
  background: var(--surface);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

img, svg { display: block; max-width: 100%; }
img { height: auto; }
h1, h2, h3, h4 { margin: 0; font-family: var(--serif); font-weight: 500; letter-spacing: -0.01em; }
p { margin: 0; }
ul { margin: 0; padding: 0; list-style: none; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }

::selection { background: var(--primary); color: var(--on-primary); }

/* A keyboard must be able to see where it is. The amber halo is the design
   file's own focus treatment, reused rather than reinvented. */
:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 3px;
  border-radius: var(--r-sm);
}

/* The scrollbar, in the house palette. */
* { scrollbar-color: var(--primary-container) var(--surface-lowest); scrollbar-width: thin; }
::-webkit-scrollbar { width: 6px; height: 6px; }
::-webkit-scrollbar-track { background: var(--surface-lowest); }
::-webkit-scrollbar-thumb { background: var(--primary-container); border-radius: var(--r-full); }

/* Visible to a screen reader, to nobody else. */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* The first thing the Tab key should find on a long page. */
.skip {
  position: absolute;
  top: 0.5rem; left: 0.5rem;
  z-index: 100;
  padding: 0.75rem 1.25rem;
  font-size: 0.8125rem;
  font-weight: 700;
  color: var(--on-primary);
  background: var(--primary);
  border-radius: var(--r-full);
  transform: translateY(-200%);
}
.skip:focus { transform: translateY(0); }

/* ---- 4. Shared furniture ------------------------------------------------ */

.wrap {
  width: 100%;
  max-width: var(--measure);
  margin-inline: auto;
  padding-inline: var(--gutter);
}
@media (max-width: 40rem) { .wrap { padding-inline: var(--gutter-mobile); } }

.section { padding-block: 6rem; position: relative; }
.section--sunk { background: var(--surface-lowest); }
.section--edge { border-top: 1px solid var(--hairline); }
@media (max-width: 48rem) { .section { padding-block: 3.75rem; } }

/* The eyebrow: uppercase, widely tracked, a hairline either side. The design
   file calls it a foil-embossed heading, and the rules are the foil. */
.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.625rem;
  margin-bottom: 0.75rem;
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.25em;
  text-transform: uppercase;
  color: var(--primary);
}
.eyebrow::before, .eyebrow::after {
  content: '';
  width: 1.5rem;
  height: 1px;
  background: var(--primary);
}
/* At the start of a left-aligned block the leading rule is just a dash in
   the margin. Drop it and keep the trailing one. */
.eyebrow--start::before { display: none; }

.lede { max-width: 44rem; margin-inline: auto; margin-bottom: 4rem; text-align: center; }
.lede__h {
  font-size: clamp(1.75rem, 4.5vw, 2.5rem);
  line-height: 1.2;
  color: var(--text-primary);
  margin-bottom: 0.75rem;
}
.lede__p { font-size: 0.9375rem; color: var(--text-muted); }
@media (min-width: 40rem) { .lede__p { font-size: 1rem; } }

/* Italic serif inside a serif headline — the design file's "narrative grace". */
.accent { font-style: italic; font-weight: 400; color: var(--primary); }

/* ---- 5. Buttons --------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 0.875rem 1.75rem;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  white-space: nowrap;
  border-radius: var(--r-full);
  transition: box-shadow 0.25s, filter 0.25s, background-color 0.25s, border-color 0.25s, color 0.25s;
}
.btn__i { width: 1.0625rem; height: 1.0625rem; flex: none; }

/* Primary: the amber-to-gold gradient with dark navy text, and the glow. */
.btn--primary {
  color: var(--on-primary);
  background: linear-gradient(to right, var(--primary), var(--secondary));
  box-shadow: 0 4px 24px rgb(var(--gold-rgb) / 0.4);
}
.btn--primary:hover { filter: brightness(1.06); box-shadow: 0 4px 32px rgb(var(--gold-rgb) / 0.6); }

/* Secondary: transparent, hairline gold, fills faintly on hover. */
.btn--ghost {
  color: var(--text-primary);
  background: var(--surface-card);
  border: 1px solid var(--gold-border);
}
.btn--ghost:hover { color: var(--primary); border-color: var(--primary); background: rgb(var(--gold-rgb) / 0.08); }

.btn--sm { padding: 0.6875rem 1.25rem; font-size: 0.6875rem; }
.btn--block { width: 100%; }

/* ---- 6. Header ---------------------------------------------------------- */

.hdr {
  position: fixed;
  inset: 0 0 auto;
  z-index: 50;
  background: var(--surface-overlay);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  border-bottom: 1px solid var(--hairline);
  transition: box-shadow 0.3s, background-color 0.3s;
}
/* Set by site.js once the page has left the hero, so the bar earns its
   shadow instead of wearing one over its own background. */
.hdr--lifted { box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5); }

.hdr__in {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  height: var(--bar-h);
}

.crest {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex: none;
}
.crest__img {
  width: 2.75rem;
  height: 2.75rem;
  object-fit: cover;
  border: 1px solid rgb(var(--glow-rgb) / 0.4);
  border-radius: var(--r-full);
  background: var(--surface-lowest);
  box-shadow: 0 0 15px rgb(var(--gold-rgb) / 0.3);
  transition: transform 0.25s;
}
.crest:hover .crest__img { transform: scale(1.05); }
.crest__text { display: flex; flex-direction: column; line-height: 1.15; }

/* ---- The wordmark --------------------------------------------------------
   Set the way the emblem sets it rather than as a plain line of text: "The"
   in italic, BUNHOUSE in tracked capitals, CAFÉ smaller and in the gold, with
   the same spacing between them the printed version has.

   The typeface is Playfair Display, which is already loaded for the headings
   and is a close match for the emblem's own lettering — the same high contrast
   between thick and thin strokes, the same flat serifs. Nothing new to
   download for it.

   It is one <span> per part so each can be tracked separately; caps and
   letter-spacing cannot be applied to parts of a single text node. The parts
   read as one name to a screen reader because they are adjacent inline spans
   with no spaces to lose — the aria-label on the link says it in full anyway. */
.crest__name {
  display: flex;
  align-items: baseline;
  gap: 0.3em;
  font-family: var(--serif);
  color: var(--text-primary);
  transition: color 0.2s;
}
.crest__the {
  font-size: 0.8125rem;
  font-style: italic;
  font-weight: 500;
}
.crest__main {
  font-size: 1.0625rem;
  font-weight: 700;
  /* The emblem's capitals are generously spaced; at this size the same optical
     looseness is about 0.06em. Tighter and it reads as ordinary bold text. */
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.crest__cafe {
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--primary);
  /* Letter-spacing adds a trailing gap after the last letter, which pushes the
     word off-centre against everything above it. Pull it back. */
  margin-right: -0.22em;
}
.crest:hover .crest__main,
.crest:hover .crest__the { color: var(--primary); }
.crest__kicker {
  font-size: 0.625rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--primary);
}
@media (max-width: 26rem) {
  .crest__img { width: 2.25rem; height: 2.25rem; }
  .crest__main { font-size: 0.9375rem; }
  .crest__the { font-size: 0.75rem; }
  .crest__cafe { font-size: 0.6875rem; }
  .crest__kicker { display: none; }
}

.nav { display: none; align-items: center; gap: 1.75rem; }
@media (min-width: 60rem) { .nav { display: flex; } }
.nav__a {
  position: relative;
  padding-block: 0.25rem;
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-muted);
  transition: color 0.2s;
}
.nav__a:hover { color: var(--primary); }
/* The underline the design file asks for, drawn rather than animated into
   existence, so it costs no layout. */
.nav__a::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: -0.125rem;
  height: 1px;
  background: var(--primary);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.25s;
}
.nav__a:hover::after { transform: scaleX(1); }

.hdr__cta { display: flex; align-items: center; gap: 0.625rem; flex: none; }
.hdr__order { display: none; }
@media (min-width: 30rem) { .hdr__order { display: inline-flex; } }

/* The hamburger, and the panel it opens. */
.burger {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.625rem;
  height: 2.625rem;
  color: var(--text-primary);
  background: var(--surface-card);
  border: 1px solid var(--gold-border);
  border-radius: var(--r-full);
}
.burger:hover { color: var(--primary); border-color: var(--primary); }
@media (min-width: 60rem) { .burger { display: none; } }
.burger__i { width: 1.25rem; height: 1.25rem; }
.burger__close { display: none; }
.burger[aria-expanded='true'] .burger__open { display: none; }
.burger[aria-expanded='true'] .burger__close { display: block; }

.sheet {
  position: fixed;
  inset: var(--bar-h) 0 auto;
  z-index: 49;
  padding: 1rem var(--gutter) 1.5rem;
  background: var(--surface-overlay);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  border-bottom: 1px solid var(--gold-border);
  box-shadow: 0 16px 40px -12px rgba(0, 0, 0, 0.7);
}
.sheet[hidden] { display: none; }
@media (min-width: 60rem) { .sheet { display: none; } }
.sheet__a {
  display: block;
  padding: 0.9375rem 0.25rem;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--on-background);
  border-bottom: 1px solid var(--hairline);
}
.sheet__a:hover { color: var(--primary); }
.sheet__cta { margin-top: 1.25rem; }

/* ---- 7. Hero ------------------------------------------------------------
   The design file's hero carried a WebGL fragment shader and a Three.js
   burger under a glass cloche. Both are gone, and deliberately: together
   they were roughly a megabyte of script, they held a phone's GPU awake for
   as long as the tab was open, and the policy above forbids them from a CDN
   anyway. The "candlelight ambient glow" they existed to produce is three
   radial gradients, costs nothing, and does not flatten a battery.         */

.hero {
  position: relative;
  display: flex;
  align-items: center;
  min-height: 100vh;
  padding-top: calc(var(--bar-h) + 3rem);
  padding-bottom: 4rem;
  overflow: hidden;
  background: var(--surface);
}
/* A tall phone's address bar makes 100vh taller than the window. */
@supports (min-height: 100svh) {
  .hero { min-height: 100svh; }
}

.hero__glow {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    radial-gradient(42rem 34rem at 76% 34%, rgb(var(--gold-rgb) / 0.20), transparent 68%),
    radial-gradient(34rem 28rem at 10% 88%, rgb(var(--gold-rgb) / 0.10), transparent 66%),
    radial-gradient(60rem 40rem at 50% 0%, rgb(var(--glow-rgb) / 0.07), transparent 70%);
}
/* A vignette, so the glow reads as light in a dark room and not as a stain
   over the edge of the section. */
.hero__glow::after {
  content: '';
  position: absolute;
  inset: 0;
  background: radial-gradient(120% 90% at 50% 45%, transparent 38%, rgb(var(--deep-rgb) / 0.85) 100%);
}

.hero__grid {
  position: relative;
  display: grid;
  gap: 3rem;
  align-items: center;
}
@media (min-width: 64rem) {
  .hero__grid { grid-template-columns: 7fr 5fr; gap: 4rem; }
}

.hero__badge {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 1.5rem;
  padding: 0.4375rem 0.875rem;
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--gold-light);
  background: rgb(var(--card-rgb) / 0.9);
  border: 1px solid rgb(var(--gold-rgb) / 0.3);
  border-radius: var(--r-full);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  box-shadow: 0 0 20px rgb(var(--gold-rgb) / 0.18);
}
.hero__badge svg { width: 0.9375rem; height: 0.9375rem; color: var(--primary); flex: none; }

.hero__h1 {
  font-size: clamp(2.375rem, 7vw, 3.75rem);
  font-weight: 600;
  line-height: 1.08;
  letter-spacing: -0.02em;
  color: var(--text-primary);
  margin-bottom: 1.5rem;
}
.hero__p {
  max-width: 36rem;
  margin-bottom: 2rem;
  font-size: 1rem;
  line-height: 1.7;
  color: var(--text-muted);
}
@media (min-width: 40rem) { .hero__p { font-size: 1.125rem; } }

.hero__cta { display: flex; flex-wrap: wrap; gap: 1rem; margin-bottom: 2.5rem; }
@media (max-width: 26rem) {
  .hero__cta { flex-direction: column; align-items: stretch; }
}

/* Three facts, and they are facts: the dish and category counts are read
   off the live menu by site.js, not typed in here. The design file had
   "4.9 Google Rating" and "48h Wild Proof Rise" in these slots — a number
   nobody can verify and a claim about bread this kitchen does not make. */
.stats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0.75rem;
  max-width: 32rem;
  padding: 0.75rem;
  background: rgb(var(--card-rgb) / 0.75);
  border: 1px solid var(--hairline);
  border-radius: var(--r-xl);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
}
.stat {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 0.5rem 0.25rem;
  text-align: center;
}
.stat + .stat { border-left: 1px solid var(--hairline); }
.stat__n {
  font-family: var(--serif);
  font-size: 1.375rem;
  font-weight: 700;
  color: var(--text-primary);
}
.stat__l {
  margin-top: 0.125rem;
  font-size: 0.625rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-muted);
}

/* The hero plate: where the 3D cloche was. A framed photograph, in the gold
   inset the design file specifies for culinary imagery. */
.plate { position: relative; }
.plate__frame {
  position: relative;
  max-width: 26rem;
  margin-inline: auto;
  padding: 1.25rem;
  border-radius: var(--r-full);
  /* A pool of candlelight behind the plate rather than a box around it. */
  background: radial-gradient(circle at 50% 46%, rgb(var(--gold-rgb) / 0.18), transparent 68%);
}
.plate__tag {
  position: absolute;
  top: -0.75rem;
  left: 50%;
  z-index: 2;
  transform: translateX(-50%);
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  padding: 0.3125rem 1rem;
  font-size: 0.625rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--gold-light);
  background: var(--surface);
  border: 1px solid rgb(var(--gold-rgb) / 0.4);
  border-radius: var(--r-full);
}
.plate__tag svg { width: 0.75rem; height: 0.75rem; }
.plate__shot {
  width: 100%;
  aspect-ratio: 1;
  object-fit: cover;
  background: #fff;
  border: 1px solid var(--gold-border);
  border-radius: var(--r-full);
  box-shadow:
    0 0 0 10px rgb(var(--gold-rgb) / 0.06),
    0 30px 70px -20px rgb(var(--gold-rgb) / 0.5),
    0 20px 50px -15px rgba(0, 0, 0, 0.7);
}

/* ---- 8. Marquee ---------------------------------------------------------
   Two identical runs side by side, translated by exactly half the track, so
   the seam lands where the copies meet and the loop is invisible.          */

.ribbon {
  position: relative;
  z-index: 20;
  padding-block: 0.8125rem;
  overflow: hidden;
  color: var(--on-primary);
  background: linear-gradient(to right, var(--primary-container), var(--secondary), var(--primary-container));
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.4);
}
.ribbon__track {
  display: flex;
  width: max-content;
  animation: slide 32s linear infinite;
}
.ribbon:hover .ribbon__track { animation-play-state: paused; }
.ribbon__run {
  display: flex;
  align-items: center;
  gap: 1.75rem;
  padding-right: 1.75rem;
  font-size: 0.6875rem;
  font-weight: 800;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  white-space: nowrap;
}
.ribbon__dot { font-size: 0.5rem; opacity: 0.7; }
@keyframes slide {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}
/* Reduced motion already kills the animation above; park the track at the
   start so the first run is the one on screen. */
@media (prefers-reduced-motion: reduce) {
  .ribbon__track { animation: none; }
}

/* ---- 9. Signature cards ------------------------------------------------- */

.cards { display: grid; gap: 2rem; }
@media (min-width: 48rem) { .cards { grid-template-columns: repeat(2, 1fr); } }

.card {
  display: flex;
  flex-direction: column;
  padding: 1.5rem;
  background: var(--surface-card);
  border: 1px solid var(--hairline);
  border-radius: var(--r-2xl);
  box-shadow: 0 16px 40px -12px rgba(0, 0, 0, 0.5);
  transition: border-color 0.3s, box-shadow 0.3s, transform 0.3s;
}
.card:hover {
  border-color: rgb(var(--glow-rgb) / 0.4);
  box-shadow: 0 16px 40px -12px rgb(var(--gold-rgb) / 0.18);
  transform: translateY(-2px);
}

/* ---- The plate -----------------------------------------------------------
   Every photograph is a studio cut-out on pure white. Knocking that white out
   so the food floats on the navy was tried and does not survive this set —
   see the long note at the top of scripts/build-menu-images.js. So the white
   is kept and made to mean something: the subject is fitted inside a square
   (never cropped), and the square is clipped to a circle here. The photo's own
   background becomes the plate, and a gold rim with a warm halo under it makes
   the circle look lit rather than cut out.

   The clip lives in CSS rather than in the files, so the shape can change
   without reprocessing 242 images.                                          */

.shot {
  position: relative;
  width: min(13.5rem, 62%);
  margin: 0.25rem auto 1.5rem;
  aspect-ratio: 1;
}
.shot__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  background: #fff;
  border: 1px solid var(--gold-border);
  border-radius: var(--r-full);
  /* The rim, a faint amber ring just outside it, and the candlelight pooling
     underneath. Three shadows rather than a wrapper element. */
  box-shadow:
    0 0 0 6px rgb(var(--gold-rgb) / 0.07),
    0 18px 38px -14px rgb(var(--gold-rgb) / 0.45),
    0 10px 30px -10px rgba(0, 0, 0, 0.6);
  transition: transform 0.5s, box-shadow 0.5s;
}
.card:hover .shot__img {
  transform: scale(1.04);
  box-shadow:
    0 0 0 8px rgb(var(--gold-rgb) / 0.12),
    0 22px 46px -14px rgb(var(--gold-rgb) / 0.6),
    0 10px 30px -10px rgba(0, 0, 0, 0.6);
}
/* Sits over the rim at the foot of the plate. The plate is not a clipping
   container, so nothing has to be cut to let this out. */
.shot__flag {
  position: absolute;
  bottom: -0.5rem;
  left: 50%;
  z-index: 2;
  transform: translateX(-50%);
  padding: 0.25rem 0.875rem;
  font-size: 0.625rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--gold-light);
  background: var(--surface-elevated);
  border: 1px solid var(--gold-border);
  border-radius: var(--r-full);
}

.card__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 0.75rem;
  margin-bottom: 0.5rem;
}
/* The plate is round and centred, so the card reads better centred with it
   down to the notes, and left-aligned again for the footer row. */
.card { text-align: center; }
.card__head { justify-content: center; align-items: center; flex-wrap: wrap; }
.card__p { margin-inline: auto; max-width: 30rem; }
.notes { justify-content: center; }
.card__foot { text-align: left; }
.card__h { font-size: 1.25rem; font-weight: 600; color: var(--text-primary); transition: color 0.2s; }
.card:hover .card__h { color: var(--primary); }
.card__p { margin-bottom: 1rem; font-size: 0.8125rem; line-height: 1.65; color: var(--text-muted); }
@media (min-width: 40rem) { .card__p { font-size: 0.875rem; } }

/* Notes: the "sensory badges", reduced to what the kitchen can stand behind
   — what is in it and how it is cooked. */
.notes { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 1.25rem; }
.note {
  padding: 0.25rem 0.625rem;
  font-size: 0.6875rem;
  color: var(--gold-light);
  background: var(--surface-elevated);
  border: 1px solid rgb(var(--gold-rgb) / 0.2);
  border-radius: var(--r);
}

.card__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-top: auto;
  padding-top: 1rem;
  border-top: 1px solid var(--hairline);
}

/* ---- 10. Diet marks ----------------------------------------------------
   The square-in-a-square every Indian menu uses. Green for veg, red for
   not. A customer has the right to read this at a glance, so it is a shape
   and a colour rather than a word in grey.                                */

.diet {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  padding: 0.1875rem 0.5rem 0.1875rem 0.3125rem;
  font-size: 0.625rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  white-space: nowrap;
  border-radius: var(--r-sm);
}
.diet__box {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 0.75rem;
  height: 0.75rem;
  flex: none;
  border: 1.5px solid currentColor;
  border-radius: 2px;
}
.diet__box::after {
  content: '';
  width: 0.375rem;
  height: 0.375rem;
  background: currentColor;
  border-radius: var(--r-full);
}
.diet--veg { color: var(--veg); background: var(--veg-soft); }
.diet--non { color: var(--non-veg); background: var(--non-veg-soft); }
/* Egg is the third mark, not a shade of the other two — see the note in
   site.js. A warm yellow, which is what the menus that bother to distinguish
   it use, and far enough from both the green and the red to be told apart at
   a glance and by most kinds of colour blindness. */
.diet--egg { color: var(--egg); background: var(--egg-soft); }

/* ---- 11. The craft strip ------------------------------------------------
   Where the design file had "The Secret Room — Interactive Dining
   Soundscapes": three buttons that started a jazz / hearth / bistro audio
   loop. A café site that begins playing music at a stranger is not
   atmosphere, it is a thing people reach for the mute key over, and on a
   phone it is somebody's data. The section is now the four steps the
   kitchen actually works in.                                              */

.steps { display: grid; gap: 1.5rem; counter-reset: step; }
@media (min-width: 40rem) { .steps { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 64rem) { .steps { grid-template-columns: repeat(4, 1fr); gap: 1.25rem; } }

.step {
  position: relative;
  padding: 1.75rem 1.5rem 1.5rem;
  background: var(--surface-card);
  border: 1px solid var(--hairline);
  border-radius: var(--r-xl);
  transition: border-color 0.3s, transform 0.3s;
}
.step:hover { border-color: var(--gold-border); transform: translateY(-2px); }
.step__n {
  counter-increment: step;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.25rem;
  height: 2.25rem;
  margin-bottom: 1rem;
  font-family: var(--serif);
  font-size: 0.9375rem;
  font-weight: 700;
  color: var(--primary);
  background: var(--surface-elevated);
  border: 1px solid var(--gold-border);
  border-radius: var(--r-full);
}
.step__n::before { content: '0' counter(step); }
.step__h { margin-bottom: 0.5rem; font-size: 1.0625rem; font-weight: 600; color: var(--text-primary); }
.step__p { font-size: 0.8125rem; line-height: 1.65; color: var(--text-muted); }

/* The hairline that joins the four steps into one sequence on a wide
   screen. Decorative, so it is drawn and never read. */
@media (min-width: 64rem) {
  .step:not(:last-child)::after {
    content: '';
    position: absolute;
    top: 2.75rem;
    right: -1.25rem;
    width: 1.25rem;
    height: 1px;
    background: linear-gradient(to right, var(--gold-border), transparent);
  }
}

/* ---- 12. The menu ------------------------------------------------------
   Built by site.js from the live menu — /api/customer/menu, the same call
   the ordering app makes, which is the same row in the same table the
   kitchen cooks from.

   NO PRICE IS TYPED INTO THIS SITE. A marketing page with its own copy of
   the prices is a page that is wrong the first week somebody changes one,
   and a customer who saw 249 here and is charged 269 at the basket is
   right to be annoyed. If the menu cannot be fetched, the section says so
   and sends people to the ordering site rather than showing a stale list. */

.dishes { display: grid; gap: 1.25rem; }
@media (min-width: 40rem) { .dishes { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 64rem) { .dishes { grid-template-columns: repeat(3, 1fr); } }

.dish {
  display: flex;
  flex-direction: column;
  padding: 1.25rem;
  background: var(--surface-card);
  border: 1px solid var(--hairline);
  border-radius: var(--r-xl);
  transition: border-color 0.25s, background-color 0.25s;
}
.dish:hover { border-color: rgb(var(--glow-rgb) / 0.3); background: var(--surface-low); }

/* A dish row is its plate and then its words. */
.dish__top { display: flex; align-items: flex-start; gap: 0.875rem; }
.dish__text { min-width: 0; flex: 1 1 auto; }

/* The same plate as the signature cards, at thumbnail size. */
.dish__plate {
  width: 4.5rem;
  height: 4.5rem;
  flex: none;
  object-fit: cover;
  background: #fff;
  border: 1px solid var(--gold-border);
  border-radius: var(--r-full);
  box-shadow: 0 6px 18px -8px rgb(var(--gold-rgb) / 0.4);
}

.dish__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 0.75rem;
  margin-bottom: 0.375rem;
}
.dish__h {
  font-family: var(--sans);
  font-size: 0.9375rem;
  font-weight: 600;
  line-height: 1.4;
  color: var(--text-primary);
}
/* Price in the design file's secondary gold, hard against the right edge,
   and tabular so a column of them lines up. */
.dish__price {
  flex: none;
  font-size: 0.875rem;
  font-weight: 700;
  color: var(--secondary);
  font-variant-numeric: tabular-nums;
}
.dish__from {
  display: block;
  font-size: 0.5625rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  text-align: right;
  color: var(--text-muted);
}
.dish__p {
  margin-bottom: 0.875rem;
  font-size: 0.75rem;
  line-height: 1.6;
  color: var(--text-muted);
}
.dish__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  margin-top: auto;
  padding-top: 0.75rem;
  border-top: 1px solid var(--hairline);
}
/* What a variant costs extra is the customer's business before they tap. */
.dish__sizes {
  font-size: 0.6875rem;
  color: var(--text-muted);
}

/* ---- The caveat and the door --------------------------------------------
   The picture disclaimer is set quietly but not hidden: muted text, a rule
   above it, centred under the food it refers to. A thing worth saying is
   worth placing where the eye already is, which is why it sits under the
   dishes rather than in the footer with the opening hours.               */

.caveat {
  display: flex;
  align-items: flex-start;
  gap: 0.625rem;
  max-width: 44rem;
  margin: 2.5rem auto 0;
  padding-top: 1.5rem;
  font-size: 0.8125rem;
  line-height: 1.6;
  text-align: left;
  color: var(--text-muted);
  border-top: 1px solid var(--hairline);
}
.caveat__i { width: 1.0625rem; height: 1.0625rem; margin-top: 0.1875rem; flex: none; color: var(--primary); }

.menu__door { margin-top: 2.5rem; text-align: center; }

/* While the menu is in flight, and if it never arrives. */
.state { padding: 3rem 1.5rem; text-align: center; }
.state__p { font-size: 0.875rem; color: var(--text-muted); }
.state__cta { margin-top: 1.5rem; }

/* Skeleton cards, so the menu section has the height it is about to need
   and the page does not jump when it arrives. */
.ghost {
  height: 8.5rem;
  background: linear-gradient(100deg, var(--surface-card) 30%, var(--surface-high) 50%, var(--surface-card) 70%);
  background-size: 300% 100%;
  border: 1px solid var(--hairline);
  border-radius: var(--r-xl);
  animation: sweep 1.4s ease-in-out infinite;
}
@keyframes sweep {
  from { background-position: 150% 0; }
  to   { background-position: -50% 0; }
}

/* ---- 13. Order ---------------------------------------------------------
   One way to order, not the design file's two. It had "Reserve an Evening
   Table — instant confirmation powered by resOS" beside it; there is no
   booking system behind this site and naming a vendor that was never
   signed up for would be a promise the shop cannot keep.                  */

.order {
  display: grid;
  gap: 2rem;
  align-items: center;
  max-width: 64rem;
  margin-inline: auto;
}
@media (min-width: 56rem) { .order { grid-template-columns: 1fr 1fr; gap: 3rem; } }

.order__panel {
  padding: 2rem;
  background: var(--surface-card);
  border: 1px solid rgb(var(--gold-rgb) / 0.2);
  border-radius: var(--r-2xl);
  box-shadow: 0 16px 40px -12px rgb(var(--gold-rgb) / 0.12);
}
.order__h { margin-bottom: 0.75rem; font-size: 1.5rem; font-weight: 600; color: var(--text-primary); }
.order__p { margin-bottom: 1.75rem; font-size: 0.875rem; line-height: 1.7; color: var(--text-muted); }

.ticks { display: grid; gap: 0.875rem; margin-bottom: 2rem; }
.tick {
  display: flex;
  align-items: flex-start;
  gap: 0.625rem;
  font-size: 0.8125rem;
  color: var(--text-muted);
}
.tick svg { width: 1rem; height: 1rem; margin-top: 0.1875rem; flex: none; color: var(--primary); }

/* The three ways an order can be taken, as plain tiles. */
.ways { display: grid; gap: 1rem; }
.way {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 1.25rem;
  background: var(--surface-container);
  border: 1px solid var(--hairline);
  border-radius: var(--r-xl);
}
.way__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.75rem;
  height: 2.75rem;
  flex: none;
  color: var(--primary);
  background: var(--surface-elevated);
  border: 1px solid var(--gold-border);
  border-radius: var(--r-md);
}
.way__icon svg { width: 1.25rem; height: 1.25rem; }
.way__h { margin-bottom: 0.125rem; font-family: var(--sans); font-size: 0.9375rem; font-weight: 600; color: var(--text-primary); }
.way__p { font-size: 0.75rem; line-height: 1.5; color: var(--text-muted); }

/* ---- 14. Visit ---------------------------------------------------------- */

.visit { display: grid; gap: 2.5rem; }
@media (min-width: 56rem) { .visit { grid-template-columns: 1fr 1fr; gap: 4rem; } }

.facts { display: grid; gap: 1.5rem; margin-top: 2rem; }
.fact { display: flex; align-items: flex-start; gap: 1rem; }
.fact__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  flex: none;
  color: var(--primary);
  background: var(--surface-card);
  border: 1px solid var(--gold-border);
  border-radius: var(--r-md);
}
.fact__icon svg { width: 1.125rem; height: 1.125rem; }
.fact__h {
  margin-bottom: 0.25rem;
  font-family: var(--sans);
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--primary);
}
.fact__p { font-size: 0.875rem; line-height: 1.65; color: var(--on-background); }
.fact__a { color: var(--on-background); border-bottom: 1px solid var(--gold-border); }
.fact__a:hover { color: var(--primary); border-bottom-color: var(--primary); }

/* Opening hours, as a definition list because that is what it is. */
.hours { display: grid; gap: 0.625rem; margin-top: 0.5rem; }
.hours__row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  font-size: 0.8125rem;
}
.hours__d { color: var(--text-muted); }
.hours__t { color: var(--text-primary); font-variant-numeric: tabular-nums; }
/* Today's row, marked by site.js. */
.hours__row--today .hours__d,
.hours__row--today .hours__t { color: var(--primary); font-weight: 700; }

/* Where a map picture would have gone. It is a panel and not an iframe for
   the reason given in index.html: an embedded map runs somebody else's script
   on the origin that serves the ordering pages, and reports every visitor to
   a map provider whether or not they wanted directions. */
.findus {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 0.75rem;
  padding: 2.5rem 2rem;
  text-align: center;
  background:
    radial-gradient(28rem 20rem at 50% 0%, var(--gold-glow), transparent 70%),
    var(--surface-card);
  border: 1px solid var(--gold-border);
  border-radius: var(--r-2xl);
  box-shadow: 0 16px 40px -12px rgb(var(--gold-rgb) / 0.18);
}
.findus__eyebrow {
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.25em;
  text-transform: uppercase;
  color: var(--primary);
}
.findus__addr {
  font-family: var(--serif);
  font-size: 1.5rem;
  font-weight: 600;
  line-height: 1.3;
  color: var(--text-primary);
}
.findus__note { font-size: 0.8125rem; color: var(--text-muted); }
.findus__cta {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.75rem;
  margin-top: 0.75rem;
}

/* ---- 15. Footer --------------------------------------------------------- */

.foot {
  padding: 4rem 0 3rem;
  background: var(--surface-lowest);
  border-top: 1px solid var(--hairline);
}
.foot__grid {
  display: grid;
  gap: 2.5rem;
  padding-bottom: 3rem;
  border-bottom: 1px solid var(--hairline);
}
@media (min-width: 48rem) { .foot__grid { grid-template-columns: 2fr 1fr 1fr; } }
@media (min-width: 64rem) { .foot__grid { grid-template-columns: 2.5fr 1fr 1fr 1.25fr; } }

.foot__p { max-width: 24rem; margin-block: 1rem 1.25rem; font-size: 0.8125rem; line-height: 1.7; color: var(--text-muted); }
.foot__h {
  margin-bottom: 1rem;
  font-family: var(--sans);
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--primary);
}
.foot__list { display: grid; gap: 0.625rem; font-size: 0.8125rem; color: var(--text-muted); }
.foot__a { transition: color 0.2s; }
.foot__a:hover { color: var(--primary); }

.social { display: flex; gap: 0.625rem; }
.social__a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.25rem;
  height: 2.25rem;
  color: var(--primary);
  background: var(--surface-card);
  border: 1px solid transparent;
  border-radius: var(--r-full);
  transition: border-color 0.2s, background-color 0.2s;
}
.social__a:hover { border-color: var(--primary); background: var(--surface-elevated); }
.social__a svg { width: 1rem; height: 1rem; }

.foot__base {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding-top: 2rem;
  font-size: 0.75rem;
  color: var(--text-muted);
}
@media (min-width: 40rem) { .foot__base { flex-direction: row; } }

/* ---- 16. Reveal on scroll ----------------------------------------------
   Added by site.js only if IntersectionObserver exists and the visitor has
   not asked for reduced motion. Nothing is hidden by CSS alone: with the
   script blocked or broken, every section is simply visible, which is the
   right failure for a page whose job is to be read.                       */

.js-reveal {
  opacity: 0;
  transform: translateY(1rem);
  transition: opacity 0.6s ease-out, transform 0.6s ease-out;
}
.js-reveal.is-in { opacity: 1; transform: none; }

/* ---- 17. A photograph that is not there yet ----------------------------
   site.js adds this when an <img> fails to load and strips its src, so the
   element keeps its box and the card holds the shape it will have once the
   photograph arrives. A broken-image glyph reads as a bug; a dark panel with
   the house gold on it reads as a photograph that has not been taken.      */

.is-missing {
  background-color: var(--surface-container);
  background-image:
    radial-gradient(14rem 10rem at 50% 45%, var(--gold-glow), transparent 70%),
    repeating-linear-gradient(135deg, transparent 0 11px, rgb(var(--gold-rgb) / 0.06) 11px 22px);
  border: 1px solid var(--gold-border);
  border-radius: inherit;
}
/* Every slot a photograph can land in is round, so the empty one is too, and
   it keeps the rim — an empty plate rather than a hole. */
.shot__img.is-missing,
.plate__shot.is-missing,
.dish__plate.is-missing {
  border-radius: var(--r-full);
  border-color: var(--gold-border);
}

/* ---- 18. Get the app ----------------------------------------------------
   The page behind the printed QR code. It is read in a doorway, one-handed,
   by somebody who has just pointed a camera at a card — so it is one card,
   centred, with one thing to press and nothing to scroll past.             */

.getapp {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
  padding: 2rem 1.25rem;
  background:
    radial-gradient(36rem 28rem at 50% 0%, rgb(var(--gold-rgb) / 0.16), transparent 68%),
    var(--surface);
}
@supports (min-height: 100svh) { .getapp { min-height: 100svh; } }

.getapp__card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1rem;
  width: min(26rem, 100%);
  padding: 2.5rem 1.75rem 2rem;
  text-align: center;
  background: var(--surface-card);
  border: 1px solid var(--gold-border);
  border-radius: var(--r-2xl);
  box-shadow: 0 20px 50px -16px rgb(0 0 0 / 0.6);
}

.getapp__crest {
  width: 5.25rem;
  height: 5.25rem;
  object-fit: cover;
  background: #fff;
  border: 1px solid var(--gold-border);
  border-radius: var(--r-full);
}
/* The wordmark stacks here, as it does in the ordering app's hero. */
.getapp__name { flex-direction: column; align-items: center; gap: 0; line-height: 1.05; }
.getapp__name .crest__main { font-size: 1.5rem; }
.getapp__name .crest__cafe { margin-top: 0.15em; }

.getapp__h {
  margin-top: 0.5rem;
  font-size: 1.5rem;
  font-weight: 600;
  color: var(--text-primary);
}
.getapp__p { font-size: 0.9375rem; line-height: 1.65; color: var(--text-muted); }
.getapp__cta { width: 100%; margin-top: 0.25rem; }
.getapp__note {
  margin-top: 0.25rem;
  font-size: 0.8125rem;
  line-height: 1.55;
  color: var(--text-muted);
}
.getapp__foot {
  margin-top: 0.5rem;
  font-size: 0.6875rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-muted);
}
