/* ============================================================
   LOKI BURGERS — design tokens
   ============================================================ */
:root{
  /* --- brand palette — official brand manual: #1B4143 / #26685E /
     #27977B / #F2D27D / #000000. Variable NAMES kept as-is (they're
     referenced all over this file) — only the hex values changed to
     match, plus one new variable (--teal-light) for the palette's
     3rd teal/green that had no prior equivalent. --gold-deep has no
     official counterpart (the manual gives 5 flat colors, no
     separate "deep" shade) — it's a manually darkened --gold, kept
     only for shadow/depth accents where --gold itself is already
     used on the same element. --red is retired: the manual has no
     red, so every former var(--red) below now points at --teal-dark. */
  --teal:        #26685E;
  --teal-dark:   #1B4143;
  --teal-light:  #27977B;
  --gold:        #F2D27D;
  --gold-deep:   #d9ad5a;
  --ink:         #000000;
  --paper:       #ffffff;
  --paper-warm:  #fbf2e2;

  /* --- type — official brand fonts, self-hosted via @font-face
     below (see assets/fonts/). 'CE' in the Passion One file name is
     the Central European glyph set — required for Czech diacritics. --- */
  --font-display: 'Passion One', 'Impact', cursive;
  --font-body:    'Gotham', 'Segoe UI', sans-serif;
  --font-kicker:  'Gotham', 'Segoe UI', sans-serif;
  /* The old comic display font, brought back on purpose for a short
     explicit list of spots (hero lines 1–2, .menu-week-banner,
     .menu-card-tag, .seam-tag) — not a site-wide default, so it's
     its own variable rather than replacing --font-display. */
  --font-comic:   'Bangers', 'Impact', cursive;

  /* --- misc --- */
  --border-w: 3px;
  --shadow-hard: 6px 6px 0 var(--ink);
  --header-h: 84px;
}

@font-face{
  font-family: 'Passion One';
  src: url("../assets/fonts/PassionOneCE-Bold.84aaf4398f5b.woff2") format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face{
  font-family: 'Gotham';
  src: url("../assets/fonts/Gotham-Light.c20fcd8ba76d.woff2") format('woff2');
  font-weight: 300;
  font-style: normal;
  font-display: swap;
}
@font-face{
  font-family: 'Gotham';
  src: url("../assets/fonts/Gotham-Book.7d6d720f83b1.woff2") format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face{
  font-family: 'Gotham';
  src: url("../assets/fonts/Gotham-Medium.b7382415f9f4.woff2") format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face{
  font-family: 'Gotham';
  src: url("../assets/fonts/Gotham-Bold.c4fa668abd29.woff2") format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
/* Bangers — was loaded from Google Fonts (fonts.googleapis.com), now
   self-hosted the same way as the brand fonts above: removes a
   render-blocking cross-origin request (Google Insights flagged it,
   ~750ms — mostly connection latency, not file size). Same two
   unicode-range subsets Google itself split the file into (latin +
   latin-ext — latin-ext covers Czech-specific diacritics like č/ř/š/ž/ě,
   see the Passion One CE comment above), so the browser still only
   downloads the subset it actually needs. */
@font-face{
  font-family: 'Bangers';
  src: url("../assets/fonts/Bangers-latin.d09b4fad5242.woff2") format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  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: 'Bangers';
  src: url("../assets/fonts/Bangers-latin-ext.fd15c519ddba.woff2") format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  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;
}

/* ============================================================
   RESET
   ============================================================ */
*, *::before, *::after{ box-sizing: border-box; }
html{ scroll-behavior: smooth; }
body{
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-body);
  font-weight: 500;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}
img{ max-width: 100%; display: block; }
a{ color: inherit; text-decoration: none; }
ul{ margin:0; padding:0; list-style:none; }
h1,h2,h3,p,figure,figcaption{ margin:0; }
button{ font-family: inherit; }

@media (prefers-reduced-motion: reduce){
  *, *::before, *::after{
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

:focus-visible{
  outline: 3px solid var(--gold);
  outline-offset: 3px;
}

.sr-only{
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0,0,0,0);
  white-space: nowrap;
  border: 0;
}

/* Fixed header covers the top of whatever's scrolled to via an
   anchor link (nav, or any #hash) — this shifts the landing point
   down by the header's own height so content never ends up hidden
   underneath it. */
#hero, #tydenni-nabidka, #stala-nabidka, #pribeh, #elixir, #galerie, #rezervace, #kontakt{
  scroll-margin-top: var(--header-h);
}

/* ============================================================
   HEADER — fixed/sticky. Starts transparent over the hero (dark
   photo behind it → on-dark logo, light nav text). JS adds
   .is-scrolled once the user scrolls past a threshold, which swaps
   in a solid light background, the full-color logo, and dark nav
   text — see the scroll handler in js/main.js. Both logo <img>s are
   stacked in the same box and crossfade via opacity; nothing swaps
   by changing `src` (avoids a flash/reflow on toggle).
   ============================================================ */
.site-header{
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 100;
  height: var(--header-h);
  background: transparent;
  box-shadow: none;
  transition: background-color .3s ease, box-shadow .3s ease;
}
.site-header.is-scrolled{
  background: var(--paper);
  box-shadow: 0 2px 14px rgba(0,0,0,0.18);
}
.site-header-inner{
  max-width: 1320px;
  height: 100%;
  margin: 0 auto;
  padding: 0 clamp(1.25rem, 4vw, 2.5rem);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
}

.site-header-logo{
  position: relative;
  display: block;
  height: 52px;
  aspect-ratio: 110.55 / 123.33;
  flex: 0 0 auto;
}
.site-header-logo-img{
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  transition: opacity .3s ease;
}
.site-header-logo-img--dark{ opacity: 1; }
.site-header-logo-img--color{ opacity: 0; }
.site-header.is-scrolled .site-header-logo-img--dark{ opacity: 0; }
.site-header.is-scrolled .site-header-logo-img--color{ opacity: 1; }

.site-header-nav{
  display: flex;
  align-items: center;
  gap: clamp(1.2rem, 2.5vw, 2.2rem);
}
.site-header-nav a{
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 0.95rem;
  letter-spacing: 0.02em;
  color: var(--paper);
  transition: color .3s ease;
}
.site-header-nav a:hover{ color: var(--gold); }
.site-header.is-scrolled .site-header-nav a{ color: var(--ink); }
.site-header.is-scrolled .site-header-nav a:hover{ color: var(--teal); }

.site-header-cta{
  display: inline-flex;
  align-items: center;
  background: var(--gold);
  color: var(--ink) !important;
  font-weight: 700 !important;
  padding: 0.55rem 1.3rem;
  border-radius: 999px;
  border: 2px solid var(--ink);
  transition: background-color .2s ease, transform .2s ease !important;
}
.site-header-cta:hover{
  background: var(--gold-deep);
  transform: translateY(-1px);
}

.site-header-toggle{
  display: none;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 40px;
  height: 40px;
  padding: 0;
  border: none;
  background: transparent;
  cursor: pointer;
  flex: 0 0 auto;
}
.site-header-toggle-bar{
  display: block;
  width: 100%;
  height: 3px;
  border-radius: 2px;
  background: var(--paper);
  transition: background-color .3s ease, transform .25s ease, opacity .25s ease;
}
.site-header.is-scrolled .site-header-toggle-bar{ background: var(--ink); }

@media (max-width: 900px){
  .site-header-toggle{ display: flex; }

  .site-header-nav{
    position: fixed;
    top: var(--header-h);
    left: 0;
    right: 0;
    flex-direction: column;
    align-items: stretch;
    gap: 1.1rem;
    background: var(--teal-dark);
    padding: 1.5rem clamp(1.25rem, 6vw, 2.5rem) 2rem;
    opacity: 0;
    transform: translateY(-8px);
    pointer-events: none;
    transition: opacity .25s ease, transform .25s ease;
    /* Fixed position + no bottom/height limit meant content taller than
       the viewport (e.g. the language list expanded) had nowhere to go
       but off-screen with no way to scroll to it. Fits the original 8
       links + CTA fine without ever kicking in; only bites once
       something pushes past that. */
    max-height: calc(100svh - var(--header-h));
    overflow-y: auto;
  }
  .site-header-nav.is-open{
    opacity: 1;
    transform: translateY(0);
    pointer-events: auto;
  }
  /* Mobile dropdown always has its own dark background regardless of
     scroll state, so its links stay light — overrides the scroll-
     based light/dark flip that applies above this breakpoint. */
  .site-header-nav a,
  .site-header.is-scrolled .site-header-nav a{
    color: var(--paper);
    font-size: 1.1rem;
    padding: 0.3rem 0;
  }
  .site-header-cta{
    justify-content: center;
    margin-top: 0.3rem;
  }

  .site-header.nav-open .site-header-toggle-bar:nth-child(1){
    transform: translateY(8px) rotate(45deg);
  }
  .site-header.nav-open .site-header-toggle-bar:nth-child(2){ opacity: 0; }
  .site-header.nav-open .site-header-toggle-bar:nth-child(3){
    transform: translateY(-8px) rotate(-45deg);
  }
}

/* ============================================================
   LANGUAGE SWITCHER — shared between the branch header nav and the
   landing hub (positioned there via hub.css). A solid opaque pill
   rather than a plain nav link on purpose: .site-header-nav a relies
   on the header's transparent/scrolled color swap, which only works
   for text sitting directly on the hero photo or the solid scrolled
   bar — a self-contained control needs to read the same way in both
   states, same reasoning as .site-header-cta below. Reuses the
   .menu-full-tab pill language (paper fill, ink border, pill radius)
   already established for category switching further down this file.
   ============================================================ */
.lang-switch{
  position: relative;
}
.lang-switch-trigger{
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  background: var(--paper);
  color: var(--ink);
  border: 2px solid var(--ink);
  border-radius: 999px;
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 0.8rem;
  letter-spacing: 0.03em;
  padding: 0.4rem 0.85rem;
  cursor: pointer;
  transition: transform .15s ease, box-shadow .15s ease;
}
.lang-switch-trigger:hover{
  transform: translate(-1px, -1px);
  box-shadow: 3px 3px 0 var(--ink);
}
.lang-switch-trigger::after{
  content: "";
  width: 0; height: 0;
  border: 4px solid transparent;
  border-top-color: currentColor;
  border-bottom: 0;
  margin-top: 2px;
  transition: transform .2s ease;
}
.lang-switch.is-open .lang-switch-trigger::after{ transform: rotate(180deg); }

.lang-switch-list{
  position: absolute;
  top: calc(100% + 0.5rem);
  right: 0;
  min-width: max-content;
  background: var(--paper);
  border: 2px solid var(--ink);
  border-radius: 12px;
  box-shadow: var(--shadow-hard);
  padding: 0.35rem;
  display: none;
  flex-direction: column;
  gap: 0.1rem;
  z-index: 10;
}
.lang-switch.is-open .lang-switch-list{ display: flex; }
.lang-switch-list form{ display: contents; }

.lang-switch-option{
  display: block;
  width: 100%;
  text-align: left;
  background: none;
  border: none;
  border-radius: 8px;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.85rem;
  padding: 0.4rem 0.7rem;
  cursor: pointer;
  white-space: nowrap;
}
/* .site-header-nav a{ color: var(--paper) } (for the plain-text nav
   links) otherwise outranks the plain .lang-switch-option rule above —
   same problem the mobile block below already had to work around — so
   the option's own color needs the .lang-switch-list-qualified
   specificity to actually win here, on the white dropdown card. */
.lang-switch-list a.lang-switch-option,
.lang-switch-list .lang-switch-option{
  color: var(--ink);
}
a.lang-switch-option:hover,
button.lang-switch-option:hover{ background: var(--paper-warm); }
.lang-switch-option[aria-current="true"]{
  background: var(--gold);
  cursor: default;
}

/* Full name (dropdown, desktop) vs. short code (mobile pill row) — same
   markup everywhere, CSS picks which one is visible so there's one
   source of truth per option instead of two separate template blocks. */
.lang-switch-option-code{ display: none; }

@media (max-width: 900px){
  /* Inside .site-header-nav's mobile column (align-items: stretch) —
     centered/auto-width like .site-header-cta, not stretched full width. */
  .site-header-nav .lang-switch{
    align-self: center;
    margin-top: 0.3rem;
  }
  /* No click-to-open here — the languages just sit in the already-open
     mobile menu, side by side. A second dropdown nested inside the
     hamburger's own dropdown was one tap too many, and the floating
     card didn't fit besides (see the max-height fix on .site-header-nav
     above): the trigger sits near the bottom of an already-tall panel,
     with nowhere on-screen left for a box positioned below it to open
     into. So: hide the trigger, always show the list, row not column. */
  .site-header-nav .lang-switch-trigger{
    display: none;
  }
  .site-header-nav .lang-switch-list{
    display: flex;
    position: static;
    flex-direction: row;
    flex-wrap: wrap;
    justify-content: center;
    background: none;
    border: none;
    box-shadow: none;
    padding: 0.5rem 0 0;
    gap: 0.4rem;
  }
  /* Same pill look as .lang-switch-trigger (paper fill, ink border,
     pill radius) rather than plain text in the nav column — reads as
     one control, and the gold fill for the current one is the same
     "this one's selected" convention already used in the dropdown
     above and .menu-full-tab.active elsewhere on the site. */
  .site-header-nav .lang-switch-list a.lang-switch-option,
  .site-header-nav .lang-switch-list .lang-switch-option{
    display: inline-flex;
    width: auto;
    justify-content: center;
    background: var(--paper);
    color: var(--ink);
    border: 2px solid var(--ink);
    border-radius: 999px;
    padding: 0.35rem 0.8rem;
    font-size: 0.8rem;
    letter-spacing: 0.03em;
  }
  .site-header-nav .lang-switch-option[aria-current="true"]{
    background: var(--gold);
  }
  .site-header-nav .lang-switch-option-code{ display: inline; }
  .site-header-nav .lang-switch-option-label{ display: none; }
}

/* ============================================================
   BUTTONS — comic style: hard border, offset shadow, tilt
   ============================================================ */
.btn{
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 1rem;
  letter-spacing: 0.01em;
  padding: 0.85rem 1.7rem;
  border-radius: 999px;
  cursor: pointer;
  transition: transform .18s ease, box-shadow .18s ease;
  white-space: nowrap;
}

.btn-comic{
  background: var(--gold);
  color: var(--ink);
  border: var(--border-w) solid var(--ink);
  box-shadow: var(--shadow-hard);
  transform: rotate(-2deg);
  font-family: var(--font-display);
  font-size: 1.25rem;
  letter-spacing: 0.03em;
  padding: 0.7rem 2rem 0.6rem;
}
.btn-comic:hover{
  transform: rotate(0deg) translate(-2px,-2px);
  box-shadow: 8px 8px 0 var(--ink);
}
.btn-comic:active{
  transform: translate(2px,2px);
  box-shadow: 2px 2px 0 var(--ink);
}
.btn-comic--lg{
  font-size: 1.5rem;
  padding: 0.85rem 2.4rem 0.7rem;
}

/* ============================================================
   HERO
   ============================================================ */
.hero{
  position: relative;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  overflow: hidden;
  isolation: isolate;
  /* Same thickness as the comic-page gutter (.comic-page's own
     clamp(4px,0.7vw,8px) padding) — every block seam on the page
     uses this same fluid line weight. */
  border-bottom: clamp(4px, 0.7vw, 8px) solid var(--ink);
}

.hero-bg{ position: absolute; inset: 0; z-index: -2; }
.hero-bg-img{
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: center 35%;
}
/* Sits right behind the dark overlay/vignette on purpose — the
   overlay tinting it is what makes it read as part of the scene
   instead of a sticker on top of it. Simple centering (works
   identically at any viewport size); the radial mask fades the
   edges to transparent so it blends into the burst rather than
   having a hard cutout edge. Decorative only. */
.hero-bg-head{
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: min(72%, 760px);
  height: auto;
  opacity: 0.92;
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 75%, transparent 96%);
  mask-image: linear-gradient(to bottom, #000 0%, #000 75%, transparent 96%);
  animation: heroHeadBreathe 18s ease-in-out infinite;
  pointer-events: none;
}
.hero-overlay{
  position: absolute; inset: 0;
  background:
    linear-gradient(100deg,
      rgba(11,36,32,0.94) 0%,
      rgba(11,36,32,0.86) 22%,
      rgba(20,60,53,0.55) 46%,
      rgba(20,60,53,0.28) 62%,
      rgba(20,60,53,0.55) 100%);
}
.hero-vignette{
  position: absolute; inset: 0;
  background: radial-gradient(ellipse at 50% 100%, rgba(0,0,0,0.55) 0%, rgba(0,0,0,0) 55%),
              linear-gradient(180deg, rgba(0,0,0,0.35) 0%, rgba(0,0,0,0) 18%, rgba(0,0,0,0) 78%, rgba(0,0,0,0.5) 100%);
}

.hero-inner{
  position: relative;
  z-index: 3;
  width: 100%;
  max-width: 1320px;
  margin: 0 auto;
  padding: clamp(1.5rem, 5vw, 3rem) clamp(1.25rem, 4vw, 2.5rem) clamp(2rem, 6vw, 4rem);
  pointer-events: none;
}
.hero-inner > *{ pointer-events: auto; }

.hero-copy{ max-width: 620px; color: var(--paper); }

.hero-title{
  font-family: var(--font-display);
  font-weight: 400;
  color: var(--paper);
  font-size: clamp(2.8rem, 7vw, 5.2rem);
  line-height: 0.96;
  letter-spacing: 0.01em;
  text-shadow: 4px 4px 0 var(--ink), 4px 4px 14px rgba(0,0,0,0.35);
}
.hero-title .line{
  display: block;
  opacity: 0;
  animation: fadeUp .7s ease-out forwards;
}
/* Explicit request: "POKUŠENÍ MÁ SVOJE JMÉNO" keeps the old comic
   font — only these two lines, not .line-3 ("LOKI BURGERS"), which
   stays on --font-display (Passion One). */
.hero-title .line-1{ animation-delay: .15s; font-family: var(--font-comic); }
.hero-title .line-2{ animation-delay: .27s; font-family: var(--font-comic); }
.hero-title .line-3{ animation-delay: .39s; color: var(--gold); text-shadow: 4px 4px 0 var(--ink); }

.hero-actions{
  margin-top: 2.1rem;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1.1rem;
  opacity: 0;
  animation: fadeUp .7s ease-out .5s forwards;
}

/* ---- hero character: bottom-anchored, oversized, bleeds to the screen edge ---- */
.hero-character-wrap{
  position: relative;
  z-index: 1;
  width: 100%;
  height: clamp(360px, 92vw, 620px);
  pointer-events: none;
}

.hero-character-pos{
  position: absolute;
  bottom: 0;
  left: 50%;
  transform: translateX(-50%);
  height: 100%;
  width: auto;
}

.hero-burst{
  position: absolute;
  left: 50%; top: 40%;
  width: 240%;
  aspect-ratio: 1;
  transform: translate(-50%, -50%);
  background: radial-gradient(circle, rgba(255,219,100,0.55) 0%, rgba(255,219,100,0.2) 45%, rgba(255,219,100,0) 72%);
  pointer-events: none;
  z-index: 0;
}

.hero-character{
  position: relative;
  z-index: 1;
  display: block;
  height: 100%;
  width: auto;
  max-width: none;
  filter: drop-shadow(0 30px 26px rgba(0,0,0,0.45));
  opacity: 0;
  transform: translateY(40px) scale(0.96);
  animation: charIn .9s cubic-bezier(.2,.8,.2,1) .2s forwards;
}

/* ---- falling burger FX ----
   Same technique as the reference: no opacity fade, no scale/bounce.
   Each piece is fully opaque from frame one — it's only ever hidden
   by being positioned off-screen via transform. JS drives --p / --spin
   / --r once per frame (see js/main.js).
   Left hand: one whole burger spins/falls into place.
   Right hand: the burger is built layer by layer, bottom to top. */
.fx-whole{
  position: absolute;
  z-index: 2;
  left: 9%; top: 28.8%; width: 19%;
  aspect-ratio: 1 / 1;
  object-fit: contain;
  --p: 0;
  --spin: 0;
  transform:
    translateY(calc((1 - var(--p)) * -70vh))
    translateX(calc((1 - var(--p)) * 5vw))
    rotate(calc((1 - var(--spin)) * 900deg));
  filter: drop-shadow(0 14px 16px rgba(0,0,0,0.4));
  will-change: transform;
}

.fx-layer{
  position: absolute;
  z-index: 2;
  left: 72.6%; width: 20%;
  aspect-ratio: 1 / 1;
  object-fit: contain;
  --p: 0;
  --r: 0;
  --wob: 0;
  transform:
    translateY(calc((1 - var(--p)) * -60vh))
    translateX(calc(var(--wob) * 1px))
    rotate(calc((1 - var(--r)) * -18deg));
  filter: none;
  will-change: transform;
}
.fx-layer--1{ top: 36.99%; } /* bottom bun */
.fx-layer--2{ top: 35.61%; } /* lettuce    */
.fx-layer--3{ top: 34.31%; } /* patty      */
.fx-layer--4{ top: 33.19%; } /* cheese     */
.fx-layer--5{ top: 32.11%; } /* tomato     */
.fx-layer--6{ top: 30.86%; } /* lettuce    */
.fx-layer--7{ top: 29.12%; } /* top bun    */

/* Once landed, JS adds .is-landed and the piece switches from the
   fall transform to a small continuous hover — resting a few px
   above the hand instead of sitting flush on it, swaying gently.
   All 7 layers get .is-landed at the same instant (when the last
   one lands), with an identical animation, so they stay locked
   together as one stack instead of drifting out of phase. */
.fx-whole.is-landed{
  animation: idleFloatWhole 4s ease-in-out infinite;
}
.fx-layer.is-landed{
  animation: idleFloatLayer 3.6s ease-in-out infinite;
}

/* A brief "juicy" squash right as each layer lands — plays once,
   before .is-landed switches over to the continuous hover a moment
   later. Same trick as idleFloat: a CSS animation on 'transform'
   always takes over from the plain calc()-driven value while it's
   running, no conflict with the fall positioning underneath. */
.fx-layer.is-splashing{
  animation: layerSquash .32s ease-out 1;
}

/* Impact glows are plain CSS animations, triggered by JS adding
   .show at the exact moment the fall completes — not guessed via
   animation-delay. */
.fx-impact{
  position: absolute;
  z-index: 5;
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(circle,
    rgba(255,255,255,0.95) 0%,
    rgba(255,219,100,0.9) 28%,
    rgba(255,219,100,0.4) 55%,
    rgba(255,219,100,0) 76%);
  filter: drop-shadow(0 0 16px rgba(255,219,100,0.65));
  opacity: 0;
  pointer-events: none;
}
.fx-impact.show{ animation: impactPulse .9s ease-out forwards; }
/* Sized a third larger than the burger itself and re-centered on the
   same anchor point, so the glow radiates out from behind/around it
   instead of being exactly the same box (which read as invisible —
   nothing to see past the burger's own edges). */
.fx-impact--whole{ left: 5.5%; top: 25.3%; width: 26%; }
.fx-impact--layers{ left: 69.1%; top: 25.6%; width: 27%; }

/* A few droplets of "juice" that squirt out and fade the instant the
   burger lands — triggered by JS adding .show at the same moment as
   the impact glow and the squash. Anchored at the landing center;
   each droplet just travels its own short --dx/--dy and fades. */
.fx-droplets{
  position: absolute;
  left: 82.6%; top: 44.31%;
  width: 0; height: 0;
  z-index: 6;
  pointer-events: none;
}
.fx-droplet{
  position: absolute;
  left: 0; top: 0;
  width: 15px; height: 15px;
  margin-left: -7.5px; margin-top: -7.5px;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 30%,
    rgba(255,244,200,0.95) 0%,
    rgba(255,178,60,0.92) 55%,
    rgba(200,100,15,0.85) 100%);
  opacity: 0;
}
.fx-droplets.show .fx-droplet{
  animation: dropletBurst .55s ease-out forwards;
}
.fx-droplet--1{ --dx: -33px; --dy: -18px; }
.fx-droplet--2{ --dx: -13px; --dy: -37px; width: 12px; height: 12px; margin-left: -6px; margin-top: -6px; }
.fx-droplet--3{ --dx: 14px;  --dy: -40px; }
.fx-droplet--4{ --dx: 35px;  --dy: -17px; width: 12px; height: 12px; margin-left: -6px; margin-top: -6px; }
.fx-droplet--5{ --dx: 25px;  --dy: 15px; }
.fx-droplet--6{ --dx: -24px; --dy: 17px; width: 12px; height: 12px; margin-left: -6px; margin-top: -6px; }

/* ---- entrance animations stay paused until JS confirms the page
   has actually painted (adds .is-ready to #hero). Without this, the
   CSS animation-delay clock starts at style-parse time, which on a
   heavy page can be seconds before anything is visible — so the
   whole sequence would finish before anyone sees it move. ---- */
.hero-title .line,
.hero-actions,
.hero-character{
  animation-play-state: paused;
}
.hero.is-ready .hero-title .line,
.hero.is-ready .hero-actions,
.hero.is-ready .hero-character{
  animation-play-state: running;
}

/* ============================================================
   ANIMATIONS
   ============================================================ */
@keyframes fadeUp{
  from{ opacity: 0; transform: translateY(18px); }
  to{ opacity: 1; transform: translateY(0); }
}
@keyframes heroHeadBreathe{
  0%, 100%{ transform: translate(-50%, -50%) scale(1); }
  50%{ transform: translate(-50%, -50%) scale(1.05); }
}
@keyframes charIn{
  from{ opacity: 0; transform: translateY(30px) scale(0.96); }
  to{ opacity: 1; transform: translateY(0) scale(1); }
}
@keyframes idleFloatWhole{
  0%, 100%{ transform: translateY(-8px) rotate(-3deg); }
  50%{ transform: translateY(-18px) rotate(3deg); }
}
@keyframes idleFloatLayer{
  0%, 100%{ transform: translateY(-6px) rotate(-2deg); }
  50%{ transform: translateY(-13px) rotate(2deg); }
}
@keyframes layerSquash{
  0%{ transform: scaleX(1) scaleY(1); }
  35%{ transform: scaleX(1.16) scaleY(0.82); }
  65%{ transform: scaleX(0.95) scaleY(1.06); }
  100%{ transform: scaleX(1) scaleY(1); }
}
@keyframes dropletBurst{
  0%{ opacity: 0; transform: translate(0, 0) scale(.3); }
  20%{ opacity: 1; transform: translate(calc(var(--dx) * .45), calc(var(--dy) * .45)) scale(1); }
  100%{ opacity: 0; transform: translate(var(--dx), var(--dy)) scale(.7); }
}
@keyframes impactPulse{
  0%{ opacity: .9; transform: scale(.4); }
  60%{ opacity: .5; transform: scale(1.3); }
  100%{ opacity: 0; transform: scale(1.6); }
}
@keyframes simpleFadeIn{
  from{ opacity: 0; }
  to{ opacity: 1; }
}
@media (prefers-reduced-motion: reduce){
  /* A instant snap (duration ~0) reads as "broken", not "accessible".
     Give reduced-motion users a short plain fade instead. */
  .hero-title .line,
  .hero-actions,
  .hero-character{
    animation-name: simpleFadeIn !important;
    animation-duration: .5s !important;
    animation-timing-function: ease-out !important;
    animation-iteration-count: 1 !important;
    animation-fill-mode: forwards !important;
  }
  .hero-title .line-1{ animation-delay: .10s !important; }
  .hero-title .line-2{ animation-delay: .18s !important; }
  .hero-title .line-3{ animation-delay: .26s !important; }
  .hero-actions{ animation-delay: .34s !important; }
  .hero-character{ animation-delay: .10s !important; }
  .hero-character{ transform: none !important; }

  /* The global 0.01ms reset above would otherwise make this flash
     imperceptible. Give it a real, if shorter, duration — and keep
     the landed hover fully static rather than a near-zero-duration
     flash of bobbing motion. */
  .fx-impact.show{
    animation-name: impactPulse !important;
    animation-duration: .6s !important;
    animation-timing-function: ease-out !important;
    animation-iteration-count: 1 !important;
    animation-fill-mode: forwards !important;
  }
  /* Levitation is hard-on for the burgers regardless of the user's
     motion preference (explicit choice) — overrides both the global
     0.01ms/iteration-count:1 reset above and would otherwise apply
     here too. The character's one-time entrance above still respects
     reduced motion; it just never had continuous floating to begin
     with. */
  .fx-whole.is-landed{
    animation-name: idleFloatWhole !important;
    animation-duration: 4s !important;
    animation-timing-function: ease-in-out !important;
    animation-iteration-count: infinite !important;
  }
  .fx-layer.is-landed{
    animation-name: idleFloatLayer !important;
    animation-duration: 3.6s !important;
    animation-timing-function: ease-in-out !important;
    animation-iteration-count: infinite !important;
  }
  .hero-bg-head{
    animation-name: heroHeadBreathe !important;
    animation-duration: 18s !important;
    animation-timing-function: ease-in-out !important;
    animation-iteration-count: infinite !important;
  }
  .fx-layer.is-splashing{
    animation-name: layerSquash !important;
    animation-duration: .32s !important;
    animation-timing-function: ease-out !important;
    animation-iteration-count: 1 !important;
  }
  .fx-droplets.show .fx-droplet{
    animation-name: dropletBurst !important;
    animation-duration: .45s !important;
    animation-timing-function: ease-out !important;
    animation-iteration-count: 1 !important;
    animation-fill-mode: forwards !important;
  }
  /* Same "explicit choice" as .fx-whole.is-landed/.fx-layer.is-landed
     above — continuous ambient decoration, not a one-time entrance,
     so it keeps spinning regardless of reduced-motion. Duration/
     direction/delay stay per-burger via each <img>'s own custom
     properties; only re-declaring what the global reset above would
     otherwise clobber. */
  .floating-burger{
    animation-duration: var(--d) !important;
    animation-iteration-count: infinite !important;
    animation-timing-function: linear !important;
  }
  /* Same category as .floating-burger above — continuous ambient
     space decoration, not a one-time entrance. */
  .comet{
    animation-duration: var(--dur) !important;
    animation-iteration-count: infinite !important;
    animation-timing-function: linear !important;
  }
  .feature-star--pulse{
    animation-duration: var(--pulse) !important;
    animation-iteration-count: infinite !important;
    animation-timing-function: ease-in-out !important;
  }
  .spark-star--pulse{
    animation-duration: var(--pulse) !important;
    animation-iteration-count: infinite !important;
    animation-timing-function: ease-in-out !important;
  }
}

/* ============================================================
   RESPONSIVE
   ============================================================ */
@media (min-width: 861px){
  /* Character escapes the flex flow, bleeds to the bottom edge of the hero,
     copy stays put on the left so the two never fight for space. */
  .hero{ display: block; position: relative; }
  .hero-character-wrap{
    position: absolute;
    inset: 0;
    height: auto;
    z-index: 1;
  }
  .hero-character-pos{
    left: auto;
    right: clamp(-30px, 1vw, 30px);
    transform: none;
    height: min(96vh, 1040px);
  }
  .hero-inner{
    min-height: 100svh;
    display: flex;
    align-items: center;
  }
}

@media (max-width: 860px){
  .hero{ display: block; }

  /* Same overlay technique as desktop: character is a full-bleed
     layer pinned to the bottom of the viewport, text sits on top of
     it in a separate layer. Centered instead of right-aligned. The
     button stays in normal flow, right after the title, sitting in
     the gap between the text and where the character starts. */
  .hero-character-wrap{
    position: absolute;
    inset: 0;
    height: auto;
    z-index: 1;
  }
  .hero-character-pos{
    /* Width-driven now, not height-driven — a wide character at a
       fixed height was overflowing past the screen edges on narrow
       phones. This keeps it inside the viewport with breathing
       room on both sides, at every mobile width. */
    width: clamp(220px, 84vw, 440px);
    height: auto;
  }
  .hero-character{
    width: 100%;
    height: auto;
  }

  /* Falling burger FX: the fall's start offset (see .fx-whole/.fx-layer
     above) is a fixed vh value subtracted from the landing position.
     That landing position sits inside .hero-character-pos, which above
     is height-driven (min(96vh,1040px) — tall, so the same offset
     clears the top of the screen easily). Here it's width-driven
     instead (clamp(220px,84vw,440px), auto height) — much shorter, so
     the landing position sits much closer to the bottom of the
     (still ~100svh-tall) .hero-character-wrap, and the desktop-tuned
     -70vh/-60vh isn't enough to push the start back above the visible
     area anymore — the piece sits visible at its "start" position for
     a moment before the fall begins. Bigger offset here, tuned for the
     worst-case shape in this width range (a tall, narrow phone), not
     just an average case — vh already scales correctly per device on
     its own, this just needed a large enough base value. */
  .fx-whole{
    transform:
      translateY(calc((1 - var(--p)) * -100vh))
      translateX(calc((1 - var(--p)) * 5vw))
      rotate(calc((1 - var(--spin)) * 900deg));
  }
  .fx-layer{
    transform:
      translateY(calc((1 - var(--p)) * -90vh))
      translateX(calc(var(--wob) * 1px))
      rotate(calc((1 - var(--r)) * -18deg));
  }

  .hero-inner{
    position: absolute;
    inset: 0;
    z-index: 3;
    display: flex;
    flex-direction: column;
    /* Was just clamp(2rem,10vh,3.5rem) — capped out at 3.5rem (56px),
       less than the fixed header's own 84px height, so the title
       could sit partly under it. Header height is now a floor, with
       the vh-based clamp added on top as breathing room below it. */
    padding-top: calc(var(--header-h) + clamp(0.75rem, 5vh, 2rem));
  }
  .hero-copy{ max-width: 100%; margin: 0 auto; text-align: center; }
  .hero-title{ text-shadow: 3px 3px 0 var(--ink); }

  .hero-actions{
    /* Anchored to the same clamp(220px, 84vw, 440px) expression that
       sizes the character (see .hero-character-pos above), scaled to
       its height (× 0.8722, its image aspect ratio) × 0.18 up from
       the bottom — between the hands (.fx-whole/.fx-layer land at
       29-37% down from the top, i.e. ~63-71% up from the bottom) and
       the hero's own bottom edge, close to the latter. Locked to the
       same formula as the character, so it shrinks in lockstep with
       it at every width in this range, not just at one checked
       breakpoint. Still a judgment call on the exact 0.18 — check
       against the live page and nudge that one number if needed.

       No translateX for centering on purpose: .hero-actions has its
       own entrance animation (animation: fadeUp, base rule above)
       which sets `transform: translateY(0)` in its final keyframe —
       animating a property always overrides a plain declared value
       for that same property, so a static transform here would get
       silently wiped once the animation finishes. left:0/right:0 +
       the justify-content:center already on this element (also base
       rule) centers it without touching transform at all. */
    position: absolute;
    left: 0;
    right: 0;
    bottom: calc(clamp(220px, 84vw, 440px) * 0.8722 * 0.11);
    z-index: 2;
    justify-content: center;
    margin-top: 0;
  }
  /* Button itself shrinks with the same width-driven formula, scoped
     to just the hero (not .reservation.html's share of .btn-comic--lg)
     so the smaller/narrower character has room under its arms instead
     of the button staying close to full size and crowding it. */
  .hero-actions .btn-comic--lg{
    font-size: clamp(0.9rem, 2.8vw, 1.5rem);
    padding: clamp(0.55rem, 1.8vw, 0.85rem) clamp(1.3rem, 4.5vw, 2.4rem) clamp(0.45rem, 1.5vw, 0.7rem);
  }
}

@media (max-width: 480px){
  .btn-comic--lg{ font-size: 1.3rem; }
}

/* ============================================================
   POLEDNÍ NABÍDKA — own block, 3 windows (1/4 + 2/4 + 1/4)
   ============================================================ */
.chapter-lunch{
  position: relative;
  border-bottom: clamp(4px, 0.7vw, 8px) solid var(--ink);
}

/* Same ink-gutter trick as .comic-mosaic: grid background = --ink,
   the gap is the visible seam. On phones the two edge windows (pure
   background art, no text) just disappear and the middle window goes
   full width — same 760px breakpoint the rest of the site uses. */
.lunch-split{
  display: grid;
  grid-template-columns: 1fr 2fr 1fr;
  gap: clamp(4px, 0.7vw, 8px);
  background: var(--ink);
}
/* Tablet / small-laptop tier: edges are pure image, so they can give
   up some width without a readability cost — shrink them from 25%
   each to 15% each and hand the freed space to the middle window
   (50% → 70%), so the menu tickets get noticeably more breathing room
   right where it's tightest, before phones just hide the edges
   outright below 760px. */
@media (min-width: 761px) and (max-width: 1100px){
  .lunch-split{ grid-template-columns: 3fr 14fr 3fr; }
}
@media (max-width: 760px){
  .lunch-split{ grid-template-columns: 1fr; }
  .lunch-edge{ display: none; }
}

.lunch-edge{
  position: relative;
  overflow: hidden;
}
.lunch-edge img{
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
}

.lunch-window{
  position: relative;
  overflow: hidden;
}
.lunch-window-bg{ position: absolute; inset: 0; z-index: 0; }
.lunch-window-bg-img{
  width: 100%; height: 100%;
  object-fit: cover;
}
.lunch-window-overlay{
  position: absolute; inset: 0;
  background: rgba(251,242,226,0.4);
}
.lunch-window-inner{
  position: relative;
  z-index: 1;
  padding: clamp(1.5rem, 3.5vw, 2.3rem) 1.5rem clamp(2.5rem, 6vw, 4rem);
}

/* ============================================================
   TÝDENNÍ SPECIÁL
   ============================================================ */
.chapter-week{
  position: relative;
  overflow: hidden;
  /* Same fluid line weight as every other block seam (.hero,
     .comic-page's own gutter, .gallery below) — separates Týdenní
     speciál from Stálá nabídka. */
  border-bottom: clamp(4px, 0.7vw, 8px) solid var(--ink);
}
.chapter-week-bg{ position: absolute; inset: 0; z-index: 0; }
.chapter-week-bg-img{
  width: 100%; height: 100%;
  object-fit: cover;
}
.chapter-week-overlay{
  position: absolute; inset: 0;
  background: rgba(251,242,226,0.4);
}
.chapter-week > .menu-week{
  position: relative;
  z-index: 1;
}

.menu-week{
  padding: clamp(1.5rem, 3.5vw, 2.3rem) 1.5rem clamp(4rem, 10vw, 7rem);
}
.menu-week-inner{
  max-width: 1200px;
  margin: 0 auto;
}

/* ============================================================
   Shared heading style (both blocks above use these)
   ============================================================ */
.menu-week-head{
  text-align: center;
  margin-bottom: clamp(2.5rem, 6vw, 4rem);
}
.menu-week-banner{
  display: inline-block;
  /* Was --ink — matches .seam-tag's --teal now, per request. */
  background: var(--teal);
  color: var(--paper);
  font-family: var(--font-comic);
  font-weight: 400;
  font-size: clamp(1.8rem, 4vw, 2.6rem);
  letter-spacing: 0.03em;
  padding: 10px 32px;
  border-radius: 6px;
  transform: rotate(-1.5deg);
  box-shadow: 6px 6px 0 var(--gold-deep);
}
/* Polední banner reuses the same badge, just tags it apart from the
   Speciál one so the two windows don't look like copy/paste twins. */
.lunch-banner{
  background: var(--gold-deep);
  transform: rotate(1.5deg);
  box-shadow: 6px 6px 0 var(--teal);
}
.menu-week-tagline{
  font-family: var(--font-kicker);
  margin: 2.5rem 0 0;
  font-weight: 600;
  color: #5c5346;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  font-size: clamp(1.25rem, 2.6vw, 1.55rem);
}

.menu-week-grid{
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: clamp(1.6rem, 3vw, 2.3rem);
}

/* Lunch menus get their own "order ticket" look — flat, left-aligned,
   receipt-style price line — on purpose distinct from the Speciál
   postcard cards (centered, rotated, single-line description) so the
   two blocks don't read as reskins of the same component. */
.lunch-grid{
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(1.4rem, 2.6vw, 1.9rem);
}
.lunch-card{
  position: relative;
  max-width: 480px;
  margin: 0 auto;
  width: 100%;
  background: var(--paper);
  border: var(--border-w) solid var(--ink);
  border-left: 8px solid var(--gold-deep);
  border-radius: 6px;
  box-shadow: var(--shadow-hard);
  padding: 1.7rem 1.7rem 1.5rem;
  text-align: left;
  transition: transform .2s ease, box-shadow .2s ease;
}
.lunch-card:nth-child(even){ border-left-color: var(--teal); }
.lunch-card:hover{
  transform: translateY(-4px);
  box-shadow: 8px 8px 0 var(--ink);
}
.lunch-card-top{
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0.6rem 0.7rem;
}
.lunch-card-tag{
  display: inline-block;
  background: var(--ink);
  color: var(--paper);
  font-family: var(--font-comic);
  font-weight: 400;
  font-size: 0.75rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 3px 12px;
  border-radius: 999px;
}
.lunch-card-title{
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 1.4rem;
  color: var(--ink);
  letter-spacing: 0.01em;
}
/* Line items stack one-per-row, receipt-style — reads far better
   than a flowing paragraph once there are 3 items to scan. */
.lunch-card-items{
  list-style: none;
  margin: 0.85rem 0 0;
  padding: 0;
  display: grid;
  gap: 0.4rem;
}
.lunch-card-items li{
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 0.88rem;
  line-height: 1.45;
  color: #5c5346;
}
.lunch-card-items li strong{ color: var(--ink); }

.lunch-card-price{
  margin: 1rem 0 0;
  padding-top: 0.7rem;
  border-top: 2px dashed rgba(0,0,0,0.22);
  text-align: right;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 1.3rem;
  letter-spacing: 0.02em;
  color: var(--gold-deep);
}

.menu-card{
  position: relative;
  max-width: 400px;
  margin: 0 auto;
  background: var(--paper);
  border: var(--border-w) solid var(--ink);
  border-radius: 10px;
  box-shadow: var(--shadow-hard);
  padding: 2.2rem 1.5rem 1.7rem;
  text-align: center;
  transition: transform .2s ease, box-shadow .2s ease;
}
.menu-card:nth-child(odd){ transform: rotate(-1.2deg); }
.menu-card:nth-child(even){ transform: rotate(1.2deg); }
.menu-card:hover{
  transform: rotate(0deg) translateY(-4px);
  box-shadow: 8px 8px 0 var(--ink);
}

.menu-card-tag{
  position: absolute;
  top: -14px; left: 18px;
  background: var(--teal);
  color: var(--paper);
  font-family: var(--font-comic);
  font-weight: 400;
  font-size: 0.85rem;
  letter-spacing: 0.04em;
  padding: 5px 14px;
  border: 2px solid var(--ink);
  border-radius: 999px;
  transform: rotate(-4deg);
  box-shadow: 3px 3px 0 var(--ink);
}

.menu-card-title{
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 1.5rem;
  color: var(--ink);
  margin-top: 0.6rem;
  letter-spacing: 0.01em;
}

.menu-card-desc{
  margin: 0.7rem 0 0;
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 0.92rem;
  line-height: 1.5;
  color: #5c5346;
}

.menu-card-price{
  margin: 1.1rem 0 0;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 1.3rem;
  letter-spacing: 0.02em;
  color: var(--gold-deep);
}


/* ============================================================
   STÁLÁ NABÍDKA — category tabs + dish grid, adapted from a
   reference demo (kept the interaction model, restyled with this
   site's own tokens). See js/main.js for the tab-switching /
   mobile picker-vs-panel logic — everything is scoped under
   .menu-full, nothing touches <body> the way the original demo did.
   ============================================================ */
.menu-full{
  /* Flat rgba(--paper-warm) overlay layered on top of the photo, so
     it reads as a faint tint over the background instead of the raw
     image at full strength — same color the mobile category-open
     panel already uses solid. Lower the 0.82 alpha for more of the
     photo to show through, raise it for less/fainter.
     var(--paper-warm) as the LAST layer's background-color is the
     fallback fill (image slow to load / cover crop gaps). On
     mobile, once a category is open, .menu-full-shell's own OPAQUE
     background fully covers all of this anyway — matches "leave the
     current mobile-open look as-is" with no extra override needed. */
  background:
    linear-gradient(rgba(251, 242, 226, 0.82), rgba(251, 242, 226, 0.82)),
    url("../assets/img/bg-bohove-1.021446e4de42.webp") center/cover no-repeat var(--paper-warm);
  padding: clamp(3rem, 8vw, 6rem) 0 clamp(4rem, 9vw, 7rem);
}
.menu-full-shell{
  width: min(1180px, calc(100% - 3rem));
  margin: 0 auto;
}
.menu-full-eyebrow{
  display: inline-block;
  background: var(--gold);
  color: var(--ink);
  font-family: var(--font-comic);
  font-size: 1.1rem;
  letter-spacing: 0.04em;
  padding: 8px 16px;
  border: 3px solid var(--ink);
  border-radius: 6px;
  box-shadow: 5px 5px 0 var(--ink);
  transform: rotate(-1deg);
}
.menu-full-title{
  font-family: var(--font-display);
  font-weight: 700;
  color: var(--ink);
  font-size: clamp(2.8rem, 7vw, 5.2rem);
  line-height: 0.9;
  letter-spacing: 0.01em;
  text-shadow: 5px 5px 0 var(--gold);
  margin: 1rem 0 0.8rem;
}
.menu-full-lead{
  max-width: 680px;
  font-family: var(--font-body);
  font-weight: 500;
  font-size: clamp(1rem, 1.8vw, 1.15rem);
  line-height: 1.5;
  color: var(--ink);
  margin: 0 0 1.8rem;
}

/* Sticks below the fixed site header (top: var(--header-h)), not at
   the viewport's very top — otherwise it would slide in underneath
   .site-header instead of sitting right below it. */
.menu-full-category-bar{
  position: sticky;
  top: var(--header-h);
  z-index: 20;
  margin: 0 -0.5rem 1.8rem;
  padding: 0.75rem 0.5rem;
  /* No background/blur/border of its own — each .menu-full-tab pill
     already has its own solid var(--paper) fill, thick ink border
     and box-shadow, so it reads fine on its own regardless of what's
     behind it. A background on this wrapper just added a visible
     rectangular band around/under the pills instead of helping. */
}
.menu-full-category-scroll{
  display: flex;
  gap: 0.6rem;
  overflow-x: auto;
  scrollbar-width: none;
  padding: 3px;
}
.menu-full-category-scroll::-webkit-scrollbar{ display: none; }

.menu-full-tab{
  flex: 0 0 auto;
  border: 3px solid var(--ink);
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 0.95rem;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  padding: 0.7rem 1.1rem;
  border-radius: 999px;
  cursor: pointer;
  box-shadow: 3px 3px 0 var(--ink);
  transition: transform .15s ease, box-shadow .15s ease, background-color .15s ease;
}
.menu-full-tab:hover{
  transform: translate(-1px, -1px);
  box-shadow: 5px 5px 0 var(--ink);
}
.menu-full-tab.active{ background: var(--gold); }

.menu-full-panel{ display: none; }
.menu-full-panel.active{
  display: block;
  animation: menuFullPop .25s ease;
}
@keyframes menuFullPop{
  from{ opacity: 0; transform: translateY(8px); }
  to{ opacity: 1; transform: none; }
}

.menu-full-panel-head{
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 1.2rem;
  margin: 0.7rem 0 1.2rem;
}
.menu-full-panel-head h2{
  font-family: var(--font-display);
  font-weight: 700;
  text-transform: uppercase;
  color: var(--ink);
  font-size: clamp(2rem, 4.5vw, 3.4rem);
  line-height: 1;
  margin: 0;
}
.menu-full-panel-note{
  font-family: var(--font-body);
  font-weight: 600;
  color: #5c5346;
  max-width: 380px;
  text-align: right;
  margin: 0;
}

/* Only present when a category has subcategories (Nápoje -> Nealko/Káva/
   ...) — see permanent_menu.html's subcategory_groups loop. A category
   without any renders straight into .menu-full-grid below, same as
   before this existed. */
.menu-full-subcategory{
  font-family: var(--font-comic);
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  font-size: 1.3rem;
  color: var(--teal-dark);
  border-bottom: 2px solid var(--gold-deep);
  margin: 1.8rem 0 0.9rem;
  padding-bottom: 0.3rem;
}
.menu-full-subcategory:first-child{ margin-top: 0; }

.menu-full-grid{
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1.1rem;
}

.menu-full-dish{
  position: relative;
  background: var(--paper);
  border: var(--border-w) solid var(--ink);
  padding: 1.3rem 1.3rem 1.2rem;
  box-shadow: 6px 6px 0 var(--ink);
  overflow: hidden;
  isolation: isolate;
}
.menu-full-dish:nth-child(3n+2){ transform: rotate(.35deg); }
.menu-full-dish:nth-child(3n){ transform: rotate(-.3deg); }

.menu-full-topline{
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 1rem;
  align-items: start;
}
.menu-full-dish h3{
  font-family: var(--font-body);
  font-weight: 800;
  text-transform: uppercase;
  font-size: 1.2rem;
  line-height: 1.1;
  color: var(--ink);
  margin: 0;
}
.menu-full-price{
  flex: 0 0 auto;
  background: var(--gold);
  border: 3px solid var(--ink);
  color: var(--ink);
  font-family: var(--font-body);
  font-weight: 800;
  padding: 6px 10px;
  white-space: nowrap;
  box-shadow: 3px 3px 0 var(--ink);
  transform: rotate(1deg);
}

.menu-full-desc{
  font-family: var(--font-body);
  font-weight: 500;
  line-height: 1.45;
  color: #51453a;
  max-width: 92%;
  margin: 0.8rem 0 0.8rem;
}
.menu-full-tags{
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
}
.menu-full-tag{
  border: 2px solid var(--ink);
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-body);
  font-weight: 800;
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  padding: 3px 8px;
}
.menu-full-tag.star{ background: var(--gold); }
.menu-full-tag.veg{ background: var(--teal-light); color: var(--paper); }
/* Deliberate one-off exception to the "no red in the brand manual"
   rule above (line 13-14) — "pikantní"/"hot" reads better as red than
   any palette color, explicitly requested. Not a CSS variable since
   it's intentionally scoped to just this one tag, not part of the
   reusable palette. */
.menu-full-tag.hot{ background: #C0392B; color: var(--paper); }

.menu-full-mobile-back{ display: none; }

@media (max-width: 760px){
  .menu-full-shell{ width: min(100% - 2rem, 650px); }
  .menu-full-lead{ margin-bottom: 1.3rem; }

  /* Category bar stops being sticky and becomes the picker grid —
     it's the whole point of this screen size, not a leftover header
     element to keep pinned. */
  .menu-full-category-bar{
    position: static;
    margin: 0 0 1.8rem;
    padding: 0;
    background: transparent;
    backdrop-filter: none;
    border-bottom: 0;
  }
  .menu-full-category-scroll{
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0.9rem;
    overflow: visible;
  }
  .menu-full-tab{
    width: 100%;
    min-height: 68px;
    border-radius: 10px;
    font-size: 0.9rem;
  }

  .menu-full-panel-head{ display: block; }
  .menu-full-panel-note{ text-align: left; max-width: none; margin-top: 0.4rem; }
  .menu-full-grid{ grid-template-columns: 1fr; }
  .menu-full-dish{ box-shadow: 5px 5px 0 var(--ink); }
  .menu-full-dish:nth-child(n){ transform: none; }
  .menu-full-dish h3{ font-size: 1.1rem; }
  .menu-full-desc{ max-width: none; }

  .menu-full-panel.active{ display: none; }

  /* Burgery ships as the default-active tab/panel so desktop has
     something open before JS ever runs. On mobile that "active"
     class would otherwise paint the Burgery tile gold in the picker
     grid — looking pre-selected even though nothing's actually open
     yet (no panel is showing). Neutralize it back to the normal tab
     look while the picker grid itself is what's visible. */
  .menu-full:not(.mobile-category-open) .menu-full-tab.active{
    background: var(--paper);
  }

  .menu-full-mobile-back{
    width: max-content;
    margin: 0 0 1.3rem;
    border: 3px solid var(--ink);
    background: var(--gold);
    color: var(--ink);
    font-family: var(--font-body);
    font-weight: 800;
    text-transform: uppercase;
    padding: 0.7rem 1rem;
    box-shadow: 3px 3px 0 var(--ink);
    cursor: pointer;
  }

  /* Scoped to .menu-full.mobile-category-open — NOT <body>, unlike
     the reference demo. Opening a category on mobile hides the
     picker/intro and shows only the chosen panel + the back button. */
  .menu-full.mobile-category-open .menu-full-eyebrow,
  .menu-full.mobile-category-open .menu-full-title,
  .menu-full.mobile-category-open .menu-full-lead,
  .menu-full.mobile-category-open .menu-full-category-bar{
    display: none;
  }
  .menu-full.mobile-category-open .menu-full-mobile-back{ display: block; }
  .menu-full.mobile-category-open .menu-full-panel.active{
    display: block;
    animation: menuFullPop .25s ease;
  }

  /* While a category is open, the shell becomes its own full-screen
     panel (pinned below the fixed site header) with its OWN scroll —
     so the user can freely scroll through every dish in that
     category, but can't just keep scrolling past it into the next
     section. js/main.js locks the page's own scroll at the same
     time (body gets .menu-full-lock), so the two don't fight or
     scroll in tandem behind the panel. Only the back button gets you
     out, same as a mobile nav drawer or a lightbox. */
  .menu-full.mobile-category-open .menu-full-shell{
    position: fixed;
    top: var(--header-h);
    left: 0;
    right: 0;
    bottom: 0;
    /* The base rule's width:min(100% - 2rem,650px) + margin:0 auto
       (meant for the normal, in-flow, centered shell) would otherwise
       still win here, leaving this "full-screen" panel centered with
       gaps on both sides instead of truly edge-to-edge — reset both
       so left:0/right:0 above are what actually determines its size. */
    width: auto;
    margin: 0;
    z-index: 50;
    background: var(--paper-warm);
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    padding: 1.5rem 1rem 2.5rem;
  }
}

/* Set on <body> while a mobile category panel is open (see
   js/main.js) — stops the page underneath from also scrolling while
   the fixed .menu-full-shell panel above it has its own scroll. */
body.menu-full-lock{
  overflow: hidden;
}

/* ============================================================
   PŘÍBĚH / KOMIKS — full-bleed comic page, asymmetric mosaic.
   No border on individual panels — the gap between grid cells
   shows the dark background through, acting as one consistent
   "gutter" everywhere (edges included, via matching page padding).
   That's what makes panels read as one connected page instead of
   separate framed photos with doubled borders at every seam.
   Each panel keeps an empty .comic-panel-content overlay, ready
   for speech bubbles / captions in a later pass.
   ============================================================ */
.comic-page{
  position: relative;
  background: var(--ink);
  /* Top/bottom only (was all 4 sides) — that outer padding was also
     drawing a thin ink line down the far left/right edges of the
     viewport, outside the panels themselves. Left/right removed so
     the outermost panels bleed to the true screen edge; the ink
     between panels comes from .comic-mosaic's own grid gap below,
     untouched by this. */
  padding: clamp(4px, 0.7vw, 8px) 0;
}

/* The one remaining "divider" badge — no line, sitting right on the
   seam between chapter-week and this block, poking about a quarter
   of its own height down into the comic page. */
.seam-tag{
  position: absolute;
  left: 50%;
  top: 0;
  transform: translate(-50%, -75%) rotate(-2deg);
  z-index: 10;
  font-family: var(--font-comic);
  font-weight: 400;
  /* Lower floor than before (was 1.15rem) so this can shrink enough
     to stay on one line even on the narrowest phones instead of
     wrapping to 2 lines. */
  font-size: clamp(0.7rem, 4.4vw, 1.5rem);
  letter-spacing: 0.02em;
  color: var(--paper);
  background: var(--teal);
  border: 3px solid var(--ink);
  padding: clamp(6px, 1.6vw, 12px) clamp(12px, 3.6vw, 26px);
  border-radius: 10px;
  box-shadow: 5px 5px 0 var(--gold-deep);
  text-align: center;
  white-space: nowrap;
  max-width: 92vw;
}

.comic-mosaic{
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  /* max() instead of clamp() — no upper ceiling, so panel height (and
     the sticker riding on it via cqh) keeps growing proportionally
     with viewport width forever, on any monitor size. Only a floor
     (240px/170px/220px) so it doesn't shrink to nothing. */
  grid-auto-rows:
    max(240px, 34vw)
    max(170px, 22vw)
    max(220px, 29vw);
  gap: clamp(4px, 0.7vw, 8px);
}

.comic-panel{
  position: relative;
  display: block;
  overflow: hidden;
  background: var(--ink);
  /* size (not just inline-size) so cqh is available too — the
     sticker below needs to cap itself by both the panel's width AND
     its height, since the two shrink at very different rates across
     breakpoints (mosaic goes from a wide 8-column row down to a
     short 2-column mobile row). */
  container-type: size;
}
.comic-panel img{
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.comic-panel-content{
  position: absolute;
  inset: 0;
  pointer-events: none;
  /* empty for now — bubbles/captions get added here next pass */
}

/* Team photo dropped in the middle of the first panel. Selector is
   bumped to .comic-panel img.comic-panel-sticker (same trick as
   img.award-badge/img.fx-banner--valhalla below) purely for
   specificity — otherwise the generic .comic-panel img rule above
   (width/height:100%, object-fit:cover) wins and force-crops it.
   - max-width/max-height are pure cqw/cqh (no px ceiling at all) —
     needs .comic-panel's container-type:size above for cqh to work.
     With width/height left auto, the browser shrinks/grows the
     photo to whichever limit bites first while keeping its own
     aspect ratio. No px cap also means no growth ceiling: since
     .comic-mosaic's row heights use max() (not clamp()) with no
     upper bound either, the panel — and this sticker riding on its
     cqh — keeps scaling up proportionally forever on wider screens,
     never plateauing.
   - top:50% + translate(-50%, Y%) instead of a fixed px offset: Y is
     a percentage of the STICKER'S OWN height (that's what transform
     percentages are relative to), and since the box itself is sized
     in cqh (66% of the panel's height, at every width), the overlap
     this produces stays the SAME proportion of the panel at every
     single viewport width, continuously, instead of only being
     right at whichever one breakpoint it was eyeballed at.
     Y = -50% is true centering (zero overlap). Less negative than
     -50% (closer to 0, or positive) pushes the box DOWN past center,
     so its BOTTOM edge pokes a bit past the panel's own bottom edge,
     where .comic-panel's overflow:hidden clips it — reads as tucked
     in behind the black panel-gutter frame at the bottom. Only ONE
     number to tune (the -8%): move it further from -50% (e.g. 0%,
     10%) for more overlap at the bottom, closer to -50% for less. */
.comic-panel img.comic-panel-sticker{
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -30%) rotate(-3deg); /* tune the second -50% */
  width: auto;
  height: auto;
  max-width: 95cqw;
  max-height: 95cqh;
  object-fit: contain;
}

/* Comic effect bubbles (onomatopoeia etc.) dropped into specific
   panels. Each gets its own modifier for position/rotation/size. */
.comic-panel img.fx-bubble{
  position: absolute;
  width: 38%;
  height: auto;
}
.comic-panel img.fx-bubble--omg{
  top: 5%;
  left: 58%;
  width: 35.76%;
  transform: rotate(30deg);
}

/* Panel 5 (dips): MMMM graphic centered near the top, dips themselves
   untouched below. Sized in cqw so it scales with the panel, not the
   viewport. */
.comic-panel img.fx-mmm{
  position: absolute;
  top: 1%;
  left: 50%;
  width: 52cqw;
  height: auto;
  transform: translateX(-50%);
}

/* Scroll-linked avatar reveal: hidden below the frame at --p:0
   (clipped by the panel's own overflow:hidden), slides up into
   place as --p rises toward 1. JS keeps --p tied continuously to
   scroll position, so it can slide back down just as smoothly if
   the user scrolls back up. */
.comic-panel img.fx-avatar{
  position: absolute;
  left: 0;
  bottom: 0;
  top: auto;
  right: auto;
  width: auto;
  height: 56%;
  max-width: 70%;
  --p: 0;
  transform: translateY(calc((1 - var(--p)) * 100%));
  will-change: transform;
}

/* New self-contained banner graphics (own text/art baked into the
   image) — sized in cqw so their position/scale stays put at any
   panel size. Specificity bumped (.comic-panel img.fx-banner) to
   beat the generic .comic-panel img rule that forces width/height
   to 100% for the photo panels. Fade in once via .is-visible,
   same one-time scroll reveal as everything else in this comic. */
.fx-banner{
  position: absolute;
  opacity: 0;
  transition: opacity 0.7s ease-out;
}
.fx-banner.is-visible{ opacity: 1; }
.fx-banner--party{
  top: 4%;
  left: 60%;
  width: 98cqw;
  transform: translateX(-50%);
}
.comic-panel img.fx-banner--valhalla{
  top: 9.5%;
  left: 4%;
  width: 45cqw;
  height: auto;
}

.span-3{ grid-column: span 3; }
.span-4{ grid-column: span 4; }
.span-5{ grid-column: span 5; }
.span-8{ grid-column: span 8; }

/* Award panel: real photo background (bg-comic-awards.webp, the
   panel's own img using the generic .comic-panel img cover rule
   above), with the real badge centered on top like a small sticker —
   not filling the whole frame like the photo panels. */
.comic-placeholder{
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}
.comic-panel img.award-badge{
  width: auto;
  height: auto;
  max-width: 66%;
  max-height: 66%;
  object-fit: contain;
  filter: drop-shadow(0 3px 8px rgba(0,0,0,0.35));
}

@media (max-width: 760px){
  .comic-mosaic{
    grid-auto-rows: minmax(140px, 42vw);
  }
  .comic-mosaic .comic-panel{
    grid-column: span 6 !important;
  }
}

/* ============================================================
   PARALAX: ELIXÍR — full-bleed, sticky scroll-driven 4-level swap.
   Outer wrapper is tall (scroll runway); the inner sticky pane pins
   to the viewport while that runway scrolls past. JS toggles which
   avatar pose is .is-active based on scroll progress through the
   runway — hard cut, no crossfade, fully reversible. Background is a
   single static image (no level-based swap).
   ============================================================ */
.parallax-elixir{
  position: relative;
  height: clamp(420px, 68vh, 780px);
  overflow: hidden;
  background: var(--ink);
  /* Same thickness as .comic-page's own edge gutter (clamp(4px,
     0.7vw, 8px)) — a crisp ink seam before Rezervace starts, instead
     of the busy background art butting straight into the cream
     section below. border survives overflow:hidden since it's part
     of the box itself, not clipped content. */
  border-bottom: clamp(4px, 0.7vw, 8px) solid var(--ink);
  /* Container query context so the avatar column below can size
     itself off this block's own HEIGHT, not the viewport's width —
     that's the actual fix for Loki shrinking on narrow phones: he's
     meant to fill ~88% of the block's height, but a %-of-width
     column runs out of pixels on a narrow screen long before the
     height target is reached. */
  container-type: size;
  container-name: elixir;
  /* Avatar column width, shared with .parallax-text below so the two
     stay aligned.
     - 85cqh: preferred width, back-calculated so the avatar (which
       has its own max-height:88%/max-width:92% below) lands right at
       its 88%-of-height size instead of being starved by a narrow
       column — matches how it renders on wide desktop.
     - 40cqw: hard ceiling — on tall/narrow (portrait-ish) blocks,
       85cqh alone would balloon past half the block's width and
       crush the headline text next to it, so this caps Loki's
       column at 40% of the block's own width no matter how tall
       the block is relative to its width.
     - 110px: floor for the smallest phones.
     Trade-off: on the squarest/tallest blocks the 40cqw ceiling wins
     and Loki renders a bit shorter than the desktop's 88% — some
     give is unavoidable once a block gets that squat, but it stays
     proportional and never starves the text. */
  --avatar-col: clamp(110px, 85cqh, 40cqw);
}

@media (max-width: 600px){
  .parallax-elixir{
    /* The 68vh formula above is tuned for desktop/tablet, where this
       section is one of several on screen at once. On a phone, 68vh
       (and the 420px floor) makes it swallow almost the entire
       viewport on its own — this cuts both the floor and the vh
       share so it reads as one section among others, not a takeover. */
    height: clamp(300px, 45vh, 440px);
  }
}

.parallax-bg{ position: absolute; inset: 0; z-index: 0; }
.parallax-paper{
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
}

/* Sits between the background art (z-index 0) and Loki/text
   (z-index 2) — a flat translucent wash that mutes the busy comic
   background so the teal headline and the logo read clearly on top
   of it, at every one of the 4 background states, without having to
   tune each background image individually.
   Tune these two by hand:
   - color: the rgb() triplet. Currently --paper-warm (#fbf2e2), the
     same warm cream used elsewhere on the site, so it reads as
     "paper" rather than a generic dim. Swap to e.g. 13,13,13 (--ink)
     for a dark scrim instead of a light one — try that if the text
     still doesn't pop enough on a particular background.
   - alpha (the 4th, 0–1 number): how strong the wash is. 0 = fully
     see-through background art, 1 = solid color, background
     invisible. Start around 0.3–0.5 and nudge from there. */
.parallax-overlay{
  position: absolute;
  inset: 0;
  z-index: 1;
  background: rgba(251, 242, 226, 0.75);
  pointer-events: none;
}

.parallax-avatar-wrap{
  position: absolute;
  left: 0; bottom: 0;
  width: var(--avatar-col);
  height: 100%;
  z-index: 2;
  pointer-events: none;
}
.parallax-avatar{
  position: absolute;
  left: 50%;
  bottom: 0;
  transform: translateX(-50%);
  max-height: 88%;
  width: auto;
  max-width: 92%;
  opacity: 0;
  filter: drop-shadow(0 20px 22px rgba(0,0,0,0.35));
}
.parallax-avatar.is-active{ opacity: 1; }

.parallax-text{
  position: absolute;
  left: var(--avatar-col);
  right: 0;
  top: 0;
  height: 100%;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  /* No shared "gap" anymore — kicker↔headline and headline↔logo
     spacing are each set independently below (via margin-top), so
     they can be tuned separately instead of moving together. */
  text-align: center;
  padding: 0 clamp(1rem, 4vw, 3rem);
}
.parallax-text p{
  margin: 0;
  font-family: var(--font-display);
  font-weight: 400;
  /* Was --ink (black) — now --paper (white) per request; shadow
     stays --teal (green). */
  color: var(--gold-deep);
  /* Shadow offset scales with vw (same driver as font-size) so it
     stays proportional to the letterforms at every width — a fixed
     px offset looked fine at desktop but smeared/doubled small
     mobile type where 3px is relatively huge. */
  text-shadow: 0.25vw 0.25vw 0 var(--ink);
  white-space: nowrap;
  /* No fixed floor on purpose — the text column is a fixed % of
     viewport width, so a pure vw value scales with it in lockstep
     at any screen size and keeps this on one line, per the brief. */
  font-size: min(4.3vw, 4.6rem);
}
/* Space between the kicker and the headline — independent of the
   headline→logo space set on .parallax-logo below. Single number to
   tune per resolution; ≤380px override further down. */
.parallax-text .parallax-kicker + p{
  margin-top: clamp(0.7rem, 2.2vw, 1.3rem);
}
.parallax-text-break{ display: none; }

/* Secondary "kicker" line above the headline — different font
   (--font-kicker / Gotham) so it reads as a distinct badge/label,
   not part of the comic headline. Specificity bumped to
   ".parallax-text p.parallax-kicker" so it wins over the generic
   ".parallax-text p" rule above (same element, but that rule has an
   extra type selector so it'd otherwise out-specify a bare
   ".parallax-kicker"). */
.parallax-kicker-break{ display: none; }
.parallax-text p.parallax-kicker{
  font-family: var(--font-kicker);
  font-weight: 800;
  color: var(--ink);
  text-shadow: none;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  white-space: nowrap;
  /* Needs to fit on ONE line through tablet width — only breaks
     into 3 lines on small phones, see ≤600px below. Bump this vw
     value up/down if it doesn't comfortably fit at some width. */
  font-size: clamp(0.65rem, 1.7vw, 1.05rem);
}

@media (max-width: 600px){
  /* "Budějovický Budvar" / "×" / "Loki Burgers" — 3 lines, only on
     phones. Tablet and desktop stay on the single line above. */
  .parallax-kicker-break{ display: inline; }
  .parallax-text p.parallax-kicker{
    white-space: normal;
    line-height: 1.35;
    font-size: clamp(0.6rem, 2.6vw, 0.8rem);
  }
}

@media (max-width: 1100px){
  /* Below tablet width, 2 shorter lines need less width each than
     one long line did, so we can afford to both (a) let Loki's
     column grow past the old 40cqw ceiling — he was still reading
     small/short on tablet and phone — and (b) size each line BIGGER
     (7vw vs. 4.3vw) than the cramped single-line version was. */
  .parallax-elixir{
    --avatar-col: clamp(130px, 85cqh, 45cqw);
  }
  .parallax-text-break{ display: inline; }
  .parallax-text p{
    font-size: min(7vw, 3.2rem);
    line-height: 1.05;
    text-shadow: 0.35vw 0.35vw 0 var(--ink);
    /* Safety net: if the wider avatar column above ever leaves a
       line too tight at some odd width, let it wrap again instead
       of silently clipping against .parallax-elixir's overflow:
       hidden — worst case is an unplanned 3rd line, not lost text. */
    white-space: normal;
  }
}
.parallax-logo{
  width: clamp(180px, 62cqh, 484px);
  height: auto;
  max-height: none;
  object-fit: contain;
  /* Space between the headline and the logo — independent of the
     kicker→headline space above. ≤380px override further down. */
  margin-top: 0.0rem;
}

@media (max-width: 600px){
  .parallax-logo{
    width: clamp(150px, 52cqh, 230px);
    margin-top: 0.0rem;
  }
}

/* Narrowest phones — placed last on purpose. It matches ≤380px, a
   subset of every "mobile"/"tablet" range above (≤1100px, ≤600px)
   that also touches .parallax-elixir/.parallax-text p/.parallax-logo.
   Since all of those match here too and specificity is identical,
   CSS cascade rules say whichever rule comes LAST in the file wins —
   this used to sit much earlier (right after the base .parallax-elixir
   rule) and was silently overridden by the ≤1100px/≤600px blocks
   below it, so none of these values ever actually applied. Keep this
   block last if you add more breakpoints above. */
@media (max-width: 380px){
  .parallax-elixir{
    height: clamp(250px, 92vw, 320px);
    --avatar-col: clamp(105px, 72cqh, 48cqw);
  }

  .parallax-avatar{
    max-height: 82%;
  }

  .parallax-text{
    padding: 0 0.55rem;
  }

  .parallax-text .parallax-kicker + p{
    margin-top: 0.35rem;
  }

  .parallax-text p{
    font-size: min(7.2vw, 1.55rem);
    line-height: 1;
    text-shadow: 0.95px 0.95px 0 var(--ink);
  }

  .parallax-logo{
    width: clamp(120px, 48cqh, 165px);
    margin-top: 0.0rem;
  }
}

/* ============================================================
   GALERIE — pinboard-style photo wall between Elixír and
   Rezervace/Kontakt. Same functional pattern as the reference demo
   (pinned/taped photos, swipe-to-scroll on mobile, click/Enter opens
   a lightbox) but restyled with this site's own tokens instead of
   the demo's own placeholder palette/fonts.
   ============================================================ */
.gallery{
  position: relative;
  overflow: hidden;
  padding: clamp(3rem, 8vw, 6rem) 1.5rem;
  background: var(--teal-dark);
  /* Same fluid line weight as every other block seam — separates
     Připnuto na zdi from Rezervace. */
  border-bottom: clamp(4px, 0.7vw, 8px) solid var(--ink);
}
/* bg-wall-1.webp is now 3800×2600 — large and roughly square-ish
   enough that a plain full-bleed cover across the section's whole
   (content-driven) height stays sharp at every breakpoint, without
   the fixed-ratio banner-strip workaround the earlier 1774×887
   panorama needed. */
.gallery-bg-photo{
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
}
.gallery-bg-img{
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
/* "Čmouhaté" smudge — soft, large, blurred color blotches over the
   whole section (photo band + solid color below it), echoing
   hand-inked comic backgrounds instead of a flat wash. Blur lives on
   this element only (inset: -10% so the blur's own soft edge doesn't
   leave a hard seam at the section boundary). */
.gallery-bg-smudge{
  position: absolute;
  inset: -10%;
  z-index: 0;
  background:
    radial-gradient(28% 22% at 15% 20%, rgba(38,104,94,0.35) 0%, transparent 70%),
    radial-gradient(24% 20% at 85% 15%, rgba(242,210,125,0.3) 0%, transparent 70%),
    radial-gradient(30% 24% at 75% 85%, rgba(27,65,67,0.4) 0%, transparent 70%),
    radial-gradient(22% 18% at 20% 80%, rgba(38,104,94,0.3) 0%, transparent 70%);
  filter: blur(28px);
}
.gallery::before{
  content: "";
  position: absolute;
  inset: 16px;
  border: 4px solid rgba(0,0,0,0.75);
  z-index: 1;
  pointer-events: none;
}
.gallery-inner{
  position: relative;
  z-index: 2;
  max-width: 1280px;
  margin: 0 auto;
}

.gallery-eyebrow{
  display: inline-block;
  background: var(--gold);
  color: var(--ink);
  font-family: var(--font-comic);
  font-size: 1.1rem;
  letter-spacing: 0.04em;
  padding: 8px 16px;
  border: 3px solid var(--ink);
  border-radius: 6px;
  box-shadow: 5px 5px 0 var(--ink);
  transform: rotate(-2deg);
}
.gallery-title{
  font-family: var(--font-display);
  font-weight: 700;
  color: var(--paper);
  text-shadow: 3px 3px 0 var(--ink);
  font-size: clamp(2.4rem, 6vw, 4.2rem);
  line-height: 0.95;
  margin: 1.2rem 0 0.8rem;
}
.gallery-lead{
  max-width: 620px;
  font-family: var(--font-body);
  font-weight: 500;
  font-size: clamp(1rem, 1.6vw, 1.15rem);
  color: var(--paper);
  text-shadow: 1px 1px 0 var(--ink);
  margin: 0 0 clamp(2.5rem, 5vw, 3.5rem);
}

.gallery-wall{
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
  gap: clamp(1.8rem, 4vw, 3rem) clamp(1.2rem, 3vw, 2rem);
  padding: 6px 4px 10px;
}

.gallery-photo{
  --rotate: -2deg;
  position: relative;
  margin: 0;
  padding: 10px 10px 44px;
  background: var(--paper-warm);
  border: var(--border-w) solid var(--ink);
  box-shadow: 8px 9px 0 var(--ink);
  transform: rotate(var(--rotate));
  transition: transform .2s ease, box-shadow .2s ease;
  cursor: pointer;
  isolation: isolate;
}
.gallery-photo:hover,
.gallery-photo:focus-within{
  transform: rotate(0deg) translateY(-8px) scale(1.02);
  box-shadow: 11px 13px 0 var(--ink);
  z-index: 5;
}
.gallery-photo img{
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  display: block;
  border: 2px solid var(--ink);
  filter: saturate(.95) contrast(1.05);
}
.gallery-photo figcaption{
  position: absolute;
  left: 14px; right: 14px; bottom: 12px;
  font-family: var(--font-comic);
  font-size: 1.05rem;
  letter-spacing: 0.02em;
  color: var(--ink);
}

/* Scattered pin/rotation variety, same spirit as the demo's manual
   nth-child(n) placements — just driven by a repeating pattern
   instead of listing all 7 cards individually. */
.gallery-photo:nth-child(2n){ --rotate: 2.5deg; }
.gallery-photo:nth-child(3n){ --rotate: -1.5deg; }
.gallery-photo:nth-child(3n+1){ margin-top: clamp(0px, 2vw, 30px); }
.gallery-photo:nth-child(4n){ margin-top: -14px; --rotate: -3deg; }
.gallery-photo:nth-child(5n){ --rotate: 3.5deg; }

.gallery-pin,
.gallery-tape{
  position: absolute;
  z-index: 3;
  pointer-events: none;
}
.gallery-pin{
  top: -12px; left: 50%;
  width: 22px; height: 22px;
  border-radius: 50%;
  background: var(--gold);
  border: 3px solid var(--ink);
  box-shadow: 2px 4px 0 rgba(0,0,0,.4);
  transform: translateX(-50%);
}
.gallery-pin::after{
  content: "";
  position: absolute;
  width: 6px; height: 6px;
  border-radius: 50%;
  background: rgba(255,255,255,.75);
  top: 3px; left: 4px;
}
.gallery-tape{
  width: 66px; height: 24px;
  top: -9px; left: 50%;
  transform: translateX(-50%) rotate(-4deg);
  background: rgba(242,210,125,.75);
  border-left: 2px dashed rgba(0,0,0,.3);
  border-right: 2px dashed rgba(0,0,0,.3);
}

.gallery-sticker{
  position: absolute;
  right: -14px;
  bottom: 40px;
  padding: 7px 11px;
  background: var(--teal);
  color: var(--paper);
  font-family: var(--font-comic);
  font-size: 1rem;
  border: 3px solid var(--ink);
  box-shadow: 4px 5px 0 var(--ink);
  transform: rotate(-8deg);
  z-index: 4;
}

.gallery-swipe-hint{
  display: none;
  margin: 1.5rem 0 0;
  text-align: center;
  font-family: var(--font-comic);
  font-size: 1.1rem;
  color: var(--paper);
}

@media (max-width: 760px){
  .gallery-wall{
    display: flex;
    overflow-x: auto;
    gap: 1.4rem;
    padding: 1.2rem 1rem 1.8rem;
    scroll-snap-type: x mandatory;
    overscroll-behavior-inline: contain;
    scrollbar-width: none;
  }
  .gallery-wall::-webkit-scrollbar{ display: none; }
  .gallery-photo,
  .gallery-photo:nth-child(n){
    flex: 0 0 min(80vw, 340px);
    margin: 0;
    scroll-snap-align: center;
  }
  .gallery-swipe-hint{ display: block; }
}

.gallery-lightbox{
  width: min(1000px, calc(100% - 32px));
  border: var(--border-w) solid var(--ink);
  padding: 12px;
  background: var(--paper-warm);
  box-shadow: 14px 16px 0 var(--ink);
  /* Native <dialog> defaults to overflow:auto — without this override,
     .gallery-lightbox-close (positioned outside the card via negative
     top/right, the "badge" trick) counts as scrollable overflow and the
     browser adds a scrollbar instead of just letting it poke out over
     the border as intended (found via the same bug on .promo-banner). */
  overflow: visible;
}
.gallery-lightbox::backdrop{ background: rgba(0,0,0,.8); }
.gallery-lightbox img{
  width: 100%;
  max-height: 78vh;
  object-fit: contain;
  display: block;
}
.gallery-lightbox-close{
  position: absolute;
  top: -18px;
  right: -18px;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: var(--border-w) solid var(--ink);
  background: var(--gold);
  color: var(--ink);
  font-size: 1.5rem;
  font-weight: 700;
  cursor: pointer;
}

/* ============================================================
   PROMO BANNER — per-branch, time-scheduled, native <dialog>. See
   apps/banners + promo_banner.html. Same bordered-card/close-button
   technique as .gallery-lightbox above, but the ::backdrop blurs the
   page behind it instead of flattening it to solid black — matches
   "vidět rozmazaný web vzadu" from spec, and reads as "the page is
   paused", not just covered. body.promo-banner-lock (added/removed by
   main.js) also pauses the otherwise-infinite floating-burger/comet/
   star animations below (REZERVACE + KONTAKT section) so nothing keeps
   animating unseen behind the banner — see main.js's entrance gate for
   the full reasoning.
   ============================================================ */
.promo-banner{
  width: min(420px, calc(100% - 32px));
  border: var(--border-w) solid var(--ink);
  padding: 12px;
  background: var(--paper-warm);
  box-shadow: 14px 16px 0 var(--ink);
  /* Native <dialog> defaults to overflow:auto — without this override,
     .promo-banner-close (deliberately positioned outside the card via
     negative top/right, same "badge" trick as .gallery-lightbox-close)
     counts as scrollable overflow and the browser adds a scrollbar
     instead of just letting it poke out over the border as intended. */
  overflow: visible;
}
.promo-banner::backdrop{
  background: rgba(0,0,0,.45);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}
.promo-banner img{
  display: block;
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  max-height: 85vh;
}
.promo-banner-close{
  position: absolute;
  top: -18px;
  right: -18px;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: var(--border-w) solid var(--ink);
  background: var(--gold);
  color: var(--ink);
  font-size: 1.5rem;
  font-weight: 700;
  cursor: pointer;
}

body.promo-banner-lock{
  overflow: hidden;
}
body.promo-banner-lock .floating-burger,
body.promo-banner-lock .comet,
body.promo-banner-lock .feature-star--pulse,
body.promo-banner-lock .spark-star--pulse{
  animation-play-state: paused;
}

/* ============================================================
   REZERVACE + KONTAKT — shared floating-burger backdrop.
   New, self-contained animation: doesn't touch/reuse the hero's
   falling-burger FX (.fx-whole/.fx-layer) or anything else already
   animating on the page.
   .reserve-contact-wrap holds one continuous field of burgers behind
   BOTH sections (they read as one shared background, not two). Each
   .floating-burger gets its position/size/speed/direction/delay from
   inline custom properties on the <img> in index.html — this single
   rule just wires them up; edit the numbers on each <img> to move or
   retime one burger without touching this CSS. */
.reserve-contact-wrap{
  position: relative;
}
/* Comic-book "deep space" backdrop, shared by both sections, sitting
   BEHIND the floating burgers (z-index 0 vs their 1) and behind both
   sections' own content (z-index 2 on .reserve/.contact) — explicit
   z-index on all three rather than relying on DOM order, so this
   can't silently end up on the wrong layer the way earlier stacking
   bugs on this page did.
   Built entirely from gradients — no image file:
   - 6 small tiled star patterns (each its own repeating 130–210px
     tile so they don't align into an obvious grid), sized/brightened
     up front so they actually read as stars, not specks
   - 6 large, saturated nebula clouds spaced down the whole height
     (not clustered near the top) using the brighter --teal/--red/
     --gold rather than --teal-dark, so they read as distinct color
     against the dark base instead of blending into it
   - the linear-gradient at the very end is the base sky, mostly
     --ink with only a brief --teal-dark band in the middle — darker
     than before so the stars/nebulas actually have contrast to pop
     against
   - ::after adds a faint dot halftone (comic-print texture) on top */
.reserve-contact-bg{
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image:
    radial-gradient(2.5px 2.5px at 20px 30px, rgba(255,255,255,0.95), transparent 60%),
    radial-gradient(2px 2px at 100px 90px, rgba(255,219,100,0.9), transparent 60%),
    radial-gradient(3px 3px at 60px 150px, rgba(255,255,255,0.9), transparent 60%),
    radial-gradient(2px 2px at 150px 40px, rgba(255,255,255,0.8), transparent 60%),
    radial-gradient(2.5px 2.5px at 30px 110px, rgba(255,219,100,0.8), transparent 60%),
    radial-gradient(2px 2px at 130px 170px, rgba(255,255,255,0.85), transparent 60%),
    radial-gradient(65% 50% at 18% 10%, rgba(255,219,100,0.4) 0%, transparent 70%),
    radial-gradient(60% 45% at 82% 22%, rgba(39,109,98,0.75) 0%, transparent 70%),
    radial-gradient(55% 45% at 25% 38%, rgba(27,65,67,0.65) 0%, transparent 70%),
    radial-gradient(60% 50% at 78% 55%, rgba(255,219,100,0.35) 0%, transparent 70%),
    radial-gradient(55% 45% at 20% 72%, rgba(39,109,98,0.7) 0%, transparent 70%),
    radial-gradient(60% 45% at 80% 88%, rgba(39,151,123,0.55) 0%, transparent 70%),
    linear-gradient(180deg, var(--ink) 0%, #16463d 50%, var(--ink) 100%);
  background-repeat:
    repeat, repeat, repeat, repeat, repeat, repeat,
    no-repeat, no-repeat, no-repeat, no-repeat, no-repeat, no-repeat,
    no-repeat;
  background-size:
    150px 150px, 190px 190px, 170px 170px, 210px 210px, 160px 160px, 180px 180px,
    100% 100%, 100% 100%, 100% 100%, 100% 100%, 100% 100%, 100% 100%,
    100% 100%;
}
.reserve-contact-bg::after{
  content: "";
  position: absolute;
  inset: 0;
  background-image: radial-gradient(rgba(255,255,255,0.07) 1px, transparent 1px);
  background-size: 6px 6px;
  mix-blend-mode: overlay;
}
/* Sits above the flat .reserve-contact-bg (z-index 0, same layer —
   DOM order puts it on top) but below the burgers (z-index 1) and
   section content (z-index 2). Holds comets/feature-stars/spark-
   stars as real elements (not background-image gradients) since
   each needs its own independent animation/timing. */
.space-extras{
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}

/* ---- Comets: bright head + a tapered trail (::before), flying
   diagonally across and looping. Fades in/out at the very start/end
   of the loop so the reset-to-start jump is never visible. */
.comet{
  position: absolute;
  top: var(--top);
  left: var(--left);
  width: 3px;
  height: 3px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 0 10px 2px rgba(255,255,255,0.9);
  animation: cometFly var(--dur) linear infinite;
  animation-delay: var(--delay);
}
.comet::before{
  content: "";
  position: absolute;
  top: 50%;
  right: 100%;
  width: 130px;
  height: 2px;
  background: linear-gradient(to left, rgba(255,255,255,0.85), transparent);
  transform: translateY(-50%) rotate(6deg);
  transform-origin: right center;
}
@keyframes cometFly{
  0%   { transform: translate(0, 0); opacity: 0; }
  4%   { opacity: 1; }
  40%  { opacity: 1; }
  50%  { opacity: 0; }
  100% { transform: translate(130vw, 45vh); opacity: 0; }
}

/* ---- Feature stars: bigger/brighter than the tiled background
   ones in .reserve-contact-bg. .feature-star--pulse adds a slow
   breathing glow; plain .feature-star stays static — deliberately
   not every star behaving the same. */
.feature-star{
  position: absolute;
  top: var(--top);
  left: var(--left);
  width: var(--sz);
  height: var(--sz);
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 0 6px 2px rgba(255,255,255,0.85);
}
.feature-star--pulse{
  animation: starPulse var(--pulse) ease-in-out infinite;
  animation-delay: var(--delay);
}
@keyframes starPulse{
  0%, 100%{ opacity: 0.5; transform: scale(0.8); }
  50%{ opacity: 1; transform: scale(1.3); }
}

/* ---- Spark stars: a 4-pointed sparkle/cross, not a round dot —
   two tapered bars (::before horizontal, ::after vertical) crossing
   at the center, each fading to transparent at both ends via
   linear-gradient. --rot:45deg turns the "+" into a "×" for variety;
   --col sets white or gold per star. */
.spark-star{
  position: absolute;
  top: var(--top);
  left: var(--left);
  width: var(--sz);
  height: var(--sz);
  transform: rotate(var(--rot, 0deg));
}
.spark-star::before,
.spark-star::after{
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  background: linear-gradient(90deg, transparent, var(--col, #fff) 45%, var(--col, #fff) 55%, transparent);
}
.spark-star::before{
  width: 100%;
  height: 16%;
  transform: translate(-50%, -50%);
}
.spark-star::after{
  width: 16%;
  height: 100%;
  transform: translate(-50%, -50%) rotate(90deg);
}
.spark-star--pulse{
  animation: sparkPulse var(--pulse) ease-in-out infinite;
  animation-delay: var(--delay);
}
@keyframes sparkPulse{
  0%, 100%{ opacity: 0.5; transform: rotate(var(--rot, 0deg)) scale(0.75); }
  50%{ opacity: 1; transform: rotate(var(--rot, 0deg)) scale(1.2); }
}

.floating-burgers{
  position: absolute;
  inset: 0;
  z-index: 1;
  overflow: hidden;
  pointer-events: none;
}
.floating-burger{
  position: absolute;
  top: var(--t);
  left: var(--l);
  width: var(--s);
  height: auto;
  opacity: var(--o);
  animation: burgerSpin var(--d) linear infinite;
  animation-direction: var(--dir);
  animation-delay: var(--delay);
}
/* Drift + spin combined, so it reads as weightless floating, not
   spinning in place. Loops back to (0,0) at 100% so it's seamless;
   each burger's own --d (duration), --delay and --dir (see the
   inline custom properties in index.html) already stagger and
   mirror the path, so 20 of them don't look like copies. */
@keyframes burgerSpin{
  0%   { transform: translate(0, 0)        rotate(0deg); }
  25%  { transform: translate(22px, -18px) rotate(90deg); }
  50%  { transform: translate(-14px, -30px) rotate(180deg); }
  75%  { transform: translate(-24px, 12px) rotate(270deg); }
  100% { transform: translate(0, 0)        rotate(360deg); }
}

/* ============================================================
   REZERVACE
   ============================================================ */
.reserve{
  /* No solid background on purpose — the space backdrop + floating
     burgers behind both sections (see .reserve-contact-wrap above)
     are the visual interest here now. Explicit z-index:2 (not just
     position:relative) so this content stacks above those two
     layers (0 and 1) regardless of DOM order. */
  position: relative;
  z-index: 2;
  padding: clamp(3rem, 8vw, 6rem) 1.5rem;
}
.reserve-inner{
  max-width: 640px;
  margin: 0 auto;
}
.reserve-head{
  text-align: center;
  margin-bottom: clamp(2rem, 5vw, 3rem);
}
.reserve-banner{
  display: inline-block;
  /* Was --ink — now matches .seam-tag's --teal, per request. */
  background: var(--teal);
  color: var(--paper);
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(1.8rem, 4vw, 2.6rem);
  letter-spacing: 0.03em;
  padding: 10px 32px;
  border-radius: 6px;
  transform: rotate(-1.5deg);
  box-shadow: 6px 6px 0 var(--gold-deep);
}
.reserve-tagline{
  font-family: var(--font-kicker);
  margin: 2.5rem 0 0;
  font-weight: 600;
  /* Was a dark brown, tuned for the old light paper background —
     sits directly on the new dark space backdrop now (not inside
     the white form card), so it needs a light color to stay
     readable. Small dark text-shadow keeps it legible over the
     brighter nebula/star patches too. */
  color: var(--gold);
  text-shadow: 1px 1px 3px rgba(13,13,13,0.6);
  text-transform: uppercase;
  letter-spacing: 0.16em;
  font-size: clamp(1.25rem, 2.6vw, 1.55rem);
}

.reserve-form{
  /* Dark cosmic panel instead of a plain white card — same dark
     teal-to-ink family as .reserve-contact-bg, so the form reads as
     part of the space scene rather than a flat sheet dropped on top
     of it. Border/shadow reuse .reserve-banner's colors (gold-deep
     badge → gold border; shadow uses --teal-dark, replacing the old
     --red now that the brand palette has no red) so the badge and
     its form visually belong together. Input FIELDS below stay
     light (paper-warm) on purpose — that's what keeps typed text/
     dates easiest to read; only the card's own surface goes dark. */
  background: linear-gradient(155deg, var(--teal-dark) 0%, var(--ink) 60%);
  border: var(--border-w) solid var(--gold);
  border-radius: 14px;
  box-shadow: 6px 6px 0 var(--teal-dark), 0 0 26px rgba(242,210,125,0.18);
  padding: clamp(1.5rem, 4vw, 2.5rem);
}
.reserve-iframe{
  /* Fills the panel's own width — bounded by .reserve-inner's
     max-width:640px (minus .reserve-form's own padding), not unbounded.
     Height: ChoiceQR's own default (620px) +30%, so later steps of its
     multi-step flow need less internal scrolling — bumped by request,
     not something ChoiceQR reports back to us (see chat: no confirmed
     auto-resize support, content still doesn't reflow to the iframe). */
  display: block;
  margin: 0 auto;
  border: none;
  width: 100%;
  height: 806px;
  border-radius: 8px;
}

/* ============================================================
   KONTAKT
   ============================================================ */
.contact{
  /* No solid background on purpose, same reasoning as .reserve above
     — this and .reserve now share one continuous space backdrop +
     floating burgers instead of each having its own flat color.
     Explicit z-index:2, same as .reserve, see that comment. */
  position: relative;
  z-index: 2;
  padding: clamp(3rem, 8vw, 6rem) 1.5rem;
}
/* Loki, straddling the Rezervace→Kontakt seam, holding a bar.
   Simple normal-flow block, not JS-measured/positioned — plain
   fixed width + negative top margin (pulls it up into .reserve's
   bottom padding), the standard CSS technique for one section's
   content overlapping the section above it. No position:absolute,
   no cross-element measurement, nothing to recompute.
   Fixed (not fluid) per breakpoint on purpose, same pattern as
   .parallax-logo elsewhere in this file — each tier below is its
   own pair of numbers you can tune independently instead of one
   formula affecting every size at once. See the two rules to
   change under each @media block. */
.reserve-contact-bridge{
  display: block;
  width: 440px;
  /* This exact -clamp(96px,16vw,192px) is not a guess — it's the
     precise negative of .reserve's bottom padding + .contact's top
     padding (each clamp(3rem,8vw,6rem), so together clamp(96px,16vw,
     192px)). Using the exact same formula, negated, means the top
     of this image (where the bar is, with zero transparent margin
     above it) lands EXACTLY on .reserve-form's bottom edge at every
     single width, not just at the breakpoints below — no gap, no
     overlap, "attached", continuously. Leave this number alone;
     only change WIDTH per tier below to resize Loki himself. */
  margin: clamp(-192px, -16vw, -96px) auto -0.5rem;
  pointer-events: none;
}

@media (max-width: 1100px){
  .reserve-contact-bridge{
    width: 300px;
    margin: clamp(-192px, -16vw, -96px) auto -0.5rem;
  }
}

@media (max-width: 900px){
  .reserve-contact-bridge{
    width: 300px;
    margin: clamp(-192px, -16vw, -96px) auto -0.5rem;
  }
}

@media (max-width: 800px){
  .reserve-contact-bridge{
    width: 300px;
    margin: clamp(-192px, -16vw, -96px) auto -0.5rem;
  }
}

@media (max-width: 700px){
  .reserve-contact-bridge{
    width: 300px;
    margin: clamp(-192px, -16vw, -96px) auto -0.5rem;
  }
}


@media (max-width: 600px){
  .reserve-contact-bridge{
    width: 280px;
    margin: clamp(-192px, -16vw, -96px) auto -0.5rem;
  }
}

@media (max-width: 380px){
  .reserve-contact-bridge{
    width: 150px;
    margin: clamp(-192px, -16vw, -96px) auto -0.5rem;
  }
}
.contact-inner{
  /* Matches .reserve-inner's width — only one location card for now,
     so the block reads as the same column width as the reservation
     form above it instead of stretching to a multi-branch grid. */
  max-width: 640px;
  margin: 0 auto;
}
.contact-head{
  text-align: center;
  margin-bottom: clamp(2rem, 5vw, 3rem);
}
.contact-banner{
  display: inline-block;
  /* Was --ink — now matches .seam-tag's --teal, per request. */
  background: var(--teal);
  color: var(--paper);
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(1.8rem, 4vw, 2.6rem);
  letter-spacing: 0.03em;
  padding: 10px 32px;
  border-radius: 6px;
  transform: rotate(1.5deg);
  box-shadow: 6px 6px 0 var(--gold);
}
.contact-tagline{
  font-family: var(--font-kicker);
  margin: 2.5rem 0 0;
  font-weight: 600;
  /* Same fix as .reserve-tagline above — light color + dark shadow
     so it stays readable on the new dark space backdrop. */
  color: var(--gold);
  text-shadow: 1px 1px 3px rgba(13,13,13,0.6);
  text-transform: uppercase;
  letter-spacing: 0.16em;
  font-size: clamp(1.25rem, 2.6vw, 1.55rem);
}

/* Grid, not a fixed layout — a second/third .location-card just
   flows in alongside this one once we have more branches. */
.locations-grid{
  display: grid;
  /* min(320px, 100%) instead of a bare 320px — a bare pixel floor in
     minmax() forces that width even when the container has less
     space than that (grid ignores the parent's own width in that
     case), which is exactly what was overflowing the viewport on
     narrow phones (~320-360px wide, once you subtract .contact's own
     padding). Wrapping the floor in min(...,100%) caps it at whatever
     width is actually available, so it can never force an overflow. */
  grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr));
  gap: clamp(1.5rem, 3vw, 2.5rem);
}

.location-card{
  /* Same dark-cosmic-panel treatment as .reserve-form, but colored
     to match .contact-banner instead (teal badge → teal border, gold
     shadow — mirrors .reserve-form using .reserve-banner's colors). */
  background: linear-gradient(155deg, var(--teal-dark) 0%, var(--ink) 60%);
  border: var(--border-w) solid var(--teal);
  border-radius: 14px;
  box-shadow: 6px 6px 0 var(--gold), 0 0 26px rgba(38,104,94,0.35);
  padding: clamp(1.5rem, 3vw, 2rem);
}
.location-name{
  font-family: var(--font-display);
  font-size: 2.4rem;
  /* Was --ink — invisible on the card's new dark background. */
  color: var(--paper);
  margin: 0 0 1rem;
}
.location-details{
  list-style: none;
  margin: 0 0 1.2rem;
  padding: 0;
  font-family: var(--font-body);
  font-size: 0.95rem;
  color: var(--paper-warm);
}
.location-details li{ margin-bottom: 0.4rem; }
.location-details a{ color: var(--gold); font-weight: 700; }

.location-hours{
  list-style: none;
  margin: 0 0 1.4rem;
  padding: 0.8rem 0;
  /* Dashed rule was near-black — invisible on the new dark card, so
     it's a light dashed line now instead. */
  border-top: 2px dashed rgba(255,255,255,0.25);
  border-bottom: 2px dashed rgba(255,255,255,0.25);
  font-family: var(--font-body);
  font-size: 0.9rem;
  color: var(--paper-warm);
}
.location-hours li{
  display: flex;
  justify-content: space-between;
  padding: 0.2rem 0;
}
.location-hours li span:first-child{ font-weight: 700; }

.location-map{
  position: relative;
  border-radius: 10px;
  overflow: hidden;
  border: 2px solid var(--ink);
  aspect-ratio: 4 / 3;
}
.location-map iframe{
  width: 100%;
  height: 100%;
  border: 0;
  display: block;
  /* Desaturates the whole embed, including Google's own default
     red pin (it just goes grey along with everything else) — our
     own teal marker below stands in for it instead. filter works on
     iframes even cross-origin since it operates on the rendered
     pixels, not the embedded page's DOM. */
  filter: grayscale(1);
  /* No drag/zoom/click reaches the map at all — we can't detect
     panning inside a cross-origin iframe, so our teal badge below
     has no way to follow the view if it moved. Freezing the view
     is what keeps the badge honest; .location-map-link below opens
     the real, fully interactive Google Maps instead. */
  pointer-events: none;
}
/* Stands in for Google's own pin, which the grayscale filter above
   already neutralized. Positioned so the tail's TIP (not the badge
   box) lands on the map's exact center — that's where this "q="-
   style simple embed always centers its marker. */
.location-map-badge{
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, calc(-100% - 10px));
  background: var(--teal);
  color: var(--paper);
  font-family: var(--font-comic);
  font-size: 0.95rem;
  letter-spacing: 0.02em;
  white-space: nowrap;
  padding: 6px 12px;
  border: 3px solid var(--ink);
  border-radius: 6px;
  box-shadow: 3px 4px 0 var(--ink);
  pointer-events: none;
  z-index: 1;
}
.location-map-badge::after{
  content: "";
  position: absolute;
  left: 50%;
  top: 100%;
  transform: translateX(-50%);
  width: 0;
  height: 0;
  border-left: 8px solid transparent;
  border-right: 8px solid transparent;
  border-top: 10px solid var(--ink);
}
/* Covers the whole (now frozen, pointer-events:none) map — this is
   what actually catches the click, opening real Google Maps in a
   new tab so users can still pan/zoom/get directions there. */
.location-map-link{
  position: absolute;
  inset: 0;
  z-index: 2;
}

