/* ==========================================================================
   TBILISO OLDENBURG
   Concept "Supra": a Georgian feast happens on a bordered cloth. The page is
   that cloth — an aged paper ground with the fibre and foxing to prove it, a
   woven runner falling the full height of both edges, and every piece of
   information held inside the frame.

   The rails are a Kazak runner: stepped hooked medallions in red and navy on
   an ivory ground, charted on a knot grid so every edge lands on a whole
   stitch. The same weave supplies the small motifs in the header band.

   Colour discipline: red is the frame and the one action. The rails carry a
   quieted brick (#B5392C) so the Reservieren button, which holds the warmed
   flag red, always outranks the border.
   ========================================================================== */

/* ── FONTS — self-hosted, no external request, so no consent banner ───────── */
@font-face{
  font-family:"Vollkorn L";
  src:url("../fonts/vollkorn-latin.woff2") format("woff2-variations");
  font-weight:400 700; font-style:normal; font-display:swap;
}
/* Lexend for body text. The shortlist was built by measuring the Mkhedruli
   already on the page and aiming the Latin at it, rather than by eye.
   Measured off Noto Georgian's own outlines, over the 33-letter alphabet,
   using the round no-extender letter as the reference:

     x-height .558 · RATIO 1.84 · roundness 1.29 · ink .408
     (RATIO = (asc + desc) / x-height; roundness = width/height of the bowl)

   Two things there read against the obvious assumption. Georgian's flow is
   not long limbs — RATIO is only 1.84, less than the Vollkorn above it. It
   comes from (a) 29 of 33 letters breaking the band at all, and (b) bowls
   that are WIDER THAN TALL, at 1.29. And the x-height is large, .558, so
   here "flowing" and "legible at 17px" are not the usual tradeoff.

   Ranked by distance from that profile, roundness weighted double:

     Epilogue        x .531  RATIO 1.88  round 0.99  ink .405   d 1.64
     Instrument Sans x .510  RATIO 1.81  round 0.95  ink .397   d 2.03
     Figtree         x .500  RATIO 1.80  round 0.95  ink .412   d 2.09
     Lexend          x .525  RATIO 1.83  round 0.98  ink .477   d 2.13  <- chosen
     Libre Franklin  x .530  RATIO 1.71  round 0.92  ink .387   d 2.23  (was)

   Lexend is not the closest on the metric — Epilogue is, and was fitted
   first. Lexend was picked over it after both were built out as full sites
   and compared. It is the more comfortable read in the dense Speisekarte,
   and it is drawn for reading proficiency, which is the right bias for a
   menu people scan hungry and in dim light.

   What it costs, and what to watch: ink .477 against Epilogue's .405 means
   body text sits noticeably darker on the tan. That is a gain in text
   contrast on a textured ground and a loss in hierarchy — it competes
   harder with the Vollkorn headings and the one red CTA. If body copy ever
   starts outshouting the button, this is the cause; lighten toward 380 on
   the weight axis before touching the red.

   No Latin sans reaches Georgian's 1.29 roundness — the field stops at 0.99
   — so no choice here closes that gap completely. */
@font-face{
  font-family:"Lexend L";
  src:url("../fonts/lexend-latin.woff2") format("woff2-variations");
  font-weight:400 700; font-style:normal; font-display:swap;
}
@font-face{
  font-family:"Noto Georgian L";
  src:url("../fonts/noto-georgian.woff2") format("woff2-variations");
  font-weight:400 600; font-style:normal; font-display:swap;
  unicode-range:U+10A0-10FF, U+1C90-1CBF, U+2D00-2D2F;
}

/* ── TOKENS ──────────────────────────────────────────────────────────────── */
:root{
  color-scheme:light;

  /* Old paper, matched to a supplied reference sheet: a handled tan stock,
     not a tinted white one. The grounds sit at hue 38-40deg.

     What reads as "orange" in that reference is CHROMA, not hue — it measures
     hue 38-42, barely off the amber this replaced, but at chroma 47-62 against
     that palette's 25. So the colour here is bought mostly with saturation,
     which is far cheaper in contrast than value: the sheet more than doubles
     its chroma (21 -> 44) while giving up only .12 of luminance.

     Value still had to move — a tan sheet cannot be as light as a cream one —
     and that is what this palette pays. Body ink lands at 12-13:1 rather than
     the 15:1 the pale grounds allowed. Everything else is held at AAA by
     re-solving the ink: --tinte-leise and --rot-tief are both darker than the
     tokens they replace, because the ground came down to meet them.

     Ratios are solved against the true worst case — a glyph on the darkest
     patch of foxing AND on an ornament stroke — not against the flat token. */
  --weiss:#F2E2C6;         /* the sheet */
  --wand:#EDDBB9;          /* one step further aged, for bands */
  --leinen:#E7D3AC;        /* deepest ground */
  --tinte:#0C0A09;         /* 11.8:1 at worst */
  --tinte-leise:#3C3526;   /* 7.2:1 at worst */
  --linie:#D3BB93;         /* hairlines — never black */
  --rot:#C63428;           /* flag red — unchanged, it is the identity */
  --rot-tief:#761E17;      /* 6.4:1 at worst — red text at small sizes */
  --offen:#285F32;         /* live opening state, restrained against the tan sheet */
  --gold:#6E5626;          /* the brass plates on the café wall */
  /* Text that sits ON red or ink. Split from --weiss so warming the ground
     can never quietly change the colour of button labels. */
  --auf-rot:#FDFAEC;       /* 5.1:1 on --rot */

  --display:"Vollkorn L", "Iowan Old Style", Georgia, serif;
  --body:"Lexend L", "Segoe UI", system-ui, sans-serif;
  --geo:"Noto Georgian L", "Vollkorn L", serif;

  --rail:16px;
  /* Phones get the guard band alone: a full medallion at 16px is mush. */
  --rail-bild:url("../ornament/rail-teppich-schmal.svg");
  --rail-grund:#F0E0C2;    /* the woven ground the runner is knotted on */

  /* Paper fibre and foxing. Unlike --gewebe this belongs to every surface,
     including the plain sections: it is the sheet itself, not an ornament, so
     it carries no motif and cannot reintroduce the wallpaper problem. */
  --papier:url("../ornament/papier.svg");
  --papier-mass:400px;

  /* The weave OF the cloth, as opposed to the runner laid on it: a tone-on-tone
     interlace damask that should never be consciously seen, only felt.

     It is deliberately NOT on <body>. A texture running edge to edge behind
     every section reads as one sheet of wallpaper the site was pasted onto.
     Carried by alternating panels instead, it reads as a page with parts: the
     hero panel, the info strip, the Raum band and the footer are woven; the
     sections between them are plain cloth. The hairlines those panels already
     own then do the separating.

     Applied only to surfaces that never nest inside one another — two stacked
     copies would double the density and become visible. */
  --gewebe:url("../ornament/textur.svg");
  --gewebe-mass:280px;
  --schale:min(70rem, 100%);
  --kopf-h:3.75rem;
  --radius:2px;
  --schatten:0 1px 2px rgb(26 22 19 / .05), 0 8px 24px rgb(26 22 19 / .07);
  --schatten-tief:0 18px 50px rgb(26 22 19 / .28);
  --ease:cubic-bezier(.22,1,.36,1);

  /* ── MOTION ───────────────────────────────────────────────────────────
     The cloth is being laid, not assembled. The ground and the frame are
     simply there at the first paint — a sheet that fades in is a screen,
     not paper — and then the weave settles into the rails, the panel's
     lines follow, and the medallion is set onto the seam last. It is over
     in .8s, and the hero is the last thing still moving, which is the
     point: the eye settles wherever the motion ends. The info strip below
     is deliberately not part of it (see .streifen-gruppe).

     Two rules the whole opening is built on, both learned the hard way:

     1. Transform only, wherever text is involved. A frame that never
        arrives can then leave a line offset by 6px, never invisible.
        Opacity is spent only on ornament that carries no information —
        the runner's knots, the medallion.
     2. Never animate a surface, only its contents. A panel that moves
        exposes the ground behind it.

     The resting state is always the declaration; the keyframes supply
     only the entrance. Where animations do not run at all, the page is
     simply the page.
     ─────────────────────────────────────────────────────────────────── */
  --auftakt-rahmen:60ms;    --dauer-rahmen:600ms;
  --auftakt-bild:80ms;      --dauer-bild:900ms;
  --auftakt-panel:120ms;    --dauer-zeile:700ms;      --stufe-zeile:70ms;
  --auftakt-medaillon:300ms;--dauer-medaillon:500ms;

  /* Act II, on scroll. Slower and wider apart than the opening: a page being
     read has time the first screen does not. */
  --dauer-auf:520ms;        --stufe-auf:70ms;
  --dauer-naht-quer:700ms;  /* the woven seam sewing itself across */
  --dauer-bild-auf:800ms;

  /* Travel. Small enough that the eye reads a settle, not a slide. */
  --weg-zeile:.7rem;
  --weg-rahmen:4px;
  --weg-auf:8px;
}

@media (min-width:46rem){
  :root{
    --rail:32px; --kopf-h:4.25rem;
    --rail-bild:url("../ornament/rail-teppich.svg");   /* full runner */
    --gewebe-mass:360px;
  }
}
@media (min-width:64rem){
  :root{ --rail:clamp(42px, 4vw, 62px); --gewebe-mass:440px; }
}

*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%; scroll-behavior:smooth}

body{
  position:relative;                   /* the rails measure themselves against it */
  margin:0;
  padding-inline:var(--rail);          /* content lives between the rails */
  background:var(--papier) 0 0 / var(--papier-mass) repeat, var(--weiss);   /* the sheet — see --papier above */
  color:var(--tinte);
  font-family:var(--body);
  font-size:clamp(1rem,.97rem + .16vw,1.06rem);
  line-height:1.62;
  overflow-x:hidden;
}

img{display:block; width:100%; height:auto}
figure,h1,h2,h3,p,dl,dd,ul,ol{margin:0}
ul,ol{padding:0; list-style:none}
a{color:inherit}

/* ── THE FRAME ───────────────────────────────────────────────────────────
   Absolute, not fixed: the woven band travels with the page. A rail pinned
   to the viewport stands still while everything slides past it, and the eye
   reads that as a stuck window rather than as a border on a cloth.
   ─────────────────────────────────────────────────────────────────────── */
.rahmen{
  position:absolute;
  top:0; bottom:0;
  width:var(--rail);
  z-index:40;
  pointer-events:none;
  background:var(--rail-grund);
}
/* The knots are carried on their own layer so they can be LAID onto a ground
   that is already there — the frame exists at the first paint, the weaving
   arrives into it. Sizing is unchanged: background-size 100% has always
   resolved against the padding box, which is exactly what inset:0 gives. */
.rahmen::before{
  content:"";
  position:absolute; inset:0;
  background:var(--rail-bild) repeat-y center top / 100% auto;
  animation:weben var(--dauer-rahmen) var(--ease) var(--auftakt-rahmen) both;
}
@keyframes weben{
  from{opacity:0; transform:translateY(var(--weg-rahmen))}
  to{opacity:1; transform:none}
}
/* Hairline on the inner edge only, so the runner reads as laid ON the cloth
   rather than printed into it. box-sizing keeps it inside var(--rail). */
.rahmen--links{left:0; border-right:1px solid var(--linie)}
.rahmen--rechts{right:0; border-left:1px solid var(--linie)}

/* ── TYPE ────────────────────────────────────────────────────────────────── */
h1,h2{
  font-family:var(--display);
  font-weight:600;
  letter-spacing:-.015em;
  text-wrap:balance;
  margin:0;
}
h1{font-size:clamp(2.2rem,1.35rem + 2.6vw,3.6rem); line-height:1.06}
h2{font-size:clamp(1.85rem,1.25rem + 2.2vw,2.9rem); line-height:1.12; max-width:17ch}
h3{font-family:var(--display); font-weight:600; font-size:1.3rem; line-height:1.2; letter-spacing:-.01em; margin:0}

.geo{
  font-family:var(--geo);
  font-weight:400;
  color:var(--tinte-leise);
  letter-spacing:.02em;
}

.augenbraue{
  display:flex; align-items:center; gap:.6rem;
  font-size:.7rem; font-weight:700;
  letter-spacing:.26em; text-transform:uppercase;
  color:var(--rot-tief);
  margin-bottom:1rem;
}
.augenbraue::before{                    /* bolnur-katskhuri cross, drawn flat */
  content:"";
  flex:none;
  width:.5rem; height:.5rem;
  background:
    linear-gradient(var(--rot),var(--rot)) center/100% 34% no-repeat,
    linear-gradient(var(--rot),var(--rot)) center/34% 100% no-repeat;
}
.leise{color:var(--tinte-leise)}
p{text-wrap:pretty}

/* ── LAYOUT ──────────────────────────────────────────────────────────────── */
.schale{width:var(--schale); margin-inline:auto; padding-inline:clamp(.75rem,2.5vw,2rem)}
.abschnitt{padding-block:clamp(3rem,5.5vw,5.5rem)}
/* The menu page opens on dishes, not on a title, so its first section sits
   closer to the header than a prose section would. */
.abschnitt--eng{padding-block:clamp(1.4rem,2.8vw,2.2rem)}
.band{
  position:relative;
  background:var(--gewebe) 0 0 / var(--gewebe-mass) repeat, var(--wand) var(--papier) 0 0 / var(--papier-mass) repeat;
  border-block:1px solid var(--linie);
}
/* Where a woven panel begins, the same cross-stitch band that runs under the
   header marks the join. It is the seam of the cloth, and it is what stops the
   page reading as one continuous sheet. */
.band::before, .fuss::before{
  content:"";
  position:absolute; left:0; right:0; top:0;
  height:7px;
  background:url("../ornament/band.svg") repeat-x center / auto 7px;
  pointer-events:none;
}

/* ── BROWSER SURFACES ─────────────────────────────────────────────────────
   The parts we did not draw still belong to the design. On an aged sheet the
   platform's blue selection reads as a different document entirely. */
::selection{background:rgb(198 52 40 / .17); color:var(--tinte)}
::-moz-selection{background:rgb(198 52 40 / .17); color:var(--tinte)}
html{accent-color:var(--rot); caret-color:var(--rot-tief)}

/* ── FOCUS / SKIP ────────────────────────────────────────────────────────── */
:focus-visible{outline:3px solid var(--rot-tief); outline-offset:3px; border-radius:var(--radius)}
.skip{
  position:fixed; z-index:90; top:.7rem; left:calc(var(--rail) + .7rem);
  padding:.75rem 1.1rem; background:var(--tinte); color:var(--auf-rot);
  font-weight:600; text-decoration:none; border-radius:var(--radius);
  transform:translateY(-220%);
}
.skip:focus{transform:translateY(0)}
.sr{position:absolute; width:1px; height:1px; padding:0; margin:-1px; overflow:hidden; clip:rect(0,0,0,0); white-space:nowrap; border:0}

/* ── BUTTONS ─────────────────────────────────────────────────────────────── */
.knopf{
  display:inline-block;
  font:inherit; font-size:.95rem; font-weight:600; line-height:1.2;
  padding:.85em 1.55em;
  border:1px solid transparent; border-radius:var(--radius);
  text-decoration:none; cursor:pointer;
  transition:background-color .2s var(--ease), color .2s var(--ease),
             border-color .2s var(--ease), transform .2s var(--ease);
}
.knopf--rot{background:var(--rot); color:var(--auf-rot)}
.knopf--rot:hover{background:var(--rot-tief); transform:translateY(-1px)}
.knopf--rand{border-color:var(--linie); color:var(--tinte); background:var(--weiss)}
.knopf--rand:hover{border-color:var(--rot); color:var(--rot-tief); transform:translateY(-1px)}

.textlink{
  color:var(--rot-tief); font-weight:500;
  text-decoration:underline; text-decoration-thickness:1px;
  text-underline-offset:.26em; text-decoration-color:rgb(198 52 40 / .45);
}
.textlink:hover{text-decoration-color:currentColor}

/* ── HEADER ──────────────────────────────────────────────────────────────── */
.kopfband{
  --kopfband-flaeche:rgb(242 226 198 / .94);
  --kopfband-grund:
    var(--papier) 0 0 / var(--papier-mass) repeat fixed,
    linear-gradient(var(--kopfband-flaeche),var(--kopfband-flaeche)),
    var(--weiss);
  --lasche-halbe-breite:calc(4.5rem - 2px);
  --medaillon-halbe-breite:calc(2.4375rem - 2px);
  position:sticky; top:0; z-index:35;
  padding-top:0;
  background:var(--kopfband-grund);
  border-bottom:0;
}
.kopfband::before{
  content:"";
  position:absolute;
  z-index:0;
  left:0; right:0; bottom:.5rem;
  height:1px;
  background:linear-gradient(
    to right,
    rgb(181 57 44 / .72) 0 calc(50% - var(--lasche-halbe-breite)),
    transparent calc(50% - var(--lasche-halbe-breite)) calc(50% + var(--lasche-halbe-breite)),
    rgb(181 57 44 / .72) calc(50% + var(--lasche-halbe-breite)) 100%
  );
  pointer-events:none;
}
.kopfband::after{
  content:none;
  position:absolute; left:0; right:0; top:0;
  height:7px;
  background:url("../ornament/band.svg") repeat-x center / auto 7px;
  pointer-events:none;
}
.kopf{
  position:relative;
  display:flex; align-items:center; gap:1.5rem;
  height:var(--kopf-h);
  width:var(--schale); margin-inline:auto;
  padding-inline:clamp(.75rem,2.5vw,2rem);
}
/* The preview's center detail is built as a real cloth seam. The rule sits
   slightly above the navbar edge; a broad, shallow paper arc begins on that
   rule and pushes into the hero, with red filigree centered over both. */
.kopf::before,
.kopf::after{
  content:"";
  position:absolute;
  left:50%;
  pointer-events:none;
}
.kopf::before{
  z-index:1;
  bottom:-1.75rem;
  width:9rem;
  height:2.5rem;
  transform:translateX(-50%);
  background:
    linear-gradient(
      to right,
      rgb(181 57 44 / .72) 0 calc(50% - var(--medaillon-halbe-breite)),
      transparent calc(50% - var(--medaillon-halbe-breite)) calc(50% + var(--medaillon-halbe-breite)),
      rgb(181 57 44 / .72) calc(50% + var(--medaillon-halbe-breite)) 100%
    ) 0 calc(.25rem - 1px) / 100% 1px no-repeat,
    var(--kopfband-grund);
  border-radius:0 0 50% 50% / 0 0 100% 100%;
}
.kopf::after{
  z-index:2;
  bottom:calc(-1.25rem + 1px);
  width:6.5rem;
  height:3.5rem;
  transform:translateX(-50%);
  background:url("../ornament/header-medallion.svg") no-repeat center / contain;
  filter:drop-shadow(0 1px 1px rgb(26 22 19 / .12));
  animation:medaillon-setzen var(--dauer-medaillon) var(--ease) var(--auftakt-medaillon) both;
}
/* Set down onto the seam last, after the panel's lines have found their
   places — and by scale alone. Fading it in was tried and rejected on the
   evidence: the paper arc behind it (.kopf::before) is ground and therefore
   never animates, so a medallion at 28% leaves a blank pale arc hanging off
   the header for a third of a second, which reads as a half-loaded page
   rather than as a page arriving. */
@keyframes medaillon-setzen{
  from{transform:translateX(-50%) scale(.93)}
  to{transform:translateX(-50%) scale(1)}
}
@media (min-width:46rem){
  /* Desktop paints the short bridges on the same layer as the SVG. Keeping
     their centerline and compositing context shared prevents zoom-level seams. */
  .kopf::before{background:var(--kopfband-grund)}
  .kopf::after{
    width:calc(9rem + 4px);
    background:
      url("../ornament/header-medallion.svg") no-repeat center / 6.5rem 3.5rem,
      linear-gradient(
        to right,
        rgb(181 57 44 / .72) 0 calc(50% - var(--medaillon-halbe-breite)),
        transparent calc(50% - var(--medaillon-halbe-breite)) calc(50% + var(--medaillon-halbe-breite)),
        rgb(181 57 44 / .72) calc(50% + var(--medaillon-halbe-breite)) 100%
      ) 0 center / 100% 1px no-repeat;
  }
}
.marke{
  margin-right:auto;
  display:flex; align-items:baseline; gap:.5rem;
  text-decoration:none;
}
.marke b{
  font-family:var(--display); font-weight:600; font-size:1.4rem;
  letter-spacing:.01em; line-height:1;
}
.marke .geo{font-size:.9rem; line-height:1}

/* ── THE BRAND LOCKUP, DESKTOP ONLY ──────────────────────────────────────
   Everything here is scoped to 64rem and up — the same breakpoint the rails
   already widen at — so phone AND tablet keep today's lockup untouched.

   64 rather than 46, which is where the desktop nav appears, because the star
   and the larger wordmark cost the row about 70px and the shell has none to
   give until roughly 800px: below 70rem the 70rem shell is ALREADY full
   width, so widening it buys nothing there while the bigger brand still
   spends. Measured at 736px the row came up 41px short and both "Infos &
   Kontakt" and the button broke to two lines through the seam. At 64rem the
   row has ~210px of slack, so it cannot compress.

   The star is a pseudo-element rather than markup, so the four pages that
   share this header need no edit and nothing new is announced to a screen
   reader — it is ornament, and the <a> already carries its own accessible
   name from the .sr span inside it.
   ─────────────────────────────────────────────────────────────────────── */
@media (min-width:64rem){
  /* The nav row runs the full width of the cloth instead of the 70rem shell
     the sections use.

     Left and right padding are deliberately split. The brand sits on the
     smaller of the two, close to the rail, on request — it no longer shares
     the hero panel's left edge, that alignment is given up here. The right
     side keeps the wider padding because "Infos & Kontakt" and the button's
     fit was measured against it (see the 64rem breakpoint choice below); a
     symmetric pass would also have to re-check that math.

     Safe against the centre medallion above: .kopf is margin-inline:auto
     inside symmetric body padding, so its 50% is the same absolute centre at
     any width — neither side padding here affects that. */
  .kopf{
    width:min(88rem, 100%);
    padding-left:0;
    padding-right:clamp(1.5rem,3vw,3rem);
    gap:1.75rem;
  }

  /* center, not baseline: baseline left the star's own box height (it has
     no baseline to give) setting the line's extent past the text's descent,
     which put the star's centre visibly below "Tbiliso"'s. Centering the
     whole row means .geo's baseline no longer sits on b's — at these two
     sizes that reads as two lines of a lockup, not a broken word pairing.

     align-items:center still isn't enough on its own: it centers the star
     against the LINE BOX, and a serif face's line box reserves ascent space
     (for accents that never appear here) well above the actual cap height.
     Measured on "Tbiliso" at this size: the line box centers at 34.0px, but
     the glyph ink itself — cap-top to baseline, no descenders in this word —
     centers at 30.4px. The nudge below is that 3.6px correction, aimed at
     the word's ink rather than the font's reserved box. */
  .marke{gap:.72rem; align-items:center}
  .marke::before{
    content:"";
    flex:none;
    width:2.1rem; height:2.1rem;
    transform:translateY(-.225rem);
    background:url("../ornament/marke.svg") center / contain no-repeat;
  }
  .marke b{font-size:1.95rem}
  .marke .geo{font-size:1.15rem}
}

.navi{display:flex; align-items:center; gap:1.5rem}
.navi a{
  font-size:.9rem; font-weight:500; text-decoration:none;
  padding:.3rem 0; border-bottom:1px solid transparent;
}
.navi a:hover{color:var(--rot-tief); border-bottom-color:var(--rot)}
.navi a[aria-current="page"]{border-bottom-color:var(--rot)}
.navi-knopf{display:none}
.kopf-knopf{padding:.65em 1.15em; font-size:.87rem}

.burger{
  display:none; position:relative; flex:none;
  width:2.75rem; height:2.75rem; padding:0; border:0; background:none; cursor:pointer;
}
.burger span{
  position:absolute; left:.7rem; right:.7rem; height:2px; border-radius:2px;
  background:var(--tinte); transition:transform .3s var(--ease), opacity .2s;
}
.burger span:nth-child(1){top:1rem}
.burger span:nth-child(2){top:1.32rem}
.burger span:nth-child(3){top:1.64rem}
body.menue-offen .burger span:nth-child(1){transform:translateY(.32rem) rotate(45deg)}
body.menue-offen .burger span:nth-child(2){opacity:0}
body.menue-offen .burger span:nth-child(3){transform:translateY(-.32rem) rotate(-45deg)}

/* ── HERO — a panel of cloth beside the room, not a card floating on it ──── */
.held{
  display:grid;
  grid-template-columns:minmax(20rem, 30rem) 1fr;
  height:calc(100svh - var(--kopf-h));
  min-height:31rem;
  max-height:48rem;        /* on a tall desktop screen the room stops growing */
  background:var(--weiss);
  overflow:hidden;
}
.held-panel{
  display:flex; flex-direction:column; justify-content:center;
  padding:clamp(2rem,3.4vw,3.4rem) clamp(1.5rem,3vw,3rem);
  background:var(--gewebe) 0 0 / var(--gewebe-mass) repeat, var(--weiss) var(--papier) 0 0 / var(--papier-mass) repeat;
  /* the panel is a piece of the same cloth: it carries the woven edge */
  border-right:1px solid var(--linie);
}
/* The one authored moment: the panel's lines settle into place, one after the
   next. The motion sits on the contents, never on the panel — a panel that
   moves would expose the ground behind it. Transform only, so text is never
   invisible if the animation is delayed or throttled. */
.held-panel > *{animation:zeile-auf var(--dauer-zeile) var(--ease) var(--auftakt-panel) both}
.held-panel > *:nth-child(2){animation-delay:calc(var(--auftakt-panel) + var(--stufe-zeile))}
.held-panel > *:nth-child(3){animation-delay:calc(var(--auftakt-panel) + 2 * var(--stufe-zeile))}
.held-panel > *:nth-child(4){animation-delay:calc(var(--auftakt-panel) + 3 * var(--stufe-zeile))}
.held-panel > *:nth-child(5){animation-delay:calc(var(--auftakt-panel) + 4 * var(--stufe-zeile))}
@keyframes zeile-auf{
  from{transform:translateY(var(--weg-zeile))}
  to{transform:none}
}
.held-bild{position:relative; overflow:hidden}
/* The room settles into its window rather than appearing in it. Transform and
   nothing else: this photograph is the page's largest paint, and fading it in
   would push that measurement out by the whole length of the fade — a scale
   is recorded the moment the pixels land. */
.held-bild img{
  width:100%; height:100%; object-fit:cover; object-position:60% 50%;
  animation:bild-setzen var(--dauer-bild) var(--ease) var(--auftakt-bild) both;
}
@keyframes bild-setzen{
  from{transform:scale(1.025)}
  to{transform:none}
}

.held-ort{
  font-size:.7rem; font-weight:700; letter-spacing:.24em; text-transform:uppercase;
  color:var(--rot-tief); margin-bottom:1rem;
}
.held h1{margin-bottom:.85rem; max-width:13ch}
.held-unter{max-width:34ch; color:var(--tinte-leise); margin-bottom:1.4rem}

/* today's hours: a plain line of text, nothing around it */
.held-heute{
  align-self:flex-start;
  margin-bottom:1.6rem;
  font-size:.95rem;
  font-variant-numeric:tabular-nums;
  color:var(--tinte-leise);
}
.heute-tag{color:var(--tinte-leise)}
#heute{font-weight:600; color:var(--tinte)}
.held-heute[data-offen],
.held-heute[data-offen] .heute-tag,
.held-heute[data-offen] #heute{color:var(--offen)}
.held-heute[data-offen]::before{
  content:"";
  display:inline-block;
  width:.48rem; height:.48rem;
  margin-right:.42rem;
  border-radius:50%;
  background:var(--offen);
  vertical-align:.08em;
}
.held-heute[data-zu] #heute{font-weight:400; color:var(--tinte-leise)}
.held-aktionen{display:flex; flex-wrap:wrap; align-items:center; gap:.7rem 1.2rem}

/* ── ICONS ───────────────────────────────────────────────────────────────
   One stroked set at 1.6/24, inlined as a <symbol> sprite so the page keeps
   its zero-external-request property and therefore needs no consent banner.
   currentColor throughout: an icon is never its own colour decision.
   ─────────────────────────────────────────────────────────────────────── */
.ikon{
  flex:none;
  width:1.05em; height:1.05em;
  fill:none; stroke:currentColor; stroke-width:1.6;
  stroke-linecap:round; stroke-linejoin:round;
}

/* ── INFO STRIP — one slim line, so the hero owns the first screen ─────────
   Three equal columns divided by hairlines. The icon+label pairing set here
   is the page's smallest unit of information, and it is repeated in the
   Hausregeln cards and the footer headings so the three read as one system. */
.streifen{
  background:var(--gewebe) 0 0 / var(--gewebe-mass) repeat, var(--wand) var(--papier) 0 0 / var(--papier-mass) repeat;
  border-bottom:1px solid var(--linie);
}
.streifen-zeile{
  /* Content-width groups, not equal columns: the opening hours are three
     times the length of the phone number, and 1fr each wraps them. */
  display:flex; flex-wrap:wrap; align-items:center;
  justify-content:space-between; gap:0;
  padding-block:.85rem;
  font-size:.88rem;
  color:var(--tinte-leise);
  font-variant-numeric:tabular-nums;
}
/* The strip does not move, and that is a decision rather than an omission.
   It once closed the opening sequence — three groups rising in reading order
   with their hairlines drawing down beside them — and the sequence was worse
   for it: whatever moves LAST is where the eye settles, so a strip arriving
   after the hero took the first screen away from the hero. It belongs with
   the ground and the frame instead: furniture that was already there when
   the page opened. The dividers went back to being borders with it; they had
   only become pseudo-elements so that they could be drawn. */
.streifen-gruppe{
  display:flex; align-items:center; gap:.55rem;
  padding-inline:clamp(.9rem,2.4vw,1.75rem);
  border-left:1px solid var(--linie);
  min-height:1.6rem;
}
.streifen-gruppe:first-child{border-left:0; padding-left:0}
.streifen-gruppe .ikon{color:var(--rot); width:1.1rem; height:1.1rem}
.streifen-zeile b{font-weight:600; color:var(--tinte)}
.streifen-zeile .trenn{color:var(--rot); opacity:.5; padding-inline:.15rem}
.zu{color:var(--tinte-leise)}
[data-heute]{font-weight:600; color:var(--tinte)}
[data-heute] span:first-child{color:var(--tinte)}
[data-heute][data-offen],
[data-heute][data-offen] span:first-child{color:var(--offen)}

/* ── SIGNATURE DISHES ────────────────────────────────────────────────────── */
.paar{display:grid; gap:clamp(2rem,4vw,3rem); grid-template-columns:1fr; margin-top:clamp(2rem,4vw,3.25rem)}
.gericht-link{display:block; color:inherit; text-decoration:none}
.gericht-gross figure{margin:0 0 1.15rem; overflow:hidden; border-radius:var(--radius); background:var(--leinen)}
.gericht-gross img{aspect-ratio:4/3; object-fit:cover; transition:transform .6s var(--ease)}
.gericht-gross:hover img{transform:scale(1.03)}
.gericht-kopf{display:flex; align-items:baseline; justify-content:space-between; gap:1rem; margin-bottom:.3rem}
.gericht-kopf .preis{font-weight:600; color:var(--rot-tief); white-space:nowrap}
.gericht-gross .geo{display:block; font-size:1.05rem; margin-bottom:.55rem}
.gericht-gross p{color:var(--tinte-leise); max-width:44ch}
.mehr{margin-top:clamp(1.75rem,3vw,2.5rem)}

/* ── DER RAUM ────────────────────────────────────────────────────────────── */
.raum{display:grid; gap:clamp(1.75rem,4vw,3.5rem); grid-template-columns:1fr; align-items:center}
.raum figure{margin:0; border-radius:var(--radius); overflow:hidden; box-shadow:var(--schatten)}
.raum-text p + p{margin-top:1rem}
.raum-text p{max-width:52ch; color:var(--tinte-leise)}

/* ── HAUSREGELN ──────────────────────────────────────────────────────────── */
.regeln{
  display:grid; gap:1px;
  grid-template-columns:1fr;
  background:var(--linie);
  border:1px solid var(--linie); border-radius:var(--radius);
  overflow:hidden;
}
.regeln > div{background:var(--weiss); padding:1.15rem 1.3rem}
.regeln .ikon{display:block; width:1.45rem; height:1.45rem; color:var(--rot); margin-bottom:.85rem}
.regeln dt{font-size:.72rem; font-weight:700; letter-spacing:.18em; text-transform:uppercase; color:var(--rot-tief); margin-bottom:.35rem}
.regeln dd{margin:0; color:var(--tinte-leise); font-size:.95rem}

/* ── SPEISEKARTE ─────────────────────────────────────────────────────────
   The page opens on the two dishes people actually come for, then hands
   straight over to the card itself. The title line stays deliberately small:
   on a menu page the dishes are the headline, and a 3rem "Speisekarte" would
   only push them below the fold.
   ─────────────────────────────────────────────────────────────────────── */
.karte-kopf{
  display:flex; align-items:baseline; justify-content:space-between;
  flex-wrap:wrap; gap:.3rem 1.5rem;
  margin-bottom:clamp(.9rem,2vw,1.35rem);
}
.karte-kopf h1{font-size:clamp(1.45rem,1.2rem + .8vw,1.95rem); max-width:none}
.karte-kopf p{color:var(--tinte-leise); font-size:.93rem}

/* The two attractions. Each is a photograph with a paper card set INTO its
   lower edge rather than placed under it: overlapping makes the price read as
   written onto the picture, and it keeps both cards the same height however
   long the description runs. The card is solid, not glass — it carries text
   over a photograph, so its contrast has to be knowable. */
.held-paar{display:grid; gap:clamp(.9rem,2.5vw,1.4rem); grid-template-columns:1fr}
.held-gericht{
  position:relative; overflow:hidden;
  border:1px solid var(--linie); border-radius:var(--radius);
  background:var(--leinen);
}
.held-gericht img{aspect-ratio:16/11; object-fit:cover; transition:transform .7s var(--ease)}
.held-gericht:hover img{transform:scale(1.035)}
/* On a phone the card is nearly as tall as the picture, so overlaying it hides
   the dish completely — the one thing this block exists to show. Below 52rem
   the card sits under the photograph instead; the overlap is an enhancement
   that only switches on once there is width to spare for it. */
.held-tafel{
  padding:.95rem 1.15rem 1.05rem;
  background:var(--weiss);
  border-top:1px solid var(--linie);
}
.held-tafel .augenbraue{margin-bottom:.3rem}
.held-tafel h2{font-size:clamp(1.3rem,1.1rem + .75vw,1.7rem); max-width:none; margin-bottom:.25rem}
.held-tafel h2 .geo{font-family:var(--geo); font-weight:400; font-size:.72em; color:var(--tinte-leise)}
.held-tafel p{color:var(--tinte-leise); font-size:.92rem; line-height:1.45; max-width:36ch}
.held-tafel .held-preis{
  margin-top:.5rem; color:var(--rot-tief);
  font-size:1rem; font-weight:700; font-variant-numeric:tabular-nums;
}
/* With the category chip row gone, these two links are the only jump the page
   offers. They are set as underlined text rather than filled buttons: the one
   filled red control on the page is "Tisch reservieren", and a second one here
   would compete with it. */
.held-sprung{
  display:inline-flex; align-items:center; gap:.4em;
  margin-top:.6rem;
  font-size:.84rem; font-weight:600;
  color:var(--rot-tief); text-decoration:none;
  border-bottom:1px solid rgb(198 52 40 / .4); padding-bottom:.12em;
  transition:color .18s var(--ease), border-color .18s var(--ease);
}
.held-sprung::after{
  content:"↓"; font-size:.95em; line-height:1;
  transition:transform .18s var(--ease);
}
.held-sprung:hover{color:var(--rot); border-bottom-color:var(--rot)}
.held-sprung:hover::after{transform:translateY(2px)}
@media (min-width:52rem){
  .held-paar{grid-template-columns:1fr 1fr}
  .held-gericht img{aspect-ratio:16/12}
  .held-tafel{
    position:absolute; z-index:1;
    left:clamp(.8rem,1.6vw,1.2rem); bottom:clamp(.8rem,1.6vw,1.2rem); right:clamp(.8rem,1.6vw,1.2rem);
    max-width:24rem;
    border:1px solid var(--linie); border-radius:var(--radius);
    box-shadow:var(--schatten);
  }
}

/* The card, in two columns. One grid rather than CSS columns, because the
   categories have to stay ROW-aligned: each row starts on a shared line, so
   the woven seam above a row runs straight across both columns. A masonry
   flow would stagger them and the seams would turn into litter. */
/* The removed chip row carried the space between the mini-heroes and the first
   category; the grid owns that gap now. */
.karte-raster{display:grid; grid-template-columns:1fr; gap:0 clamp(2rem,4.5vw,4rem); margin-top:clamp(1.2rem,2.6vw,2rem)}
@media (min-width:60rem){ .karte-raster{grid-template-columns:1fr 1fr} }

/* Groups are separated by the woven band, not by a plain rule. */
/* The 5rem of slack here used to clear the sticky chip row. With only the
   header left to clear, the same offset would park the heading in the middle
   of the screen on arrival. */
.gruppe{position:relative; scroll-margin-top:calc(var(--kopf-h) + 1.5rem); padding-block:clamp(1.6rem,2.8vw,2.4rem)}
.gruppe::before{
  content:"";
  position:absolute; left:0; right:0; top:0;
  height:9px;
  background:url("../ornament/band.svg") repeat-x center / auto 9px;
}
/* The first row carries no seam — there is nothing above it to separate from. */
.gruppe:first-child::before{content:none}
@media (min-width:60rem){ .gruppe:nth-child(2)::before{content:none} }

.gruppe-kopf{display:flex; align-items:center; flex-wrap:wrap; gap:.35rem .7rem; margin-bottom:.9rem}
.gruppe-kopf::before{           /* the star that marks a course */
  content:""; flex:none;
  width:1rem; height:1rem;
  background:url("../ornament/rail.svg") no-repeat center top / 1rem auto;
}
/* Category names are set as small red capitals rather than as display-size
   headings: at twelve categories on one page, headings that competed with the
   dish names would turn the card into a list of section titles. */
.gruppe h2{
  font-family:var(--display); font-weight:700;
  font-size:1rem; letter-spacing:.16em; text-transform:uppercase;
  color:var(--rot-tief); max-width:none;
}
.gruppe-kopf .geo{font-size:.95rem; color:var(--tinte-leise)}
.gruppe-notiz{
  color:var(--tinte-leise); font-size:.9rem; font-style:italic;
  margin:-.45rem 0 1.05rem; max-width:52ch; padding-left:1.7rem;
}

/* Rules between every item were affordable at full width. In a column half
   that wide they stack up into a ledger, so the separation is carried by
   space instead and the dotted leader goes with them — over a short measure
   the price is already unambiguous without one. */
.speisen{display:grid; gap:1.05rem}
.speisen li{
  display:grid; grid-template-columns:1fr auto; align-items:baseline;
  gap:.15rem .9rem;
}
.gericht{
  display:flex; align-items:baseline; flex-wrap:wrap; gap:.4rem .5rem;
  font-size:1rem; font-weight:600; line-height:1.32;
}
.gericht .geo{font-family:var(--geo); font-weight:400; font-size:.92rem; flex:none}
.preis{font-size:1rem; font-weight:600; color:var(--rot-tief); white-space:nowrap; font-variant-numeric:tabular-nums}
.zutaten{grid-column:1/-1; font-size:.88rem; line-height:1.45; color:var(--tinte-leise); max-width:52ch}

/* A photograph inside a category, with the portion size stated on it. */
.gruppe-bild{position:relative; margin:0 0 1.1rem; overflow:hidden; border-radius:var(--radius); background:var(--leinen)}
.gruppe-bild img{aspect-ratio:16/9; object-fit:cover}
.gruppe-marke{
  position:absolute; top:.55rem; right:.55rem;
  padding:.32em .75em;
  font-size:.7rem; font-weight:700; letter-spacing:.06em;
  background:var(--rot); color:var(--auf-rot); border-radius:99px;
  box-shadow:var(--schatten);
}

/* Warmes is nine dishes against a four-dish neighbour. Left in a column it
   would run most of a screen past whatever sits beside it and leave that half
   of the row empty; given the full measure and split internally, the length
   stops being a defect and reads as the centre of the card. */
.gruppe--breit{grid-column:1/-1}
@media (min-width:60rem){
  .gruppe--breit .speisen{display:block; columns:2; column-gap:clamp(2rem,4.5vw,4rem)}
  .gruppe--breit .speisen li{break-inside:avoid; margin-bottom:1.05rem}
  .gruppe--breit .gruppe-bild img{aspect-ratio:21/6}
}
.veg{
  flex:none;
  display:inline-block; padding:.1em .5em;
  font-family:var(--body);
  font-size:.64rem; font-weight:700; letter-spacing:.1em; text-transform:uppercase;
  /* warmed with the sheet: a mint chip on amber paper reads cold and imported */
  color:#3A6630; background:#E5EBC6; border:1px solid #BFCC98; border-radius:99px;
  vertical-align:.14em;
}

/* Closing band. The card ends on a woven panel rather than trailing off the
   last price, and the reservation button sits where the reading finishes. */
.hinweis{
  margin-top:clamp(2rem,4vw,3rem);
  display:grid; grid-template-columns:1fr; align-items:center;
  gap:1rem clamp(1.25rem,3vw,2.25rem);
  padding:clamp(1.3rem,3vw,1.9rem) clamp(1.3rem,3vw,2rem);
  background:var(--gewebe) 0 0 / var(--gewebe-mass) repeat,
             var(--wand) var(--papier) 0 0 / var(--papier-mass) repeat;
  border:1px solid var(--linie); border-radius:var(--radius);
}
.hinweis-siegel{
  flex:none; width:3rem; height:3rem;
  background:url("../ornament/rail.svg") no-repeat center / contain;
}
.hinweis p{color:var(--tinte-leise); font-size:.95rem; max-width:62ch}
.hinweis p + p{margin-top:.55rem}
.hinweis strong{color:var(--tinte)}
.hinweis .knopf{white-space:nowrap}
@media (min-width:52rem){
  .hinweis{grid-template-columns:auto 1fr auto}
}

/* ── RECHTSTEXT (Impressum / Datenschutz) ────────────────────────────────── */
.recht{max-width:44rem}
.recht h2{font-size:clamp(1.35rem,1.1rem + 1vw,1.75rem); max-width:none; margin-top:clamp(2rem,3.5vw,2.75rem)}
.recht h3{font-size:1.05rem; margin-top:1.6rem}
.recht p, .recht li{color:var(--tinte-leise); max-width:68ch}
.recht p + p{margin-top:.8rem}
.recht h2 + p, .recht h3 + p{margin-top:.6rem}
.recht ul{margin-top:.6rem; display:grid; gap:.35rem}
.recht ul li{padding-left:1.1rem; position:relative}
.recht ul li::before{content:""; position:absolute; left:0; top:.65em; width:.32rem; height:.32rem; background:var(--rot); opacity:.6}
/* The TBD marks have to stay visible now that the sheet itself is amber:
   #FFF6D6 separated from the old ground 1.01:1 and would have disappeared.
   Held apart by chroma rather than by value, so they do not read as darker. */
.platzhalter{
  background:#FBEEA8; border:1px dashed #CFA92F; border-radius:var(--radius);
  padding:.1em .4em; color:#6B5310; font-weight:600; font-size:.92em;
}
.recht-warnung{
  margin-bottom:clamp(1.75rem,3vw,2.5rem); padding:1.15rem 1.3rem;
  background:#FBEEA8; border:1px solid #CFA92F; border-radius:var(--radius);
  font-size:.95rem; color:#6B5310;
}
.recht-warnung b{color:#4A3A0B}

/* ── FOOTER ──────────────────────────────────────────────────────────────── */
.fuss{position:relative; background:var(--gewebe) 0 0 / var(--gewebe-mass) repeat, var(--wand) var(--papier) 0 0 / var(--papier-mass) repeat; border-top:1px solid var(--linie)}
.fuss-raster{
  display:grid; gap:clamp(1.75rem,3vw,2.5rem);
  grid-template-columns:1fr;
  padding-block:clamp(2.5rem,4.5vw,3.75rem);
}
.fuss h2{font-family:var(--display); font-size:1.5rem; max-width:none; margin-bottom:.2rem}
.fuss .geo{font-size:.95rem}
.fuss dt{display:flex; align-items:center; gap:.45rem; font-size:.7rem; font-weight:700; letter-spacing:.22em; text-transform:uppercase; color:var(--rot-tief); margin-bottom:.5rem}
.fuss dt .ikon{width:.95rem; height:.95rem; color:var(--rot)}
.fuss dd{margin:0 0 1.15rem; color:var(--tinte-leise)}
.fuss dd:last-child{margin-bottom:0}
.fuss a{color:var(--tinte-leise)}
.fuss a:hover{color:var(--rot-tief)}
.fuss .zeile{display:flex; justify-content:space-between; gap:1.5rem; max-width:17rem; font-variant-numeric:tabular-nums}
.fuss-siegel{display:flex; gap:.5rem; margin-bottom:1rem}
.fuss-siegel span{width:.75rem; height:.75rem; background:
  linear-gradient(var(--rot),var(--rot)) center/100% 32% no-repeat,
  linear-gradient(var(--rot),var(--rot)) center/32% 100% no-repeat;}
.fuss-legal{
  border-top:1px solid var(--linie);
  padding-block:1.15rem 1.4rem;
  display:flex; flex-wrap:wrap; justify-content:space-between; gap:.5rem 1.5rem;
  font-size:.85rem; color:var(--tinte-leise);
}
.fuss-legal nav{display:flex; flex-wrap:wrap; gap:.5rem 1.25rem}

/* ── ACT II — arriving on scroll ──────────────────────────────────────────
   Everything here hangs off html.bewegung, a class set by a few lines in the
   <head> only when an IntersectionObserver exists AND the visitor has not
   asked for less motion — and taken back again if app.js never arrives to
   lift the veil. Without the class none of these rules match at all, so no
   reveal here can strand content behind a script that failed. That guarantee
   is what buys this act the opacity Act I was not allowed to spend.

   The roots are chosen and marked in app.js, so four static pages stay free
   of classes that exist only for motion:
     [data-vorhang]  veils its own children and lets them in one by one
     [data-raster]   a bare grid wrapper — passes the cue to its cells so the
                     two dish cards count as two beats, not one
     [data-naht]     carries a woven seam
     [data-bild]     a photograph that settles into its frame
   The step each child waits for is written to --i from there too, which is
   why one rule here does the work of a rule per position.
   ───────────────────────────────────────────────────────────────────────── */
html.bewegung [data-vorhang] > *:not([data-raster]),
html.bewegung [data-vorhang] > [data-raster] > *{
  opacity:0;
  transform:translateY(var(--weg-auf));
  transition:opacity var(--dauer-auf) var(--ease) calc(var(--i,0) * var(--stufe-auf)),
             transform var(--dauer-auf) var(--ease) calc(var(--i,0) * var(--stufe-auf));
}
html.bewegung [data-vorhang][data-erschienen] > *:not([data-raster]),
html.bewegung [data-vorhang][data-erschienen] > [data-raster] > *{
  opacity:1;
  transform:none;
}

/* The seam sews itself across from the middle as its panel is reached.
   clip-path and not scaleX: the band is a repeating cross-stitch, and scaling
   it horizontally would squash every stitch on the way in. */
html.bewegung [data-naht]::before{
  clip-path:inset(0 50% 0 50%);
  transition:clip-path var(--dauer-naht-quer) var(--ease);
}
html.bewegung [data-naht][data-erschienen]::before{clip-path:inset(0)}

/* A photograph settles into its frame rather than arriving at rest in it.
   Only the pictures that own no hover scale: on the dish cards a second
   transform on the same property would take that hover transition over.
   The cue waits for the pixels (see app.js) — a picture revealed before it
   has decoded settles as an empty frame and then pops. */
html.bewegung [data-bild]{
  transform:scale(1.04);
  transition:transform var(--dauer-bild-auf) var(--ease);
}
html.bewegung [data-bild][data-erschienen]{transform:none}

/* ── ACT III — between pages — BUILT, MEASURED, NOT SHIPPED ───────────────
   Four pages share one frame, so the frame should not blink when you move
   between them. The rule for it is four lines:

       @view-transition{navigation:auto}
       ::view-transition-old(root),
       ::view-transition-new(root){animation-duration:260ms}
       .kopfband{view-transition-name:kopfband}

   naming the header so it holds still while the content between the rails
   cross-fades, and deliberately NOT naming the rails — they are identical on
   every page at the same scroll position and never appear to change, whereas
   naming them would ask the browser to morph a 4400px runner into a 2000px
   one and animate the difference.

   It was written, and then taken out again. On Chromium 149 the navigation
   itself is fine — load fires in 90ms — but after the transition the
   document stops producing animation frames: the DOM stays queryable and
   scriptable while any rAF-gated wait never resolves. Headless shell, new
   headless and HEADED all behave the same, and a page containing nothing but
   the at-rule and twenty lines of CSS reproduces it exactly, so it is not
   this stylesheet, the sticky header, or the rails.

   That is very probably a bug in one Chromium build rather than a hazard on
   real machines — the feature is widely shipped — but "probably" is not the
   standard for a page whose job is to be open when someone wants a table.
   Re-test by pasting the four lines back and clicking index → Speisekarte in
   a real browser: if the second page scrolls and animates normally, ship it.
   ───────────────────────────────────────────────────────────────────────── */

/* ── RESPONSIVE ──────────────────────────────────────────────────────────── */
@media (min-width:46rem){
  .paar{grid-template-columns:1fr 1fr}
  .raum{grid-template-columns:1.05fr .95fr}
  .regeln{grid-template-columns:repeat(2,1fr)}
  .karte-kopf{grid-template-columns:1.15fr .85fr}
  .fuss-raster{grid-template-columns:1.1fr .95fr .95fr}

  /* .held caps out at 48rem tall on a tall desktop screen (see .held above),
     which used to leave a bare gap between the info strip and the next
     section, inside the first screen. The strip absorbs exactly that gap —
     the sum of header + hero + strip still equals the viewport height,
     the strip just carries whatever the hero didn't need. Below the cap
     this resolves to 0 and the strip is untouched. */
  .streifen{
    display:flex; flex-direction:column; justify-content:center;
    min-height:max(0px, 100svh - var(--kopf-h) - 48rem);
  }
}
@media (min-width:64rem){
  .regeln{grid-template-columns:repeat(4,1fr)}
}

/* Once the full opening-hours sentence fits, the desktop strip becomes one
   uninterrupted line. Compact windows keep the existing responsive wrap,
   and the phone layout below remains unchanged. */
@media (min-width:74rem){
  .streifen .schale{width:min(88rem,100%)}
  .streifen-zeile{flex-wrap:nowrap}
  .streifen-gruppe{
    flex:none;
    white-space:nowrap;
    padding-inline:clamp(.75rem,1.5vw,1.35rem);
  }
  .streifen-gruppe:last-child{padding-right:0}
}

@media (max-width:45.999rem){
  h2{max-width:none}
  .kopf{gap:.6rem}
  .kopf-knopf{display:none}
  .burger{display:block}

  .navi{
    position:absolute; top:100%; left:0; right:0; z-index:70;
    height:calc(100vh - var(--kopf-h));
    height:calc(100dvh - var(--kopf-h));
    flex-direction:column; justify-content:center; align-items:center;
    gap:.5rem; padding:5rem 2rem 3rem;
    background:var(--weiss);
    clip-path:inset(0 0 100% 0); visibility:hidden; pointer-events:none;
    transition:clip-path .4s var(--ease), visibility .4s;
  }
  body.menue-offen{overflow:hidden}
  body.menue-offen .navi{clip-path:inset(0); visibility:visible; pointer-events:auto}
  /* Hidden, not removed. display:none takes the pseudo out of the animation
     model entirely, so restoring it RESTARTS the medallion's entrance — the
     ornament came back at 93% and then sat there for the 300ms load cue
     before settling, every time the menu was dismissed. visibility keeps the
     finished animation finished and returns it whole. */
  body.menue-offen .kopf::before,
  body.menue-offen .kopf::after,
  body.menue-schliesst .kopf::before,
  body.menue-schliesst .kopf::after{visibility:hidden}
  .navi a{font-family:var(--display); font-size:1.85rem; font-weight:600; padding:.35rem 0; border:0}
  .navi a.navi-knopf{
    display:inline-block; margin-top:1.4rem;
    font-family:var(--body); font-size:1rem; font-weight:600;
    padding:.85em 1.55em; color:var(--auf-rot);
  }
  .marke,.burger{position:relative; z-index:75}
  .kopfband{
    --lasche-halbe-breite:3.25rem;
    --medaillon-halbe-breite:calc(1.96875rem - 2px);
  }
  .kopfband::before{
    bottom:.375rem;
    background:rgb(181 57 44 / .72);
  }
  .kopf::before{bottom:-1.5rem; width:6.5rem; height:2.125rem}
  .kopf::after{bottom:-1.05rem; width:5.25rem; height:2.85rem}

  /* Phones stack the two pieces: the room first, then the cloth beneath it.
     A tall crop of this wide photograph would leave a vertical sliver, so it
     keeps a 3:2 window instead — short enough that the info strip below still
     lands on the first screen on common phone heights (~390×844 and up). */
  .held{
    display:flex; flex-direction:column;
    height:auto; min-height:0; max-height:none;
    background:var(--weiss);
  }
  .held-bild{order:-1; aspect-ratio:3/2}
  .held-panel{
    padding:clamp(1.2rem,5vw,2rem) clamp(1.25rem,5vw,2rem) clamp(1.3rem,5vw,2.25rem);
    text-align:center;
    border-right:0;
    border-bottom:1px solid var(--linie);
  }
  .held-ort{margin-bottom:.7rem}
  .held h1{max-width:none; margin-bottom:.65rem}
  .held-unter{max-width:none; margin-bottom:1.1rem}
  .held-heute{margin-inline:auto; margin-bottom:1.1rem}
  .held-aktionen{width:fit-content; max-width:100%; margin-inline:auto}
  .held-aktionen > *{margin-inline:auto}

  /* Phones stack the three groups; vertical dividers become horizontal ones,
     because a 1fr column at 390px would break "Ammerländer Heerstraße 57".
     Padding is trimmed from the desktop .6rem so the phone number — the last
     of the three — still lands inside the first screen, not past it. */
  .streifen-zeile{display:block; padding-block:.25rem}
  .streifen-gruppe{
    padding-inline:0; padding-block:.45rem;
    border-left:0; border-top:1px solid var(--linie);
    align-items:flex-start;          /* hours wrap to two lines at 390px */
  }
  .streifen-gruppe:first-child{border-top:0}
  .streifen-gruppe .ikon{margin-top:.18rem}
  .fuss .zeile{max-width:none}
  .gruppe-notiz{padding-left:0}
}

@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  /* The delay has to go with the duration. A cue that still waits its 380ms
     holds the element on the first frame of an animation that no longer
     runs — a hairline missing, an ornament not yet there — and then snaps
     it in, which is the one thing this query exists to prevent. */
  *,*::before,*::after{
    animation-duration:.01ms !important;
    animation-delay:0s !important;
    animation-iteration-count:1 !important;
    transition-duration:.01ms !important;
  }
  .knopf:hover,.gericht-gross:hover img{transform:none}

  /* Kept against the day Act III goes in: the page transition lives in its
     own pseudo tree, which the * rule above does not reach. */
  @view-transition{navigation:none}
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*){animation:none !important}
}

@media print{
  .rahmen,.kopfband,.held-sprung,.skip{display:none}
  body{padding-inline:0}
}
