/* =========================================================================
   BAD & BOUJEE

   The idea: this brand has never shot a landscape frame in its life.
   Every asset it owns is a 9:16 reel. So the site is built in portrait —
   the content is shown at the size it was made for, on a counter, in a
   room. Stretch a 640px reel across a 1440px hero and it looks like a
   mockup; stand it up at phone scale and it looks like the shop.

   Palette sampled from their own assets:
     #F9DB49  the yellow in their logo lettering
     #E14C5F  the wall of the shop (see --wall for the text-safe variant)
     #F4A6C8  the donut that replaces the O in BOUJEE
     #0B0A08  their logo ground
   The checkerboard is the floor they actually stand on, used as a floor.
   Single-theme on purpose: the brand is a black room. Everything painted.
   ========================================================================= */

:root {
  scroll-padding-top: 74px;
  /* Nicht Schwarz. Ty: "das komplette Schwarz im Hintergrund tut meinen
     Augen weh" — und der bessere Grund dafuer ist, dass Schwarz der Grund
     ist, den JEDE dunkle Seite hat. Ihre Marke ist pink, also liegt ihr
     Pink im Grund: so wenig, dass man es nicht als Farbe sieht, genug,
     dass die Seite nicht wie eine Vorlage aussieht. akibon.studio macht es
     genauso, nur mit seinem Violett — das System wird uebernommen, die
     Farbe nicht.
     Gemessen, was es kostet: --ash faellt von 12,8 auf 12,5:1. Nichts. */
  --void:      #140B11;
  --void-2:    #1E1219;
  --void-3:    #281A22;
  --yellow:    #F9DB49;
  --coral:     #E14C5F;   /* sampled from the shop wall — accents, dots, borders */
  --wall:      #B02F41;   /* the same hue, deep enough to carry text:
                             white 6.3:1, yellow 4.6:1. The sampled value
                             came off a warm-lit photo and failed both. */
  --pink:      #F4A6C8;
  --cream:     #FBF3E2;
  /* Gemessen im Browser gegen den tatsaechlich zusammengesetzten Grund,
     nicht geschaetzt. Die alten Werte bestanden die Norm gerade so und lasen
     sich trotzdem wie Hintergrund: 4,5:1 ist der Boden, nicht das Ziel.
     Alles hier liegt jetzt darueber, und --ash-dim ist keine Textfarbe mehr
     knapp unter der Grenze, sondern selbst lesbar. */
  /* Zweiter Anlauf. Beim ersten habe ich gegen die Pruefnorm gemessen und
     bei 8,7:1 aufgehoert — bestanden, und trotzdem las es sich wie Grau auf
     Schwarz. Der Fehler war die Marke, nicht die Messung: Beschreibungen
     und Anweisungen sind INHALT, kein Beiwerk, und Inhalt gehoert nicht in
     ein gedaempftes Grau. Jetzt liegt Fliesstext dicht unter Cream, und
     gedaempft ist nur noch, was wirklich nebensaechlich ist. */
  --ash:       #D7CFC3;   /* 12,6:1 — Fliesstext, Beschreibungen, Anweisungen */
  --ash-quiet: #C0B8AC;   /* 10,1:1 — Kleingedrucktes, Meta, Etiketten */
  --ash-dim:   #A29A8E;   /* 7,1:1  — Punkte, Trenner, das Leiseste */
  --line:      #362834;   /* dieselbe Tuenchung wie der Grund */

  /* Dritter Anlauf, und diesmal an ihrem Logo gemessen statt an einer
     Eigenschaft davon.

     Ihr Logo ist HANDGEZEICHNET: dicke, breite, runde Versalien in Gelb,
     Marker-Optik, ein ganz normales &. Ich hatte daraus "wackelig und rund"
     gelesen und Fraunces genommen, weil es WONK- und SOFT-Achsen hat, die
     genau das koennen. Nur ist Fraunces eine BUCHSERIFE. Die Textur stimmte,
     die Familie war falsch - "Vanilla Bomb" las sich wie eine Weinkarte, und
     klein wurde es zappelig. Ty, dreimal: "die scheiss schriftart ... finde
     eine geilere die cleaner ist und passender".

     Gabarito trifft die Familie: breite, runde, satte Versalien, dieselbe
     freundliche Schwere wie ihre gemalten Buchstaben, ein &, das jeder kennt
     - und bei 19px in einer Liste sauber statt verspielt. Nebeneinander
     gestellt mit Bricolage, Archivo, Rubik, Unbounded und Figtree auf ihrem
     eigenen Inhalt; die Probe liegt in .probe/fonts.html.

     Schibsted Grotesk darunter fuer Fliesstext, DM Mono nur fuer kleine
     technische Anzeigen. Keine vierte Familie. */
  --display: "Gabarito", "Helvetica Neue", Arial, sans-serif;
  --boujee:  "Gabarito", "Helvetica Neue", Arial, sans-serif;
  --body:    "Schibsted Grotesk", "Helvetica Neue", Arial, sans-serif;
  --mono:    "DM Mono", ui-monospace, "SF Mono", Menlo, monospace;

  --pad: clamp(20px, 5vw, 64px);
  --maxw: 1240px;
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--void);
  color: var(--cream);
  font-family: var(--body);
  font-size: 17px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img { max-width: 100%; display: block; }
a { color: inherit; }
:focus-visible { outline: 2px solid var(--yellow); outline-offset: 3px; border-radius: 2px; }

.shell { max-width: var(--maxw); margin: 0 auto; padding-inline: var(--pad); }
.sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }

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

/* =========================================================================
   THE FLOOR — their tile, used as a floor rather than as a divider
   ========================================================================= */
.floor {
  height: 26px;
  background-color: var(--void);
  background-image: conic-gradient(
    var(--cream) 90deg, transparent 90deg 180deg,
    var(--cream) 180deg 270deg, transparent 270deg);
  background-size: 26px 26px;
}
.floor--tall { height: 44px; background-size: 44px 44px; }
/* Finer, for the strip directly under the reels, so the two of them do not
   read as the same rule twice. */
.checker--thin { height: 15px; background-size: 15px 15px; }

/* =========================================================================
   THE HEADER.

   Three tries got this wrong. First a black status strip, then a red slab
   under it, then both merged into one red block — every version was system
   furniture standing in front of the brand, and none of it did anything for
   somebody who had just arrived. The page also had no navigation at all.

   So it carries what belongs at the top of a shop's page: whether they are
   open, where the four sections are, the phone, and the one button that
   starts an order. The break notice is a single slim line underneath, and
   only while the break is still ahead.
   ========================================================================= */
/* The bar follows the page down now, so it has to earn every pixel of its
   height: one row, 52px, solid ground (no backdrop blur — ten of those cost
   this page 3fps on a phone once). */
.top {
  position: sticky; top: 0; z-index: 60;
  background: var(--void-2);
  border-bottom: 1px solid var(--line);
}
.top__in {
  max-width: var(--maxw); margin: 0 auto;
  padding-block: 9px; padding-inline: var(--pad);
  display: flex; align-items: center; gap: clamp(12px, 2vw, 26px);
  /* Was DM Mono, all of it. A whole header in monospace reads as a terminal
     — retro, technical, and nothing at all like a pink donut shop. The mono
     is for small labels and prices; the header speaks in the body face. */
  font-family: var(--body); font-size: 14px;
}

/* The wordmark used to hide until the big one in the hero had scrolled past,
   so the bar had two appearances. Ty: "warum muss es 2 versionen geben? Lass
   doch das Logo da stehen." It stands. The whole is-past machinery existed
   for this one rule and has gone with it — no scroll listener, no measuring
   of where the hero's wordmark ends. */
.top__brand {
  display: flex; align-items: center; gap: 9px; margin-right: 4px;
  text-decoration: none; color: var(--cream);
  font-family: var(--display); font-weight: 800;
  font-size: 15px; letter-spacing: -.02em; white-space: nowrap;
}
/* The same mark in the bar, at the bar's size. */
.top__brand em {
  display: inline-block; vertical-align: baseline;
  height: .607em; width: .437em;
  margin-inline: .09em; position: relative; top: .02em;
  background: var(--pink);
  -webkit-mask: url(assets/brand/amp.svg) center / contain no-repeat;
          mask: url(assets/brand/amp.svg) center / contain no-repeat;
  overflow: hidden; text-indent: -10em;
}

/* The long half of the status ("Open again tomorrow from 11:30am") is
   nowrap, so when the bar ran out of room it did not shrink — it simply
   painted over the navigation next to it. Clipped now, and the detail
   drops out while the navigation is still there, because the navigation
   is the thing you cannot guess. */
.top__now {
  margin: 0; display: flex; align-items: center; gap: 9px;
  min-width: 0; overflow: hidden;
}
.top__state { color: var(--cream); white-space: nowrap; }
.top__detail { color: var(--ash); white-space: nowrap; }
.top__detail:not(:empty)::before { content: "\00b7"; margin-right: 9px; color: var(--ash-dim); }

/* Navigation is back. It was pulled out because the bar did not stick, so
   it only ever appeared alongside the hero's own three buttons pointing at
   the same three places. A bar that follows you is the one place where it
   is not a duplicate. */
.top__nav { display: flex; gap: clamp(14px, 1.8vw, 24px); margin-left: auto; }
.top__nav a {
  color: var(--ash); text-decoration: none; white-space: nowrap;
  transition: color .18s ease;
}
.top__nav a:hover { color: var(--cream); }

.top__acts { display: flex; align-items: center; gap: clamp(10px, 1.4vw, 18px); }
.top__tel {
  color: var(--cream); text-decoration: none; white-space: nowrap;
  font-variant-numeric: tabular-nums;      /* the digits line up without mono */
}
.top__tel:hover { text-decoration: underline; }
.top__telshort { display: none; }


@media (max-width: 1180px) { .top__detail { display: none; } }
@media (max-width: 1000px) { .top__nav { display: none; } .top__now { margin-right: auto; } }
@media (min-width: 1001px) and (max-width: 1180px) { .top__now { margin-right: auto; } }
@media (max-width: 560px) {
  .top__telfull { display: none; }
  .top__telshort { display: inline; }
  .top__in { gap: 10px; }
}

/* The break: one sentence, a coral dot in front of it. The uppercase mono
   chip that used to sit here was the most retro thing on the page. It sits
   under the sticky bar and scrolls away, because the bar has to stay slim. */
.top__note {
  margin: 0;
  background: rgba(225,76,95,.10);
  border-bottom: 1px solid rgba(225,76,95,.22);
  color: var(--cream);
  font-family: var(--body); font-size: 14px;
  padding-block: 10px; padding-inline: var(--pad);
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
}
.top__note[hidden] { display: none; }
.top__tag {
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--coral); flex: 0 0 auto;
  align-self: center;
  font-size: 0; overflow: hidden;          /* the words go, the marker stays */
}
.top__sub { color: var(--ash); }
.top__sub:not(:empty)::before { content: "\2014"; margin-right: 10px; color: var(--ash-dim); }

.dot { width: 8px; height: 8px; border-radius: 50%; background: var(--ash-dim); flex: 0 0 auto; }
.dot--open  { background: #5BD68A; box-shadow: 0 0 0 3px rgba(91,214,138,.18); }
.dot--soon  { background: var(--yellow); box-shadow: 0 0 0 3px rgba(249,219,73,.18); }
.dot--shut  { background: var(--ash-dim); box-shadow: 0 0 0 3px rgba(255,255,255,.07); }
.dot--break { background: var(--coral); box-shadow: 0 0 0 3px rgba(225,76,95,.20); }


/* =========================================================================
   THE ROOM — hero. Type on the left, their reels standing on the counter.
   Deliberately not a full-bleed photo with a headline over it.
   ========================================================================= */
.room { background: var(--void); padding-top: clamp(48px, 8vw, 92px); overflow: hidden; }
.room__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(40px, 6vw, 72px);
  align-items: end;
}
@media (min-width: 940px) { .room__grid { grid-template-columns: 1fr 1.12fr; align-items: center; } }
/* Grid items default to min-width:auto, so a flex row of fixed-ish tiles
   grows its own track and pushes past the viewport. Pin it to zero. */
.room__grid > * { min-width: 0; }

.room__eyebrow {
  font-family: var(--mono); font-size: 11.5px; letter-spacing: .2em;
  text-transform: uppercase; color: var(--yellow); margin: 0 0 20px;
}
.wordmark {
  font-family: var(--display); font-weight: 800;
  font-size: clamp(3rem, 11vw, 7.6rem);
  line-height: .82; letter-spacing: -.045em;
  color: var(--yellow); margin: 0 0 24px; text-transform: uppercase;
}
/* <em> is italic by browser default, and Gabarito has no italic — the browser
   then slants it by hand, which is precisely the cheap look this whole change
   was about. Every <em> that wears the display face says normal explicitly;
   this catches any that is added later and forgets to. */
.top__brand em, .room__lede em, .sec-title em, .strip__one em, .dbox__lid em,
.wordmark em { font-style: normal; }

/* The ampersand used to need a whole recipe here: Fraunces' italic swaps in
   a swash Et-ligature, and Ty was blunt about it — "kein Mensch kennt die
   Version des & Zeichens was du gewaehlt hast. Das muss schon mit dem Logo
   harmonieren." Gabarito has one ampersand and it is the ordinary one, so
   all that is left is the size and the pink. */
/* THEIR ampersand, not Gabarito's.

   Ty: "dieses & zeichen ist anders als in deren offiziellem branding/LOGO."
   It is. So this one is traced out of assets/brand/logo.png - the shape is
   theirs, drawn with a marker, with the loop and the tail - and painted as a
   mask so the colour still comes from the stylesheet and nothing is a
   picture that would blur when the heading grows.

   In their logo the ampersand stands 57px against a 64px capital, so 0.89 of
   the cap height. The cap height of Gabarito was measured in the browser,
   not assumed, and the number below follows from the two. */
.wordmark .amp {
  display: inline-block; vertical-align: baseline;
  /* Gabarito's capital measures .681em here, and their ampersand stands at
     .891 of a capital, so: .681 x .891 = .607em tall, and the viewBox's
     1000:1390 gives the width. */
  height: .607em; width: .437em;
  margin-inline: .08em; position: relative; top: .02em;
  background: var(--pink);
  -webkit-mask: url(assets/brand/amp.svg) center / contain no-repeat;
          mask: url(assets/brand/amp.svg) center / contain no-repeat;
  /* The character stays in the markup for anything reading the page aloud;
     it is pushed out of the box and clipped rather than set to font-size 0,
     which would have collapsed the em-based height above to nothing. */
  overflow: hidden; text-indent: -10em;
}
.room__lede {
  font-size: clamp(1.05rem, 2.2vw, 1.35rem);
  max-width: 26ch; margin: 0 0 30px; line-height: 1.35;
}
/* No italic: Gabarito has none, and a browser-slanted fake is exactly the
   cheap look being fixed. The pink does the emphasising. */
.room__lede em { font-family: var(--boujee); font-style: normal; font-weight: 600; color: var(--pink); }

/* ---------- the counter -------------------------------------------------
   A fanned hand of cards rather than three polite thumbnails in a row:
   they overlap, the middle one is dominant, all three are playing, and
   each drifts on its own slow cycle so the block is never quite still.
   Tiles share the column rather than claiming a fixed width — a fixed
   width pushed the third card off the edge, where the body's overflow
   clip silently ate it. */
.counter {
  position: relative;
  display: flex;
  justify-content: center;
  align-items: center;
  padding-block: 30px;
  perspective: 1400px;
}
.counter .tile {
  flex: 1 1 0;
  min-width: 0;
  max-width: 268px;
  will-change: transform;
}
/* negative margins do the overlap; the middle card sits on top */
.counter .tile:nth-child(1) { margin-right: -5%; transform-origin: bottom right; }
.counter .tile:nth-child(3) { margin-left:  -5%; transform-origin: bottom left; }
.counter .tile:nth-child(2) { z-index: 3; }
.counter .tile:nth-child(1),
.counter .tile:nth-child(3) { z-index: 1; filter: brightness(.82) saturate(.9); }
/* The tiles in the hero stack used to jump forward when the cursor passed
   over them. Ty: "there is no reason for the ones in the back to come to
   the front by hovering" — right, there is not. They are a photograph of a
   counter, not a control. */

.counter .tile:nth-child(1) { animation: driftL 11s ease-in-out infinite; }
.counter .tile:nth-child(2) { animation: driftC  9s ease-in-out infinite; }
.counter .tile:nth-child(3) { animation: driftR 13s ease-in-out infinite; }

@keyframes driftL {
  0%,100% { transform: rotate(-7deg) translateY(20px) scale(.9); }
  50%     { transform: rotate(-8.5deg) translateY(10px) scale(.91); }
}
@keyframes driftC {
  0%,100% { transform: rotate(1.5deg) translateY(-10px) scale(1.1); }
  50%     { transform: rotate(0deg) translateY(-22px) scale(1.11); }
}
@keyframes driftR {
  0%,100% { transform: rotate(8deg) translateY(26px) scale(.9); }
  50%     { transform: rotate(6.5deg) translateY(14px) scale(.91); }
}
@media (prefers-reduced-motion: reduce) {
  .counter .tile { animation: none; }
  .counter .tile:nth-child(1) { transform: rotate(-7deg) translateY(20px) scale(.9); }
  .counter .tile:nth-child(2) { transform: rotate(1.5deg) translateY(-10px) scale(1.1); }
  .counter .tile:nth-child(3) { transform: rotate(8deg) translateY(26px) scale(.9); }
}
@media (max-width: 620px) {
  .counter .tile:nth-child(3) { display: none; }
  /* two cards, sized so the drift animation's 1.11 scale still never
     reaches the bezel — at 190px the peak of the cycle clipped */
  .counter .tile { max-width: 158px; }
  .counter .tile:nth-child(1) { margin-right: -8%; }
}

/* A 9:16 frame. The reels are 720x1280, so at this width they are sharp
   rather than upscaled the way the 360px grid thumbnails were. */
.tile {
  position: relative;
  aspect-ratio: 9 / 16;
  border-radius: 12px;
  overflow: hidden;
  background: var(--void-3);
  border: 1px solid var(--line);
  box-shadow: 0 24px 50px -22px rgba(0,0,0,.95);
  transition: transform .3s cubic-bezier(.2,.7,.3,1), border-color .3s ease;
}
.tile img, .tile video { width: 100%; height: 100%; object-fit: cover; }
.tile:hover { border-color: var(--yellow); }

/* =========================================================================
   THE REEL WALL — the brother's work, given the room it earns
   ========================================================================= */
.wall { background: var(--void-2); padding-block: clamp(56px, 8vw, 96px); }
.wall__head {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 24px; flex-wrap: wrap; margin-bottom: 28px;
}
.wall__credit {
  font-family: var(--mono); font-size: 11.5px; color: var(--ash);
  border: 1px solid var(--line); border-radius: 999px; padding: 7px 14px;
  text-decoration: none; white-space: nowrap;
}
.wall__credit:hover { border-color: var(--yellow); color: var(--yellow); }

.reels {
  display: flex; gap: 16px;
  overflow-x: auto; overflow-y: hidden;
  padding-block: 6px 20px;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: thin;
  scrollbar-color: var(--line) transparent;
}
.reels::-webkit-scrollbar { height: 6px; }
.reels::-webkit-scrollbar-thumb { background: var(--line); border-radius: 99px; }
.reel { flex: 0 0 auto; width: clamp(168px, 44vw, 232px); scroll-snap-align: start; }
/* An invisible marker riding at the end of the rail. When it comes into
   view the next batch of clips is pulled in — which is what carries the
   wall on a phone, where there are no arrows. */
.reels__end { flex: 0 0 1px; width: 1px; height: 1px; }
/* Same for the wall: a clip is something you watch, not something that
   reacts to being approached. */
/* .reel__cap stand hier: eine Zeile unter jedem Clip, die sagte, was
   darin zu sehen ist. Sie stimmte nicht verlaesslich mit dem Clip ueberein,
   unter dem sie stand, und eine falsche Bildunterschrift ist schlechter als
   keine. */
/* The pink wall lived here: an earlier version of today's board, on the
   red of their shop wall. It has not been in the markup for a long time,
   and its bare `.board` rule was quietly turning the new board into a
   grid. Gone, along with .pinkwall, .slat and the stamp keyframes. */


/* =========================================================================
   SECTION FURNITURE
   ========================================================================= */
.band { padding-block: clamp(56px, 8vw, 104px); }
/* Two classes were being used in the markup that had never been written:
   .band--raise did nothing, so every section sat on the identical ground
   and only the checkerboard strip ever separated them — which is a large
   part of why the whole lower half read as one repeated section. The
   grounds alternate now, and most of the strips have gone. */
.band--raise { background: var(--void-2); }
/* The eyebrow used to sit ABOVE the heading in small mono caps with a
   hairline ruled across the column — the arrangement every generated
   landing page ships with. It sits UNDER the heading now, in the studio's
   own label spec (11px / 800 / .24em), finishing the sentence rather than
   announcing it. No rule. */
.eyebrow {
  font-family: var(--body); font-size: 11px; font-weight: 800;
  letter-spacing: .24em; text-transform: uppercase;
  color: var(--yellow); margin: 0 0 22px; display: block;
}
.eyebrow::after { content: none; }

/* Five sections in a row carried a huge all-caps headline with an italic
   serif tail hanging off it. One of those is a signature; five is a
   template, and it was the loudest thing on the page. Sentence case now,
   at the size the ranking block already used and looked right at —
   which is also, measured, what akibon.studio sets its own sections in. */
h2.sec-title {
  font-family: var(--display); font-weight: 800;
  font-size: clamp(1.7rem, 3.2vw, 2.5rem);
  line-height: 1.06; letter-spacing: -.028em;
  margin: 0 0 12px; text-wrap: balance; text-transform: none;
  max-width: 24ch;
}
/* The emphasis stays — it just stops changing typeface to do it. Same
   face, same weight, their pink. The italic serif lives in the hero only,
   where one of it reads as a signature. */
h2.sec-title em {
  font-family: inherit; font-style: normal; font-weight: 800;
  text-transform: none; color: var(--pink); letter-spacing: inherit;
}
/* The one lead-in sentence a section gets, and all three of them are set
   from here. They had drifted to three different sizes in three places —
   1.03rem, .97rem and 1.2rem — which is why one section kept reading as the
   weak one next to the others. */
.sec-lede, .deliver__note {
  color: var(--ash);
  font-size: clamp(1.06rem, 1.3vw, 1.28rem); line-height: 1.5;
}
.sec-lede b, .deliver__note b { color: var(--cream); font-weight: 700; }
.sec-lede { max-width: 46ch; margin: 18px 0 38px; }

/* ---------- buttons ---------- */
.row { display: flex; gap: 11px; flex-wrap: wrap; }
.btn {
  font-family: var(--body); font-weight: 600; font-size: .98rem;
  text-decoration: none; padding: 13px 23px; border-radius: 999px;
  border: 1.5px solid transparent; display: inline-flex; align-items: center; gap: 8px;
  /* Zentriert, nicht linksbuendig. Solange sich ein Knopf nach seinem Inhalt
     richtet, faellt das nicht auf - erst wo er gestreckt wird, klebte die
     Schrift links. Deshalb an der Wurzel und nicht an einer Stelle. */
  justify-content: center; text-align: center;
  cursor: pointer;
  transition: transform .18s cubic-bezier(.2,.8,.3,1), background-color .18s ease, color .18s ease, border-color .18s ease;
}
.btn:hover { transform: translateY(-2px); }
.btn:active { transform: translateY(0); }
.btn--y { background: var(--yellow); color: var(--void); }
.btn--y:hover { background: #FFE879; }
.btn--c { background: var(--wall); color: #fff; }
.btn--c:hover { background: var(--coral); }
.btn--w { background: #fff; color: var(--wall); }
.btn--w:hover { background: var(--cream); }
.btn--ghost { border-color: var(--line); color: var(--cream); }
.btn--ghost:hover { border-color: var(--yellow); color: var(--yellow); }

/* =========================================================================
   MENU — a narrow editorial column beside one tall frame
   ========================================================================= */
@media (min-width: 980px) { .menu-wrap { grid-template-columns: minmax(0,1.35fr) minmax(0,.65fr); } }


/* Nothing is pinned at the top any more, so this no longer has to
   duck under a bar that is not there. */
.box--pop { border-color: var(--yellow); background: var(--void-3); }

/* =========================================================================
   CATERING
   ========================================================================= */
.cater-grid { display: grid; grid-template-columns: 1fr; gap: clamp(34px, 5vw, 60px); }
@media (min-width: 940px) { .cater-grid { grid-template-columns: .85fr 1.15fr; } }
/* The four kinds of order are what gives somebody the idea — but only if
   the eye lands on them. As four lines of text they get skipped, so each
   one carries its own tower of boxes at the size that order really is. */
.cater-list { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 12px; margin: 0 0 clamp(30px, 4vw, 48px); }

.cater-pick {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 0;
  text-align: left;
  width: 100%;
  background: var(--void-2);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 20px 20px 18px;
  cursor: pointer;
  font-family: var(--body);
  color: var(--cream);
  transition: border-color .2s ease, background-color .2s ease, transform .2s cubic-bezier(.2,.9,.3,1);
}
.cater-pick:hover { border-color: var(--yellow); background: var(--void-3); transform: translateY(-3px); }
.cater-pick.on { border-color: var(--yellow); background: var(--void-3); }

/* -------------------------------------------------------------------------
   THE FOUR SCENES. Full width of the card, not a thumbnail beside the text:
   at 76px the picture was texture and the eye skipped it. Each has its own
   ground, and the wedding one is ivory so that in a row of dark cards there
   is one your eye stops on.
   ------------------------------------------------------------------------- */
.scene {
  display: block;
  width: 100%;
  border-radius: 9px;
  overflow: hidden;
  background: var(--void-3);
  margin-bottom: 14px;
}
.scene svg { display: block; width: 100%; height: auto; }

/* Coloured light rather than flat panels — the way a room actually looks
   when somebody has put LEDs in it. Each card keeps its own two or three
   colours so they still read apart, and every bloom stays under the lid's
   contrast so the writing on it never gets lost. */
.scene--office {
  background:
    radial-gradient(58% 80% at 16% 12%, rgba(86,150,255,.30), transparent 62%),
    radial-gradient(52% 74% at 88% 22%, rgba(120,225,255,.20), transparent 64%),
    linear-gradient(#2C3137, #1B1F24);
}
.scene--birthday {
  background:
    radial-gradient(58% 80% at 14% 14%, rgba(255,54,158,.44), transparent 62%),
    radial-gradient(56% 76% at 88% 20%, rgba(104,110,255,.40), transparent 64%),
    radial-gradient(78% 92% at 50% 112%, rgba(249,219,73,.26), transparent 66%),
    linear-gradient(#2E1524, #190C14);
}
/* Uplighting is what a venue actually does for a wedding — warm from below,
   a wash of violet across the back. */
.scene--wedding {
  background:
    radial-gradient(70% 86% at 50% 112%, rgba(255,196,96,.30), transparent 64%),
    radial-gradient(56% 74% at 84% 16%, rgba(168,120,255,.24), transparent 64%),
    linear-gradient(#26302A, #171D19);
}
.scene--wholesale {
  background:
    radial-gradient(56% 78% at 82% 16%, rgba(255,170,60,.22), transparent 62%),
    radial-gradient(52% 70% at 14% 84%, rgba(120,255,190,.14), transparent 64%),
    linear-gradient(#37332C, #211E1A);
}

/* The whole card lifts, and the picture leans in a little under it. */
.cater-pick .scene svg { transition: transform .45s cubic-bezier(.2,.9,.3,1); }
.cater-pick:hover .scene svg { transform: scale(1.035); }

@media (prefers-reduced-motion: reduce) {
  .cater-pick .scene svg { transition: none; }
}

.cater-pick__body { flex: 1 1 auto; min-width: 0; }
.cater-pick h3 {
  font-family: var(--display); font-weight: 700;
  font-size: 1.2rem; margin: 0 0 3px; letter-spacing: -.015em;
}
.cater-pick .min {
  display: block;
  font-family: var(--mono); font-size: 10.5px; letter-spacing: .08em;
  text-transform: uppercase; color: var(--yellow); margin-bottom: 8px;
}
.cater-pick p { margin: 0; color: var(--ash); font-size: .92rem; }
.cater-pick__go {
  display: block;
  font-family: var(--mono); font-size: 10px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--ash-dim); margin-top: 12px;
  transition: color .2s ease;
}
.cater-pick:hover .cater-pick__go, .cater-pick.on .cater-pick__go { color: var(--yellow); }
.cater-pick__go span { display: inline-block; transition: transform .2s ease; }
.cater-pick:hover .cater-pick__go span { transform: translateX(4px); }
@media (prefers-reduced-motion: reduce) {
  .cater-pick, .cater-pick__go span, .mini__box { transition: none; }
}

.pair { display: grid; grid-template-columns: 1fr 1fr; gap: 15px; }
@media (max-width: 520px) { .pair { grid-template-columns: 1fr; } }
/* 10,5px mit Laufweite ist keine Beschriftung, das ist ein Muster. */
label {
  font-family: var(--body); font-weight: 700;
  font-size: 12px; letter-spacing: .1em; text-transform: uppercase;
  color: var(--ash-quiet); display: block;
}
input, textarea, select {
  font-family: var(--body); font-size: 1rem; color: var(--cream);
  background: var(--void-2); border: 1px solid var(--line);
  border-radius: 6px; padding: 12px 14px; width: 100%;
  transition: border-color .16s ease;
}
input:hover, textarea:hover, select:hover { border-color: var(--ash-dim); }
input:focus, textarea:focus, select:focus { border-color: var(--yellow); outline: none; }
textarea { resize: vertical; min-height: 104px; }
select {
  appearance: none;
  background-image: linear-gradient(45deg, transparent 50%, var(--ash) 50%), linear-gradient(135deg, var(--ash) 50%, transparent 50%);
  background-position: calc(100% - 20px) 21px, calc(100% - 14px) 21px;
  background-size: 6px 6px; background-repeat: no-repeat;
}
/* Das Schlimmste auf der Seite: 13,3px auf 3,23:1. Es steht unter jedem
   Knopf und unter jeder Summe, also ist es das Kleingedruckte, das am
   haeufigsten gelesen wird. Groesser, heller, mehr Zeilenabstand. */
.form-note {
  font-size: .91rem; line-height: 1.6;
  color: var(--ash-quiet); margin: 0;
}

/* =========================================================================
   VISIT — the streetcar photo is their one landscape frame, so it gets to
   be the only wide image on the site
   ========================================================================= */
.visit { display: grid; grid-template-columns: 1fr; gap: clamp(32px, 5vw, 56px); align-items: start; }
@media (min-width: 940px) { .visit { grid-template-columns: 1fr 1fr; } }
.score { display: flex; align-items: baseline; gap: 14px; margin-bottom: 26px; }
.score__num { font-family: var(--display); font-weight: 800; font-size: 3.2rem; line-height: .8; color: var(--yellow); letter-spacing: -.05em; font-variant-numeric: tabular-nums; }
.score__meta { font-family: var(--mono); font-size: 11.5px; letter-spacing: .1em; text-transform: uppercase; color: var(--ash); }
.score__stars { color: var(--yellow); letter-spacing: .16em; display: block; margin-bottom: 4px; font-size: .95rem; }
.hours { list-style: none; margin: 0 0 24px; padding: 0; }
.hours li {
  display: flex; justify-content: space-between; gap: 16px;
  padding-block: 10px; border-bottom: 1px solid var(--line);
  font-family: var(--mono); font-size: .9rem; font-variant-numeric: tabular-nums;
}
.hours li.today { color: var(--yellow); }
/* This list used the class name .day, and so did the pick-up chips in the
   cart — so every weekday here picked up a border, a radius and padding
   and looked like a button you could press. Ty: "warum sind das buttons?
   die Tage". They are not; they are a list of days. Renamed, because two
   different things must never share a class name. */
.hours li.today .hours__day::before { content: "\25B8 "; }
.hours .shut { color: var(--ash-dim); }
.wide { border-radius: 8px; overflow: hidden; border: 1px solid var(--line); }
.wide img { width: 100%; aspect-ratio: 16/9; object-fit: cover; }
.wide__cap { font-family: var(--mono); font-size: 11px; color: var(--ash-dim); margin: 9px 2px 0; letter-spacing: .05em; }

/* =========================================================================
   FOOTER — stands on the floor
   ========================================================================= */
footer { background: var(--void-2); padding-block: 56px 34px; }

/* Was a flex row with space-between: three blocks of different widths, so
   the middle gap yawned open and nothing lined up with anything. A grid
   gives every column the same top edge and a fixed share of the width. */
/* Four columns and twenty links became one row. Everything that went was
   a second copy of something already on the screen: the hours stand
   complete in the Visit section above, and the open/closed line plus the
   navigation are in the bar that follows you down the page. */
.foot {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: clamp(20px, 4vw, 52px);
  padding-bottom: clamp(26px, 3vw, 38px);
}
.foot__logo { display: block; flex: 0 0 auto; }
.foot__logo img { width: clamp(96px, 11vw, 124px); height: auto; display: block; }

.foot__where {
  font-style: normal; display: grid; gap: 5px;
  margin-right: auto;
}
.foot__where a {
  color: var(--ash); text-decoration: none; font-size: .95rem;
  transition: color .18s ease;
}
.foot__where a:hover { color: var(--cream); }

.foot__links { display: flex; flex-wrap: wrap; gap: clamp(14px, 2vw, 26px); align-items: center; }
.foot__links a,
.foot__link {
  background: none; border: 0; padding: 0; cursor: pointer;
  font-family: var(--body); font-size: .95rem;
  color: var(--ash); text-decoration: none;
  transition: color .18s ease;
}
.foot__links a:hover,
.foot__link:hover { color: var(--yellow); }

.colophon {
  margin-top: 38px; padding-top: 20px; border-top: 1px solid var(--line);
  font-family: var(--mono); font-size: 12.5px; color: var(--ash-quiet);
  display: flex; flex-wrap: wrap; gap: 12px; justify-content: space-between;
}

/* Die Besitzer-Anmeldung steht VOR dem Akibon-Hinweis, damit Akibon das
   letzte Wort behaelt. Am Handy bekommen die beiden eine eigene Zeile und
   der Trennpunkt dazwischen faellt weg. */
.colophon__end a { color: inherit; text-decoration: none; border-bottom: 1px solid var(--line); }
.colophon__end a:hover { color: var(--yellow); border-bottom-color: var(--yellow); }
.colophon__end a:focus-visible { outline: 2px solid var(--yellow); outline-offset: 3px; }
@media (max-width: 700px) {
  .colophon__end { display: flex; width: 100%; justify-content: space-between; gap: 12px; }
  .colophon__dot { display: none; }
}

/* Die Fusszeile am Handy, nach der Kafe-Daki-Seite (Ty, 09.10.2026).

   Vorher war .foot auch hier eine umbrechende Zeile: Logo, Adresse und vier
   Textlinks suchten sich auf 335px ihren Platz, und die Links standen am
   Ende als 24px hohe Zeile nebeneinander - unter der Daumengroesse, die eine
   Schaltflaeche haben sollte. Eine Spalte mit einem Rhythmus: Logo, Adresse,
   dann die Ziele als Tasten.

   Uber Eats liegt unten ueber die volle Breite und in Gelb, weil das die
   einzige Stelle im Fuss ist, an der tatsaechlich bestellt wird - dieselbe
   Rolle, die "Order online" bei Kafe Daki hat. Der Datenschutz-Knopf bleibt
   Text: er oeffnet nur ein Fenster und waere als gleich grosse Taste eine
   Behauptung ueber seine Wichtigkeit. */
@media (max-width: 620px) {
  footer { padding-block: 40px 76px; }
  .foot { display: grid; gap: 20px; padding-bottom: 0; }
  .foot__logo img { width: 104px; }
  .foot__where { gap: 6px; margin: 0; }
  .foot__where a { font-size: 15px; }

  .foot__links { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
  .foot__links a {
    display: flex; align-items: center; justify-content: center;
    min-height: 46px; border: 1px solid var(--line); border-radius: 999px;
    font-weight: 600; color: var(--cream);
  }
  #footUber {
    grid-column: 1 / -1;
    background: var(--yellow); border-color: var(--yellow); color: var(--void);
  }
  .foot__link { grid-column: 1 / -1; justify-self: center; font-size: 13px; color: var(--ash-quiet); }

  .colophon { margin-top: 28px; padding-top: 18px; flex-direction: column; gap: 10px; }
}

/* =========================================================================
   ?check — Tyrone's pre-flight list. The client never sees it.
   ========================================================================= */
.check {
  position: fixed; right: 16px; bottom: 16px; z-index: 200;
  width: min(360px, calc(100vw - 32px)); max-height: 70svh; overflow-y: auto;
  background: var(--void-3); border: 1px solid var(--coral); border-radius: 8px;
  padding: 18px 20px; font-family: var(--mono); font-size: 12px; line-height: 1.55;
  box-shadow: 0 20px 60px -20px rgba(0,0,0,.9);
}
.check h5 { margin: 0 0 10px; color: var(--coral); font-size: 11px; letter-spacing: .14em; text-transform: uppercase; }
.check ul { margin: 0; padding-left: 16px; color: var(--ash); }
.check li { margin-bottom: 7px; }
.check b { color: var(--cream); font-weight: 400; }
.check .ok { color: #5BD68A; }
.check button {
  margin-top: 12px; background: none; border: 1px solid var(--line); color: var(--ash);
  font-family: var(--mono); font-size: 11px; padding: 5px 11px; border-radius: 4px; cursor: pointer;
}
.check button:hover { border-color: var(--coral); color: var(--coral); }

/* ---------- reveal ---------- */
.rise { opacity: 0; transform: translateY(16px); transition: opacity .6s ease, transform .6s cubic-bezier(.2,.8,.3,1); }
.rise.seen { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) { .rise { opacity: 1; transform: none; } }

/* =========================================================================
   THE CATERING QUOTE
   Boxes stack as you drag, with a real price on them. A form that asks an
   office manager to guess the number is a form they close.
   ========================================================================= */
.quote { margin-bottom: 34px; }
.quote__label {
  font-family: var(--mono); font-size: 10.5px; letter-spacing: .13em;
  text-transform: uppercase; color: var(--ash); display: block; margin-bottom: 16px;
}

.quote__range {
  appearance: none; -webkit-appearance: none;
  width: 100%; height: 4px; padding: 0; border: 0;
  background: var(--line); border-radius: 99px; cursor: pointer;
}
.quote__range::-webkit-slider-thumb {
  appearance: none; -webkit-appearance: none;
  width: 22px; height: 22px; border-radius: 50%;
  background: var(--yellow); border: 3px solid var(--void-2);
  box-shadow: 0 2px 8px rgba(0,0,0,.6); cursor: grab;
}
.quote__range::-moz-range-thumb {
  width: 22px; height: 22px; border-radius: 50%;
  background: var(--yellow); border: 3px solid var(--void-2);
  box-shadow: 0 2px 8px rgba(0,0,0,.6); cursor: grab;
}
.quote__range:focus-visible { outline: 2px solid var(--yellow); outline-offset: 6px; }

/* A stack you can count, in the same pink card as the box in the builder.
   Towers of five, growing upward, each slab showing its own lid seam and
   the shadow of the one above it. */
/* Stack left, answer right — one row rather than a narrow tower with the
   whole right half of the column empty beside it. */
.quote__body {
  display: grid;
  grid-template-columns: 1fr;
  gap: 22px;
  align-items: end;
  margin: 26px 0 20px;
}
@media (min-width: 620px) {
  .quote__body { grid-template-columns: auto 1fr; gap: 34px; }
}

.quote__stack {
  display: flex;
  align-items: flex-end;
  gap: 14px;
  min-height: 132px;
  padding-left: 2px;
}
.qcol { display: flex; flex-direction: column-reverse; gap: 2px; }

.qbox {
  position: relative;
  width: 62px;
  height: 21px;
  border-radius: 3px;
  background: linear-gradient(#F7B8D2 0%, #F0A3C4 46%, #DE8CB0 100%);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.7),
    0 2px 4px rgba(0,0,0,.5);
  animation: stackUp .3s cubic-bezier(.2,1.5,.4,1) both;
}
/* the seam where the lid meets the base */
.qbox::after {
  content: "";
  position: absolute; left: 4px; right: 4px; top: 7px;
  height: 1px;
  background: rgba(140,45,80,.32);
}
@keyframes stackUp { from { transform: translateY(-14px) scaleY(.5); opacity: 0; } to { transform: none; opacity: 1; } }

.quote__out {
  display: flex; flex-direction: column; align-items: flex-start;
  gap: 8px; min-width: 0;
}
.quote__n {
  display: block; font-family: var(--display); font-weight: 800;
  font-size: clamp(1.8rem, 4vw, 2.6rem); line-height: 1;
  letter-spacing: -.03em; font-variant-numeric: tabular-nums;
}
.quote__sub { display: block; color: var(--ash); font-size: .88rem; margin-top: 2px; }
.quote__price {
  margin-top: 4px;
  font-family: var(--mono); font-weight: 700; font-size: clamp(1.8rem, 4vw, 2.4rem);
  color: var(--yellow); font-variant-numeric: tabular-nums; white-space: nowrap;
}
.quote__note { color: var(--ash-dim); font-size: .86rem; margin: 14px 0 0; }

@media (prefers-reduced-motion: reduce) { .qbox { animation: none; } }

/* The leader-dot row needs name / dots / price on one line, but with a
   104px donut beside it there is not always a line's worth of room — a
   long name plus the SIGNATURE flag pushed the price 41px off a phone.
   The name may now shrink, and the row may wrap before it overflows. */
@media (max-width: 480px) {
}

/* =========================================================================
   MENU — bigger donuts, and hovering a row actually does something
   ========================================================================= */
@media (max-width: 560px) { .dn--row { width: 78px; height: 78px; } .menu li { gap: 14px; } }

/* ---------- the preview the rows drive ---------- */
@keyframes peekIn { from { opacity: 0; transform: scale(1.04); } to { opacity: 1; transform: none; } }
@media (max-width: 979px) { .peek { display: none; } }
@media (prefers-reduced-motion: reduce) { .peek__frame.swap { animation: none; } .dn--row, .said { transition: none; } }



/* =========================================================================
   THE PRAISE STRIP
   Seven cards in a grid is the most generic shape social proof has. This is
   one line of what people said, running past like the floor does — no
   section of its own, and the coral still breaks up the black.
   ========================================================================= */
.strip {
  background: var(--wall);
  color: #fff;
  overflow: hidden;
  padding-block: 16px;
  border-block: 1px solid rgba(0,0,0,.25);
}
.strip__run {
  display: flex;
  width: max-content;
  animation: runPast 68s linear infinite;
}
.strip:hover .strip__run { animation-play-state: paused; }

.strip__one { display: inline-flex; align-items: baseline; gap: 12px; padding-inline: 26px; white-space: nowrap; }
.strip__mark { color: var(--yellow); font-size: .8rem; }
.strip__one em {
  font-family: var(--boujee);
  font-style: normal;
  font-weight: 600;
  font-size: 1.3rem;
  line-height: 1;
}
.strip__one b {
  font-family: var(--mono);
  font-weight: 400;
  font-size: 11px;
  letter-spacing: .06em;
  color: rgba(255,255,255,.62);
}

@keyframes runPast { from { transform: translateX(0); } to { transform: translateX(-50%); } }

/* No motion: let it be a normal wrapped line instead of a frozen one. */
@media (prefers-reduced-motion: reduce) {
  .strip__run { animation: none; width: auto; flex-wrap: wrap; gap: 4px 0; }
  .strip__one:nth-child(n+8) { display: none; }
}

/* The score is a standing fact about the shop, like the phone number. */

/* Reports the slider rather than asking again — styled like the inputs it
   sits beside so the row still reads as one row. */
.readback {
  display: block;
  font-family: var(--body);
  font-size: 1rem;
  color: var(--cream);
  background: var(--void-3);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 12px 14px;
  font-variant-numeric: tabular-nums;
}

/* ---------- the like count on a reel ---------- */
.reel__likes {
  display: inline-block;
  color: var(--yellow);
  font-family: var(--mono);
  font-size: 11px;
  margin-right: 9px;
  font-variant-numeric: tabular-nums;
}

/* =========================================================================
   COMMENTS ON THE CLIP
   A box of testimonials sitting on its own was never attached to anything.
   These are the comments left under this exact post, so they surface over
   this exact clip — one after another, unhurried, and only when asked.
   ========================================================================= */
.said {
  position: absolute;
  inset: auto 0 0 0;
  z-index: 3;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: 13px;
  padding: 48px 14px 16px;
  background: linear-gradient(to top, rgba(20,11,17,.97) 40%, rgba(20,11,17,.82) 70%, transparent);
  /* Wieder exakt wie im Backup. Ich hatte hier opacity: 1 hart gesetzt und
     damit .tile.talking ausgehebelt - und mit ihm das gestaffelte Auftauchen
     der Zeilen UND das Ausblenden der Zaehler. Die Kommentare waren zwar da,
     aber ohne alles, was sie gut gemacht hat.

     Der Unterschied zum Backup ist nur noch die Farbe des Verlaufs: die
     folgt dem Grund der Seite, der nicht mehr schwarz ist. Sichtbar sind
     sie trotzdem, weil .talking jetzt vom Beobachter kommt und nicht mehr
     vom Mauszeiger - das war Tys urspruengliche Beschwerde. */
  opacity: 0;
  pointer-events: none;
  transition: opacity .45s ease;
}
.tile.talking .said { opacity: 1; }

/* The handle used to run into the comment and both lost. It sits above
   now, small and quiet, so the sentence itself is the thing you read. */
.said__row {
  display: block;
  color: #fff;
  font-size: .96rem;
  line-height: 1.32;
  text-shadow: 0 1px 4px rgba(0,0,0,.95);
  opacity: 0;
  transform: translateY(8px);
}
.said__row b {
  display: block;
  font-family: var(--mono);
  font-weight: 400;
  font-size: 9.5px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--yellow);
  margin-bottom: 2px;
  opacity: .85;
}

/* Each one waits its turn — 260ms apart, so they arrive rather than appear. */
.tile.talking .said__row {
  animation: sayUp .55s cubic-bezier(.2,.9,.3,1) forwards;
  animation-delay: calc(var(--n) * .26s + .12s);
}
@keyframes sayUp { to { opacity: 1; transform: none; } }

@media (prefers-reduced-motion: reduce) {
  .said, .said__row { transition: none; }
  .tile.talking .said__row { animation: none; opacity: 1; transform: none; }
}

/* =========================================================================
   FINDING IT
   "Will I recognise it?" is half the decision for a small shop on a long
   street. A map answers where; the window, the stools and the streetcar
   answer what it looks like when you get there.
   ========================================================================= */
/* One row of three, all the same height. The old block was a stack of big
   pictures and ate the screen; this reads as a strip of the street, and the
   captions sit ON the image so they cost no height at all. */
.place {
  display: grid;
  grid-template-columns: 1fr;
  gap: 10px;
  margin-bottom: clamp(24px, 3.4vw, 38px);
}
@media (min-width: 700px) {
  .place { grid-template-columns: 1.55fr 1fr 1fr; }
}

.place__shot { position: relative; margin: 0; border-radius: 10px; overflow: hidden; }
.place__shot img {
  width: 100%;
  height: clamp(170px, 20vw, 250px);
  object-fit: cover;
  display: block;
  transition: transform .5s cubic-bezier(.2,.9,.3,1), filter .4s ease;
}
/* On one column the lead shot is the one worth the extra height. */
@media (max-width: 699px) {
  .place__shot--lead img { height: clamp(200px, 52vw, 280px); }
}
.place__shot:hover img { transform: scale(1.03); filter: brightness(1.05); }

.place__shot figcaption {
  position: absolute; left: 0; right: 0; bottom: 0;
  padding: 22px 12px 9px;
  font-family: var(--mono); font-size: 11px; letter-spacing: .04em;
  color: #fff;
  background: linear-gradient(to top, rgba(8,7,6,.86), rgba(8,7,6,0));
  pointer-events: none;
}

.map {
  border-radius: 10px;
  overflow: hidden;
  border: 1px solid var(--line);
  background: var(--void-2);
  aspect-ratio: 16 / 11;
}
.map iframe { width: 100%; height: 100%; border: 0; display: block; filter: saturate(.85); }

@media (prefers-reduced-motion: reduce) { .place__shot img { transition: none; } }

/* Re-stated after the background above, which came later in the file and
   was flattening the highlighted card back to the others. */
.box--pop { background: var(--void-3); border-color: var(--yellow); }

/* -------------------------------------------------------------------------
   BACK TO THE TOP. Hidden by default and hidden from the tab order with it.
   It never moves sideways when it hides: a fixed element parked off the
   right edge is exactly what gave this page a phantom horizontal scrollbar
   once already, so the hide is opacity and a few pixels of lift, no more.

   The entrance and the hover used to fight over the same transform, which
   is what made it snap. Now the button itself only ever animates in and
   out, and the hover moves the arrow inside it.
   ------------------------------------------------------------------------- */
.totop {
  position: fixed;
  right: clamp(14px, 3vw, 26px);
  bottom: clamp(14px, 3vw, 26px);
  z-index: 70;
  width: 46px; height: 46px;
  display: grid; place-items: center;
  border: 1px solid rgba(20,11,17,.25);
  border-radius: 50%;
  background: var(--yellow);
  box-shadow: 0 6px 18px rgba(0,0,0,.45);
  cursor: pointer;
  opacity: 0; visibility: hidden;
  transform: translateY(14px) scale(.9);
  transition:
    opacity .30s ease,
    transform .42s cubic-bezier(.16,1,.3,1),
    box-shadow .25s ease,
    visibility 0s .30s;
}
.totop.is-on {
  opacity: 1; visibility: visible; transform: none;
  transition:
    opacity .30s ease,
    transform .42s cubic-bezier(.16,1,.3,1),
    box-shadow .25s ease,
    visibility 0s;
}
.totop.is-on:hover { box-shadow: 0 10px 26px rgba(249,219,73,.30); }
.totop.is-on:active { transform: scale(.94); transition-duration: .12s; }
.totop:focus-visible { outline: 2px solid var(--cream); outline-offset: 3px; }

/* the arrow, drawn rather than typed, so it never becomes a font's idea of one */
.totop__arrow {
  width: 11px; height: 11px;
  border-left: 2.5px solid var(--void);
  border-top: 2.5px solid var(--void);
  transform: rotate(45deg);
  margin-top: 3px;
  transition: transform .28s cubic-bezier(.2,1.35,.4,1);
}
.totop.is-on:hover .totop__arrow { transform: translateY(-3px) rotate(45deg); }

@media (prefers-reduced-motion: reduce) {
  .totop, .totop__arrow { transition: opacity .01s, visibility 0s; }
  .totop { transform: none; }
  .totop.is-on:hover .totop__arrow { transform: rotate(45deg); }
}

/* "Ask" is a phone call, not a shrug. A price nobody has confirmed still
   gets you a way to find it out. */

/* Likes and comments where they live on the post: top corners, over the
   clip. A pill each so they hold on a bright frame as well as a dark one,
   and pointer-events off so they never eat a tap meant for the video. */
.reel__stats {
  position: absolute; inset: 10px 10px auto 10px; z-index: 2;
  display: flex; justify-content: space-between; align-items: flex-start;
  pointer-events: none;
}
.reel__stat {
  font-family: var(--mono); font-size: 11px; line-height: 1;
  color: #fff; background: rgba(20,11,17,.58);
  backdrop-filter: blur(5px);
  border: 1px solid rgba(251,243,226,.20);
  border-radius: 99px; padding: 5px 9px;
  font-variant-numeric: tabular-nums;
}
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
/* while the comments run they would sit on top of each other */
.tile.talking .reel__stats { opacity: 0; transition: opacity .3s ease; }


/* The preview notice inside a submitted form: the first half has to read as
   a status, not as a confirmation somebody can skim past. */

/* The privacy sheet. Reads like a page, not like a legal notice nobody opens. */
.sheet {
  border: 0; padding: 0; max-width: 640px; width: min(92vw, 640px);
  background: var(--void-2); color: var(--cream);
  border-radius: 14px;
  box-shadow: 0 30px 80px rgba(0,0,0,.7);
}
.sheet::backdrop { background: rgba(6,5,4,.72); backdrop-filter: blur(3px); }
.sheet__in { padding: clamp(24px, 4vw, 38px); position: relative; }
.sheet__x {
  position: absolute; top: 14px; right: 16px;
  background: none; border: 0; color: var(--ash);
  font-size: 26px; line-height: 1; cursor: pointer; padding: 4px 8px;
}
.sheet__x:hover { color: var(--cream); }
.sheet h2 {
  font-family: var(--display); font-weight: 800; font-size: clamp(1.4rem, 3vw, 1.8rem);
  margin: 0 0 14px; letter-spacing: -.02em; max-width: 22ch;
}
.sheet h3 {
  font-family: var(--mono); font-size: 10.5px; letter-spacing: .14em;
  text-transform: uppercase; color: var(--yellow);
  margin: 26px 0 8px;
}
.sheet p, .sheet li { font-size: .95rem; line-height: 1.6; color: var(--ash); margin: 0 0 10px; }
.sheet__lede { color: var(--cream) !important; }
.sheet ul { margin: 0 0 10px; padding-left: 20px; }
.sheet strong { color: var(--cream); font-weight: 600; }
.sheet a { color: var(--yellow); }
/* what still needs the shop's own answer, marked rather than made up */
.sheet__todo {
  display: block; margin-top: 6px;
  border-left: 2px solid var(--coral); padding-left: 10px;
  color: var(--ash-dim); font-size: .86rem;
}
.sheet__note {
  margin-top: 26px; padding-top: 16px; border-top: 1px solid var(--line);
  font-size: .86rem !important; color: var(--ash-dim) !important;
}

/* =========================================================================
   PHONE

   Everything below is what the desktop layout gets wrong once it is 375px
   wide. It was not a rescale problem — three of these are real bugs that
   only appear on a touch device.
   ========================================================================= */

/* --- the reel wall -------------------------------------------------------
   168px was a thumbnail, not a video. One clip nearly fills the screen now
   with the next one peeking, which is how a phone carousel should read, and
   the snap points make it land cleanly. */
@media (max-width: 700px) {
  .reel { width: min(72vw, 300px); }
  .reels { gap: 12px; scroll-padding-left: var(--pad); }
}

/* On a touch device the tile in view gets .talking permanently — there is no
   hover to end it — so the comment layer sat over the whole clip and you
   could not see a single donut. It becomes a caption strip: the two newest
   comments along the bottom, the clip itself left alone. */
@media (hover: none) {
  .said {
    padding: 22px 12px 12px;
    gap: 7px;
    background: linear-gradient(to top, rgba(20,11,17,.94) 52%, rgba(20,11,17,.55) 78%, transparent);
  }
  .said__row { font-size: .86rem; line-height: 1.28; }
  .said__row:nth-child(n+3) { display: none; }
  .said__row b { font-size: 8.5px; margin-bottom: 1px; }

  /* the like/comment pills were hidden whenever a tile was "talking", which
     on a phone is always — they can stay now that the comments are a strip */
  .tile.talking .reel__stats { opacity: 1; }
}

/* --- the hero row --------------------------------------------------------
   Three pills wrapped 1 + 2 and looked ragged. The main action takes the
   full width, the two supporting ones share the line under it. */
@media (max-width: 560px) {
  .room .row { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
  .room .row .btn {
    width: 100%; justify-content: center; text-align: center;
    /* half of a 375px screen is not much: tighten the pill rather than let
       "Order for a crowd" break across two lines */
    padding-inline: 12px; font-size: .93rem; white-space: nowrap;
  }
  .room .row .btn:first-child { grid-column: 1 / -1; padding-inline: 23px; font-size: .98rem; }

  /* Mittig auf dem Handy (Ty). Auf dem Schreibtisch steht der Kopf links,
     weil rechts daneben die drei Clips stehen - die sind hier weg, und links
     ausgerichteter Text vor leerer rechter Haelfte sah angeschnitten aus.
     Die Zeile bekommt dabei eine Breite, sonst zentriert sich ein Umbruch
     nach 40 Zeichen gegen den Rand. */
  .room__grid { justify-items: center; text-align: center; }
  .room__eyebrow { text-align: center; }
  /* balance verteilt die Zeilen gleichmaessig, sonst haengt ein einzelnes
     Wort am Ende - hier blieb "for" allein stehen. */
  .room__lede { margin-inline: auto; max-width: 30ch; text-wrap: balance; }
  .wordmark { text-align: center; }
}

/* --- the footer ----------------------------------------------------------
   "Privacy" has to be a <button> because it opens a dialog, and a button
   carries the user agent's own horizontal padding — so it sat a few pixels
   to the right of the two real links above it. */
.foot__link { padding-inline: 0; }

/* --- the map -------------------------------------------------------------
   OpenStreetMap draws its own attribution inside the frame and it wrapped
   onto two lines over a short map. Required credit, so it stays; the map
   gets the height to carry it instead. */
@media (max-width: 700px) {
  .map { aspect-ratio: 4 / 5; }
}

/* --- the map cover -------------------------------------------------------
   Sits over the embed and takes the wheel and the touches, so neither a
   scroll nor a swipe that happens to be over the map does anything to the
   map. One click hands it over.

   This used to be switched off entirely on a pointer device — "on a pointer
   device the map never blocked anything", said the comment, which was simply
   wrong: a wheel over an embedded map zooms it and the page stops moving
   under you. Ty: "Die map soll nicht direkt scrollbar sein, das triggert."
   The cover is on everywhere now. */
.map { position: relative; }
.map__cover {
  position: absolute; inset: 0; z-index: 2;
  display: grid; place-items: center;
  background: transparent;
  border: 0; cursor: pointer; padding: 0;
  transition: background-color .2s ease;
}
.map__cover span {
  font-family: var(--body); font-weight: 600; font-size: .86rem;
  color: var(--void); background: var(--cream);
  padding: 9px 16px; border-radius: 999px;
  box-shadow: 0 4px 14px rgba(0,0,0,.34);
  opacity: 0; transform: translateY(6px);
  transition: opacity .22s ease, transform .22s ease;
}
.map__cover:hover, .map__cover:focus-visible { background: rgba(20,11,17,.22); }
.map__cover:hover span, .map__cover:focus-visible span { opacity: 1; transform: none; }
.map--live .map__cover { display: none; }

/* On a touch screen there is no hover to reveal the label, so it stands. */
@media (hover: none) {
  .map__cover span { opacity: 1; transform: none; }
  .map__cover { align-items: end; padding-bottom: 46px; }  /* clear of OSM's credit */
}

/* The way back out. Top left, because OpenStreetMap puts its own zoom
   buttons top right and its credit along the bottom. */
.map__tools {
  position: absolute; top: 10px; left: 10px; z-index: 3;
  display: flex; gap: 7px;
}
.map__tools[hidden] { display: none; }
.map__tool {
  font-family: var(--body); font-weight: 600; font-size: .78rem;
  color: var(--void); background: var(--cream);
  border: 0; border-radius: 999px; padding: 7px 13px; cursor: pointer;
  box-shadow: 0 3px 10px rgba(0,0,0,.34);
  transition: background-color .18s ease;
}
.map__tool:hover { background: var(--yellow); }
.map__tool:focus-visible { outline: 2px solid var(--void); outline-offset: 2px; }

/* --- the header on a phone ----------------------------------------------
   Status and phone number wrapped onto two lines. They fit on one at this
   size; the detail gives way first if a longer status ever needs the room. */
@media (max-width: 560px) {
  .top__in { flex-wrap: nowrap; gap: 10px; font-size: 12.5px; }
  .top__now { min-width: 0; flex: 0 1 auto; }
  .top__state { white-space: nowrap; }
  .top__detail {
    min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .top__tel { flex: 0 0 auto; }
}

/* --- weight off the phone ------------------------------------------------
   Measured at the reel wall on a phone viewport: 3 frames per second, with
   NO video playing. So it was never the video decode — it was ten live
   backdrop-filter blurs, one behind each stat pill, each one forcing the
   compositor to re-sample what is underneath on every frame while the strip
   moves. A solid translucent ground looks all but identical at that size and
   costs nothing.

   The tile shadows go the same way: a 50px blur radius under five cards that
   are being scrolled is paint work for an effect nobody looks at on a 375px
   screen. */
@media (max-width: 700px) {
  .reel__stat { backdrop-filter: none; background: rgba(20,11,17,.78); }
  .sheet::backdrop { backdrop-filter: none; background: rgba(6,5,4,.82); }
  .reels .tile { box-shadow: 0 8px 18px -10px rgba(0,0,0,.8); }
  .reels .tile { will-change: auto; }
}

/* =========================================================================
   THE OTHER COUNTER

   One row, not three cards. The .way rules that built the old grid are gone
   with the markup that used them — the "Reserve and pick it up" card was a
   link back to the board directly above it, and Too Good To Go had already
   come out.
   ========================================================================= */
/* The left column was ~800px wide with the text capped at 46ch inside it, so
   a third of the row was empty down the middle and the copy looked timid at
   .97rem. Ty: "there is literally no need for u to have the text so small...
   du kannst mehr breite nutzen und es dafuer groesser machen."

   Wider card, smaller gap, and the sentence set at a size worth reading.
   52ch is still inside the comfortable measure for running text — the fill
   comes from the type growing into the column, not from the line getting
   longer than an eye can track. */
.deliver {
  display: grid; gap: 26px; align-items: center;
}
/* The note used to be three lines of argument and is now one line of answer,
   so the weight shifts: the card takes the room the paragraph gave back
   instead of leaving a hole where the paragraph was. */
@media (min-width: 880px) {
  .deliver { grid-template-columns: 1fr minmax(380px, 520px); gap: clamp(32px, 3.4vw, 56px); }
}
/* One line, and it is the line that decides whether to press the button.
   Size and colour come from the shared .sec-lede rule. */
.deliver__note { margin: 20px 0 0; }

/* Uber's own wordmark on Uber's own near-black, so the link reads as their
   store front rather than as a button we drew.

   The first version of this was a flat box with everything set in DM Mono —
   the rating, the stars and the link all in the same small technical type,
   which is what made it look, in Ty's words, hässlich. Mono is for meters
   and clock times, not for a shop's rating. Now: the mark, a rule, the
   score at a size worth reading, and a real filled button at the bottom.
   Green appears once, on the thing you press. */
.deliver__card {
  display: flex; flex-direction: column; align-items: stretch; gap: 20px;
  padding: 28px 28px 24px; border-radius: 18px; text-decoration: none;
  background: linear-gradient(168deg, #1B2E33 0%, #142328 62%);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.07), 0 10px 30px rgba(0,0,0,.3);
  transition: transform .22s ease, box-shadow .22s ease;
}
.deliver__card:hover {
  transform: translateY(-4px);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 18px 44px rgba(0,0,0,.42);
}
/* The page-wide focus ring is yellow, which on Uber's near-black looked like
   a warning label around the card. Theirs is green. */
.deliver__card:focus-visible {
  outline: 2px solid #06C167; outline-offset: 3px; border-radius: 18px;
}
.deliver__logo { display: block; width: 146px; height: 24px; }
.deliver__rule { height: 1px; background: rgba(255,255,255,.1); }

.deliver__rate {
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
  font-family: var(--body);
}
.deliver__stars {
  color: #FFFFFF; font-size: 17px; letter-spacing: .1em; line-height: 1;
  position: relative; top: -1px;
}
.deliver__rate b {
  font-family: var(--display); font-weight: 700; font-size: 1.7rem;
  line-height: 1; letter-spacing: -.02em; color: #FFFFFF;
}
.deliver__rate i {
  font-style: normal; font-size: .92rem; color: #9FB3AD; margin-left: auto;
}

/* Uber Eats green, once, on the one thing there is to press. */
.deliver__go {
  display: flex; align-items: center; justify-content: center; gap: 9px;
  padding: 15px 20px; border-radius: 999px;
  background: #06C167; color: #0B1A1E;
  font-family: var(--body); font-weight: 700; font-size: 1.02rem;
  letter-spacing: -.01em;
  transition: background-color .2s ease;
}
.deliver__card:hover .deliver__go { background: #05D873; }
.deliver__arrow { transition: transform .2s ease; }
.deliver__card:hover .deliver__arrow { transform: translateX(3px); }

/* the footer's own live line and hours table */
.foot__id .foot__logo { margin-bottom: 16px; }
.foot__live {
  display: flex; align-items: center; gap: 8px;
  font-family: var(--mono); font-size: 11.5px; color: var(--cream) !important;
  margin: 0 0 14px !important;
}
.foot__id a { color: var(--ash); text-decoration: none; }
.foot__id a:hover { color: var(--cream); text-decoration: underline; }

.foot__hours { list-style: none; margin: 0; padding: 0; display: grid; gap: 5px; }
.foot__hours li {
  display: flex; justify-content: space-between; gap: 14px;
  font-family: var(--mono); font-size: 11.5px; color: var(--ash);
}
.foot__hours li span:last-child { font-variant-numeric: tabular-nums; }
.foot__hours .is-today { color: var(--yellow); }

@media (min-width: 761px) {
  .foot { grid-template-columns: minmax(0,1.15fr) minmax(0,.85fr) minmax(0,.8fr) minmax(0,.8fr); }
}

/* =========================================================================
   AFTER AKIBON.STUDIO

   Their own site is the standard this has to clear, so the system is lifted
   from it rather than guessed at:

     label      11px / 800 / 2.4px tracking / uppercase   — the small gold line
     heading    800 weight, NEGATIVE tracking, sentence case, not shouted
     body       15.5px / 400 / 1.62 line-height, muted
     panels     one step up from the ground, hairline at ~6% white

   What it is NOT: giant all-caps headlines over equal-height card grids with
   decorative quote marks. That is the look this page had, and it is the look
   every generated landing page has.

   The palette stays Bad & Boujee's — their yellow, their coral, their black.
   Borrowing Akibon's violet would just make it somebody else's site.
   ========================================================================= */

.label {
  font-family: var(--body);
  font-size: 12px; font-weight: 800;
  letter-spacing: .16em; text-transform: uppercase;
  color: var(--ash-quiet);
  margin: 0;
}
.label--gold  { color: var(--yellow); }
.label--coral { color: var(--coral); }


/* -------------------------------------------------------------------------
   THE 5.0 — their reviews
   ------------------------------------------------------------------------- */
.said-head {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 28px; flex-wrap: wrap; margin-bottom: clamp(28px, 3.6vw, 44px);
}
.said-head > :first-child { flex: 1 1 340px; min-width: 0; }
.said-head .sec-title { max-width: 20ch; }

.score {
  display: grid; justify-items: center; gap: 3px;
  text-decoration: none; flex: 0 0 auto;
  border: 1px solid var(--line); border-radius: 13px;
  padding: 16px 26px; background: var(--void-2);
  transition: border-color .2s ease, transform .2s ease;
}
.score:hover { border-color: var(--yellow); transform: translateY(-2px); }
.score__n {
  font-family: var(--display); font-weight: 800; font-size: 2.5rem;
  line-height: 1; color: var(--cream); letter-spacing: -.04em;
}
.score__stars { color: var(--yellow); font-size: .8rem; letter-spacing: .14em; }
.score__sub {
  font-family: var(--body); font-size: 10.5px; font-weight: 800;
  letter-spacing: .16em; text-transform: uppercase; color: var(--ash-quiet);
}

/* Columns, not a grid: eight real reviews of different lengths were being
   stretched to equal heights, which is exactly what makes a set of genuine
   quotes read as a template. They flow at their own size now. */
/* The newest review, set as the section's lead. Real sentences at a size
   that admits they are the point of the section. */
.lead-say { margin: 0 0 clamp(34px, 4vw, 52px); max-width: 30ch; }
.lead-say blockquote {
  margin: 0 0 16px;
  font-family: var(--display); font-weight: 700;
  font-size: clamp(1.3rem, 2.5vw, 1.85rem);
  line-height: 1.24; letter-spacing: -.024em; color: var(--cream);
  text-wrap: pretty;
}
@media (min-width: 900px) {
  .lead-say { max-width: 46ch; }
}

/* Eight reviews. They were eight boxes on a dark ground in three columns —
   the exact arrangement that makes writing somebody actually wrote look
   like filler somebody generated. Two columns, no boxes, no borders: the
   words sit on the page the way words do. Columns rather than a grid so
   they keep their own heights; equal-height cards are what made real
   quotes look like a template in the first place. */
.says { columns: 1; column-gap: clamp(32px, 4vw, 58px); }
@media (min-width: 900px) { .says { columns: 2; } }

.say {
  break-inside: avoid; -webkit-column-break-inside: avoid;
  margin: 0 0 clamp(30px, 3.4vw, 44px);
}
.say blockquote {
  margin: 0 0 12px;
  font-size: 1.04rem; line-height: 1.66; color: var(--cream);
  letter-spacing: -.004em;
}

.say__by, .lead-say .say__by { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px; }
.say__who {
  font-family: var(--display); font-weight: 700;
  font-size: .95rem; letter-spacing: -.012em; color: var(--cream);
}
.say__meta {
  font-family: var(--mono); font-size: 10.5px; color: var(--ash-quiet);
  letter-spacing: .02em;
}

/* The only ruled thing in the section, and deliberately so: he answers
   every one of them, and that is the argument the section is making. */
.say__reply {
  margin: 14px 0 0; padding: 12px 0 12px 16px;
  border-left: 2px solid var(--coral);
}
.say__reply .label { margin-bottom: 5px; }
.say__reply p:last-child {
  margin: 0; font-size: .92rem; line-height: 1.55; color: var(--ash);
}


/* =========================================================================
   THE BOARD — fifteen flavours, sideways, one section at a time.

   What it replaces: a vertical list of fifteen rows, each carrying a name,
   a price, a description and an orders figure, beside a preview panel and
   three box cards. Every fact at once, and nothing legible.

   Three type roles in this whole section and no more: the section heading,
   the card line, and the small print. The card line is ONE size and ONE
   weight — cream for the name, yellow for the price. Nothing here is set
   in the monospace; that face is for the live readouts at the top of the
   page, not for money on a menu.
   ========================================================================= */
.board { margin-top: clamp(20px, 2.6vw, 30px); }

/* ---------- one section ----------
   The three sections used to be tabs. Tabs hid two thirds of the menu
   behind a control that was easy to miss, so the best-liked flavours were
   never seen. Each section is its own block now, headed the way the drinks
   block is headed, because that is the one that read clearly. */
.grp {
  padding-top: clamp(22px, 2.6vw, 30px);
  border-top: 1px solid var(--line);
  margin-top: clamp(26px, 3vw, 38px);
}
.grp:first-child { margin-top: clamp(14px, 1.8vw, 22px); }

.grp__head {
  display: flex; align-items: center; justify-content: space-between; gap: 18px;
}
.grp__name { font-size: 12px; letter-spacing: .24em; margin: 0; }
.grp__name em {
  font-style: normal; font-size: 11px; font-weight: 800;
  color: var(--ash-quiet); margin-left: 4px; letter-spacing: .14em;
}
.grp__note { margin: 11px 0 0; color: var(--ash); font-size: .95rem; }

/* ---------- arrows ---------- */
.grp__nav { display: flex; align-items: center; gap: 9px; flex: 0 0 auto; }
.grp.is-short .grp__nav,
.grp.is-short .grp__bar { display: none; }
.board__arrow {
  width: 36px; height: 36px; border-radius: 50%;
  border: 1px solid var(--line); background: transparent;
  cursor: pointer; position: relative;
  transition: border-color .2s ease, background-color .2s ease, opacity .2s ease;
}
.board__arrow::before {
  content: ""; position: absolute; top: 50%; left: 50%;
  width: 7px; height: 7px;
  border-top: 1.5px solid var(--cream); border-right: 1.5px solid var(--cream);
  transform: translate(-25%, -50%) rotate(-135deg);
}
.board__arrow--next::before { transform: translate(-75%, -50%) rotate(45deg); }
.board__arrow:hover:not(:disabled) { border-color: var(--yellow); background: var(--void-3); }
.board__arrow:hover:not(:disabled)::before { border-color: var(--yellow); }
.board__arrow:disabled { opacity: .28; cursor: default; }

/* ---------- the rail ----------
   No wheel handler anywhere near this. Turning a wheel over it scrolls the
   page. Sideways is the arrows, a trackpad swipe, a drag, or arrow keys. */
.grp__rail {
  display: flex; gap: 18px;
  overflow-x: auto; overflow-y: hidden;
  scroll-snap-type: x proximity;
  /* NO scroll-behavior here on purpose. Every arrow on this page asks for
     a smooth scroll in the script; declaring one in the CSS as well makes
     the two cancel, and the rail does not move at all. Measured: with the
     declaration scrollBy lands on 2, without it on 342. */
  padding: 20px 2px 4px; margin-inline: -2px;
  scrollbar-width: none; -ms-overflow-style: none;
  overscroll-behavior-x: contain;
}
.grp__rail::-webkit-scrollbar { display: none; }
.grp__rail:focus-visible { outline: 2px solid var(--yellow); outline-offset: 6px; border-radius: 4px; }

.grp__bar {
  height: 2px; margin-top: 14px; border-radius: 2px;
  background: var(--line); overflow: hidden;
}
.grp__bar span {
  display: block; height: 100%; background: var(--yellow);
  transform: scaleX(0); transform-origin: left;
  transition: transform .3s cubic-bezier(.2,.9,.3,1);
}

/* ---------- one flavour ---------- */
.fl {
  flex: 0 0 clamp(196px, 21vw, 252px);
  scroll-snap-align: start;
  opacity: 0; transform: translateY(16px);
  transition: opacity .5s ease, transform .55s cubic-bezier(.2,.9,.3,1);
  transition-delay: calc(var(--i) * 65ms);
  cursor: default;
}
.grp__rail.is-in .fl { opacity: 1; transform: none; }
/* Der Fokus-Ring war gelb und 2px breit - genau die Goldmedaille. Wer mit
   der Tastatur durch die Reihe geht, haette jede Karte golden gesehen, und
   die Auszeichnung waere wertlos. Jetzt creme und AUSSERHALB der Karte, die
   Medaille sitzt innen: zwei Dinge, zwei Orte, keine Verwechslung. */
.fl:focus-visible { outline: 2px solid var(--cream); outline-offset: 3px; border-radius: 13px; }

.fl__shot {
  position: relative; aspect-ratio: 4 / 5;
  border-radius: 12px; overflow: hidden;
  background: var(--void-3);
}
.fl__shot img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform .6s cubic-bezier(.2,.9,.3,1);
}
.fl:hover .fl__shot img { transform: scale(1.055); }

/* The description waits until it is asked for. At rest a card says two
   things; that is the whole point of the section. */
.fl__more {
  position: absolute; inset: auto 0 0 0;
  padding: 34px 15px 15px;
  background: linear-gradient(to top, rgba(20,11,17,.96) 42%, rgba(20,11,17,.72) 74%, transparent);
  transform: translateY(101%); opacity: 0;
  transition: transform .36s cubic-bezier(.2,.9,.3,1), opacity .26s ease;
}
.fl:hover .fl__more,
.fl:focus-within .fl__more,
.fl.is-open .fl__more { transform: none; opacity: 1; }
.fl__more p { margin: 0; font-size: .87rem; line-height: 1.5; color: #EFE8DE; }

/* -------------------------------------------------------------------------
   GOLD, SILBER, BRONZE

   Die drei meistbestellten Sorten JEDER Reihe, ausgezeichnet dort, wo die
   Entscheidung faellt - auf der Karte selbst. Ein Ring um das Bild, und
   beim Daruebergehen steht "Customers choice" in derselben Farbe ueber der
   Beschreibung.

   Der Ring liegt als box-shadow innen, nicht als border: eine Rahmenlinie
   haette die Karte breiter gemacht als ihre Nachbarn, und dann waere die
   Reihe an der Rasterung vorbeigelaufen.
   ------------------------------------------------------------------------- */
.fl--gold,   .fl--gold   .fl__pick-label { --medaille: #F9DB49; }
.fl--silber, .fl--silber .fl__pick-label { --medaille: #D6DCE4; }
.fl--bronze, .fl--bronze .fl__pick-label { --medaille: #D09154; }

/* Der Ring ist eine eigene Ebene, kein inset-Schatten am Kasten.

   Erster Versuch war genau das - und die Messung sagte, er sei gesetzt,
   waehrend auf dem Bildschirm nichts zu sehen war. Ein innerer Schatten
   wird HINTER dem Inhalt gemalt, und der Inhalt ist hier ein formatfuellendes
   Foto. Als Ueberlagerung liegt er darueber, auch ueber der Beschreibung,
   die beim Daruebergehen hochfaehrt.

   Dahinter eine dunkle Haarlinie: die Haelfte der Sorten liegt auf weissem
   Marmor, und Silber auf Weiss ist kein Ring, sondern ein Geruecht. */
.fl--gold .fl__shot::after,
.fl--silber .fl__shot::after,
.fl--bronze .fl__shot::after {
  content: ""; position: absolute; inset: 0; z-index: 2;
  border-radius: inherit; pointer-events: none;
  box-shadow: inset 0 0 0 3px var(--medaille),
              inset 0 0 0 4.5px rgba(20,11,17,.55);
}

.fl__pick-label {
  margin: 0 0 5px !important;
  font-family: var(--body); font-size: 10px !important; font-weight: 800;
  letter-spacing: .2em; text-transform: uppercase;
  color: var(--medaille) !important;
}

.fl__out {
  position: absolute; top: 11px; left: 11px; z-index: 2;
  font-family: var(--body); font-size: 10px; font-weight: 800;
  letter-spacing: .14em; text-transform: uppercase;
  color: #fff; background: var(--coral);
  padding: 5px 9px; border-radius: 999px;
}
.fl.is-out .fl__shot img { filter: grayscale(1) brightness(.5); }
.fl.is-out .fl__name { color: var(--ash); }
.fl.is-out .fl__price { color: var(--coral); }

/* No photograph: their own mark, held well back. All fifteen have one
   today, so this is a net rather than a look. */
.fl__mark {
  position: absolute; inset: 0;
  background: url("assets/brand/icon.png") 50% 50% / 46% no-repeat;
  opacity: .34;
}

/* Two things, one size, one weight, two colours. */
.fl__line {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 10px; margin-top: 13px;
}
.fl__name {
  font-family: var(--display); font-weight: 700; font-size: 1rem;
  letter-spacing: -.017em; color: var(--cream); margin: 0;
}
.fl__price {
  font-family: var(--display); font-weight: 700; font-size: 1rem;
  color: var(--yellow); font-variant-numeric: tabular-nums; flex: 0 0 auto;
}

@media (max-width: 720px) {
  .fl { flex-basis: 68vw; }
}

@media (prefers-reduced-motion: reduce) {
  .fl { transition: none; transition-delay: 0s; opacity: 1; transform: none; }
  .grp__rail { scroll-behavior: auto; }
  /* Die Kante wechselt dann sofort statt weich - die Maske bleibt. */
  .reels, .grp__rail, .gr__rail { transition: none; }
  .grp__rail .fl { opacity: 1; }
  .fl__more { transition: none; }
}

/* ---------- coffee and milk ----------
   These were the last two rows of the donut list, which is not how the shop
   lists them and is not how anybody thinks about them. Their own menu has
   Drinks as a heading of its own. */
.sips {
  margin-top: clamp(26px, 3vw, 38px);
  padding-top: clamp(22px, 2.6vw, 30px);
  border-top: 1px solid var(--line);
}
/* There are two of them. Stacking two things down a page that is already
   long enough is a waste of the width sitting empty beside them. */
.sips__list {
  list-style: none; margin: 14px 0 0; padding: 0;
  display: grid; gap: 0 clamp(26px, 4vw, 60px);
  grid-template-columns: 1fr 1fr; max-width: 900px;
}
.sips__list li {
  display: flex; align-items: baseline; gap: 12px;
  padding: 13px 0 0; border-top: 1px solid var(--line);
}
@media (max-width: 620px) {
  .sips__list { grid-template-columns: 1fr; }
}
.sips__name {
  font-family: var(--display); font-weight: 700; font-size: 1rem;
  letter-spacing: -.017em; color: var(--cream); flex: 0 0 auto;
}
.sips__desc { color: var(--ash); font-size: .88rem; flex: 1 1 auto; min-width: 0; }
.sips__price {
  font-family: var(--display); font-weight: 700; font-size: 1rem;
  color: var(--yellow); font-variant-numeric: tabular-nums;
}

/* =========================================================================
   THE GOOGLE REVIEWS — hellogreek.ca's widget, measured off the live page

   The first version of this had the arrangement right and everything else
   wrong. Every number below was read out of their rendered Trustindex
   widget rather than remembered:

     card 270px wide, 206px tall and IDENTICAL for every review
     inner white #FFF, 12px radius, 20px padding
     shadow 1px 4px 10px rgba(0,0,0,.1), 0 0 2px rgba(0,0,0,.05)
     name 600 / 15px          date 13px / #6B6B6B
     text 15px / 21.75px, four lines, then cut

   White cards on our own ground rather than dark ones in our palette: a
   review is somebody else's word, and it reads as somebody else's word when
   it does not wear our paint. It is also, for better or worse, what people
   recognise as a Google review.
   ========================================================================= */
.gr {
  display: grid; gap: clamp(26px, 3.4vw, 46px); align-items: start;
  margin-top: clamp(26px, 3vw, 38px);
}
@media (min-width: 900px) { .gr { grid-template-columns: 232px minmax(0, 1fr); } }

/* Their summary block is small: a mark, the name, the stars, the count, and
   an outlined button. The 3.6rem "5.0" that stood here said the same thing
   the headline two lines above already says. */
.gr__sum {
  display: grid; grid-template-columns: auto 1fr; gap: 4px 14px;
  align-items: center;
}
.gr__logo {
  width: 48px; height: 48px; border-radius: 10px; display: block;
  background: var(--void-3);
}
.gr__id { min-width: 0; }
.gr__name {
  margin: 0; font-family: var(--body); font-weight: 700; font-size: .95rem;
  color: var(--cream); letter-spacing: -.01em;
}
.gr__stars {
  margin: 3px 0 0; color: #F5B72F; font-size: .92rem; letter-spacing: .1em;
}
.gr__count { margin: 3px 0 0; color: var(--ash); font-size: .82rem; }
.gr__write {
  grid-column: 1 / -1; justify-self: start; margin-top: 14px;
  display: inline-block; padding: 9px 18px; border-radius: 999px;
  border: 1px solid var(--line); color: var(--cream); text-decoration: none;
  font-family: var(--body); font-weight: 600; font-size: .88rem;
  transition: border-color .2s ease, background-color .2s ease;
}
.gr__write:hover { border-color: var(--yellow); background: var(--void-3); }

/* Arrow, cards, arrow. On hellogreek the circles sit slightly over the first
   and last card; here they get their own tracks, because an arrow standing on
   the content is the exact thing Ty had just told me off about on the reel
   wall. Both gutters stay reserved, so nothing shifts when one disappears. */
.gr__deck {
  display: grid; align-items: center;
  grid-template-columns: 30px minmax(0, 1fr) 30px;
  column-gap: 12px;
}
/* Not a scroll container. scrollTo({behavior:"smooth"}) was measured doing
   nothing at all on this rail — 500ms after the call, scrollLeft was still 0
   while a direct assignment moved it at once — and a carousel that jumps is
   what "die animationen ... falsch" meant. So the cards ride on a track that
   a transform moves, where the transition is real. touch-action keeps
   vertical page scrolling with the page while a sideways drag is ours. */
/* ---------- der Verlauf an einer angeschnittenen Kante ----------
   Gilt fuer ALLE drei Schienen, die seitlich laufen: die Reel-Wand, die
   Reihen auf der Tafel und die Bewertungen. Ty: "ueberall wo man seitlich
   scrollt will ich dass nicht so hart kantik abgeschnitten sein sondern so
   einen fade haben."

   Einen Verlauf bekommt nur die Kante, die gerade wirklich eine Karte
   zerschneidet. An einer buendigen Kante waere er kein Auslaufen, sondern
   ein Schleier auf einer vollstaendigen Karte - deshalb bleibt links hart,
   solange die Schiene am Anfang steht. Welche Seite dran ist, setzt das
   Skript als data-fade, aus demselben Scroll-Zustand, der auch schon die
   Pfeile ausgraut.

   --fade-l/--fade-r sind mit @property angemeldet, weil eine nicht
   angemeldete Custom Property springt statt zu animieren - die Kante waere
   dann ein Aufploppen. Wo @property fehlt, schaltet sie hart um; die Maske
   selbst stimmt trotzdem. */
@property --fade-l { syntax: "<length>"; inherits: false; initial-value: 0px; }
@property --fade-r { syntax: "<length>"; inherits: false; initial-value: 0px; }

.reels, .grp__rail, .gr__rail {
  /* 92px war auf dem Schreibtisch richtig und auf dem Handy viel zu breit:
     die Bewertungsschiene ist dort nur 267px breit, zwei Verlaeufe zu 92px
     haetten 69 % davon verwaschen - und man sieht dort immer nur EINE Karte.
     Gemessen bei 375px Fensterbreite: 46px laesst Name, Sterne und Text
     lesbar und die Kante trotzdem weich. Oben bleibt es bei den 92px. */
  --fade-w: clamp(46px, 6.5vw, 92px);
  --fade-l: 0px;
  --fade-r: 0px;
  transition: --fade-l .28s ease, --fade-r .28s ease;
  -webkit-mask-image: linear-gradient(to right, transparent 0,
                        #000 var(--fade-l),
                        #000 calc(100% - var(--fade-r)), transparent 100%);
          mask-image: linear-gradient(to right, transparent 0,
                        #000 var(--fade-l),
                        #000 calc(100% - var(--fade-r)), transparent 100%);
}
[data-fade~="links"]  { --fade-l: var(--fade-w); }
[data-fade~="rechts"] { --fade-r: var(--fade-w); }

.gr__rail {
  grid-column: 2;
  overflow: hidden;
  padding: 6px 2px 10px; margin-inline: -2px;
  touch-action: pan-y; cursor: grab;
}
.gr__rail:active { cursor: grabbing; }
.gr__track {
  display: flex; gap: 18px; align-items: stretch;
  will-change: transform;
}
.gr__rail:focus-visible { outline: 2px solid var(--yellow); outline-offset: 6px; border-radius: 4px; }

.gr__arrow {
  grid-column: 3;
  width: 30px; height: 30px; border-radius: 50%; position: relative;
  border: 0; background: #FFFFFF; cursor: pointer;
  box-shadow: 0 1px 4px rgba(0,0,0,.28);
  transition: transform .2s ease, opacity .2s ease;
}
.gr__arrow { grid-column: 1; }
.gr__arrow--next { grid-column: 3; }
.gr__arrow::before {
  content: ""; position: absolute; top: 50%; left: 50%;
  width: 7px; height: 7px;
  border-top: 1.6px solid #3C3C3C; border-right: 1.6px solid #3C3C3C;
  transform: translate(-25%, -50%) rotate(-135deg);
}
.gr__arrow--next::before { transform: translate(-75%, -50%) rotate(45deg); }
.gr__arrow:hover:not(:disabled) { transform: scale(1.08); }
/* Never disabled any more: the rail loops, so there is always a next one
   and always a previous one. */
.gr__arrow:disabled { opacity: 0; pointer-events: none; }

/* ---------- one review ----------
   min-height rather than height: the four-line cut caps the tallest element
   on the card, so this floor is what makes a two-word review the same size
   as a four-line one. */
.grc {
  flex: 0 0 clamp(250px, 27vw, 292px);
  min-height: 206px; box-sizing: border-box;
  display: flex; flex-direction: column;
  background: #FFFFFF; border-radius: 12px; padding: 20px;
  text-decoration: none;
  box-shadow: 1px 4px 10px rgba(0,0,0,.1), 0 0 2px rgba(0,0,0,.05);
  transition: transform .2s ease, box-shadow .2s ease;
}
.grc:hover { transform: translateY(-3px); box-shadow: 1px 8px 20px rgba(0,0,0,.22); }
.grc__top { display: flex; align-items: center; gap: 11px; }
.grc__face {
  width: 40px; height: 40px; border-radius: 50%; flex: 0 0 auto;
  background: var(--f); color: #FFFFFF;
  display: grid; place-content: center;
  font-family: var(--body); font-weight: 600; font-size: 1.05rem;
}
.grc__who { display: grid; gap: 0; min-width: 0; margin-right: auto; }
.grc__who b {
  font-family: var(--body); font-weight: 600; font-size: 15px; line-height: 21px;
  color: #1A1A1A;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.grc__who i {
  font-style: normal; font-size: 13px; line-height: 18px; color: #6B6B6B;
}
.grc__g { flex: 0 0 auto; display: block; }

/* Measured twice. On the original the star is a 17px image and the tick is
   15px, so the tick is the smaller, quieter thing. Mine had it the other way
   round: the star glyph's ink at 15px is 14.1px tall, against a 15px tick —
   and a filled disc reads heavier than a star outline of the same height, so
   the tick sat there looking like the main event. Ty: "Ist es normal das der
   haken so komisch positioniert ist?"

   Stars up to 17px (ink 15.9), tick down to 14px: the same 0.88 ratio the
   original has. The 1px nudge puts the disc on the star's ink centre rather
   than on the text box's centre — a star has almost no descender, so those
   two are not the same line. */
.grc__stars {
  margin: 12px 0 9px; color: #F5B72F; font-size: 17px; letter-spacing: .06em;
  display: flex; align-items: center; gap: 7px;
}
/* The blue tick at the end of the star row. It is an <svg> in the markup
   now: as two CSS rules — a circle plus a rotated border for the check — the
   check's position was two typed pixel values, and it sat off centre inside
   its own circle. */
.grc__ok { display: block; flex: 0 0 auto; position: relative; top: 1px; }
/* Four lines, then an ellipsis — the rest of that review is one tap away on
   Google, which is where it lives anyway. */
.grc__text {
  margin: 0; color: #1A1A1A; font-size: 15px; line-height: 21.75px;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 4;
  overflow: hidden;
}
/* 76vw was wider than the rail it sits in once the two 30px arrow gutters
   come off a 375px screen, so no card was ever fully visible. Matching the
   rail exactly means one whole review at a time, which is what the phone
   version of the original does too. */
@media (max-width: 620px) {
  .gr__deck { grid-template-columns: 28px minmax(0, 1fr) 28px; column-gap: 8px; }
  .grc { flex-basis: 100%; }

  /* Der Verlauf an den Kanten: ein leiser Hinweis, kein Schleier ueber den
     weissen Bewertungskarten. Von der Kafe-Daki-Seite uebernommen, wo das
     schon so steht. 46px waren hier zu viel - die Bewertungsschiene ist am
     Handy nur 267px breit, zwei Verlaeufe zu 46px nehmen also ein Drittel
     davon, und man sieht dort immer nur EINE Karte, deren Rand dadurch
     dauerhaft ausgewaschen aussah. */
  .reels, .grp__rail, .gr__rail { --fade-w: 16px; }
}

/* =========================================================================
   DIE SEITWAERTS-SCHIENEN AUF EINEM ZEIGEGERAET

   Mit Maus oder Trackpad scrollt der Browser diese Schienen nicht mehr
   selbst - das Skript bewegt sie, und nur wenn die Geste eindeutig
   seitwaerts ist. Sonst nahm eine minimale Seitwaerts-Abweichung beim
   Runterlesen die Schiene mit. Programmgesteuertes scrollLeft funktioniert
   bei overflow:hidden unveraendert, Pfeile und Nachladen bleiben also heil.

   Auf einem Touchscreen bleibt es ein ganz normaler Scroller: ein Finger
   bekommt seine Achsensperre schon vom System, und dort gibt es kein Rad.
   ========================================================================= */
@media (hover: hover) and (pointer: fine) {
  .reels, .grp__rail { overflow-x: hidden; }

  /* Und keine Rasterung. Sie wurde am Gestenende wieder eingeschaltet und
     riss die Schiene dann ohne Uebergang auf die naechste Karte - 68px in
     einem Bild, genau in dem Moment, in dem der Finger schon runterscrollt.
     Ty: "buggt die Anzeige und rastet sich ein... soll clean sein und 0
     ruckartig." Ein Rad haelt an, wo es anhaelt. */
  .reels, .grp__rail { scroll-snap-type: none; }
}

/* Auf dem Handy jetzt ebenfalls nicht mehr, und das ist die Aenderung von der
   neueren Kafe-Daki-Seite: das Rasten schob jeden Wisch, der zwischen zwei
   Karten endete, noch auf die naechste weiter. Jetzt zieht wischEinrasten()
   in main.js erst nach, wenn die Schiene steht und der Finger weg ist - bis
   zur naechsten Kante, nicht darueber hinaus. */
@media (pointer: coarse) {
  .reels, .grp__rail { scroll-snap-type: none; }
}
