/* ============================================================
   Delhi Haveli — local overrides
   Loaded AFTER the generated Webflow stylesheet so these win.
   Put ALL hand-written CSS here; never edit the .min.css.
   ============================================================ */

/* ---- Display face -------------------------------------------
   Playfair Display (SIL Open Font License 1.1) replaces the
   "TT Ramillas Trial" face that shipped with the template.
   Trial fonts are not licensed for production use.

   NOTE: this is deliberately declared under the ORIGINAL family
   name. ~30 Webflow classes reference "TT Ramillas Variable", so
   re-pointing the name swaps the typeface everywhere without
   touching the generated stylesheet. The files really are
   Playfair Display.

   Self-hosted rather than pulled from fonts.googleapis.com:
   hotlinking Google Fonts transmits visitor IPs to Google and has
   been ruled a GDPR breach in the EU. Relevant — the restaurant
   is in Prague. latin-ext is included for Czech diacritics
   (ř š č ž ě ů á í é).
   ------------------------------------------------------------- */

@font-face {
  font-family: 'TT Ramillas Variable';
  font-style: normal;
  font-weight: 200 900;
  font-display: swap;
  src: url('fonts/PlayfairDisplay-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'TT Ramillas Variable';
  font-style: normal;
  font-weight: 200 900;
  font-display: swap;
  src: url('fonts/PlayfairDisplay-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'TT Ramillas Variable';
  font-style: italic;
  font-weight: 200 900;
  font-display: swap;
  src: url('fonts/PlayfairDisplay-Italic-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'TT Ramillas Variable';
  font-style: italic;
  font-weight: 200 900;
  font-display: swap;
  src: url('fonts/PlayfairDisplay-Italic-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* The weight range is declared 200-900 to match the descriptor on the
   original face exactly - otherwise it does not shadow it, and the
   site asks for weight 300 throughout. Playfair's real axis starts
   at 400, so 300 simply clamps to 400.
   Anything asking for <400 would otherwise snap to 400 anyway, so
   this just makes the intent explicit. */

/* ---- "Novinka" badge on new menu items ----------------------
   Marks the dishes flagged NEW on the printed menu (107, 109-113).
   Inline-block so it never breaks the name/price baseline.
   ------------------------------------------------------------- */

.tag_new {
  display: inline-block;
  margin-left: 0.6em;
  padding: 0.15em 0.55em;
  border: 1px solid currentColor;
  border-radius: 2em;
  font-family: Satoshi, Arial, sans-serif;
  font-size: 0.62em;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  vertical-align: middle;
  opacity: 0.75;
  white-space: nowrap;
}

/* Prices must never wrap between the number and "Kč" (a non-breaking
   space in the markup handles the split; this stops the whole cell
   from being squeezed on narrow screens). */

.name_price > div:last-child {
  white-space: nowrap;
}

/* ---- Hero headline: flanked layout --------------------------
   The hero is three cells on one row — caption, headline, caption.
   The reference sits the two captions right up against the headline
   as a centred cluster, low, near its baseline, tracked out.

   NOTE for anyone reading the history: an earlier pass pushed the
   captions out to the container's outer edges. That was read off a
   cropped screenshot whose edges were mistaken for the container's.
   A full-width shot showed the labels start ~340px in from a ~30px
   container edge — they hug the headline. The template's original
   `justify-self:end` on the left cell was right; it is left alone.

   Desktop-only — below 768px the template already stacks
   `.flex_heading` into a column and that stays as it was.
   ------------------------------------------------------------- */

@media screen and (min-width: 768px) {

  /* Centre column shrinks to the headline and the two 1fr cells split
     what is left, which keeps the headline centred on the viewport
     whatever the captions weigh. The captions then sit at the inner
     edge of their cells, so the visible gap IS the column-gap.
     Replaces the per-page column ratios, which existed only to guess
     a width for the middle text. */
  .hero_headline .flex_heading {
    grid-template-columns: 1fr auto 1fr;
    align-items: end;
    column-gap: 1.9em;    /* reference measures ~1.9vw at 1920 */
  }

  /* store.html nests its hero inside `.bottom_part.center`, a column
     flex with `align-items:center`, so the headline block shrink-wraps
     to its content and will not centre on the container. No-op on the
     six pages that already stretch. */
  .hero_headline {
    width: 100%;
  }

  /* The headline must not wrap. "které zůstanou" needed 814px at
     1280px wide and the old middle column gave it 508, so the
     homepage hero was silently rendering as three lines, not two.
     Everything here is sized in `em` off `body{font-size:1vw}`, so a
     line that fits at one desktop width fits at all of them. */
  .hero_headline .h1_hero {
    white-space: nowrap;
  }

  /* `> div` picks out exactly the two caption cells, since the middle
     child of the row is an <h1>. The template pins the left one with a
     per-page Webflow node-id rule (`#w-node-…{justify-self:end}`) and
     leaves the right one alone; both are stated here instead, so the
     pairing is a property of the layout rather than of one page's
     generated ids. The story heroes are hand-written and carry no node
     id at all — without this the left caption drifts out to the
     container edge while the right one still hugs the headline. */
  .hero_headline .flex_heading > div:first-child {
    justify-self: end;
  }

  .hero_headline .flex_heading > div:last-child {
    justify-self: start;
  }

  /* `align-items:end` puts the caption's bottom edge on the headline's
     baseline (line-height .8 makes the line box bottom and the
     baseline coincide within a pixel); the padding then lifts it.
     Reference sits the label baseline 0.43 cap heights above the
     headline's. */
  .hero_headline .caption_heading {
    padding-bottom: 2.6em;
    letter-spacing: 0.14em;
  }
}

/* Tablet: the template jumps `.caption_heading` to 1.5em, which at
   768px is wide enough that two tracked captions plus the headline
   overflow the row. Scaled back for the hero only. */
@media screen and (min-width: 768px) and (max-width: 991px) {
  .hero_headline .caption_heading {
    font-size: 0.9em;
    letter-spacing: 0.12em;
  }
}

/* ---- Hero scrim: keep the type off the food ------------------
   The template ships one gradient on `.overlay` — solid #101010 at
   the top fading to 20% at the bottom. That is backwards for this
   layout. The headline sits at 27–49% of the hero and the standfirst
   paragraph at 92–98%, so the copy that needed the most cover was
   getting the least: sampling hero-1600.avif, ~6% of the pixels
   under the bottom paragraph are brighter than 150/255 (naan, ghee
   highlights, a lit rim of a thali), and against those the beige
   #d8cbb8 text measured 1.4:1. Anything under 3:1 reads as the
   "invisible" the eye actually complains about.

   Three stacked layers instead, so the darkness follows the text
   rather than the vertical axis:
     1. a bottom scrim under the paragraph,
     2. the template's top scrim, held higher through the headline
        and the two flanking captions, then released,
     3. a flat 22% base so a hotspot anywhere never blows out.

   Through 55–65%, where the photo carries the composition and no
   copy sits, the stack lands within a hair of the gradient it
   replaces (0.60/0.49 vs 0.56/0.48). Below that it ramps into the
   bottom scrim and does go darker, which is the point — and it
   hands off into `.video_section`, whose own `.overlay_base` is
   black at 55%, so the seam stays quiet.

   Measured against the shipped images at 1440x900 and 390x844,
   compositing each gradient over the actual pixels: worst-case
   contrast for the standfirst went 1.43:1 -> 8.53:1 (desktop) and
   1.49:1 -> 6.38:1 (mobile); the desktop captions cleared 4.5:1
   for the first time (4.01 -> 5.03). Every string in the hero now
   passes WCAG AA at its own size threshold.

   Direct-child selectors keep this off `.overlay.super_dark`
   (catering cards) and `.overlay.special_store` (store.html), both
   of which carry their own treatment.
   ------------------------------------------------------------- */

.hero_section > .background_hero > .overlay {
  background-image:
    linear-gradient(to top,
      rgba(16, 16, 16, 0.90) 0%,
      rgba(16, 16, 16, 0.62) 20%,
      rgba(16, 16, 16, 0)    38%),
    linear-gradient(to bottom,
      rgba(16, 16, 16, 0.95) 0%,
      rgba(16, 16, 16, 0.78) 30%,
      rgba(16, 16, 16, 0.55) 52%,
      rgba(16, 16, 16, 0.12) 72%),
    linear-gradient(rgba(16, 16, 16, 0.22), rgba(16, 16, 16, 0.22));
}

/* ---- Modal shell --------------------------------------------
   Chrome shared by every modal on the site — `assets/modal.js` builds
   it, `reservation.js` and `order.js` fill it. Both replaced nav
   dropdowns that pointed at URLs which were never going to exist.

   Sized in px/rem rather than em on purpose. `body` is `font-size:1vw`,
   so anything em-based here would grow with the viewport; a form has to
   stay readable at 320px and must not turn into billboard type at
   2560px.
   ------------------------------------------------------------- */

.dh-modal[hidden] { display: none; }

.dh-modal {
  position: fixed;
  inset: 0;
  z-index: 2147483647;    /* over .header (99) and the mobile overlay */
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  font-family: Satoshi, Arial, sans-serif;
  letter-spacing: -0.01em;
  line-height: 1.45;
}

.dh-modal__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(16, 16, 16, 0.74);
  -webkit-backdrop-filter: blur(4px);
  backdrop-filter: blur(4px);
  animation: dh-modal-fade 0.28s ease both;
}

.dh-modal__dialog {
  position: relative;
  width: 100%;
  max-width: 520px;
  max-height: calc(100vh - 32px);
  max-height: calc(100dvh - 32px);   /* mobile URL bar */
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
  padding: 34px 32px 30px;
  background: var(--surface, #491f11);
  color: var(--biege, #d8cbb8);
  border: 1px solid rgba(216, 203, 184, 0.2);
  border-radius: 4px;
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.45);
  font-size: 16px;
  animation: dh-modal-rise 0.28s ease both;
}

/* The entrance is a keyframe, not a class the script toggles on the
   next frame. `both` leaves the element at the animation's end state,
   so the form is on screen even where the animation never runs — a
   throttled tab, reduced motion, a skipped frame. Visibility is the
   absence of [hidden] and nothing else. */
@keyframes dh-modal-fade {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@keyframes dh-modal-rise {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .dh-modal__backdrop,
  .dh-modal__dialog { animation: none; }
}

/* ---- close button ---- */

.dh-modal__close {
  position: absolute;
  top: 10px;
  right: 10px;
  width: 44px;      /* 44px is the smallest comfortable tap target; the */
  height: 44px;     /* glyph stays 20px, the padding does the rest */
  padding: 12px;
  background: none;
  border: 0;
  border-radius: 50%;
  color: var(--biege, #d8cbb8);
  cursor: pointer;
  opacity: 0.65;
  transition: opacity 0.3s, background-color 0.3s;
}

.dh-modal__close:hover,
.dh-modal__close:focus-visible { opacity: 1; background: rgba(216, 203, 184, 0.1); }

.dh-modal__close svg {
  width: 100%;
  height: 100%;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
}

/* ---- heading ---- */

.dh-modal__head { margin-bottom: 22px; padding-right: 44px; }   /* clears the close button */

.dh-modal__eyebrow {
  margin: 0 0 6px;
  color: var(--primary, #d49653);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

.dh-modal__title {
  margin: 0 0 8px;
  font-family: "TT Ramillas Variable", Georgia, serif;   /* = Playfair, see above */
  font-size: 34px;
  font-weight: 300;
  line-height: 1.05;
  letter-spacing: -0.02em;
  text-transform: lowercase;
}

.dh-modal__lead {
  margin: 0;
  font-size: 14px;
  opacity: 0.72;
}

/* ---- Reservation form ---------------------------------------
   Everything below is specific to `assets/reservation.js`; the shell
   it sits in is shared with the order picker above.
   ------------------------------------------------------------- */

.dh-reserve__field { margin-bottom: 16px; }

.dh-reserve__row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  column-gap: 16px;
}

.dh-reserve__field label {
  display: block;
  margin-bottom: 6px;
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  opacity: 0.8;
}

.dh-reserve__opt { text-transform: none; letter-spacing: 0; opacity: 0.6; }

.dh-reserve__field input,
.dh-reserve__field select,
.dh-reserve__field textarea {
  width: 100%;
  min-height: 46px;
  padding: 11px 14px;
  background: rgba(216, 203, 184, 0.06);
  border: 1px solid rgba(216, 203, 184, 0.22);
  border-radius: 3px;
  color: var(--biege, #d8cbb8);
  font-family: inherit;
  font-size: 15px;
  line-height: 1.4;
  transition: border-color 0.3s, background-color 0.3s;
  -webkit-appearance: none;
  appearance: none;
}

.dh-reserve__field textarea { min-height: 64px; resize: vertical; }

.dh-reserve__field input::placeholder,
.dh-reserve__field textarea::placeholder { color: var(--biege, #d8cbb8); opacity: 0.38; }

.dh-reserve__field input:focus,
.dh-reserve__field select:focus,
.dh-reserve__field textarea:focus {
  outline: none;
  border-color: var(--primary, #d49653);
  background: rgba(216, 203, 184, 0.1);
}

.dh-reserve__field [aria-invalid="true"] { border-color: #e0714f; }

.dh-reserve__field select {
  /* Native arrow is hidden by appearance:none; draw our own. Inline
     SVG data URI, so it costs no request and inherits no colour. */
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%23d8cbb8' stroke-width='1.4' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 14px center;
  background-size: 12px 8px;
  padding-right: 36px;
}

.dh-reserve__field select:disabled { opacity: 0.45; }

/* Dark UA widgets — otherwise the date picker renders a black glyph on
   a dark field and the calendar popup comes up white. */
.dh-reserve__field input[type="date"],
.dh-reserve__field input[type="time"] { color-scheme: dark; }

.dh-reserve__field option { background: var(--surface, #491f11); color: var(--biege, #d8cbb8); }

/* ---- messages ---- */

.dh-reserve__error {
  margin: 6px 0 0;
  min-height: 0;
  color: #e8a48c;
  font-size: 12.5px;
}

.dh-reserve__error:empty { display: none; }

.dh-reserve__error--form {
  margin-bottom: 10px;
  padding: 10px 12px;
  background: rgba(224, 113, 79, 0.12);
  border-radius: 3px;
}

.dh-reserve__hours {
  margin: -4px 0 14px;
  font-size: 12.5px;
  opacity: 0.6;
}

.dh-reserve__hours:empty { display: none; }

/* ---- submit ---- */

.dh-reserve__submit {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  width: 100%;
  min-height: 52px;
  padding: 14px 20px;
  background: var(--biege, #d8cbb8);
  border: 0;
  border-radius: 2px;
  outline: 1px solid var(--biege, #d8cbb8);
  outline-offset: 4px;
  color: var(--dark, #2c2c2c);
  font-family: inherit;
  font-size: 15px;
  font-weight: 500;
  letter-spacing: -0.01em;
  cursor: pointer;
  transition: background-color 0.4s, outline-color 0.4s, color 0.4s;
}

.dh-reserve__submit:hover,
.dh-reserve__submit:focus-visible {
  background: var(--primary, #d49653);
  outline-color: var(--primary, #d49653);
}

.dh-reserve__wa { width: 20px; height: 20px; fill: currentColor; flex: none; }

.dh-modal__fine {
  margin: 12px 0 0;
  font-size: 11.5px;
  line-height: 1.5;
  opacity: 0.5;
  text-align: center;
}

/* ---- confirmation state ---- */

.dh-reserve__done[hidden] { display: none; }
.dh-reserve__done { text-align: center; }
.dh-reserve__done .dh-modal__lead { margin-bottom: 22px; }
.dh-reserve__done a { color: var(--primary, #d49653); }

/* ---- narrow screens ---- */

@media screen and (max-width: 479px) {
  .dh-modal { padding: 0; align-items: flex-end; }

  .dh-modal__dialog {
    max-width: none;
    max-height: 92vh;
    max-height: 92dvh;
    padding: 28px 20px 24px;
    border-width: 1px 0 0;
    border-radius: 10px 10px 0 0;
  }

  .dh-modal__title { font-size: 28px; }

  /* Date and time stay side by side — stacking them pushes the submit
     button below the fold on a 667px-tall phone. */
  .dh-reserve__row { column-gap: 10px; }
}

/* ---- Order picker -------------------------------------------
   The delivery-platform list in `assets/order.js`. Rows are big,
   because on a phone this is the last thing between a hungry guest
   and their dinner.
   ------------------------------------------------------------- */

.dh-order .dh-modal__dialog { max-width: 460px; }

.dh-order__list {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin: 22px 0 0;
}

.dh-order__option {
  display: flex;
  align-items: center;
  gap: 14px;
  min-height: 68px;
  padding: 14px 16px;
  background: rgba(216, 203, 184, 0.06);
  border: 1px solid rgba(216, 203, 184, 0.22);
  border-radius: 3px;
  color: var(--biege, #d8cbb8);
  text-decoration: none;
  transition: background-color 0.3s, border-color 0.3s, transform 0.3s;
}

a.dh-order__option:hover,
a.dh-order__option:focus-visible {
  background: rgba(216, 203, 184, 0.12);
  border-color: var(--primary, #d49653);
}

a.dh-order__option:hover .dh-order__arrow { transform: translateX(3px); }

.dh-order__text { flex: 1; min-width: 0; }

.dh-order__name {
  display: block;
  margin-bottom: 3px;
  font-size: 16px;
  font-weight: 500;
  letter-spacing: -0.01em;
}

.dh-order__note {
  display: block;
  font-size: 12.5px;
  line-height: 1.4;
  opacity: 0.62;
}

.dh-order__badge {
  display: inline-block;
  margin-left: 8px;
  padding: 0.15em 0.6em;
  border: 1px solid currentColor;
  border-radius: 2em;
  color: var(--primary, #d49653);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  vertical-align: middle;
  white-space: nowrap;
}

.dh-order__arrow {
  flex: none;
  width: 20px;
  height: 20px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: 0.5;
  transition: transform 0.3s;
}

/* No URL yet. Rendered as a <div>, not an <a>, so there is nothing to
   click — this only has to look inert as well as be inert. */
.dh-order__option.is-pending {
  opacity: 0.4;
  border-style: dashed;
  cursor: default;
}

.dh-order__option.is-pending .dh-order__arrow { display: none; }

@media (prefers-reduced-motion: reduce) {
  .dh-order__option,
  .dh-order__arrow { transition: none; }
}

@media screen and (max-width: 479px) {
  .dh-order__option { min-height: 64px; }
}

/* ---- nav triggers -------------------------------------------
   The header links and the framed mobile-menu row that replaced the
   two-level location dropdowns. All reuse the template's own classes,
   so only what the dropdown chrome used to provide is set here.
   ------------------------------------------------------------- */

.reserve_table .reserve_link {
  justify-content: center;
  color: inherit;
  text-decoration: none;
  cursor: pointer;
}

/* "Objednat" in the header and in the mobile fixed bar. The wrapper
   keeps its .link_header styling; this is the anchor that replaced the
   dropdown inside it, and it swallows the order icon too so the whole
   thing is one target rather than just the word. */
.order_link {
  display: flex;
  align-items: center;
  grid-column-gap: 12px;
  gap: 12px;
  color: inherit;
  text-decoration: none;
  cursor: pointer;
}

/* ---- Wordmark logo ------------------------------------------
   The template's three logo slots (.logo in the header,
   .middle_logo_footer in the footer, .image_logo on checkout)
   were all SQUARE, sized for the old badge mark. The wordmark is
   a wide lockup — 600x271 compact, 600x340 with the tagline — so
   each slot is re-proportioned here and the image fills it.

   Sized in px rather than em on purpose: body is font-size:1vw,
   so em units would tie the logo to viewport width and it would
   shrink away on a narrow window. Same reasoning as the
   reservation modal above.

   The live mark is the owner's supplied wordmark, traced to
   vector by `tools/make-wordmark.py`:
     delhi-haveli-wordmark.svg   1935x333, aspect 5.81 (header
       AND the big footer wordmark — one file, one request)
   The generated DIWALI HAVELI lockups it replaced are still on
   disk and still built by `tools/make-logo.py`, but no page
   loads them any more:
     diwali-haveli-logo-compact.svg  was the header mark
     diwali-haveli-logo.svg          was the footer's centred mark
   assets/diwali-haveli-logo.png is the raster twin, still
   referenced from the JSON-LD "logo" field.

   HEIGHT DROPPED FROM 58px TO 26px WITH THAT SWAP, and 26 is not
   a typo. The old compact lockup was two stacked words plus an
   ornament, aspect 2.22, so 58px tall came out 128px wide. This
   one is a single line at aspect 5.81, so the same 128px of
   header width is 22px of height — the ladder below is tuned to
   hold the mark's WIDTH near what the old one occupied, because
   width is what has to coexist with the five nav items beside it.
   Read the numbers as widths: 151 / 134 / 116 / 105 px.

   Cap height is 83% of the box; the rest is the D's swash, which
   drops below the baseline. Vertical centring is the template's
   own `align-items:center` on `.flex_header` and it is correct —
   as long as the SVG viewBox is cropped tight to the ink. It was
   not, once: the first artwork carried a soft alpha halo and the
   generator cropped on alpha > 0 while tracing at alpha > 128, so
   the letters sat in the top two-thirds of their own viewBox and
   the logo visibly rode high in the header. Fixed in the
   generator, not here — see `tools/make-wordmark.py`.
   ------------------------------------------------------------- */

.logo,
.logo.w--current {
  width: auto;
  height: 26px;
}

/* THE LOGO MUST NOT BE A SHRINKABLE FLEX ITEM. The template gives `.left-side`
   a percentage width at every breakpoint — 40% on desktop, 25% from 767px down
   — and the wordmark plus the five nav items no longer fit inside either. When
   they do not, flex shrinks them, and an <img> at `height:100%` still obeys the
   inherited `max-width:100%`, so it SQUASHES SIDEWAYS rather than overflowing:
   the mark silently loses its aspect ratio and nothing errors. It measured
   149.3x26 against a true 151.1x26 at 1440, and 86x28 against 104x28 at 375.
   `.right-side` is pinned right by its own `margin-left:auto`, so letting the
   left half size to its content costs nothing and fixes both ends.
   Check it with `img.width / img.height` — it must equal 5.811. */
.left-side { width: auto; }
.logo img {
  width: auto;
  height: 100%;
  display: block;
  /* OPTICAL CENTRING, and the reason `align-items:center` is not enough.
     The artwork's box runs cap-top to swash-bottom: the caps start 5 units
     under the top edge, but the D's swash drops 51 units below the baseline
     (of 333). Centre that box and the eye — which reads the cap/baseline
     band, not the swash — sees the wordmark riding high by half the
     difference: (51 - 5) / 2 / 333 = 6.9% of its own height.
     Expressed as a percentage so it tracks every step of the height ladder
     below instead of needing a second magic number, and as a transform so
     it moves the ink without moving the box (the header keeps its height).
     Re-derive it from the cap/baseline line `tools/make-wordmark.py` prints
     if the artwork is ever replaced. */
  transform: translateY(6.9%);
}

.middle_logo_footer {
  width: 190px;
  height: auto;
}
.image_logo {
  width: 168px;
  height: auto;
}
.middle_logo_footer img,
.image_logo img {
  width: 100%;
  height: auto;
  display: block;
  /* both carry Webflow's .image, which is object-fit:cover + height:100%
     — that would crop the lockup. */
  object-fit: contain;
}

@media screen and (max-width: 991px) {
  .logo,
  .logo.w--current { height: 23px; }
  .middle_logo_footer { width: 175px; }
  .image_logo { width: 156px; }
}
@media screen and (max-width: 767px) {
  .logo,
  .logo.w--current { height: 20px; }
  .middle_logo_footer { width: 162px; }
  .image_logo { width: 148px; }

}
@media screen and (max-width: 479px) {
  .logo,
  .logo.w--current { height: 18px; }
  .middle_logo_footer { width: 150px; }
  .image_logo { width: 140px; }
}


/* ==============================================================
   Dish stories — "Příběhy za našimi jídly"
   ==============================================================
   Three pages (story-butter-chicken / -dal-makhani / -tandoori)
   plus the card grid that replaced the catering slider on the
   homepage. Everything below is sized in `em` off `body{font-size:1vw}`,
   the way the template's own sections are, so a story page scales
   with the viewport exactly like `.catering` did.

   The pages are built from template classes wherever one exists
   (`.hero_section`, `.i`, `.ii`, `.fullsize_section`, `.sides.story`,
   `.card_philosophy`). Only the four things the template had no
   equivalent for are defined here: the card grid, the photo mosaic,
   the source note and the dish call-to-action.
   ------------------------------------------------------------- */

/* ---- Story card grid ----------------------------------------
   Used twice: on the homepage in place of the catering slider, and
   at the foot of each story page as "the other two". The old slider
   needed Splide plus three hand-synced slides; three <a> cards in a
   grid need neither, and unlike the slider every card is visible at
   once, which is the point when each one is a link.
   ------------------------------------------------------------- */

.story_grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1.6em;
  margin-top: 4.2em;
}

.story_card {
  display: flex;
  flex-direction: column;
  text-decoration: none;
  color: inherit;
}

.story_card_media {
  position: relative;
  width: 100%;
  aspect-ratio: 4 / 5;
  overflow: hidden;
  border-radius: 2px;
  background-color: var(--surface, #491f11);
}

/* `.image` is object-fit:cover + 100%/100%, so the frame's
   aspect-ratio is what actually decides the crop. */
.story_card_media .image {
  transition: transform 0.9s cubic-bezier(0.25, 0.46, 0.45, 0.94);
}

.story_card:hover .story_card_media .image {
  transform: scale(1.045);
}

/* Scrim, so the index numeral stays legible over a light plate. */
.story_card_media:after {
  content: "";
  position: absolute;
  inset: 0;
  background-image: linear-gradient(to bottom,
    rgba(16, 16, 16, 0.55) 0%,
    rgba(16, 16, 16, 0.12) 30%,
    rgba(16, 16, 16, 0) 55%);
  pointer-events: none;
}

.story_card_index {
  position: absolute;
  z-index: 2;
  top: 1.1em;
  left: 1.2em;
  color: var(--biege);
  font-family: "TT Ramillas Variable", Georgia, serif;
  font-size: 1.6em;
  font-weight: 300;
  line-height: 1;
  letter-spacing: -0.03em;
}

.story_card_body {
  display: flex;
  flex-direction: column;
  gap: 0.55em;
  padding-top: 1.5em;
}

.story_card_kicker {
  color: var(--dark);
  text-transform: uppercase;
  font-size: 0.72em;
  letter-spacing: 0.14em;
  opacity: 0.65;
}

/* `.desc_catering` would have been the template's match here, but it
   is `width:46ch` + centred — sized for a slide, not a grid cell. */
.story_card_desc {
  color: var(--dark);
  font-size: 0.9em;
  line-height: 1.4;
  max-width: 34ch;
}

.story_card_more {
  margin-top: 0.5em;
  color: var(--dark);
  text-transform: uppercase;
  font-size: 0.72em;
  letter-spacing: 0.14em;
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
}

.story_card_more:after {
  content: "";
  width: 2.4em;
  height: 1px;
  background-color: currentColor;
  opacity: 0.5;
  transition: width 0.45s cubic-bezier(0.25, 0.46, 0.45, 0.94);
}

.story_card:hover .story_card_more:after {
  width: 3.6em;
  opacity: 1;
}

/* The dark variant sits on `.stories_more` at the foot of a story
   page, which is `--dark` ground rather than beige. */
.stories_more {
  background-color: var(--surface, #491f11);
}

.stories_more .story_card_kicker,
.stories_more .story_card_desc,
.stories_more .story_card_more,
.stories_more .title_catering {
  color: var(--biege);
}

.stories_more .story_grid {
  grid-template-columns: repeat(2, 1fr);
  max-width: 62em;
  margin-left: auto;
  margin-right: auto;
}

/* ---- Photo mosaic -------------------------------------------
   Four photographs per story on a six-column grid: one wide pair on
   top, two portraits below, so the block reads as a spread rather
   than a row of thumbnails. Aspect ratios are set on the frame, not
   the image, because `.image` is object-fit:cover.
   ------------------------------------------------------------- */

.story_gallery {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 1.1em;
  margin-top: 3.6em;
}

.story_gallery figure {
  grid-column: span 3;
  margin: 0;
}

.story_gallery_frame {
  position: relative;
  width: 100%;
  aspect-ratio: 3 / 2;
  overflow: hidden;
  border-radius: 2px;
  background-color: var(--surface, #491f11);
}

.story_gallery figure.is_tall .story_gallery_frame {
  aspect-ratio: 4 / 5;
}

.story_gallery_frame .image {
  transition: transform 1.1s cubic-bezier(0.25, 0.46, 0.45, 0.94);
}

.story_gallery figure:hover .story_gallery_frame .image {
  transform: scale(1.04);
}

.story_gallery figcaption {
  padding-top: 0.9em;
  color: var(--dark);
  font-size: 0.78em;
  line-height: 1.35;
  opacity: 0.7;
  max-width: 40ch;
}

/* ---- Source note --------------------------------------------
   Where a dish's authorship is genuinely disputed the page says so
   instead of picking a side. Set quieter than body copy — it is a
   footnote, not a paragraph of the story.
   ------------------------------------------------------------- */

.story_note {
  max-width: 62em;
  margin: 0 auto;
  padding: 2.2em 2.4em;
  border: 1px solid rgba(44, 44, 44, 0.22);
  border-radius: 2px;
}

.story_note_label {
  color: var(--dark);
  text-transform: uppercase;
  font-size: 0.72em;
  letter-spacing: 0.14em;
  opacity: 0.6;
  margin-bottom: 0.9em;
}

.story_note_txt {
  color: var(--dark);
  font-size: 0.85em;
  line-height: 1.5;
}

.story_note_txt + .story_note_txt {
  margin-top: 0.8em;
}

/* ---- Dish call-to-action ------------------------------------
   Closes each story on the thing it is actually selling: the row as
   it appears on the menu, with its number and price, then the two
   buttons every other page ends on.
   ------------------------------------------------------------- */

.story_dish {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.6em;
  text-align: center;
}

.story_dish_row {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 0.8em;
  flex-wrap: wrap;
}

.story_dish_name {
  color: var(--dark);
  font-family: "TT Ramillas Variable", Georgia, serif;
  font-size: 2.4em;
  font-weight: 300;
  letter-spacing: -0.035em;
  line-height: 1.05;
}

.story_dish_price {
  color: var(--dark);
  font-size: 1.1em;
  white-space: nowrap;
  opacity: 0.75;
}

.story_dish_desc {
  color: var(--dark);
  font-size: 0.9em;
  line-height: 1.4;
  max-width: 46ch;
}

.story_dish_buttons {
  display: flex;
  gap: 0.8em;
  flex-wrap: wrap;
  justify-content: center;
  margin-top: 0.6em;
}

/* ---- Story page chrome --------------------------------------
   `.fullsize_section` is 135vh of hard-cropped background; that is
   right for the homepage's one video but too tall on a story page,
   where it appears alongside a mosaic and a card grid. `.is_story`
   trims it to a screen and a bit.
   ------------------------------------------------------------- */

.fullsize_section.is_story {
  height: 92vh;
}

/* `<video>` in place of `.background_fullsize`'s `<img>`: same
   `.video` class the homepage hero uses (object-fit:cover, inset:0),
   so no extra geometry is needed. The background colour is stated
   because a poster frame that has not decoded yet would otherwise
   show the UA's black box against beige. */
.background_fullsize .video {
  background-color: var(--surface, #491f11);
}

.story_section_pad {
  padding-top: 6.4em;
  padding-bottom: 6.4em;
}

/* ---- Narrow screens -----------------------------------------
   Below 992px the template's `body{font-size:1vw}` no longer holds
   the layout together on its own — three 1fr columns of a card grid
   land at ~30% of a phone. Both grids collapse in two steps.
   ------------------------------------------------------------- */

@media screen and (max-width: 991px) {
  .story_grid { gap: 1.4em; }
  .story_gallery { gap: 0.9em; }
  .story_note { padding: 2em; }
  .story_dish_name { font-size: 2em; }
  .fullsize_section.is_story { height: 78vh; }
}

@media screen and (max-width: 767px) {
  .story_grid,
  .stories_more .story_grid {
    grid-template-columns: 1fr;
    gap: 2.4em;
    margin-top: 3em;
  }
  .story_card_media { aspect-ratio: 3 / 2; }
  .story_card_index { font-size: 1.9em; }
  .story_card_kicker,
  .story_card_more,
  .story_note_label { font-size: 1.05em; }
  .story_card_desc,
  .story_dish_desc { font-size: 1.25em; max-width: none; }
  .story_gallery {
    grid-template-columns: repeat(2, 1fr);
    margin-top: 2.6em;
  }
  .story_gallery figure,
  .story_gallery figure.is_tall { grid-column: span 1; }
  .story_gallery figcaption { font-size: 1.05em; max-width: none; }
  .story_note_txt { font-size: 1.15em; }
  .story_dish_name { font-size: 3em; }
  .story_dish_price { font-size: 1.4em; }
  .story_section_pad { padding-top: 4.4em; padding-bottom: 4.4em; }
}

@media screen and (max-width: 479px) {
  .story_gallery { grid-template-columns: 1fr; }
  .story_gallery figure .story_gallery_frame,
  .story_gallery figure.is_tall .story_gallery_frame { aspect-ratio: 3 / 2; }
  .story_dish_buttons { flex-direction: column; align-items: stretch; width: 100%; }
  .fullsize_section.is_story { height: 68vh; }
}

/* ---- Reduced motion: keep the headlines visible --------------
   Every page ships `[text-split] {opacity: 0}` in an inline <style>
   and relies on the vendored GSAP script to set it back to 1 once
   SplitType has run. That script does its work inside

       mm.add("(prefers-reduced-motion: no-preference)", ...)

   and the `gsap.set(splitSelector, {opacity: 1})` that reveals the
   type is the last line *inside* that callback. So a visitor with
   "reduce motion" switched on never gets the reveal: on a machine
   with the OS setting enabled, every split headline on the site
   stays at opacity 0 — the hero, the section titles, all of it.

   Pre-existing and site-wide, not specific to the story pages, but
   they lean on split headings more than any other page, so the
   floor is set here. A media query costs nothing when the
   preference is absent and cannot race the script: when the
   preference IS set the script never touches opacity at all, so
   there is nothing for this to fight with.
   ------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  [text-split],
  [letters-fade-in],
  [letters-fade-in-hover] {
    opacity: 1 !important;
  }
}

/* ==============================================================
   Testimonials — on the Delhi Haveli theme
   ==============================================================
   This section began as a verbatim port of a supplied React
   reference (`testimonial-v2.tsx` — shadcn / Tailwind /
   framer-motion) and was kept deliberately off-theme on the
   owner's instruction: white cards on a white band, 24px corners,
   Tailwind's neutral ramp, Tailwind's default sans, and a floating
   dark-mode toggle fixed to the viewport.

   THAT INSTRUCTION WAS REVERSED. The section now uses the site's
   own palette, type and geometry, and the toggle is gone from the
   markup, from this file and from `testimonials.js`. There is no
   `.dark` variant of anything here any more — do not reintroduce
   one; the rest of the site has no dark mode to be consistent with.

   The template's own `.testimonials` class already supplies the
   beige ground, `width:100vw` and `overflow:hidden`. What is left
   here is the head, the three-column loop and the card — the parts
   the template had no equivalent for.

   The theme it now follows, the same one `.story_card` and
   `.dh-lunch` follow:

     ground   var(--biege)   #d8cbb8
     ink      var(--dark)    #2c2c2c
     accent   var(--primary) #d49653
     corners  the deliberate exception — 24px on the card, a full
              circle on the avatar, a pill on the badge. The rest of
              the site is 2px; this section keeps the reference's soft
              geometry on request. See `.dh-tv2__card`.
     rules    1px hairlines at 16–28% ink; NO drop shadows anywhere
     display  Playfair ("TT Ramillas Variable"), uppercase, w300
     body     Satoshi, w500
     kickers  uppercase, 0.14–0.16em tracking, ~0.65 opacity

   px/rem only, never `em`: `body` is `font-size:1vw`, so an `em`
   here would scale with the viewport. Same reasoning as the modal
   and lunch CSS. The one deliberate exception is the heading, which
   borrows the template's own `.h2` class precisely so that it DOES
   scale, in step with the section titles above and below it.
   ------------------------------------------------------------- */

.testimonials.dh-tv2 {
  font-family: Satoshi, Arial, sans-serif;
  color: var(--dark, #2c2c2c);
  background-color: var(--biege, #d8cbb8);
  padding: 6rem 0;
  position: relative;
  overflow: hidden;
}

.dh-tv2__container {
  width: 100%;
  max-width: 1180px;         /* three 320px cards + two 24px gaps + air */
  margin: 0 auto;
  padding: 0 28px;           /* the gutter `.dh-lunch` uses */
  position: relative;
  z-index: 10;
}

/* The framer-motion entrance: opacity 0 / y 50 / rotate -2 settling to
   rest over 1.2s on [0.16,1,0.3,1], fired once when 15% is in view.
   Kept from the port — it is the one thing about the reference that
   already reads at this site's pace.

   The hidden start state is on `is_armed`, which testimonials.js adds
   at run time — it is deliberately NOT the resting state of the
   markup. Putting `opacity:0` directly on `.dh-tv2__reveal` is how
   this site already lost every split headline to a reduced-motion
   visitor (see the note at the top of this file): the reveal lived in
   a script, the script did not always run, and the type stayed
   invisible. Nothing here may hide content unless JS is demonstrably
   alive and has committed to showing it again. */
.dh-tv2__reveal.is_armed {
  opacity: 0;
  transform: translateY(50px) rotate(-2deg);
}

.dh-tv2__reveal.is_armed.is_inview {
  opacity: 1;
  transform: none;
  transition: opacity 0.8s cubic-bezier(0.16, 1, 0.3, 1),
              transform 1.2s cubic-bezier(0.16, 1, 0.3, 1);
}

/* ---- Head ---------------------------------------------------- */

.dh-tv2__head {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  /* Wide enough for the uppercase Playfair heading at its desktop size;
     the lead has its own, much narrower cap below. */
  max-width: 720px;
  margin: 0 auto 3.5rem;
  text-align: center;
}

/* The site's tag idiom, shared with `.dh-lunch__hours` and `.tag_new`:
   hairline pill, uppercase, tracked out, no fill. */
.dh-tv2__badge {
  display: inline-block;
  padding: 0.4rem 0.9rem;
  border: 1px solid rgba(44, 44, 44, 0.28);
  border-radius: 999px;
  font-family: Satoshi, Arial, sans-serif;
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

/* The heading is `<h2 class="h2 middle dh-tv2__title">` — Playfair,
   uppercase, viewport-scaled, exactly like every other section title.
   The port had to fight both of those off to reproduce the reference's
   sans sentence-case heading, which is why the old rule set
   `font-family: inherit` and `text-transform: none`. Both are gone on
   purpose; putting them back brings the off-theme heading back.

   IT IS A SPLIT HEADLINE, and it was not always. Every section title
   on this site carries `text-split letters-fade-in`; the inline
   `[text-split]{opacity:0}` in each page head hides it and the
   vendored GSAP script splits it into `.char` spans and staggers them
   back in. These four hand-built titles — `.dh-tv2__title`,
   `.dh-lunch__title`, `.dh-cf__title`, `.dh-ct__title` — were kept
   plain because that reveal had failed site-wide once and there was no
   floor under it: markup that looks perfectly correct, painting
   nothing.

   TWO FLOORS EXIST NOW, which is what changed the decision.
   `assets/reveal-fallback.js` forces any heading that was split and is
   still completely blank back to visible, and the
   `prefers-reduced-motion` block above keeps every `[text-split]`
   at opacity 1 when GSAP skips the animation altogether. So the
   failure this avoided cannot go unhandled any more.

   Do NOT reintroduce the plain version to "protect" the heading — the
   protection is those two files, and removing the attributes only
   makes this title the odd one out again. */
.dh-tv2__title {
  /* `.middle` sets `width: 52ch`, and `ch` resolves against this h2's
     OWN font size — ~70px here — so it measures thousands of px inside
     a 560px head. That is the exact trap that painted the lunch title
     off the right edge of the screen. Constrain it; `.dh-tv2__head`
     already centres the text. */
  width: auto;
  max-width: 100%;
  margin: 1.4rem 0 0;
  color: var(--dark, #2c2c2c);
}

.dh-tv2__sub {
  margin: 1.1rem 0 0;
  max-width: 420px;
  font-size: 1rem;
  line-height: 1.55;
  opacity: 0.78;
}

/* ---- The three columns --------------------------------------
   As before, the clip / fade / animation are scoped to `is_looping`,
   which testimonials.js only adds once it has cloned each column.
   No JS or reduced motion leaves a still, readable grid.
   ------------------------------------------------------------- */

.dh-tv2__cols {
  display: flex;
  justify-content: center;
  align-items: flex-start;
  gap: 1.5rem;
  margin-top: 2.5rem;
}

.dh-tv2__cols.is_looping {
  max-height: 740px;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(to bottom, transparent, #000 10%, #000 90%, transparent);
  mask-image: linear-gradient(to bottom, transparent, #000 10%, #000 90%, transparent);
}

/* Column 2 is hidden below `md`, column 3 below `lg`. */
.dh-tv2__col--md,
.dh-tv2__col--lg { display: none; }

@media (min-width: 768px)  { .dh-tv2__col--md { display: block; } }
@media (min-width: 1024px) { .dh-tv2__col--lg { display: block; } }

.dh-tv2__track {
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
  margin: 0;
  padding: 0;
  list-style: none;
  background: transparent;
}

.dh-tv2__cols.is_looping .dh-tv2__track {
  padding-bottom: 1.5rem;
  will-change: transform;
  animation: dh_tv2_scroll var(--dh-tv2-duration, 17s) linear infinite;
}

@keyframes dh_tv2_scroll {
  from { transform: translateY(0); }
  to   { transform: translateY(-50%); }
}

/* Three different durations, so the columns never line up. */
.dh-tv2__col:nth-child(1) { --dh-tv2-duration: 15s; }
.dh-tv2__col:nth-child(2) { --dh-tv2-duration: 19s; }
.dh-tv2__col:nth-child(3) { --dh-tv2-duration: 17s; }

/* A card drifting upward cannot be read. Stop on hover or focus. */
.dh-tv2__cols.is_looping:hover .dh-tv2__track,
.dh-tv2__cols.is_looping:focus-within .dh-tv2__track {
  animation-play-state: paused;
}

/* ---- One card ------------------------------------------------ */

.dh-tv2__card {
  position: relative;
  padding: 2.25rem;
  /* THE ONE THING KEPT FROM THE REFERENCE'S GEOMETRY, on request. Every
     other corner on this site is 2px — `.story_card_media`,
     `.card_philosophy`, the menu rows — and an earlier pass squared
     these to match. That was reversed: the soft corner is what makes
     nine small plates read as cards rather than as a table, and it is
     the shape this section is supposed to have. Do not re-square it.
     The pill on `.dh-tv2__badge` and the round avatar below belong to
     the same decision. */
  border-radius: 24px;
  border: 1px solid rgba(44, 44, 44, 0.2);
  max-width: 320px;
  width: 100%;
  /* A warm lift off the beige rather than a white card: 30% white over
     var(--biege) resolves to about #e4dacd, still inside the palette.
     `.card_philosophy` gets away with beige-on-beige and a hairline
     because there is one of it; nine of these in motion need the plate
     to read as a plate. No drop shadow — the site has none anywhere. */
  background-color: rgba(255, 255, 255, 0.3);
  cursor: default;
  -webkit-user-select: none;
  user-select: none;
  transition: transform 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94),
              border-color 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94),
              background-color 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94);
}

/* The reference's spring lift (scale 1.03, y -8) plus a three-layer
   shadow, restated in this site's vocabulary: a small rise and the
   hairline warming to the accent. Same gesture as `.story_card`. */
.dh-tv2__card:hover,
.dh-tv2__card:focus-within {
  transform: translateY(-4px);
  border-color: rgba(212, 150, 83, 0.9);
  background-color: rgba(255, 255, 255, 0.45);
}

.dh-tv2__card:focus-visible {
  outline: 2px solid var(--primary, #d49653);
  outline-offset: 2px;
}

/* Decorative open quote in the display face — the same move as
   `.story_card_index`, which sets its numeral in Playfair over the
   photo. Top-right, so it never collides with the first line. */
.dh-tv2__card:before {
  content: "\201C";
  /* Repeated with an empty alt so screen readers do not announce a bare
     quote glyph before every card. Browsers without `content: x / alt`
     ignore this line and keep the plain one above; the worst case is
     losing a decoration, never losing the alt. */
  content: "\201C" / "";
  position: absolute;
  top: 0.3rem;
  right: 1.1rem;
  font-family: "TT Ramillas Variable", Georgia, serif;
  font-size: 3.4rem;
  font-weight: 300;
  line-height: 1;
  color: var(--dark, #2c2c2c);
  opacity: 0.18;
  pointer-events: none;
}

.dh-tv2__quote {
  margin: 0;
  padding: 0;
  border: 0;                 /* Webflow gives bare <blockquote> a rule */
  font-size: 1rem;
  line-height: 1.55;
}

.dh-tv2__text {
  font-family: Satoshi, Arial, sans-serif;
  margin: 0;
  color: var(--dark, #2c2c2c);
  font-size: 1rem;
  font-weight: 500;
  line-height: 1.55;
  opacity: 0.82;
}

/* ---- Author row ---------------------------------------------- */

.dh-tv2__author {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-top: 1.35rem;
  padding-top: 1.25rem;
  border-top: 1px solid rgba(44, 44, 44, 0.16);
}

/* The reference has a round photograph with a `ring-2`. There are no
   guest photographs, so this is a monogram disc: the reference's circle
   kept, inked the way `.stories_more` inverts the story cards, and set
   in the display face. testimonials.js writes the initials
   (Briana Patton -> BP). Round rather than the site's 2px tile for the
   same reason the card is — see the note on `.dh-tv2__card`. */
.dh-tv2__avatar {
  flex: none;
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 9999px;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: var(--surface, #491f11);
  color: var(--biege, #d8cbb8);
  font-family: "TT Ramillas Variable", Georgia, serif;
  font-size: 0.95rem;
  font-weight: 300;
  line-height: 1;
  letter-spacing: 0.04em;
  transition: background-color 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94),
              color 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94);
}

.dh-tv2__card:hover .dh-tv2__avatar {
  background-color: var(--primary, #d49653);
  color: var(--dark, #2c2c2c);
}

.dh-tv2__id {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.dh-tv2__name {
  font-style: normal;
  font-weight: 700;
  font-size: 0.95rem;
  line-height: 1.2;
  letter-spacing: -0.01em;
  color: var(--dark, #2c2c2c);
}

/* The site's kicker, the same one `.story_card_kicker` uses — except
   for the opacity. `.story_card_kicker` is 0.65, which measures 3.8:1
   against the beige and fails WCAG AA; it is not worth copying a
   failure into new markup. 0.75 over the card plate measures 5.1:1.
   (The `.story_card_kicker` instances are a separate, pre-existing
   fix — they are not touched here.) */
.dh-tv2__role {
  margin-top: 0.35rem;
  font-size: 0.68rem;
  line-height: 1.2;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  opacity: 0.75;
}

/* ---- Narrow screens -----------------------------------------
   Only breathing room. Columns 2 and 3 are already hidden, and the
   heading carries the template's own breakpoints, so it needs
   nothing here.
   ------------------------------------------------------------- */

@media (max-width: 479px) {
  .testimonials.dh-tv2 { padding: 4rem 0; }
  .dh-tv2__container { padding: 0 20px; }
  .dh-tv2__head { margin-bottom: 2.5rem; }
  .dh-tv2__card { padding: 1.75rem; }
  .dh-tv2__card:before { font-size: 2.6rem; right: 0.9rem; }
  .dh-tv2__sub { font-size: 0.95rem; }
}

/* Reduced motion: testimonials.js never adds `is_looping` or
   `is_inview`, so there is no clone, no clip, no fade and no
   entrance. This makes sure the start state cannot strand the
   section at opacity 0 if the class is missing for any reason. */
@media (prefers-reduced-motion: reduce) {
  .dh-tv2__reveal,
  .dh-tv2__reveal.is_armed { opacity: 1; transform: none; transition: none; }
  .dh-tv2__cols { flex-wrap: wrap; }
  .dh-tv2__card { transition: none; }
}

/* ==============================================================
   Polední menu — the stacked deck
   ==============================================================
   A hand port of the 21st.dev "carousel-07" stacked drag carousel. The
   original is React + motion/react; this site has no build step and
   motion/react is not vendored, so `lunch.js` rebuilds the transform
   graph and GSAP — which IS vendored — drives the settle. All geometry
   below the card box is written by JS, not by CSS.

   It replaced a GSAP card fan, which replaced a face-on rotating wheel.
   If you are hunting for `--dh-fan-card-w`, `--dh-lunch-radius`, or any
   `@keyframes` for this section, all three are gone.

   WHAT THIS FILE OWNS: the card box, the deck's reserved height, and the
   drag surface. Nothing else — every x/y/rotate/scale/opacity/z-index on
   a card is an inline style from `render()`.

   STACKING IS OPT-IN, AND THAT IS LOAD-BEARING. `.dh-lunch__deck` is a
   plain grid; `lunch.js` adds `.is_stacked`, and only then do the cards
   go absolute. Backwards — absolute by default — and any visitor whose
   JS fails gets four cards piled at dead centre, because only `render()`
   ever gives them a position. Same invariant as the fan before it and as
   `.dh-tv2__cols.is_looping` on the testimonials.

   Phones and reduced motion never receive `.is_stacked`: a deck you can
   only read by dragging is a poor menu on a phone, and the whole point of
   it is motion. Both fall out to the grid, which is why the media queries
   here are so short.

   THE DRAG SURFACE COVERS THE CARDS. `.dh-lunch__drag` is `inset: 0` at
   `z-index: 50`, above every card, and the cards are `pointer-events:
   none` — that is the reference's design and it is what makes dragging
   feel continuous instead of snagging on card edges. The cost is that a
   card cannot be clicked, so `lunch.js` hit-tests a tap by hiding the
   surface for one `elementFromPoint` call. If you remove the surface, fix
   that too.

   px/rem only, never `em`: `body` is `font-size:1vw`.
   -------------------------------------------------------------- */

.lunch_section {
  position: relative;
  z-index: 5;
  background-color: var(--biege, #d8cbb8);
  color: var(--dark, #2c2c2c);
  overflow: hidden;
}

.dh-lunch {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 6rem 28px 5rem;
}

/* PX, NOT `ch` — same trap as `em`, and the reason this head collapsed
   on phones. `ch` resolves against the element's font size, which here
   inherits `body { font-size: 1vw }`: 12.8px on a 1280px viewport, but
   3.75px on a 375px one. So `max-width: 46ch` measured a reasonable
   408px on desktop and about 119px on a phone, squeezing the hours pill,
   the title and the lead into a 120px column on a 375px screen — with
   the title overflowing it and `.lunch_section { overflow: hidden }`
   clipping the remainder. A fixed px cap measures the same everywhere
   and the section padding still narrows it on small screens. */
.dh-lunch__head {
  max-width: 420px;
  margin-bottom: 2rem;
  text-align: center;
}

.dh-lunch__hours {
  display: inline-block;
  margin-bottom: 1.1rem;
  padding: 0.4rem 0.9rem;
  border: 1px solid rgba(44, 44, 44, 0.28);
  border-radius: 999px;
  font-family: Satoshi, Arial, sans-serif;
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

/* A SPLIT HEADLINE — `text-split letters-fade-in`, like every other
   section title. See `.dh-tv2__title` for why these four stopped being
   the exception.

   THE `opacity: 1` FLOOR THAT USED TO BE HERE IS GONE WITH THEM. It was
   dead anyway: the inline `[text-split]{opacity:0}` sits in the page
   head, AFTER this stylesheet and at equal specificity, so it won every
   time. What actually made this title invisible was the `52ch` width
   below, not the reveal. */
.dh-lunch__title {

  /* THE WEBFLOW `.middle` CLASS SETS `width: 52ch`, AND THAT IS WHY THIS
     TITLE WAS INVISIBLE. `ch` resolves against the element's OWN font
     size, and this h2 renders at ~61px, so 52ch measures ~1917px — inside
     a `.dh-lunch__head` that is 408px wide. The h2 blew out to nearly
     five times its parent with a -1508px right margin, and because
     `.middle` also centres the text, the glyphs painted around x=1394 on
     a 1280px viewport. `.lunch_section` is `overflow: hidden`, so they
     were clipped off the right edge entirely: present in the DOM, at
     opacity 1, correct colour, and simply not on screen.

     `.middle` is fine where the template uses it — on headings whose
     parent is the full content column. It only misfires here because
     this head is deliberately narrow. Constrain rather than drop the
     class: `.dh-lunch__head` already sets `text-align: center`, so the
     centring survives on its own. */
  width: auto;
  max-width: 100%;
}

.dh-lunch__lead {
  margin: 0;
  font-family: Satoshi, Arial, sans-serif;
  font-size: 1rem;
  line-height: 1.55;
  opacity: 0.78;
}

/* ---- the deck --------------------------------------------------- */

/* Default, and all a visitor without working JS ever sees. */
.dh-lunch__deck {
  position: relative;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 2rem 1.25rem;
  width: 100%;
  max-width: 88rem;
  margin: 0 auto;
}

/* Stacked. The height is reserved rather than derived: every card is out
   of flow once stacked, so the section would otherwise collapse. The
   values are the reference's own container heights (h-112 / h-128). */
/* Three tiers. The two larger ones are the reference's own breakpoints —
   w-56/h-80 in an h-112 stage to 1024, w-64/h-96 in h-128 above.

   THE PHONE TIER IS DELIBERATELY BIGGER THAN THE REFERENCE'S. Its w-44
   (11rem) card left the tray small on a 375px screen, and on a menu the
   dish is the point. At 16rem the card is ~68% of a 375px viewport, so
   the front tray reads properly.

   The cost is overlap, and that is intended: the JS x-spread on this tier
   is 90px, so a neighbour sits only 90px off-centre while the card is
   256px wide — they tuck well behind the front one, and the outermost
   pair runs past the viewport edge. The overflow:hidden below is what
   turns that into a clean crop instead of a horizontal scrollbar, so do
   not remove it while these numbers stand. */
.dh-lunch__deck.is_stacked {
  --dh-card-w: 16rem;
  --dh-card-h: 21rem;

  display: block;
  height: 26rem;
  overflow: hidden;
  user-select: none;
  -webkit-user-select: none;

  /* Load-bearing on a phone: the deck claims the horizontal axis for the
     drag and hands the vertical one back to the page. Without it a thumb
     that starts on the deck cannot scroll past the section. */
  touch-action: pan-y;
}

@media screen and (min-width: 640px) {
  .dh-lunch__deck.is_stacked {
    --dh-card-w: 14rem;
    --dh-card-h: 20rem;

    height: 28rem;
  }
}

/* Desktop was using barely half its width: at 1280px the visible cards
   spanned 631px of a 1224px deck, leaving ~300px dead on each side.

   THE LEVER IS CARD WIDTH, NOT SPREAD. The tray photos are ~0.86 wide-to
   -tall, and the card is taller than that, so the tray fits to the card's
   WIDTH and leaves the extra height unused. Pushing the cards further
   apart would fill the deck while leaving every dish exactly as small —
   and past a spread equal to the card width they stop overlapping and the
   deck stops reading as a deck at all. So the card grows 16rem -> 24rem
   and the spread only 170 -> 250 (in lunch.js), which keeps 134px of
   overlap.

   Height follows the tray rather than being chosen: a 384px-wide card
   fits a 446px-tall tray, plus ~48px of label, so 31rem is the smallest
   card that does not waste the width. The section is already taller than
   a 900px viewport, so the padding below is trimmed to pay for some of
   the extra. */
@media screen and (min-width: 1024px) {
  .dh-lunch__deck.is_stacked {
    --dh-card-w: 24rem;
    --dh-card-h: 31rem;

    height: 36rem;
  }

  .dh-lunch { padding-top: 4.5rem; padding-bottom: 3.5rem; }
}

/* Large monitors. There is a ceiling on this and it is worth knowing why:
   only three of the four cards are ever visible at once, so the deck can
   only be as wide as spread + card, and the spread cannot exceed the card
   width without the cards ceasing to overlap. At 28rem/300px that is
   ~1050px of content — comfortably filling a 1440 screen, and a deliberate
   band rather than a sprawl on anything wider. Chasing 100% of a 2560px
   monitor would mean cards taller than the viewport. */
@media screen and (min-width: 1536px) {
  .dh-lunch__deck.is_stacked {
    --dh-card-w: 28rem;
    --dh-card-h: 35rem;

    height: 40rem;
  }
}

/* left/top + negative margins put each card's own centre on the deck's
   centre, so every translate from render() is measured from there. */
.dh-lunch__deck.is_stacked .dh-lunch__card {
  position: absolute;
  left: 50%;
  top: 50%;
  width: var(--dh-card-w);
  height: var(--dh-card-h);
  margin: calc(var(--dh-card-h) / -2) 0 0 calc(var(--dh-card-w) / -2);
  pointer-events: none;       /* the surface below handles input */
  will-change: transform, opacity;
}

/* Only present while stacked — see the note above on why it sits on top. */
.dh-lunch__drag {
  display: none;
}

.dh-lunch__deck.is_stacked .dh-lunch__drag {
  display: block;
  position: absolute;
  inset: 0;
  z-index: 50;
  cursor: grab;
}

.dh-lunch__deck.is_stacked .dh-lunch__drag:active {
  cursor: grabbing;
}

/* The deck takes arrow keys, so it must show it has focus. */
.dh-lunch__deck:focus-visible {
  outline: 2px solid var(--gold, #d49653);
  outline-offset: 6px;
}

/* The label fades with distance from centre (render() writes the value),
   so it must not also fade on hover — two owners of one property.

   The resting transform goes too. It is a translateY(4px) that the tile
   design cancels on hover, but a card in the deck is never hovered (the
   drag surface owns the pointer), so it would sit 4px below the card box
   permanently and push the label out of its own card. */
.dh-lunch__deck.is_stacked .dh-lunch__label {
  transition: none;
  transform: none;
}


/* ---- one tile -------------------------------------------------- */

.dh-lunch__tile {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
  width: 100%;
  height: 100%;
  padding: 0;
  background: none;
  border: 0;
  color: inherit;
  cursor: pointer;
  font: inherit;
  -webkit-tap-highlight-color: transparent;
}

.dh-lunch__photo {
  display: flex;
  flex: 1 1 auto;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: 0;
  /* The trays are cut out on transparency, so the shadow has to come
     from the alpha channel — a box-shadow would draw a rectangle
     around nothing. */
  filter: drop-shadow(0 18px 22px rgba(44, 44, 44, 0.32));
  transition: transform 0.45s cubic-bezier(0.22, 1, 0.36, 1),
              filter 0.45s ease;
}

.dh-lunch__photo img {
  width: auto;
  max-width: 100%;
  height: auto;
  max-height: 100%;
  object-fit: contain;
}

.dh-lunch__tile:hover .dh-lunch__photo,
.dh-lunch__tile:focus-visible .dh-lunch__photo {
  transform: translateY(-10px) scale(1.06);
  filter: drop-shadow(0 26px 30px rgba(44, 44, 44, 0.42));
}

/* ---- the label ------------------------------------------------- */

/* Present at rest but quiet, so a tile is never a mystery photo; hover
   and focus bring it up to full contrast and lift it clear of the
   tray. Opacity rather than display, so it does not reflow. */
.dh-lunch__label {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.15rem;
  margin-top: 0.85rem;
  font-family: Satoshi, Arial, sans-serif;
  text-align: center;
  opacity: 0.82;
  transform: translateY(4px);
  transition: opacity 0.35s ease, transform 0.35s ease;
}

.dh-lunch__tile:hover .dh-lunch__label,
.dh-lunch__tile:focus-visible .dh-lunch__label {
  opacity: 1;
  transform: none;
}

.dh-lunch__name {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.92rem;
  font-weight: 500;
  letter-spacing: -0.01em;
  line-height: 1.2;
}

.dh-lunch__veg {
  padding: 0.1rem 0.3rem;
  border: 1px solid rgba(44, 44, 44, 0.35);
  border-radius: 2px;
  font-size: 0.58rem;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  opacity: 0.7;
}

.dh-lunch__variant {
  font-size: 0.76rem;
  font-style: italic;
  opacity: 0.66;
}

.dh-lunch__price {
  margin-top: 0.15rem;
  font-size: 0.82rem;
  font-weight: 500;
  letter-spacing: 0.04em;
  color: #8a5a22;              /* --primary is too pale on the beige */
}

/* Keyboard focus has to be visible on a tile that may be mid-orbit, so
   the ring is drawn on the tile rather than relying on the lift. */
.dh-lunch__tile:focus-visible {
  outline: 2px solid var(--dark, #2c2c2c);
  outline-offset: 6px;
  border-radius: 3px;
}

/* ---- the detail modal ------------------------------------------ */

.dh-lunch__detail {
  display: grid;
  grid-template-columns: 116px 1fr;
  gap: 18px;
  align-items: start;
  padding-bottom: 20px;
  border-bottom: 1px solid rgba(216, 203, 184, 0.18);
}

.dh-lunch__detail-photo {
  width: 100%;
  height: auto;
  filter: drop-shadow(0 10px 16px rgba(0, 0, 0, 0.45));
}

.dh-lunch__detail-kicker {
  margin: 0 0 8px;
  color: var(--primary, #d49653);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

.dh-lunch__includes {
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: 14px;
  line-height: 1.5;
}

.dh-lunch__includes li {
  position: relative;
  padding-left: 16px;
  margin-bottom: 6px;
  opacity: 0.86;
}

.dh-lunch__includes li::before {
  content: "";
  position: absolute;
  top: 0.55em;
  left: 0;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--primary, #d49653);
}

.dh-lunch__price-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  padding: 18px 0;
}

.dh-lunch__detail-price {
  font-family: "TT Ramillas Variable", Georgia, serif;   /* = Playfair, see above */
  font-size: 30px;
  font-weight: 300;
  letter-spacing: -0.01em;
}

/* Unused while all four menus are priced, but kept: a menu may ship
   before its price is confirmed, and the modal should say so rather
   than guess a number that is not printed in the PDF. */
.dh-lunch__detail-price.is-pending {
  font-size: 20px;
  font-style: italic;
  opacity: 0.6;
}

.dh-lunch__takeaway {
  font-size: 12.5px;
  opacity: 0.62;
}

.dh-lunch__actions {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
  margin-bottom: 18px;
}

.dh-lunch__cta {
  flex: 1 1 auto;
  min-height: 46px;
  padding: 12px 22px;
  background: var(--primary, #d49653);
  border: 0;
  border-radius: 3px;
  color: #1e1e1e;
  cursor: pointer;
  font-family: Satoshi, Arial, sans-serif;
  font-size: 14px;
  font-weight: 500;
  letter-spacing: 0.02em;
  transition: background-color 0.3s;
}

.dh-lunch__cta:hover,
.dh-lunch__cta:focus-visible { background: #e2a765; }

.dh-lunch__link {
  color: var(--biege, #d8cbb8);
  font-size: 13.5px;
  text-decoration: underline;
  text-underline-offset: 3px;
  opacity: 0.72;
  transition: opacity 0.3s;
}

.dh-lunch__link:hover,
.dh-lunch__link:focus-visible { opacity: 1; }

/* ---- narrow screens -------------------------------------------- */

/* The deck is stacked on phones too now, so this block only shapes the
   grid that reduced motion still falls out to — plus the section padding,
   which applies either way. `:not(.is_stacked)` keeps the two-column rule
   from fighting the stacked layout's `display: block`. */
@media screen and (max-width: 767px) {
  .dh-lunch { padding: 4rem 16px 3.5rem; }
  .dh-lunch__deck:not(.is_stacked) {
    grid-template-columns: 1fr 1fr;
    gap: 1.75rem 1rem;
  }
  .dh-lunch__deck:not(.is_stacked) .dh-lunch__photo { height: 150px; }
}

@media screen and (max-width: 560px) {
  .dh-lunch__detail { grid-template-columns: 84px 1fr; gap: 14px; }
  .dh-lunch__actions { flex-direction: column; align-items: stretch; }
  .dh-lunch__link { text-align: center; }
}

@media screen and (max-width: 479px) {
  .dh-lunch__photo { height: 130px; }
  .dh-lunch__name { font-size: 0.84rem; }
}

/* A deck you drag is exactly the kind of motion this is for. lunch.js
   checks this query before opting into `.is_stacked`, so the grid is
   already what renders and the only work left is stilling the tile's own
   transitions. */
@media (prefers-reduced-motion: reduce) {
  .dh-lunch__photo { height: 190px; transition: none; }
  .dh-lunch__label { opacity: 1; transform: none; transition: none; }
}

/* ==============================================================
   Footer — port of the supplied `footer-2.tsx`
   ==============================================================
   A hand port of a React/shadcn/Tailwind reference (`Footer2`) to
   plain HTML + CSS. There is no React, no Tailwind and no build
   step in this project, so the component could not be dropped in;
   what survives is its LAYOUT, which is the part that was asked for:

     4-column link grid  →  1px rule  →  social icons left /
     two badge buttons right  →  1px rule  →  centred fine print.

   Two departures from the reference, both deliberate:

   - THE BIG WORDMARK IS KEPT. It sits between the badge row and
     the last rule. The reference has no such block; this site
     does, and it was the one thing asked to survive the port.
   - The reference's App Store / Play Store badges became
     "Objednat online" and "Rezervace stolu" — same two-line badge
     shape, real destinations. Delhi Haveli has no mobile app, and
     a store badge that goes nowhere is worse than no badge.

   Tailwind tokens map onto the site's palette, not shadcn's:

     bg-card            var(--surface) #491f11 (see "Dark surface")
     foreground         var(--biege)   #d8cbb8
     muted-foreground   var(--biege) at 66%
     border             var(--biege) at 16%
     primary            var(--primary) #d49653
     rounded-md         2px — the site's corner, not shadcn's 6px

   SIZED IN PX/REM, NEVER `em`. `body` is `font-size:1vw`, so an
   `em` here would scale with the viewport and the reference's
   fixed Tailwind sizes would not survive. Same rule as the modal
   and testimonial CSS.
   ============================================================== */

/* The template's own `.footer` already supplies the ground colour,
   `width:100vw` and the stacking context. Everything below is the
   inner layout only. */

.dh-f2 {
  max-width: 72rem;        /* max-w-6xl */
  margin: 0 auto;
  padding: 0 16px;         /* px-4 */
}

@media screen and (min-width: 1024px) {
  .dh-f2 { padding: 0 24px; }   /* lg:px-6 */
}

/* ---- link grid ----------------------------------------------- */

.dh-f2__grid {
  display: grid;
  grid-template-columns: 1fr 1fr;   /* grid-cols-2 */
  gap: 2rem;                        /* gap-8 */
  padding: 3.5rem 0 2rem;
}

@media screen and (min-width: 768px) {
  .dh-f2__grid { grid-template-columns: repeat(4, 1fr); }   /* md:grid-cols-4 */
}

/* WEBFLOW TRAP, the same one `.dh-tv2__title` documents: the template
   styles a bare `h3` as Playfair, uppercase, `3.5em` — which at
   `body{font-size:1vw}` is a display headline, not a column label.
   Every one of those declarations has to be undone here. */
.dh-f2__title {
  color: var(--biege);
  margin: 0 0 1rem;
  font-family: Satoshi, Arial, sans-serif;
  font-size: 0.72rem;
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.dh-f2__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;             /* space-y-2 */
  font-size: 0.875rem;     /* text-sm */
  line-height: 1.45;
}

.dh-f2__link,
.dh-f2__meta {
  color: rgba(216, 203, 184, 0.66);   /* text-muted-foreground */
  text-decoration: none;
}

.dh-f2__link {
  display: inline-block;
  transition: color 0.4s;
}

/* The reference goes dim → foreground on hover. On this ground that
   is the gold, which is what every other link in the footer already
   does (`.txt_footer:hover`). */
.dh-f2__link:hover,
.dh-f2__link:focus-visible { color: var(--primary); }

.dh-f2__link.w--current { color: var(--biege); }

/* ---- the two rules ------------------------------------------- */

.dh-f2__rule { height: 1px; background: rgba(216, 203, 184, 0.16); }

/* ---- social icons + badges ----------------------------------- */

.dh-f2__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.25rem 0;      /* py-5 */
}

.dh-f2__social { display: flex; align-items: center; gap: 0.5rem; }

/* shadcn's `buttonVariants({ variant: "outline", size: "icon" })` —
   40x40 and a 1px border, but 2px corners rather than `rounded-md`,
   because 2px is this site's corner everywhere else. */
.dh-f2__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border: 1px solid rgba(216, 203, 184, 0.24);
  border-radius: 2px;
  color: rgba(216, 203, 184, 0.62);
  transition: color 0.3s, background-color 0.3s, border-color 0.3s;
}

.dh-f2__icon:hover,
.dh-f2__icon:focus-visible {
  color: var(--dark);
  background-color: var(--primary);
  border-color: var(--primary);
}

.dh-f2__icon svg { width: 20px; height: 20px; }   /* size-5 */

.dh-f2__badges { display: flex; flex-wrap: wrap; gap: 0.75rem; }

/* The reference's store badge: `h-11 gap-2`, filled with `primary`,
   icon on the left and a two-line label on the right. */
.dh-f2__badge {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  height: 44px;                    /* h-11 */
  padding: 0 1rem 0 0.875rem;
  border: 1px solid var(--primary);
  border-radius: 2px;
  background-color: var(--primary);
  color: var(--dark);
  text-decoration: none;
  transition: background-color 0.3s, border-color 0.3s;
}

.dh-f2__badge:hover,
.dh-f2__badge:focus-visible {
  background-color: var(--biege);
  border-color: var(--biege);
}

.dh-f2__badge svg { width: 20px; height: 20px; flex: none; }

.dh-f2__badge_txt {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  padding-right: 0.5rem;
  text-align: left;
}

/* `<span>`, not the reference's `<p>`: the template puts a bottom
   margin on a bare paragraph. */
.dh-f2__badge_sm { font-size: 10px; line-height: 1; letter-spacing: -0.02em; }
.dh-f2__badge_lg { font-size: 1rem; font-weight: 700; line-height: 1; margin-top: 3px; }

/* ---- the wordmark -------------------------------------------- */

/* FULL BLEED ON PURPOSE — it sits outside `.dh-f2`'s 72rem measure.
   Nested inside the container it would render at roughly half the
   width and stop being the big text.

   The template's `.footer_txt_lg` wrapper is no longer used; its
   232px top margin belonged to the much taller layout this replaced. */

/* IT IS THE LOGO ARTWORK NOW, NOT TYPE. Until the owner supplied a
   wordmark this was `<div class="txt_lg">delhi haveli</div>` — the
   template's own 13.8em (= 13.8vw at `body{font-size:1vw}`) Satoshi
   caps, tuned to span ~86% of the viewport. It is the same file the
   header loads, `delhi-haveli-wordmark.svg`, so the footer costs no
   extra request and the two marks can never drift apart.

   The width is set in vw rather than `width:100%` so the padding is
   not doing the sizing. 84vw is deliberately just short of the old
   type's 86%: the mark is aspect 5.81 against the type's ~7.8, so
   matching the width outright would make a noticeably deeper band
   (14.9vw against 11vw). At 84vw it stands 14.5vw — 209px at 1440,
   where the type made 159px — which is as much depth as the block
   can take before it stops being a sign-off and starts being a
   section. Do not push it to 100vw: the mark is trimmed to the ink,
   so there is no built-in margin and it would touch both edges.

   Vector, so it stays crisp at any viewport; see `tools/make-wordmark.py`.
   The bottom padding is generous for the same reason — a tighter
   value puts the closing rule through the feet of the letters. */
.dh-f2__wordmark { padding: 4.5rem 16px 1.75rem; }

.dh-f2__wordmark_img {
  display: block;
  width: 84vw;
  max-width: 100%;
  height: auto;
  margin: 0 auto;
}

/* ---- fine print ---------------------------------------------- */

.dh-f2__legal {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 0.35rem 1.25rem;
  padding: 1rem 0 1.5rem;
  color: rgba(216, 203, 184, 0.62);
  font-size: 0.75rem;      /* text-xs */
  line-height: 1.5;
  text-align: center;
}

.dh-f2__legal a {
  color: inherit;
  text-decoration: none;
  transition: color 0.3s;
}

.dh-f2__legal a:hover,
.dh-f2__legal a:focus-visible { color: var(--primary); text-decoration: underline; }

/* ---- narrow screens ------------------------------------------- */

@media screen and (max-width: 767px) {
  .dh-f2__grid { gap: 1.75rem 1rem; padding: 2.75rem 0 1.75rem; }
  .dh-f2__actions { justify-content: center; }
  .dh-f2__badges { width: 100%; }
  .dh-f2__badge { flex: 1 1 auto; justify-content: center; }
  .dh-f2__wordmark { padding-top: 2.5rem; }
  /* A phone has no width to spare and the block is short here anyway —
     88vw is 330x57 at 375, which still reads as the sign-off. */
  .dh-f2__wordmark_img { width: 88vw; }
}

@media screen and (max-width: 479px) {
  .dh-f2__list { font-size: 0.82rem; }
  .dh-f2__badge_lg { font-size: 0.9rem; }
}

/* ==============================================================
   Nejoblíbenější — the 3D coverflow
   ==============================================================
   A hand port of a supplied React reference
   (`3-d-coverflow-carousel.tsx` — "use client" + Tailwind + a large
   inline `style` object per card). No build step here, so the same
   route was taken as for `testimonial-v2.tsx`, `footer-2.tsx` and the
   21st.dev deck behind `.dh-lunch`: keep the geometry, rebuild the
   skin on this site's theme. `coverflow.js` has the full port note.

   THE GEOMETRY IS THE COMPONENT and it is NOT in this file. Every
   transform / opacity / filter / z-index on a card is an inline style
   from `render()`, exactly as with `.dh-lunch`. What lives here is the
   card box, the stage's reserved height, the two rings' spacing
   (`--dh-cf-spread`, which is the one number the breakpoints move and
   the script reads back at render time), and the skin.

   COVERFLOW IS OPT-IN, AND THAT IS LOAD-BEARING. `.dh-cf__stage` is a
   scroll-snap row; `coverflow.js` adds `.is_coverflow`, and only then
   do the cards go absolute. Backwards — absolute by default — and any
   visitor whose JS fails gets five cards piled at dead centre, because
   only `render()` ever gives one a position. Same invariant as
   `.dh-tv2__cols.is_looping` and `.dh-lunch__deck.is_stacked`.

   Nothing here sets `opacity: 0` on a card or its body. The side
   cards fade because the script fades them, and the script is also
   what brings them back. This site has already lost every split
   headline once to a stylesheet that hid content a script never
   un-hid (see the reduced-motion note at the top of this file).

   Phones and reduced motion never receive `.is_coverflow` — side cards
   sit 285px and 510px off centre, and the point of the thing is the
   motion. Both fall out to the row, which is why the media queries
   below are so short.

   The skin, the same theme `.story_card`, `.dh-lunch` and `.dh-tv2`
   follow, on this section's dark ground rather than the beige one:

     ground   var(--dark)    #2c2c2c
     ink      var(--biege)   #d8cbb8
     accent   var(--primary) #d49653
     corners  2px — a pill only for a tracked uppercase control
     rules    1px hairlines at 14-30% ink; NO drop shadows, NO glows
     display  Playfair ("TT Ramillas Variable"), uppercase, w300
     body     Satoshi, w500

   The reference's `#0c0a09`/`#c5a880` palette, 18px corners,
   `system-ui`, four box-shadows and two gold glows are all gone. That
   round trip — build to the reference, convert afterwards — is what
   CLAUDE.md 11 records for the testimonials; it was not repeated.

   px/rem only, never `em`: `body` is `font-size:1vw`. The one
   exception is the heading, which borrows the template's `.h2` so it
   DOES scale in step with the section titles above and below it.
   -------------------------------------------------------------- */

.coverflow_section.dh-cf {
  position: relative;
  z-index: 5;
  overflow: hidden;
  padding: 6rem 0 5rem;
  background-color: var(--surface, #491f11);
  color: var(--biege, #d8cbb8);
  font-family: Satoshi, Arial, sans-serif;
}

/* ---- Ambience ------------------------------------------------
   The reference's blurred backdrop of the active photograph. It
   carries the first card's `src` in the markup, so a visitor with no
   JS still gets a ground rather than a broken-image icon; the script
   only ever swaps it. Decorative — `alt=""`, and it is never the
   only place a dish is shown.
   -------------------------------------------------------------- */

.dh-cf__ambience {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}

.dh-cf__ambience img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transform: scale(1.15);
  filter: brightness(0.22) blur(32px);
  transition: opacity 1s ease, filter 1s ease;
}

/* Pulls the corners down so the outer cards, which the section clips,
   fade out instead of ending on a hard edge. */
.dh-cf__ambience:after {
  content: "";
  position: absolute;
  inset: 0;
  background-image: radial-gradient(circle at center,
    rgba(28, 25, 23, 0.3) 0%,
    rgba(28, 25, 23, 0.94) 100%);
}

.dh-cf__inner {
  position: relative;
  z-index: 10;
  width: 100%;
  max-width: 1180px;
  margin: 0 auto;
  padding: 0 28px;
}

/* ---- Head ----------------------------------------------------- */

.dh-cf__head {
  display: flex;
  flex-direction: column;
  align-items: center;
  max-width: 720px;
  margin: 0 auto;
  text-align: center;
}

/* The site's tag idiom, shared with `.dh-tv2__badge`, `.dh-lunch__hours`
   and `.tag_new`: hairline pill, uppercase, tracked out, no fill. */
.dh-cf__badge {
  display: inline-block;
  padding: 0.4rem 0.9rem;
  border: 1px solid rgba(216, 203, 184, 0.3);
  border-radius: 999px;
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

/* A SPLIT HEADLINE — `text-split letters-fade-in`, like every other
   section title. See `.dh-tv2__title` for why these four stopped being
   the exception. */
.dh-cf__title {
  /* `.middle` carries `width: 52ch`, and `ch` resolves against this
     h2's OWN ~70px font size — thousands of px inside a 720px head.
     That is the trap that painted the lunch title off the right edge
     of the screen. Constrain it; the head already centres the text. */
  width: auto;
  max-width: 100%;
  margin: 1.4rem 0 0;
}

.dh-cf__lead {
  margin: 1.1rem 0 0;
  max-width: 440px;
  font-size: 1rem;
  line-height: 1.55;
  opacity: 0.78;
}

/* ---- Stage: the no-JS / phone fallback ------------------------
   A plain scroll-snap row. Readable, swipeable and keyboard-
   scrollable with nothing running, which is why the arrows and the
   dots below are hidden until `.is_coverflow` exists to need them.
   -------------------------------------------------------------- */

.dh-cf__viewport {
  position: relative;
  margin-top: 3.2rem;
}

.dh-cf__stage {
  --dh-cf-spread: 285px;      /* read back by coverflow.js at render */

  display: flex;
  gap: 18px;
  margin: 0;
  padding: 0 0 14px;
  list-style: none;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: thin;
  scrollbar-color: rgba(216, 203, 184, 0.35) transparent;
}

.dh-cf__stage::-webkit-scrollbar { height: 3px; }
.dh-cf__stage::-webkit-scrollbar-track { background: rgba(216, 203, 184, 0.1); }
.dh-cf__stage::-webkit-scrollbar-thumb { background: rgba(216, 203, 184, 0.35); }

/* ---- Stage: coverflow ----------------------------------------- */

.dh-cf__stage.is_coverflow {
  display: block;
  position: relative;
  height: 520px;
  padding: 0;
  overflow: visible;
  perspective: 1400px;        /* the reference's depth */
  scroll-snap-type: none;
}

/* ---- The card -------------------------------------------------
   One box in both modes: fixed 33:50 portrait, media and body both
   absolute inside it. That is what lets the row and the coverflow
   share every rule below this line.
   -------------------------------------------------------------- */

.dh-cf__card {
  position: relative;
  flex: 0 0 300px;
  aspect-ratio: 33 / 50;
  scroll-snap-align: center;
  overflow: hidden;
  border: 1px solid rgba(216, 203, 184, 0.14);
  border-radius: 2px;
  background-color: #241f1c;
}

.dh-cf__stage.is_coverflow .dh-cf__card {
  position: absolute;
  top: 50%;
  left: 50%;
  flex: none;
  width: 330px;
  height: 500px;
  margin: -250px 0 0 -165px;   /* centre the box; render() moves it */
  aspect-ratio: auto;
  transform-origin: center center;
  backface-visibility: hidden;
  transition: transform 0.8s cubic-bezier(0.25, 1, 0.5, 1),
              opacity 0.8s cubic-bezier(0.25, 1, 0.5, 1),
              filter 0.8s cubic-bezier(0.25, 1, 0.5, 1);
}

/* The centre card lifts a hair on hover — the site's `.story_card`
   move, at the same duration and ease. */
.dh-cf__stage.is_coverflow .dh-cf__card[aria-hidden="false"]:hover .dh-cf__media .image {
  transform: scale(1.05);
}

.dh-cf__media {
  position: absolute;
  inset: 0;
  overflow: hidden;
}

.dh-cf__media .image {
  transition: transform 0.9s cubic-bezier(0.25, 0.46, 0.45, 0.94);
}

/* Two stops rather than the reference's four: enough to seat the type
   at the foot of the plate, not so much that the dish goes dark. */
.dh-cf__media:after {
  content: "";
  position: absolute;
  inset: 0;
  background-image: linear-gradient(to bottom,
    rgba(16, 14, 13, 0.5) 0%,
    rgba(16, 14, 13, 0.08) 26%,
    rgba(16, 14, 13, 0.72) 62%,
    rgba(16, 14, 13, 0.95) 100%);
  pointer-events: none;
}

/* The menu number, in the `.story_card_index` position and face. It is
   not decoration: guests order by number and the allergen table
   cross-references it (root CLAUDE.md, "The menu"). */
.dh-cf__num {
  position: absolute;
  z-index: 2;
  top: 14px;
  left: 16px;
  font-family: "TT Ramillas Variable", Georgia, serif;
  font-size: 20px;
  font-weight: 300;
  line-height: 1;
  letter-spacing: -0.03em;
  color: var(--biege, #d8cbb8);
  opacity: 0.85;
}

/* ---- Card body ------------------------------------------------ */

.dh-cf__body {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  align-items: center;
  padding: 20px 18px 22px;
  text-align: center;
  transition: opacity 0.5s ease, transform 0.5s ease;
}

.dh-cf__kicker {
  font-size: 0.7rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  opacity: 0.72;
}

.dh-cf__name {
  margin: 0.5rem 0 0;
  font-family: "TT Ramillas Variable", Georgia, serif;
  font-size: 1.55rem;
  font-weight: 300;
  line-height: 1.1;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--biege, #d8cbb8);
}

.dh-cf__rule {
  display: block;
  width: 34px;
  height: 1px;
  margin: 0.7rem 0 0.65rem;
  background-color: var(--primary, #d49653);
}

.dh-cf__desc {
  margin: 0;
  max-width: 260px;
  font-size: 0.8rem;
  line-height: 1.45;
  opacity: 0.82;
}

.dh-cf__foot {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.7rem;
  margin-top: 0.95rem;
}

.dh-cf__price {
  font-size: 0.95rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  color: var(--primary, #d49653);
}

/* The reference's CTA is a gold gradient pill with two shadows. This
   is the same control in this site's language: hairline pill, tracked
   uppercase, filling with `--primary` on hover — `.dh-tv2__badge`
   plus `.dh-reserve__submit:hover`. */
.dh-cf__cta {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 1.05rem;
  border: 1px solid rgba(216, 203, 184, 0.45);
  border-radius: 999px;
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--biege, #d8cbb8);
  transition: background-color 0.3s, border-color 0.3s, color 0.3s;
}

.dh-cf__cta:hover,
.dh-cf__cta:focus-visible {
  background-color: var(--primary, #d49653);
  border-color: var(--primary, #d49653);
  color: var(--dark, #2c2c2c);
}

.dh-cf__cta:after {
  content: "";
  width: 1.5rem;
  height: 1px;
  background-color: currentColor;
  opacity: 0.6;
  transition: width 0.45s cubic-bezier(0.25, 0.46, 0.45, 0.94);
}

.dh-cf__cta:hover:after { width: 2.1rem; opacity: 1; }

/* ---- Controls -------------------------------------------------
   Built by coverflow.js and shown only in coverflow mode: the row
   fallback scrolls and snaps on its own, so with no JS there is
   nothing for them to drive.
   -------------------------------------------------------------- */

.dh-cf__arrow,
.dh-cf__dots { display: none; }

.dh-cf.is_coverflow .dh-cf__arrow { display: flex; }
.dh-cf.is_coverflow .dh-cf__dots { display: flex; }

.dh-cf__arrow {
  position: absolute;
  z-index: 40;
  top: 50%;
  width: 46px;
  height: 46px;
  margin-top: -23px;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 1px solid rgba(216, 203, 184, 0.28);
  border-radius: 50%;
  background-color: rgba(20, 18, 17, 0.55);
  color: var(--biege, #d8cbb8);
  cursor: pointer;
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  transition: background-color 0.3s, border-color 0.3s, color 0.3s;
}

.dh-cf__arrow--prev { left: 0; }
.dh-cf__arrow--next { right: 0; }

.dh-cf__arrow:hover,
.dh-cf__arrow:focus-visible {
  background-color: var(--primary, #d49653);
  border-color: var(--primary, #d49653);
  color: var(--dark, #2c2c2c);
}

.dh-cf__dots {
  align-items: center;
  justify-content: center;
  gap: 8px;
  margin-top: 2.2rem;
}

.dh-cf__dot {
  width: 8px;
  height: 8px;
  padding: 0;
  border: none;
  border-radius: 999px;
  background-color: rgba(216, 203, 184, 0.25);
  cursor: pointer;
  transition: width 0.3s ease, background-color 0.3s ease;
}

.dh-cf__dot.is_on {
  width: 28px;
  background-color: var(--primary, #d49653);
}

/* The slide announcement. Spoken only after a real interaction — see
   the `announce` flag in coverflow.js — so autoplay does not talk over
   a screen-reader user every five seconds. */
.dh-cf__status {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ---- Narrower screens -----------------------------------------
   Above 768px the script is in charge, so all these move is
   `--dh-cf-spread`, which it reads back on resize. Below it, the row
   fallback is what renders and none of this applies.
   -------------------------------------------------------------- */

@media screen and (max-width: 1200px) {
  .dh-cf__stage { --dh-cf-spread: 250px; }
}

@media screen and (max-width: 991px) {
  .coverflow_section.dh-cf { padding: 5rem 0 4rem; }
  .dh-cf__stage { --dh-cf-spread: 215px; }
  .dh-cf__stage.is_coverflow { height: 470px; }
  .dh-cf__stage.is_coverflow .dh-cf__card {
    width: 290px;
    height: 440px;
    margin: -220px 0 0 -145px;
  }
}

@media screen and (max-width: 767px) {
  .coverflow_section.dh-cf { padding: 4.5rem 0 3.5rem; }
  .dh-cf__inner { padding: 0 20px; }
  .dh-cf__viewport { margin-top: 2.4rem; }
  /* Let the row bleed to both edges so a card can sit centred in it. */
  .dh-cf__stage {
    margin: 0 -20px;
    padding: 0 20px 14px;
    scroll-padding: 0 20px;
  }
  .dh-cf__card { flex-basis: 260px; }
}

@media (prefers-reduced-motion: reduce) {
  .dh-cf__card,
  .dh-cf__body,
  .dh-cf__media .image,
  .dh-cf__dot,
  .dh-cf__cta:after { transition: none; }
}


/* ==============================================================
   Dark surface — dark saffron red, not neutral grey
   ==============================================================
   The template shipped two near-identical neutral greys: `--dark`
   (#2c2c2c) for every dark panel AND for body ink, plus a one-off
   #292622 on `.footer`. Against #d8cbb8 beige and #d49653 gold
   they read as flat photographic grey — the gold goes yellow-on-
   grey rather than gold.

   WHY THIS PARTICULAR HEX. The hue is the balance point of the
   dark saffron-red family: redder than a rust (#3b1d09 reads
   tobacco, not red) and more saffron than an oxblood (#3a1410
   reads maroon, with no warmth left in it).

   The VALUE is set by contrast, not by taste. The binding
   constraint is `.dh-f2__link` / `__meta` — beige at 66% alpha —
   which lands at 4.69:1 here against WCAG AA's 4.5:1. That is
   roughly two more steps of lightness in hand: #4c2112 gives
   4.59:1 and #4f2212 gives 4.52:1, and past that the link text
   fails. Going lighter than #4f2212 means raising the alpha too
   (0.72 buys about six more steps) — do both or neither.

   Measure that text COMPOSITED over the ground, never as flat
   beige-on-ground; the alpha is the whole point and ignoring it
   overstates the ratio by about two to one.

   `--surface` splits the two jobs apart:

     --surface  #491f11   every dark PANEL (dark saffron red)
     --dark     #2c2c2c   INK only — body copy, hairlines, dots

   Ink deliberately did not move. Re-toning the type as well shifts
   every dark word on the beige ground, which is a different and
   much larger decision.

   TRANSLUCENT SCRIMS ARE ALSO LEFT ALONE. The template has
   #2c2c2c00/33/40/59/66/b8 veils over photographs; at those alphas
   the hue is imperceptible and they are not what reads as grey.

   Nothing below edits the generated stylesheet (see 1) — these are
   plain overrides of its own selectors, and they win on being
   later in the cascade at equal specificity. Two selectors are
   load-bearing:

   - The header is NOT in the list below; it has its own block
     further down, because it is transparent over a hero and only
     takes `--surface` once the hero has scrolled away.
   - `.left_side` is the dark half of the featured-menu split.
     `.left_side.biege` overrides it to beige at higher
     specificity, so the drinks section is untouched.

   Dead rules were skipped on purpose: `.add_to_cart`,
   `.checkout_form`, `.chip_size`, `.tag_box_pr`, `.footer_bot`
   and the rest belong to the deleted store/checkout pages.
   ============================================================== */

:root { --surface: #491f11; }

.left_side,
.contact_body,
.ii,
.button_box.dark { background-color: var(--surface); }

/* The footer's one-off #292622 goes with them. */
.footer { background-color: var(--surface); }


/* ==============================================================
   Header — transparent over the hero, solid once it is past
   ==============================================================
   The template ships a header that is `#2c2c2c00` over the hero and
   only gains a background once the hero scrolls away. The
   "Dark surface" pass above painted BOTH states `--surface`, which
   lost the effect — and on the pages whose header links are
   `.h-link.dark` it put #2c2c2c ink on a #491f11 panel, about
   1.3:1. Both halves are fixed here.

   THERE IS ONE COLOURED STATE NOW, not two. `is-colored` and
   `is-colored-diff` are the same beige glass — `--biege` at .85
   with a 10px backdrop blur — so the header reads the same on every
   page and the ink question has exactly one answer: **the coloured
   header is always light, and its ink is always `--dark`.** The
   ink-on-ink trap the two states used to pose is closed.

   The classes are still two because the script tells them apart,
   and which one a page gets is decided by the IntersectionObserver
   in its script tail from the section it finds:

     #hero-section  index + the three story pages  → `is-colored`
     #diff-hero     menu.html                      → `is-colored-diff`
     no target      the legal pages                → `is-colored-diff`
                                                      added up front

   `is-colored-diff` shipped with NO RULE AT ALL, which is why
   menu.html had no scrolled state before this. `is-colored` was
   also being fought over: every page carried a second, scroll-based
   header script with inverted logic that ran last and won, so the
   homepage was solid over its hero and never went back. It was
   deleted on 27 August 2026 — see CLAUDE.md 19.

   Backdrop blur and the hairline started as the template's own
   `.header.is-colored`; the 0.45s `transition:all` is still the
   template's, so the change of state fades rather than snaps, ink
   included — `.h-link` and `.link_header` carry their own 0.4s.
   These rules win over the 991/767/479 restatements by being later
   in the cascade at equal specificity.
   ============================================================== */

.header { background-color: transparent; }

/* ONE material for both coloured states. `is-colored` used to be the dark
   `--surface` panel and `is-colored-diff` this beige glass; the two are the
   same thing now, so the ink question below is the only thing left to get
   right. Keep them in one rule — splitting them is how they drift apart. */
.header.is-colored,
.header.is-colored-diff {
  -webkit-backdrop-filter: blur(10px) saturate(1.08);
  backdrop-filter: blur(10px) saturate(1.08);
  background-color: #d8cbb8d9;          /* --biege at .85 */
  border-bottom: 1px solid #2c2c2c1f;
}

/* THE INK HAS TO MOVE WITH THE GLASS, and only on the pages that do not
   already carry `.dark` in their markup — the hero pages, whose header is
   beige-on-photograph while it is transparent. Beige ink on beige glass is
   invisible; this is the same ink-on-ink trap the two coloured states used
   to pose, closed for good by making the coloured header always light and
   always dark-inked.

   Worst case for #2c2c2c on `--biege` at .85 is over pure black, where the
   glass composites to rgb(184,173,156) — 6.31:1, past AA at any size. Over
   anything lighter it only improves, so no background can break it. */
.header.is-colored .h-link,
.header.is-colored .link_header,
.header.is-colored .menu_txt { color: var(--dark); }

.header.is-colored .h-link:hover,
.header.is-colored .link_header:hover { color: var(--primary); }

.header.is-colored .line_1,
.header.is-colored .line_2 { background-color: var(--dark); }

.header.is-colored .line_splitter { background-color: #2c2c2c59; opacity: 1; }


/* ==============================================================
   Kontakt — the homepage contact band
   ==============================================================
   The last section before the footer on `index.html`, and the only
   place the restaurant's own details are laid out on the site now:
   `contact.html` was folded into this and archived. The header, the
   mobile menu and the footer all point at `index.html#kontakt`.

   Two panels under a centred head — business info left, map right.
   The head follows the same badge / `.h2` / lead idiom as
   `.dh-cf__head` and `.dh-tv2__head`.

   THE MAP IS A GOOGLE MAPS `output=embed` IFRAME, and it is the one
   thing on this site that talks to a third-party host at page load.
   Everything else — fonts, brand marks, libraries — is vendored
   precisely so it does not (see CLAUDE.md 3 and 15). It is
   `loading="lazy"`, so nothing is fetched until the band is near the
   viewport, but a visitor who scrolls that far does hand Google an IP
   and take Google's cookies. TBC-CHECKLIST.md carries the entry.

   GROUND IS BEIGE, NOT `--surface`, and that is a decision about the
   map rather than about the section. The embed renders in Google's
   own light styling and cannot be themed without the paid Embed API,
   so a bright rectangle on the dark saffron ground reads as a hole
   punched in the page. On beige it sits down. The weight the band
   needs comes from the info panel instead, which IS `--surface`, so
   the row goes dark-left / light-right and the beige testimonials
   above still have an edge to end on.

   px/rem only, never `em` — `body` is `font-size:1vw`. The one
   exception is the heading, on the template's `.h2` so it scales in
   step with every other section title. It deliberately does NOT also
   take `.middle`: the head is already centred by its own flex column,
   and that pairing is the trap `.dh-cf__title`, `.dh-tv2__title` and
   `.dh-lunch__title` all document. `width: auto` is pinned anyway.
   -------------------------------------------------------------- */

.contact_section.dh-ct {
  position: relative;
  padding: 6rem 0 5rem;
  background-color: var(--biege, #d8cbb8);
  color: var(--dark, #2c2c2c);
  font-family: Satoshi, Arial, sans-serif;
}

/* The band above is beige too. A hairline is how this theme separates
   two planes of the same value — the same move as `.dh-f2`'s rules. */
.contact_section.dh-ct:before {
  content: "";
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  width: calc(100% - 56px);
  max-width: 1180px;
  height: 1px;
  background-color: rgba(44, 44, 44, 0.16);
}

.dh-ct__inner {
  width: 100%;
  max-width: 1180px;
  margin: 0 auto;
  padding: 0 28px;
}

/* ---- Head ----------------------------------------------------- */

.dh-ct__head {
  display: flex;
  flex-direction: column;
  align-items: center;
  max-width: 720px;
  margin: 0 auto;
  text-align: center;
}

/* The site's tag idiom: hairline pill, uppercase, tracked out, no
   fill. Shared with `.dh-cf__badge`, `.dh-tv2__badge` and `.tag_new`. */
.dh-ct__badge {
  display: inline-block;
  padding: 0.4rem 0.9rem;
  border: 1px solid rgba(44, 44, 44, 0.3);
  border-radius: 999px;
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

/* A SPLIT HEADLINE — `text-split letters-fade-in`, like every other
   section title. See `.dh-tv2__title` for why these four stopped being
   the exception. */
.dh-ct__title {
  width: auto;
  max-width: 100%;
  margin: 1.4rem 0 0;
}

.dh-ct__lead {
  margin: 1.1rem 0 0;
  max-width: 460px;
  font-size: 1rem;
  line-height: 1.55;
  opacity: 0.78;
}

/* ---- The two panels ------------------------------------------
   Equal height by default (grid stretches), which is what lets the
   map fill its column rather than sit at a fixed height inside it.
   -------------------------------------------------------------- */

.dh-ct__grid {
  display: grid;
  grid-template-columns: minmax(0, 0.82fr) minmax(0, 1.18fr);
  gap: 20px;
  margin-top: 3.2rem;
}

/* ---- Info panel ---------------------------------------------- */

.dh-ct__info {
  display: flex;
  flex-direction: column;
  padding: 2.6rem 2.4rem;
  border-radius: 2px;
  background-color: var(--surface, #491f11);
  color: var(--biege, #d8cbb8);
}

.dh-ct__facts {
  margin: 0;
  padding: 0;
}

/* Hairlines between the rows, none above the first or below the last
   — the panel's own edge already does that job. */
.dh-ct__fact + .dh-ct__fact {
  margin-top: 1.5rem;
  padding-top: 1.5rem;
  border-top: 1px solid rgba(216, 203, 184, 0.18);
}

.dh-ct__label {
  margin: 0;
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  /* Composited over `--surface` this is the same 4.69:1 floor the
     footer links sit on. Do not drop the alpha without re-measuring
     — see the "Dark surface" note at the foot of this file. */
  color: rgba(216, 203, 184, 0.66);
}

.dh-ct__value {
  margin: 0.55rem 0 0;
  font-size: 1.05rem;
  line-height: 1.5;
}

.dh-ct__line { display: block; }

.dh-ct__link {
  color: var(--biege, #d8cbb8);
  text-decoration: none;
  border-bottom: 1px solid rgba(216, 203, 184, 0.35);
  transition: color 0.3s, border-color 0.3s;
}

.dh-ct__link:hover,
.dh-ct__link:focus-visible {
  color: var(--primary, #d49653);
  border-color: var(--primary, #d49653);
}

/* ---- Actions -------------------------------------------------
   `data-open-reserve` / `data-open-order` are the modal triggers from
   CLAUDE.md 7, so these carry no markup of their own. The `href` is
   the hash those same scripts deep-link on, which is also where a
   visitor with no JS lands.
   -------------------------------------------------------------- */

.dh-ct__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: auto;
  padding-top: 2.4rem;
}

.dh-ct__btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 44px;
  padding: 0 1.4rem;
  border: 1px solid var(--primary, #d49653);
  border-radius: 2px;
  background-color: var(--primary, #d49653);
  color: var(--dark, #2c2c2c);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  text-decoration: none;
  cursor: pointer;
  transition: background-color 0.3s, border-color 0.3s, color 0.3s;
}

.dh-ct__btn:hover,
.dh-ct__btn:focus-visible {
  background-color: var(--biege, #d8cbb8);
  border-color: var(--biege, #d8cbb8);
  color: var(--dark, #2c2c2c);
}

.dh-ct__btn_ghost {
  border-color: rgba(216, 203, 184, 0.45);
  background-color: transparent;
  color: var(--biege, #d8cbb8);
}

.dh-ct__btn_ghost:hover,
.dh-ct__btn_ghost:focus-visible {
  background-color: var(--primary, #d49653);
  border-color: var(--primary, #d49653);
  color: var(--dark, #2c2c2c);
}

.dh-ct__route {
  align-self: flex-start;
  margin-top: 1.4rem;
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--primary, #d49653);
  transition: color 0.3s;
}

.dh-ct__route:after { content: " \2197"; }

.dh-ct__route:hover,
.dh-ct__route:focus-visible { color: var(--biege, #d8cbb8); }

/* ---- Map panel -----------------------------------------------
   The iframe is `inset: 0` inside a relative frame, so it takes
   whatever height the info panel beside it settles at. `min-height`
   is the floor for when the info panel is the shorter of the two.
   -------------------------------------------------------------- */

.dh-ct__map {
  position: relative;
  min-height: 520px;
  border: 1px solid rgba(44, 44, 44, 0.16);
  border-radius: 2px;
  overflow: hidden;
  background-color: rgba(44, 44, 44, 0.06);
}

.dh-ct__frame {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
  display: block;
}

/* Over the embed's bottom-right corner. Google puts its own
   "Zobrazit na větší mapě" link bottom-LEFT, so the two do not
   collide; this one is the site's own control and says where it goes. */
.dh-ct__maplink {
  position: absolute;
  right: 12px;
  bottom: 12px;
  z-index: 2;
  padding: 0.55rem 1rem;
  border: 1px solid var(--surface, #491f11);
  border-radius: 2px;
  background-color: var(--surface, #491f11);
  color: var(--biege, #d8cbb8);
  font-size: 0.66rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  text-decoration: none;
  transition: background-color 0.3s, border-color 0.3s, color 0.3s;
}

.dh-ct__maplink:hover,
.dh-ct__maplink:focus-visible {
  background-color: var(--primary, #d49653);
  border-color: var(--primary, #d49653);
  color: var(--dark, #2c2c2c);
}

/* ---- Narrow screens -------------------------------------------
   One column below 991px, info first: the address and the phone are
   what a guest on a phone came for, and the map follows.
   -------------------------------------------------------------- */

@media screen and (max-width: 991px) {
  .contact_section.dh-ct { padding: 5rem 0 4rem; }
  .dh-ct__grid {
    grid-template-columns: minmax(0, 1fr);
    margin-top: 2.8rem;
  }
  .dh-ct__map { min-height: 420px; }
}

@media screen and (max-width: 767px) {
  .contact_section.dh-ct { padding: 4.5rem 0 3.5rem; }
  .contact_section.dh-ct:before { width: calc(100% - 40px); }
  .dh-ct__inner { padding: 0 20px; }
  .dh-ct__info { padding: 2rem 1.5rem; }
  .dh-ct__actions { padding-top: 2rem; }
  .dh-ct__btn { flex: 1 1 100%; }
  .dh-ct__map { min-height: 340px; }
}

/* Between 768 and 991 the panel is the full measure and four stacked
   facts leave most of it empty. Two columns fill it; the hairlines go
   with the stack they were dividing, the same way the footer's own
   four-column grid carries none. */
@media screen and (min-width: 768px) and (max-width: 991px) {
  .dh-ct__facts {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 1.6rem 3rem;
  }
  .dh-ct__fact + .dh-ct__fact {
    margin-top: 0;
    padding-top: 0;
    border-top: 0;
  }
}


/* ==============================================================
   Jídelní lístek — search, filters and the dish badges
   ==============================================================
   `menu.html` is 264 rows over 13 sections and, until this, the only
   way through it was to scroll. This adds a sticky toolbar — search,
   diet / heat / allergen pills, a live count — plus a badge row under
   every dish and an active marker on the category bar that was
   already at the foot of the page.

   THE ENHANCEMENT IS OPT-IN. The toolbar ships `hidden` in the markup
   and `assets/menu-filter.js` is the only thing that reveals it;
   NOTHING BELOW HIDES A DISH. That is the same invariant
   `.dh-tv2__cols.is_looping`, `.dh-lunch__deck.is_stacked` and
   `.dh-cf__stage.is_coverflow` keep, and for the same reason: this
   site has already lost content once to a class that hid something
   the script was supposed to reveal and then did not run. With no
   JavaScript a visitor gets the whole lístek, badges and all.

   `.dh-mf__tags` under each dish is likewise plain markup, stamped in
   by `tools/menu-tags.py`. The Veg mark, the chilli gauge and the
   allergen numbers are readable with the script deleted.

   SIZED IN PX/REM, NEVER `em` — `body` is `font-size:1vw`, so an `em`
   would make the search field grow with the window. Same rule as the
   modal, lunch, testimonial and footer CSS.

   THREE COLOURS ARE DECLARED HERE and both are measured against
   `--biege` #d8cbb8, the ground the menu sits on:

     --dh-heat  #9c3a17   the chilli gauge.  4.34:1 — an icon, so the
                          bar is 3:1. `--surface` #491f11 was the first
                          choice and is 8.84:1, but at 12px it reads
                          black rather than red and stops saying
                          "chilli". This is the same saffron-red hue
                          lifted to icon weight.
     --dh-veg   #3f5b26   the Veg mark. 4.81:1, so it passes AA as
                          text. A green on a beige-and-saffron site is
                          a deliberate exception: it is signage, not
                          decoration, and green-for-vegetarian is the
                          one convention an Indian menu can rely on
                          every guest already knowing.
     --dh-mute  #57544f   the allergen line — `--dark` composited on
                          the beige at 0.75. 4.72:1. NOT an `opacity`
                          or an alpha: at the .65 the template gives
                          `.description_menu` this lands at 2.9:1, and
                          allergen information is the last thing on
                          the page that should be hard to read.
   ============================================================== */

:root {
  --dh-heat: #9c3a17;
  --dh-veg: #3f5b26;
  --dh-mute: #57544f;
  --dh-rule: rgba(44, 44, 44, 0.2);
  /* Overwritten by menu-filter.js from the real header height; the
     fallback only ever paints if the script dies between revealing the
     toolbar and measuring, which it cannot. */
  --dh-mf-top: 64px;
  --dh-mf-anchor: 140px;
}

/* ---- The toolbar ---------------------------------------------
   Full bleed rather than inset: `.wrapper_base.menu_wrapper` has no
   horizontal padding, and a sticky bar with side margins lets the
   list scroll through the gutters beside it. The inner padding
   matches `.menu_overview`'s 28px so the search field lines up with
   the standfirst above it.
   --------------------------------------------------------------- */

.dh-mf__sentinel {
  height: 1px;
  margin-bottom: -1px;
}

/* The script hides the clear-x, the reset and the count badge with the
   `hidden` ATTRIBUTE, and every one of them is given an explicit
   `display` below — which beats the UA sheet's `[hidden]{display:none}`
   at equal specificity and leaves them all on screen. (It showed as a
   clear-x on an empty field and a "0" pinned to the Filtry button.)
   Restated here so the attribute wins. Any new control in this toolbar
   that the script toggles with `hidden` has to join this list. */
.dh-mf[hidden],
.dh-mf__clearq[hidden],
.dh-mf__reset[hidden],
.dh-mf__result[hidden],
.dh-mf__badgecount[hidden],
.dh-mf__empty[hidden] { display: none; }

.dh-mf {
  position: sticky;
  top: var(--dh-mf-top, 64px);
  z-index: 80;                       /* under `.header` (99) */
  margin: 34px 0 40px;
  padding: 14px 28px 13px;
  border-top: 1px solid var(--dh-rule);
  border-bottom: 1px solid var(--dh-rule);
  background-color: #d8cbb8f2;       /* --biege at .95 */
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  color: var(--dark, #2c2c2c);
  font-family: Satoshi, Arial, sans-serif;
}

.dh-mf__bar {
  display: flex;
  align-items: center;
  gap: 10px;
}

/* ---- Search field --------------------------------------------- */

.dh-mf__search {
  position: relative;
  display: flex;
  align-items: center;
  flex: 1 1 auto;
  min-width: 0;
}

.dh-mf__search_icon {
  position: absolute;
  left: 14px;
  width: 17px;
  height: 17px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
  opacity: 0.5;
  pointer-events: none;
}

.dh-mf__input {
  width: 100%;
  min-width: 0;
  padding: 11px 40px 11px 41px;
  border: 1px solid rgba(44, 44, 44, 0.28);
  border-radius: 2px;
  background-color: #e6dccd;         /* 10.3:1 with --dark */
  color: var(--dark, #2c2c2c);
  font-family: Satoshi, Arial, sans-serif;
  font-size: 15px;
  line-height: 1.3;
  -webkit-appearance: none;
  appearance: none;
  transition: border-color 0.25s, box-shadow 0.25s;
}

.dh-mf__input::placeholder { color: rgba(44, 44, 44, 0.55); opacity: 1; }

.dh-mf__input:focus {
  outline: none;
  border-color: var(--primary, #d49653);
  box-shadow: 0 0 0 2px rgba(212, 150, 83, 0.35);
}

/* The field supplies its own clear button, so the browser's must go —
   otherwise Safari and Chrome stack a second X on top of it. */
.dh-mf__input::-webkit-search-cancel-button,
.dh-mf__input::-webkit-search-decoration { -webkit-appearance: none; display: none; }

.dh-mf__clearq {
  position: absolute;
  right: 6px;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  padding: 0;
  border: 0;
  border-radius: 2px;
  background: transparent;
  color: var(--dark, #2c2c2c);
  cursor: pointer;
  opacity: 0.55;
  transition: opacity 0.2s;
}
.dh-mf__clearq:hover { opacity: 1; }
.dh-mf__clearq svg {
  width: 15px;
  height: 15px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
}

/* ---- Count, reset, the Filtry toggle -------------------------- */

.dh-mf__result {
  margin: 0;
  flex: 0 0 auto;
  font-size: 12.5px;
  font-weight: 500;
  letter-spacing: 0.02em;
  color: var(--dh-mute);
  white-space: nowrap;
}
.dh-mf__result:empty { display: none; }

.dh-mf__reset {
  flex: 0 0 auto;
  padding: 0;
  border: 0;
  border-bottom: 1px solid currentColor;
  border-radius: 0;
  background: transparent;
  color: var(--dh-mute);
  font-family: Satoshi, Arial, sans-serif;
  font-size: 12.5px;
  font-weight: 500;
  white-space: nowrap;
  cursor: pointer;
  transition: color 0.2s;
}
.dh-mf__reset:hover { color: var(--surface, #491f11); }

.dh-mf__toggle {
  display: none;                     /* only while stuck, or on a phone */
  align-items: center;
  gap: 7px;
  flex: 0 0 auto;
  padding: 10px 14px;
  border: 1px solid rgba(44, 44, 44, 0.28);
  border-radius: 2px;
  background-color: transparent;
  color: var(--dark, #2c2c2c);
  font-family: Satoshi, Arial, sans-serif;
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  transition: border-color 0.25s;
}
.dh-mf__toggle:hover { border-color: var(--primary, #d49653); }
.dh-mf__toggle svg {
  width: 16px;
  height: 16px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
}
.dh-mf__badgecount {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: 9px;
  background-color: var(--surface, #491f11);
  color: var(--biege, #d8cbb8);
  font-size: 11px;
  font-weight: 600;
  line-height: 1;
}

/* ---- The pill panel ------------------------------------------- */

.dh-mf__panel {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 22px;
  margin-top: 12px;
}

.dh-mf__group {
  display: flex;
  align-items: center;
  gap: 9px;
  flex-wrap: wrap;
}

.dh-mf__legend {
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--dh-mute);
}

.dh-mf__pills {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

/* The pill shape is `.tag_new`'s — the badge this menu already uses.
   Selected goes to the dark saffron panel rather than to gold: the
   category bar at the foot of the page is a solid `--primary` slab,
   and a second gold thing on screen stops reading as "chosen".
   Beige on `--surface` is 8.84:1. */
.dh-mf__pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 13px;
  border: 1px solid rgba(44, 44, 44, 0.28);
  border-radius: 2em;
  background-color: transparent;
  color: var(--dark, #2c2c2c);
  font-family: Satoshi, Arial, sans-serif;
  font-size: 12.5px;
  font-weight: 500;
  line-height: 1;
  letter-spacing: 0.01em;
  cursor: pointer;
  transition: background-color 0.25s, border-color 0.25s, color 0.25s;
}
.dh-mf__pill:hover { border-color: var(--surface, #491f11); }

.dh-mf__pill[aria-pressed="true"] {
  border-color: var(--surface, #491f11);
  background-color: var(--surface, #491f11);
  color: var(--biege, #d8cbb8);
}

.dh-mf__pill:focus-visible,
.dh-mf__toggle:focus-visible,
.dh-mf__reset:focus-visible,
.dh-mf__clearq:focus-visible {
  outline: 2px solid var(--primary, #d49653);
  outline-offset: 2px;
}

.dh-mf__pills .dh-mf__pip { color: var(--dh-heat); }
/* On the dark pill the gauge has to come up off the ground with it —
   #9c3a17 on #491f11 is 1.6:1 and disappears. Gold is 5.6:1 there. */
.dh-mf__pill[aria-pressed="true"] .dh-mf__pip { color: var(--primary, #d49653); }

.dh-mf__pips { display: inline-flex; align-items: center; gap: 1px; }

.dh-mf__note {
  margin: 11px 0 0;
  font-size: 11.5px;
  line-height: 1.5;
  color: var(--dh-mute);
  max-width: 92ch;
}

/* ---- Collapsed while stuck ------------------------------------
   At rest every pill is on screen, because a filter nobody can see is
   a filter nobody uses. Pinned under the header the toolbar has to
   earn its space back, so it drops to the one row the search field
   needs and the pills go behind the Filtry button. `is_open` — set by
   that button — overrides it without leaving the top of the page.
   --------------------------------------------------------------- */

.dh-mf.is_stuck { padding-top: 11px; padding-bottom: 10px; }
.dh-mf.is_stuck .dh-mf__panel,
.dh-mf.is_stuck .dh-mf__note { display: none; }
.dh-mf.is_stuck.is_open .dh-mf__panel { display: flex; }
.dh-mf.is_stuck.is_open .dh-mf__note { display: block; }
.dh-mf.is_stuck .dh-mf__toggle { display: inline-flex; }

/* ---- Empty state ---------------------------------------------- */

.dh-mf__empty {
  padding: 64px 28px 72px;
  text-align: center;
  font-family: Satoshi, Arial, sans-serif;
  color: var(--dark, #2c2c2c);
}
.dh-mf__empty_title {
  margin: 0 0 8px;
  font-family: 'TT Ramillas Variable', Georgia, serif;
  font-size: 34px;
  font-weight: 400;
  letter-spacing: -0.02em;
}
.dh-mf__empty_text {
  margin: 0 0 18px;
  font-size: 14px;
  color: var(--dh-mute);
}
.dh-mf__empty .dh-mf__reset {
  border: 1px solid rgba(44, 44, 44, 0.28);
  border-radius: 2px;
  padding: 10px 18px;
  font-size: 13px;
  color: var(--dark, #2c2c2c);
}
.dh-mf__empty .dh-mf__reset:hover {
  border-color: var(--surface, #491f11);
  background-color: var(--surface, #491f11);
  color: var(--biege, #d8cbb8);
}

/* ---- The badge row under each dish ----------------------------
   Static markup from tools/menu-tags.py, so it survives with no JS.
   It sits OUTSIDE `.description_menu`, which the template runs at
   `opacity:.65` — allergen numbers must not inherit that.
   --------------------------------------------------------------- */

.dh-mf__tags {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 14px;
  margin-top: 11px;
  font-family: Satoshi, Arial, sans-serif;
}

.dh-mf__badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 10.5px;
  font-weight: 600;
  line-height: 1;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.dh-mf__badge--veg {
  padding: 3px 7px 3px 8px;
  border: 1px solid currentColor;
  border-radius: 2em;
  color: var(--dh-veg);
}

.dh-mf__badge--heat { gap: 1px; color: var(--dh-heat); }

.dh-mf__pip {
  width: 12px;
  height: 12px;
  flex: none;
  fill: currentColor;
}
/* The gauge is 1-of-3, not a bare count: one chilli on its own does
   not say whether one is the top of the scale. */
.dh-mf__pip--off { opacity: 0.2; }

.dh-mf__badge--alrg {
  gap: 5px;
  color: var(--dh-mute);
  font-weight: 500;
  letter-spacing: 0.06em;
}
.dh-mf__alrg_label { opacity: 0.85; }
.dh-mf__badge--alrg abbr {
  border-bottom: 1px dotted currentColor;
  text-decoration: none;
  font-variant-numeric: tabular-nums;
  cursor: help;
}

/* Screen-reader text for the marks above, which are glyphs. */
.dh-mf__sr {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ---- Search hits ---------------------------------------------- */

.dh-mf__hit {
  padding: 0 1px;
  border-radius: 2px;
  background-color: rgba(212, 150, 83, 0.45);
  color: inherit;
}

/* ---- What the filter hides ------------------------------------
   The ONLY rules on this stylesheet that take a dish off the page,
   and `filter()` in menu-filter.js is the only thing that can add
   the class. Nothing here fires without the script.
   --------------------------------------------------------------- */

.menu_box.is_filtered_out,
.rest_section.is_filtered_out,
.link_box.is_filtered_out { display: none; }

/* Grid borders while filtering — see the long note in menu-filter.js.
   :nth-child counts rows that are display:none, so the template's own
   column and end-of-list rules land on the wrong cells the moment
   anything is hidden. `.is_col_odd` / `.is_last_row` are counted over
   what is actually on screen and beat those selectors on specificity,
   so cascade order does not matter. Scoped to >=992px, which is the
   only width `.grid_menu` has two columns. */
@media screen and (min-width: 992px) {
  .restaurant_menu.is_filtering .menu_box { border-right: 0; }
  .restaurant_menu.is_filtering .menu_box.is_col_odd {
    border-right: 1px solid var(--dh-rule);
  }
  .restaurant_menu.is_filtering .menu_box { border-bottom: 1px solid var(--dh-rule); }
  .restaurant_menu.is_filtering .menu_box.is_last_row { border-bottom: 0; }
}

/* ---- The category bar knows where you are ---------------------
   13 links in a fixed gold bar at the foot of the page, and until now
   nothing in it said which section you were reading. `.is_current` is
   set by the scroll spy in menu-filter.js.
   --------------------------------------------------------------- */

.link_box.is_current {
  background-color: var(--surface, #491f11);
  color: var(--biege, #d8cbb8);
}
.link_box.is_current:hover { opacity: 1; }

/* ---- Narrow screens -------------------------------------------
   The pills are always behind the Filtry button below 992px: five diet
   pills, three heat, four more and their legends do not fit next to a
   search field on a phone, and the toolbar is sticky — it would take
   half the screen with it.
   --------------------------------------------------------------- */

@media screen and (max-width: 991px) {
  .dh-mf { padding-left: 20px; padding-right: 20px; }
  .dh-mf__panel,
  .dh-mf__note { display: none; }
  .dh-mf.is_open .dh-mf__panel { display: flex; }
  .dh-mf.is_open .dh-mf__note { display: block; }
  .dh-mf__toggle { display: inline-flex; }
  /* Search and Filtry share the top row; the count and the reset drop to
     a second one — and only exist while something is filtered, so at rest
     the sticky bar is the height of the field and nothing else. `search`
     growing to fill is what forces the wrap, so the two never squeeze in
     beside it. */
  .dh-mf__bar { flex-wrap: wrap; row-gap: 9px; }
  .dh-mf__search { order: 1; flex: 1 1 auto; }
  .dh-mf__toggle { order: 2; flex: 0 0 auto; }
  .dh-mf__result { order: 3; }
  .dh-mf__reset { order: 4; }
  .dh-mf__input { font-size: 16px; }   /* under 16px iOS zooms the page */
}

@media screen and (max-width: 767px) {
  .dh-mf { padding-left: 16px; padding-right: 16px; }
  .dh-mf__panel { gap: 10px 0; }
  .dh-mf__group { flex: 1 1 100%; }
  .dh-mf__empty { padding: 48px 16px 56px; }
  .dh-mf__empty_title { font-size: 28px; }
  /* Below 992 the grid is one column, so the badge row has the width to
     sit on the same line as nothing else. Give it a little more air. */
  .dh-mf__tags { margin-top: 13px; }
}

/* ---- Reduced motion -------------------------------------------
   The pill and field transitions are colour only, so they stay. The
   two smooth scrolls this script starts — a category jump and the
   scroll back to the toolbar after a reset — are the ones to drop.
   --------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  .dh-mf,
  .dh-mf * { scroll-behavior: auto; }
  .dh-mf__pill,
  .dh-mf__input,
  .dh-mf__toggle,
  .dh-mf__clearq,
  .dh-mf__reset { transition: none; }
}

/* ==== Časté dotazy — the FAQ band (tools/make-seo.py) ==== */
/* Sized in px/rem, never em: body is font-size:1vw and this must not scale
   with the viewport. Same rule as the modal, lunch, testimonial and footer
   CSS. The heading is the one exception - it borrows the template's .h2 so
   it scales with the section titles around it, which means it has to pin
   width:auto against .middle's 52ch (the trap .dh-cf__title, .dh-tv2__title
   and .dh-lunch__title all document). */
.faq_section.dh-faq { background: var(--biege); padding: 96px 0; width: 100vw; }
.dh-faq__inner { max-width: 72rem; margin: 0 auto; padding: 0 24px; }
.dh-faq__head { max-width: 46rem; margin: 0 0 40px; }
.dh-faq__badge {
  font-family: Satoshi, Arial, sans-serif; font-size: 13px; font-weight: 500;
  letter-spacing: .14em; text-transform: uppercase; color: var(--primary);
  margin-bottom: 12px;
}
/* line-height, because Czech uppercase diacritics need the room: the
   template's .h2 is tight enough that the carons on Č and Ě in
   "NEJČASTĚJI" collide into the line above. Any multi-line Czech heading
   set in .h2 has this problem - it just does not show on a heading whose
   second line happens to have no tall marks. */
.dh-faq__title { width: auto; margin: 0 0 14px; line-height: 1.14; }
.dh-faq__lead {
  font-family: Satoshi, Arial, sans-serif; font-size: 16px; line-height: 1.6;
  color: var(--dh-mute, #57544f); margin: 0;
}
.dh-faq__link { color: var(--dark); text-decoration: underline; }
.dh-faq__link:hover { color: var(--primary); }

.dh-faq__list { border-top: 1px solid rgba(44,44,44,.18); }
.dh-faq__item { border-bottom: 1px solid rgba(44,44,44,.18); }
.dh-faq__q {
  font-family: Satoshi, Arial, sans-serif; font-size: 18px; font-weight: 500;
  line-height: 1.45; color: var(--dark); cursor: pointer; list-style: none;
  padding: 20px 44px 20px 0; position: relative;
}
.dh-faq__q::-webkit-details-marker { display: none; }
/* A plain + / − rather than a rotating chevron: the site separates planes
   with hairlines and has no icon system beyond the footer brand marks. */
.dh-faq__q::after {
  content: "+"; position: absolute; right: 8px; top: 50%;
  transform: translateY(-50%); font-size: 22px; line-height: 1;
  color: var(--primary); transition: color .18s ease;
}
.dh-faq__item[open] .dh-faq__q::after { content: "\2013"; }
.dh-faq__q:hover { color: var(--primary); }
.dh-faq__a { padding: 0 44px 24px 0; }
.dh-faq__a p {
  font-family: Satoshi, Arial, sans-serif; font-size: 16px; line-height: 1.7;
  color: var(--dh-mute, #57544f); margin: 0; max-width: 62ch;
}

@media (max-width: 767px) {
  .faq_section.dh-faq { padding: 64px 0; }
  .dh-faq__q { font-size: 16px; padding-right: 36px; }
  .dh-faq__a { padding-right: 0; }
}
