/* ═══════════════════════════════════════════════════════════
   Guest ordering — photography led, full-bleed cards.
   Card treatment follows the reference template: image fills the
   frame, type sits on it, everything reveals on scroll.
   ═══════════════════════════════════════════════════════════ */

body{overflow:auto;height:auto;}

/* ══════════════════ HERO — signature drinks ══════════════════
   A coloured stage the whole section takes its background from. Everything
   here is white-on-colour, because the backdrop is a saturated brand tone
   that changes with the drink rather than a photograph. */
.sig{
  position:relative;width:100%;height:100svh;min-height:560px;overflow:hidden;
  background:#F4845F;                     /* first slide; hero.js drives it after */
  --sig-panel:#F79B7F;
}

/* Fine noise over the flat colour. Flat fills band on cheap panels and read
   as unfinished; a little grain is what makes them look printed. */
.sig-grain{
  position:absolute;inset:0;z-index:50;pointer-events:none;opacity:.4;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23n)' opacity='0.08'/%3E%3C/svg%3E");
  background-size:200px 200px;background-repeat:repeat;
}

/* The word the drinks stand in front of. Deliberately larger than the
   viewport can hold at small widths — it is texture, not a heading. */
.sig-ghost{
  position:absolute;top:16%;left:0;right:0;z-index:2;
  display:flex;align-items:center;justify-content:center;
  pointer-events:none;user-select:none;
  font-family:'Anton',var(--display),sans-serif;
  font-size:clamp(84px,26vw,360px);font-weight:400;line-height:1;
  letter-spacing:-.02em;text-transform:uppercase;white-space:nowrap;
  color:#fff;opacity:.96;
}

.sig-top{
  position:absolute;top:0;left:0;right:0;z-index:60;
  display:flex;align-items:center;gap:12px;
  padding:20px clamp(16px,4vw,44px);
}
.sig-top .spacer{flex:1;}
.sig-top .theme-btn{
  background:rgba(255,255,255,.16);border-color:rgba(255,255,255,.3);color:#fff;
}
.sig-top .theme-btn:hover{background:rgba(255,255,255,.28);}

/* ── the stage ── */
.sig-stage{position:absolute;inset:0;z-index:3;}
/* left/bottom/height are set once by hero.js's layoutBase() and never
   transition — every role's difference is a transform instead (see hero.js),
   so the sweep only ever touches transform and opacity, the two properties a
   compositor can animate without re-running layout on every frame. */
.sig-fig{
  position:absolute;aspect-ratio:.6 / 1;
  will-change:transform,filter,opacity;
  transition:transform 650ms cubic-bezier(.4,0,.2,1),
             filter    650ms cubic-bezier(.4,0,.2,1),
             opacity   650ms cubic-bezier(.4,0,.2,1);
}
.sig-fig img{
  width:100%;height:100%;object-fit:contain;object-position:bottom center;
  filter:drop-shadow(0 30px 50px rgba(0,0,0,.22));
}
/* Only the two flanking figures are worth a pointer — the centre one is
   already here and the back one is not reachable in a single step. */
.sig-fig[style*="z-index: 10"]{cursor:pointer;}

/* A soft shadow tucked behind the centre cup only — the side and back
   figures are already dimmed by blur, so an extra shadow there just reads as
   smudged. It sits behind the cup image (negative z-index, within the figure's
   own stacking context) and overlaps the base, so the cup itself hides most of
   it and only a soft edge shows past the silhouette — a shadow cast behind the
   object, not a puddle sitting in front of it. */
.sig-fig[style*="z-index: 20"]::after{
  content:'';
  position:absolute;left:50%;bottom:2%;z-index:-1;
  width:64%;height:14%;transform:translateX(-50%);
  background:radial-gradient(ellipse at center,rgba(0,0,0,.4) 0%,rgba(0,0,0,0) 72%);
  filter:blur(6px);pointer-events:none;
}

/* ── what it is ── */
.sig-say{
  position:absolute;left:clamp(16px,4vw,60px);bottom:clamp(20px,5vh,64px);
  z-index:60;max-width:min(360px,72vw);color:#fff;
}
.sig-eyebrow{
  font-family:var(--mono);font-size:.6rem;font-weight:500;
  letter-spacing:.22em;text-transform:uppercase;opacity:.75;margin-bottom:8px;
}
.sig-name{
  font-family:'Anton',var(--display),sans-serif;font-weight:400;
  font-size:clamp(30px,5.2vw,52px);line-height:1.02;letter-spacing:-.01em;
  text-transform:uppercase;margin-bottom:10px;white-space:pre-line;
}
.sig-note{
  font-size:.83rem;line-height:1.62;opacity:.9;margin-bottom:14px;
}
.sig-pills{display:flex;gap:7px;flex-wrap:wrap;margin-bottom:16px;}
.sig-pill{
  padding:5px 11px;border-radius:100px;
  background:rgba(255,255,255,.16);border:1px solid rgba(255,255,255,.26);
  font-family:var(--mono);font-size:.56rem;font-weight:500;
  letter-spacing:.09em;text-transform:uppercase;
}
.sig-pill b{font-weight:700;}

.sig-controls{display:flex;align-items:center;gap:10px;}
.sig-arrow{
  width:42px;height:42px;border-radius:50%;flex:none;display:grid;place-items:center;
  background:transparent;border:2px solid rgba(255,255,255,.85);color:#fff;
  transition:transform 150ms var(--ease),background-color 150ms var(--ease);
}
.sig-arrow:hover{transform:scale(1.08);background:rgba(255,255,255,.14);}
.sig-arrow:active{transform:scale(.94);}
.sig-arrow svg{width:18px;height:18px;stroke:currentColor;fill:none;
  stroke-width:2.25;stroke-linecap:round;stroke-linejoin:round;}

.sig-dots{display:flex;align-items:center;gap:7px;margin-left:6px;}
.sig-dots button{
  width:7px;height:7px;border-radius:50%;padding:0;
  background:rgba(255,255,255,.42);
  transition:width 400ms var(--ease),background-color 400ms var(--ease);
}
.sig-dots button.on{width:22px;border-radius:100px;background:#fff;}

/* ── to the menu ── */
.sig-go{
  position:absolute;right:clamp(16px,4vw,44px);bottom:clamp(20px,5vh,64px);z-index:60;
  display:flex;align-items:center;gap:10px;color:#fff;opacity:.95;
  transition:opacity 200ms var(--ease),transform 200ms var(--ease);
}
.sig-go:hover{opacity:1;transform:translateX(3px);}
.sig-go span{
  font-family:'Anton',var(--display),sans-serif;font-weight:400;
  font-size:clamp(19px,3.6vw,50px);line-height:1;letter-spacing:-.02em;
  text-transform:uppercase;
}
.sig-go svg{width:clamp(19px,3vw,32px);height:clamp(19px,3vw,32px);
  stroke:currentColor;fill:none;stroke-width:2.25;stroke-linecap:round;
  stroke-linejoin:round;}

@media (max-width:640px){
  /* The description is the first thing to go — on a phone the figure and the
     name carry it, and the arrows must stay above the fold. */
  .sig-note{display:none;}
  .sig-say{bottom:16px;max-width:66vw;}
  .sig-go{bottom:16px;}
  .sig-arrow{width:38px;height:38px;}
  .sig-arrow svg{width:16px;height:16px;}
}

@media (prefers-reduced-motion:reduce){
  .sig,.sig-fig,.sig-dots button{transition-duration:1ms !important;}
}

/* ══════════════════ BROWSE + DOCK ══════════════════
   The menu's controls sit beside the food rather than in a bar pinned across
   the top of it. On a wide screen the dock is a rail that follows you down the
   page and lights up whichever section you are reading; narrower, it drops to
   a floating bar inside thumb reach. Either way it never covers the menu. */
/* The rail sits closer to the left edge than the cards do — it is furniture
   rather than content, so it hugs the window while the menu keeps its margin. */
.browse{
  max-width:1480px;margin:0 auto;
  /* A breath between the hero and the first heading — the menu should start,
     not collide with the bottom of the stage. */
  padding:clamp(30px,5vw,64px) clamp(14px,2.4vw,24px) 0 clamp(8px,1.3vw,14px);
  display:grid;grid-template-columns:244px minmax(0,1fr);
  gap:clamp(18px,2.4vw,34px);align-items:start;
}
.browse-main{min-width:0;}

/* Deliberately NOT a scroll container.
 *
 * It was `max-height:100vh; overflow-y:auto` as a guard for short screens, and
 * that quietly broke the sort popover: an overflow value other than visible
 * makes the element clip its absolutely-positioned descendants, so the menu
 * opened inside the rail and was cut away to nothing. Nothing looked wrong —
 * the button just stopped doing anything.
 *
 * With no clipping the rail can simply be as tall as it needs to be; sticky
 * does not crop, so a rail longer than the window is reached by scrolling. */
.dock{
  position:sticky;top:20px;
  z-index:60;align-self:start;
  display:flex;flex-direction:column;gap:12px;
  padding:12px;border-radius:var(--r-lg);
  background:color-mix(in srgb,var(--surface) 78%,transparent);
  border:1px solid var(--line);
  backdrop-filter:blur(18px) saturate(1.25);
  -webkit-backdrop-filter:blur(18px) saturate(1.25);
  box-shadow:var(--shadow-sm);
}

/* A centred variant was tried here — `top:50vh` plus a `translateY(-50%)` to
   pull the stuck rail up around the middle of a tall screen. `transform`
   applies unconditionally, though, not only once sticky actually engages, so
   it also yanked the rail up by half its own height while still in normal
   flow — on a tall enough viewport that showed up as the rail overlapping the
   bottom of the hero before the page had even been scrolled. A sticky element
   can't tell CSS "only once you're actually stuck," so the fixed offset stays
   the same at every viewport height instead. */

/* ── search ── */
.dock-search{
  display:flex;align-items:center;gap:9px;flex:none;
  padding:10px 12px;border-radius:100px;
  background:var(--surface-2);border:1px solid transparent;
  transition:border-color var(--tap) var(--ease),background-color var(--tap) var(--ease);
}
.dock-search:focus-within{border-color:var(--accent-line);background:var(--surface);}
.dock-search svg{width:15px;height:15px;flex:none;stroke:var(--fg-3);fill:none;stroke-width:1.9;}
.dock-search input{flex:1;min-width:0;font-size:.86rem;}
.dock-search input::placeholder{color:var(--fg-3);}
.sort-clear{
  width:20px;height:20px;border-radius:50%;flex:none;display:grid;place-items:center;
  background:var(--surface-3);color:var(--fg-3);font-size:.6rem;
  transition:background-color var(--tap) var(--ease),color var(--tap) var(--ease);
}
.sort-clear:hover{background:var(--danger);color:#fff;}

/* ── the sections list ──
   Vertical on a rail. The marker on the left is the thing that makes it a
   position indicator rather than a set of buttons: it slides to whichever
   section the page is actually showing. */
/* Every section listed, no inner scroller. The list capped itself at 52vh
   before, which hid the last few categories behind a scrollbar inside a panel
   that was itself scrolling — two nested scrollers for one short list. If the
   whole rail outgrows the window, .dock scrolls; this never does. */
.sort-cats{
  display:flex;flex-direction:column;gap:1px;
}

.sort-cats button{
  position:relative;display:flex;align-items:center;gap:8px;
  padding:9px 12px 9px 14px;border-radius:var(--r-sm);
  text-align:left;white-space:nowrap;
  color:var(--fg-3);font-size:.85rem;font-weight:500;
  transition:color var(--tap) var(--ease),background-color var(--tap) var(--ease);
}
.sort-cats button::before{
  content:'';position:absolute;left:4px;top:50%;translate:0 -50%;
  width:2px;height:0;border-radius:2px;background:var(--accent);
  transition:height .34s var(--ease);
}
.sort-cats button span{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;}
.sort-cats button i{
  flex:none;font-style:normal;font-family:var(--mono);
  font-size:.58rem;letter-spacing:.04em;opacity:.5;
}
.sort-cats button:hover{color:var(--fg);background:var(--surface-2);}
.sort-cats button.on{color:var(--fg);background:var(--surface-2);}
.sort-cats button.on::before{height:17px;}
.sort-cats button.on i{color:var(--accent);opacity:1;}

/* ── sort ── */
.dock-foot{position:relative;flex:none;padding-top:2px;border-top:1px solid var(--line);}
.sort-trigger{
  display:flex;align-items:center;gap:9px;width:100%;
  padding:10px 12px;border-radius:var(--r-sm);
  color:var(--fg-2);font-size:.82rem;font-weight:500;
  transition:background-color var(--tap) var(--ease),color var(--tap) var(--ease);
}
.sort-trigger:hover{background:var(--surface-2);color:var(--fg);}
.sort-trigger.open{background:var(--surface-2);color:var(--fg);}
.sort-trigger svg{width:15px;height:15px;flex:none;stroke:currentColor;fill:none;
  stroke-width:1.9;stroke-linecap:round;}
.sort-trigger span{flex:1;min-width:0;text-align:left;overflow:hidden;text-overflow:ellipsis;}
.sort-trigger i{
  width:0;height:0;flex:none;
  border-left:4px solid transparent;border-right:4px solid transparent;
  border-top:5px solid var(--fg-3);
  transition:transform var(--tap) var(--ease);
}
.sort-trigger.open i{transform:rotate(180deg);}

.sort-menu{
  position:absolute;bottom:calc(100% + 8px);left:0;right:0;z-index:80;
  min-width:230px;padding:6px;border-radius:var(--r);
  background:var(--surface);border:1px solid var(--line-2);
  box-shadow:var(--shadow);
  opacity:0;transform:translateY(6px) scale(.98);pointer-events:none;
  transition:opacity .18s var(--ease),transform .18s var(--ease);
}
.sort-menu.open{opacity:1;transform:none;pointer-events:auto;}
.sort-menu button{
  display:flex;align-items:center;gap:10px;width:100%;
  padding:9px 11px;border-radius:var(--r-sm);text-align:left;
  transition:background-color var(--tap) var(--ease);
}
.sort-menu button:hover{background:var(--surface-2);}
.sort-menu button span{flex:1;min-width:0;}
.sort-menu button b{display:block;font-size:.85rem;font-weight:600;}
.sort-menu button i{
  display:block;margin-top:2px;font-style:normal;
  font-size:.72rem;color:var(--fg-3);
}
.sort-menu button svg{
  width:15px;height:15px;flex:none;stroke:var(--accent);fill:none;
  stroke-width:2.6;stroke-linecap:round;stroke-linejoin:round;opacity:0;
}
.sort-menu button.on{background:var(--accent-soft);}
.sort-menu button.on svg{opacity:1;}

/* The "Showing …" summary that used to sit here is gone. It restated what the
   rail, the search box and the sort button were each already showing, and on
   picking a section it pushed the whole menu down by its own height. */

/* ── narrow: the rail becomes a floating bar ──
   Fixed to the bottom rather than the top, so it stays under the thumb and
   never sits between the reader and the food. The search collapses to its
   icon and opens on focus, which is the only way all three controls fit on a
   phone without stacking into a second row. */
@media (max-width:1080px){
  /* Keeps the top breathing space — a bare `padding:0 …` here wiped the gap
     the wide layout sets between the hero and the first heading. */
  .browse{display:block;padding:clamp(30px,6vw,48px) clamp(14px,3vw,20px) 0;}

  /* Floating, so it would otherwise hang over the hero from the moment the
     page opens — furniture for a menu the reader has not reached yet. It
     stays tucked below the fold until the menu itself is in view; customer.js
     adds .show when that happens. */
  .dock{
    position:fixed;left:12px;right:12px;bottom:calc(26px + env(safe-area-inset-bottom));
    top:auto;z-index:190;
    flex-direction:row;align-items:center;gap:8px;
    padding:8px;border-radius:100px;
    box-shadow:var(--shadow);

    transform:translateY(calc(100% + 22px));opacity:0;pointer-events:none;
    transition:transform .42s var(--ease),opacity .3s var(--ease);
  }
  .dock.show{transform:none;opacity:1;pointer-events:auto;}

  .dock-search{
    width:40px;padding:9px;overflow:hidden;flex:none;
    transition:width .32s var(--ease),border-color var(--tap) var(--ease);
  }
  .dock-search:focus-within{width:min(210px,46vw);}
  .dock-search input{width:0;transition:width .32s var(--ease);}
  .dock-search:focus-within input{width:auto;flex:1;}
  .sort-clear{display:none;}
  .dock-search:focus-within .sort-clear:not(.hidden){display:grid;}

  .sort-cats{
    flex-direction:row;gap:4px;flex:1;min-width:0;max-height:none;
    overflow-x:auto;overflow-y:hidden;scrollbar-width:none;
  }
  .sort-cats::-webkit-scrollbar{display:none;}
  .sort-cats button{
    flex:none;padding:8px 13px;border-radius:100px;
  }
  .sort-cats button::before{display:none;}
  .sort-cats button.on{background:var(--fg);color:var(--bg);}
  .sort-cats button.on i{color:inherit;opacity:.65;}

  .dock-foot{border-top:none;padding-top:0;flex:none;}
  .sort-trigger{width:auto;padding:10px;}
  .sort-trigger span,.sort-trigger i{display:none;}
  .sort-menu{right:0;left:auto;min-width:236px;}

  /* Clear the floating dock. The bar's own offset is set further down, after
     its base rule — put here it lost to that rule at tablet widths. */
  .c-main{padding-bottom:150px;}
}

@media (prefers-reduced-motion:reduce){
  .dock-search,.dock-search input,.sort-cats button::before{transition:none;}
}

/* ══════ MENU ══════ */
/* The old 140px tail was there to clear a fixed bottom bar that no longer sits
   over this column on a wide screen, and it left the footer stranded a screen
   below the last card. */
.c-main{max-width:1240px;margin:0 auto;padding:34px 4px 24px;}

.c-sec{margin-bottom:clamp(56px,8vw,86px);scroll-margin-top:78px;}
/* The gap after the last section is the footer's business, not the section's —
   stacked, the two left a screen of dead space above the footer. */
.c-sec:last-child{margin-bottom:0;}

/* A numbered chapter head with the name ghosted behind it at size. What makes
   a long scroll feel edited rather than dumped: you always know which part of
   the menu you are in, even mid-scroll. */
.c-sec-head{
  position:relative;display:flex;align-items:baseline;gap:14px;
  margin-bottom:clamp(20px,3vw,30px);padding-top:18px;
}
/* Sits high and slightly left of the heading so the two overlap only at the
   shoulders — enough to feel layered, not so much that either is hard to
   read. Kept faint on purpose: it is a watermark, not a second title. */
/* Bounded on the right and clipped.
 *
 * It is set nowrap at a size measured in vw, so a long category — "Premium
 * Single Origin Coffee" — ran about 90px past a phone screen. Being absolutely
 * positioned it still counts toward the page's scrollable width, so the whole
 * document could be dragged sideways, and every fixed bar then sized itself
 * against that wider layout viewport instead of the screen. */
.c-sec-ghost{
  position:absolute;left:-6px;right:0;top:-26px;overflow:hidden;
  z-index:0;pointer-events:none;user-select:none;
  font-family:'Anton',var(--display),sans-serif;font-weight:400;
  font-size:clamp(44px,8.4vw,96px);line-height:1;letter-spacing:-.03em;
  text-transform:uppercase;white-space:nowrap;
  color:var(--fg);opacity:.045;
}
.c-sec-no{
  position:relative;z-index:1;flex:none;
  font-family:var(--mono);font-size:.62rem;font-weight:500;letter-spacing:.12em;
  color:var(--accent);
}
.c-sec-head h2{
  position:relative;z-index:1;
  font-size:clamp(1.55rem,4.2vw,2.3rem);letter-spacing:-.034em;line-height:1.05;
}
.c-sec-rule{flex:1;height:1px;background:var(--line);position:relative;top:-6px;}
.c-sec-count{
  position:relative;z-index:1;flex:none;
  font-family:var(--mono);font-size:.62rem;color:var(--fg-3);letter-spacing:.1em;
}

.c-grid{
  display:grid;gap:clamp(14px,1.6vw,20px);
  grid-template-columns:repeat(auto-fill,minmax(238px,1fr));
}
/* The first card of a section takes two columns and stands taller — an
   entry point for the eye, borrowed from how a menu gives its house drink
   more room than the rest of the list.
 *
 * Two earlier attempts put the photo beside the words: first stacked full
 * height (roughly twice its neighbours' height, a well of empty white beside
 * it), then on its side with the photo stretched to match the row (a well of
 * empty air above the price instead, since a short description rarely fills
 * a tall photo's own height). Both left the row's height at the mercy of
 * whichever side was taller. A full-bleed photo with the words set on top of
 * it, the way a poster carries a title, needs no such match — one layer,
 * nothing left over to fill. `height:100%` rather than a number pins it to
 * the row's own height, so it stands exactly as tall as the ordinary cards
 * beside it instead of a fixed guess that happened to be close. */
@media (min-width:760px){
  .c-card.lead{grid-column:span 2;position:relative;overflow:hidden;height:100%;padding:0;}
  .c-card.lead .c-card-img{
    position:absolute;inset:0;width:100%;height:100%;aspect-ratio:auto;border-radius:0;
  }
  .c-card.lead .c-card-body{
    position:absolute;left:0;right:0;bottom:0;z-index:1;
    padding:22px 22px 18px;
    background:linear-gradient(to top,rgba(0,0,0,.94) 0%,rgba(0,0,0,.68) 55%,transparent 100%);
  }
  .c-card.lead .c-card-info{margin-block:0;}
  .c-card.lead .c-card-foot{margin-top:12px;}
  .c-card.lead h3{font-size:1.4rem;color:#fff;}
  .c-card.lead .c-kcal{color:rgba(255,255,255,.85);}
  .c-card.lead .c-kcal i{color:rgba(255,255,255,.55);}
  .c-card.lead .c-recipe{-webkit-line-clamp:2;font-size:.85rem;color:rgba(255,255,255,.8);}
  .c-card.lead .c-meta-pill{
    background:rgba(255,255,255,.14);border-color:rgba(255,255,255,.28);color:rgba(255,255,255,.9);
  }
  .c-card.lead .c-price{color:#fff;}
  .c-card.lead .c-price small{color:rgba(255,255,255,.62);}
}

/* ── the card ──
   The photo sits in its own tinted well inside the card rather than filling
   the top edge of it, and is allowed to overhang that well slightly. A cup
   then stands proud of its frame instead of being cropped into a tile, which
   is the whole difference between a menu and a spreadsheet of food. */
.c-card{
  position:relative;display:flex;flex-direction:column;text-align:left;width:100%;
  padding:10px;border-radius:var(--r-lg);
  background:var(--surface);border:1px solid var(--line);
  transition:transform .4s var(--ease),border-color .4s var(--ease),
             box-shadow .4s var(--ease);
}

/* Inset inside the card rather than bleeding off its top edge — the card
   keeps a visible margin all the way round, which is what makes a grid of
   them read as considered rather than as a contact sheet.
 *
 * The photo fills the well. An earlier pass let it overhang the top, copied
 * from menu sites that use cut-out product shots on transparent backgrounds;
 * ours are rectangular lifestyle photographs, so `contain` letterboxed them
 * into a grey frame and the overhang had nothing to overhang with. */
.c-card-img{
  position:relative;aspect-ratio:5 / 4;flex:none;overflow:hidden;
  border-radius:calc(var(--r-lg) - 5px);
  background:var(--surface-2);
}
.c-card-img img{
  width:100%;height:100%;object-fit:cover;
  opacity:0;transform:scale(1.04);
  transition:opacity .55s var(--ease),transform .7s var(--ease);
}
.c-card-img img.ready{opacity:1;transform:scale(1);}

.c-card-body{
  flex:1;padding:14px 8px 6px;display:flex;flex-direction:column;
}
.c-card-info{display:flex;flex-direction:column;gap:7px;}
.c-card-top{display:flex;align-items:flex-start;gap:10px;}
.c-card h3{
  flex:1;min-width:0;
  font-size:1.04rem;line-height:1.22;letter-spacing:-.024em;color:var(--fg);
}
/* Calories moved off the photo and into the type, where it is information
   rather than a sticker — and where it stops covering the drink. */
.c-kcal{
  flex:none;display:flex;flex-direction:column;align-items:flex-end;line-height:1;
  font-family:var(--mono);font-size:.82rem;font-weight:500;color:var(--fg-2);
}
.c-kcal i{
  font-style:normal;font-size:.46rem;letter-spacing:.12em;
  text-transform:uppercase;color:var(--fg-3);margin-top:3px;
}
.c-card .c-recipe{
  color:var(--fg-3);font-size:.79rem;line-height:1.45;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;
}
.c-card-meta{display:flex;gap:6px;flex-wrap:wrap;margin-top:2px;}
.c-meta-pill{
  padding:4px 9px;border-radius:100px;
  background:var(--surface-2);border:1px solid var(--line);
  color:var(--fg-3);font-family:var(--mono);font-size:.5rem;
  font-weight:500;letter-spacing:.08em;text-transform:uppercase;
}

.c-card-foot{
  display:flex;align-items:center;gap:10px;margin-top:auto;padding-top:14px;
}
.c-price{
  display:flex;align-items:baseline;gap:5px;
  font-family:var(--display);font-size:1.2rem;font-weight:600;
  letter-spacing:-.028em;color:var(--fg);
}
.c-price small{
  font-family:var(--mono);font-size:.55rem;font-weight:400;
  letter-spacing:.09em;color:var(--fg-3);
}
.c-add{
  margin-left:auto;width:38px;height:38px;border-radius:50%;flex:none;
  background:var(--accent-grad);color:var(--accent-ink);
  display:grid;place-items:center;
  transition:transform var(--tap) var(--ease),filter var(--tap) var(--ease);
}
.c-add svg{width:17px;height:17px;stroke:currentColor;fill:none;
  stroke-width:2.6;stroke-linecap:round;}
.c-add:active{transform:scale(.85);}

/* still used by the item panel header */
.c-tag{
  padding:5px 10px;border-radius:100px;
  background:rgba(8,8,9,.62);backdrop-filter:blur(8px);
  border:1px solid rgba(255,255,255,.16);color:#fff;
  font-family:var(--mono);font-size:.53rem;font-weight:500;letter-spacing:.09em;
  text-transform:uppercase;
}

@media (hover:hover){
  .c-card:hover{transform:translateY(-5px);border-color:var(--accent-line);box-shadow:var(--shadow);}
  /* The cup lifts a little further than the card does, so it reads as
     standing in the well rather than printed on it. */
  .c-card:hover .c-card-img img.ready{transform:translateY(-6px) scale(1.03);}
  .c-add:hover{filter:brightness(1.08);}
}

/* The choice chips, .c-opt rows and .i-qty stepper live in app.css — both
   this page and the counter till use them, and duplicating them here once
   left the back office rendering bare unstyled text. */

/* required / optional flag on a question */
.i-block > .mono .req,
.i-block > .mono .opt{
  font-style:normal;margin-left:9px;padding:2px 7px;border-radius:100px;
  font-size:.52rem;letter-spacing:.09em;
}
.i-block > .mono .req{background:var(--accent-soft);color:var(--accent);}
.i-block > .mono .opt{background:var(--surface-3);color:var(--fg-3);}

/* scroll reveal */
.c-card{opacity:0;transform:translateY(26px);}
.c-card.in{opacity:1;transform:none;
  transition:opacity .7s var(--ease),transform .7s var(--ease),
             border-color .45s var(--ease),box-shadow .45s var(--ease);}
@media (prefers-reduced-motion:reduce){.c-card{opacity:1;transform:none;}}

/* ══════ BASKET BAR ══════
   Hidden by opacity and visibility, not by sliding alone.
 *
 * The slide is 180% of the bar's own height, which cleared the screen while it
 * sat 20px from the bottom. Once it was raised to stand clear of the dock, 180%
 * no longer reached past the edge and an empty basket sat visibly on top of the
 * category pills reading "0.00 EGP". Fading it out as well makes the hidden
 * state independent of whatever offset it is given. */
.c-bar{
  position:fixed;left:50%;bottom:20px;transform:translate(-50%,180%);
  opacity:0;visibility:hidden;
  z-index:200;width:min(560px,calc(100% - 32px));
  padding:12px 12px 12px 22px;border-radius:100px;
  background:var(--surface);border:1px solid var(--line-2);
  display:flex;align-items:center;gap:16px;
  box-shadow:var(--shadow);
  transition:transform .48s var(--ease),opacity .3s var(--ease),
             visibility 0s linear .48s;
}
.c-bar.up{
  transform:translate(-50%,0);
  opacity:1;visibility:visible;
  transition:transform .48s var(--ease),opacity .3s var(--ease),
             visibility 0s linear 0s;
}

/* Stands the bar clear of the floating dock, at every width where that dock
   exists. It has to live HERE, after the base rule above — the same
   declaration inside the earlier max-width:1080px block lost to that base at
   tablet widths, where the narrow-phone block that also sets it never applies.
   Two rules of equal specificity, and the later one in the file wins. */
@media (max-width:1080px){
  .c-bar{bottom:calc(118px + env(safe-area-inset-bottom));}
}
.c-bar-info b{display:block;font-size:1.05rem;font-weight:600;font-variant-numeric:tabular-nums;}
.c-bar-info span{color:var(--fg-3);font-family:var(--mono);font-size:.55rem;letter-spacing:.1em;}
.c-bar .btn{margin-left:auto;}

/* ══════ SHEET ══════ */
.c-sheet-back{
  position:fixed;inset:0;z-index:300;background:var(--scrim);
  display:flex;align-items:flex-end;justify-content:center;
  backdrop-filter:blur(5px);animation:fade .26s var(--ease);
}
.c-sheet{
  width:100%;max-width:580px;max-height:92dvh;overflow-y:auto;
  background:var(--surface);border:1px solid var(--line-2);border-bottom:none;
  border-radius:var(--r-xl) var(--r-xl) 0 0;
  padding:22px 22px calc(26px + env(safe-area-inset-bottom));
  animation:sheet-up .44s var(--ease);
}
@keyframes sheet-up{from{transform:translateY(100%);}}
.c-sheet-grip{width:40px;height:4px;border-radius:2px;background:var(--line-2);
  margin:-8px auto 18px;}
.c-sheet h3{font-size:1.4rem;}
.c-sheet > .mono{color:var(--fg-2);margin-top:4px;}
.c-sheet-body{margin:20px 0;display:flex;flex-direction:column;gap:14px;}

/* step 2 and 3 of checkout — a way back that does not look like Cancel */
.c-back{
  color:var(--fg-3);font:inherit;font-size:.82rem;margin-bottom:6px;
  padding:4px 0;align-self:flex-start;
}
.c-back:hover{color:var(--fg-2);}

/* review step: where it is going, and who is paying — plain fact rows, the
   same shape wherever the till and the reports print one. */
.c-review-where,.c-review-pay{
  display:flex;flex-direction:column;gap:2px;padding:12px 14px;
  background:var(--surface-2);border-radius:var(--r);
}
.c-review-where span,.c-review-pay span{color:var(--fg-3);}
.c-review-where b{font-size:1.02rem;}
.c-review-where i{color:var(--fg-3);font-style:normal;margin-top:2px;}
.c-review-note{color:var(--fg-3);line-height:1.7;}

/* basket lines */
.c-line{display:flex;gap:13px;align-items:flex-start;padding:13px 0;
  border-bottom:1px solid var(--line);}
.c-line:last-of-type{border-bottom:none;}
.c-line-shot{width:58px;height:58px;border-radius:var(--r-sm);flex:none;
  overflow:hidden;background:var(--surface-2);}
.c-line-shot img{width:100%;height:100%;object-fit:cover;}
.c-line-main{flex:1;min-width:0;}
.c-line-main b{font-size:.94rem;font-weight:600;line-height:1.3;display:block;}
.c-line-main .mono{color:var(--fg-3);margin-top:4px;}
.c-line-note{margin-top:4px;color:var(--warn);font-size:.74rem;}
.c-line-right{display:flex;flex-direction:column;align-items:flex-end;gap:9px;}
.c-line-total{font-family:var(--mono);font-size:.88rem;}

.c-qty{display:flex;align-items:center;gap:3px;background:var(--surface-2);
  border-radius:100px;padding:3px;border:1px solid var(--line);}
.c-qty button{width:28px;height:28px;border-radius:50%;display:grid;place-items:center;
  font-size:1.05rem;line-height:1;color:var(--fg-2);}
.c-qty button:active{background:var(--surface-3);color:var(--fg);}
.c-qty b{min-width:20px;text-align:center;font-family:var(--mono);font-size:.78rem;}

/* ── how they want it: eaten in, collected, or delivered ── */
.c-types{display:flex;gap:9px;}
.c-types .c-opt{flex:1;justify-content:center;min-width:0;}
/* Three across is tight on a small phone; let them wrap rather than squash. */
@media (max-width:380px){
  .c-types{flex-wrap:wrap;}
  .c-types .c-opt{flex:1 1 46%;}
}
.c-deliv-note{
  color:var(--fg-3);line-height:1.7;margin-top:10px;
}
#addrWrap textarea{
  width:100%;resize:vertical;min-height:76px;font:inherit;line-height:1.6;
}
/* an address is long — let it wrap on the confirmation rather than clip */
.c-done-addr{
  display:block;line-height:1.5;word-break:break-word;
  font-size:1rem;margin-top:2px;
}

/* The phone field with its country code is defined in app.css — the guest
   types one at checkout and staff type one at the till, and admin.html (the
   back office) never loads this file. .c-opt lives there for the same reason. */

/* ══════ CONFIRMATION ══════ */
.c-done{text-align:center;padding:12px 0 4px;}
.c-tick{
  width:66px;height:66px;border-radius:50%;margin:0 auto 20px;
  background:var(--accent);display:grid;place-items:center;
  animation:pop .55s var(--ease) backwards;
}
@keyframes pop{from{transform:scale(0) rotate(-25deg);}}
.c-tick svg{width:31px;height:31px;stroke:var(--accent-ink);fill:none;stroke-width:2.8;
  stroke-linecap:round;stroke-linejoin:round;}
.c-done h3{font-size:1.6rem;}
.c-orderno{
  display:inline-block;margin:14px 0 6px;padding:9px 18px;border-radius:100px;
  background:var(--surface-2);border:1px solid var(--line);
  font-family:var(--mono);font-size:.88rem;letter-spacing:.08em;
}
.c-done p{color:var(--fg-2);font-size:.9rem;line-height:1.65;margin-top:16px;}
.c-done p b{color:var(--fg);}

/* where it is going — the thing the guest checks twice */
.c-done-where{
  margin-top:18px;padding:14px 18px;border-radius:var(--r);
  background:var(--accent-soft);border:1px solid var(--accent-line);
}
.c-done-where .mono{display:block;color:var(--accent);opacity:.85;}
.c-done-where b{
  display:block;margin-top:5px;font-family:var(--display);
  font-size:1.5rem;font-weight:600;letter-spacing:-.028em;color:var(--fg);
}

.c-done-total{
  margin-top:14px;padding:14px 18px;border-radius:var(--r);
  background:var(--surface-2);border:1px solid var(--line);
}
.c-done-total .mono{display:block;color:var(--fg-3);}
.c-done-total b{
  display:block;margin-top:5px;font-family:var(--display);
  font-size:1.4rem;font-weight:600;letter-spacing:-.028em;
}
.c-done-total em{
  display:block;margin-top:4px;font-style:normal;
  font-family:var(--mono);font-size:.56rem;letter-spacing:.09em;
  text-transform:uppercase;color:var(--fg-3);
}

/* the tax lines read quieter than the items they sit under */
.c-sheet .sums .sum span:first-child{color:var(--fg-2);}
.c-sheet .sums{
  padding:14px 16px;border-radius:var(--r);
  background:var(--surface-2);border:1px solid var(--line);
}
.c-sheet .sums .sum.total{border-top:none;padding-top:0;margin-top:0;}
.bill-note{
  margin-top:9px;padding-top:9px;border-top:1px solid var(--line);
  color:var(--fg-3);line-height:1.7;
}

/* ══════════════════ FOOTER ══════════════════
   Small mono capitals over a wordmark that is cut out of horizontal rules.
   The ruling is a repeating gradient clipped to the glyphs, so the mark stays
   real text — selectable, searchable, and it scales with the window instead of
   being an image that has to be redrawn whenever the café is renamed. */
.foot{
  position:relative;margin-top:clamp(28px,4vw,52px);
  padding:clamp(34px,5vw,58px) clamp(16px,4vw,54px) clamp(20px,3vw,30px);
  border-top:1px solid var(--line);
  background:linear-gradient(180deg,transparent,color-mix(in srgb,var(--bg) 60%,transparent));
}

.foot-grid{
  display:grid;gap:clamp(26px,4vw,60px);
  grid-template-columns:1.4fr 1fr 1fr;align-items:start;
  max-width:1480px;margin:0 auto;
}
.foot-col{min-width:0;}

.foot-key{
  font-family:var(--mono);font-size:.66rem;font-weight:500;
  letter-spacing:.14em;text-transform:uppercase;color:var(--fg-2);
  line-height:2;
}
.foot-dim{color:var(--fg-3);}

.foot-head{
  font-family:var(--mono);font-size:.7rem;font-weight:600;
  letter-spacing:.2em;text-transform:uppercase;color:var(--fg);
  margin-bottom:16px;
}

.foot-list{list-style:none;display:flex;flex-direction:column;gap:9px;}
.foot-list li{display:flex;align-items:baseline;gap:12px;}
/* The letter is a label, not a bullet — fixed width so the values line up. */
.foot-list i{
  flex:none;width:14px;font-style:normal;
  font-family:var(--mono);font-size:.6rem;letter-spacing:.1em;
  color:var(--accent);
}
.foot-list span{color:var(--fg);font-size:.95rem;word-break:break-word;}
.foot-list a{border-bottom:1px solid transparent;transition:border-color var(--tap) var(--ease);}
.foot-list a:hover{border-bottom-color:var(--accent);}

.foot-links{gap:6px;}
.foot-links li{display:block;}
.foot-links a{
  color:var(--fg);font-size:.95rem;
  border-bottom:1px solid transparent;transition:border-color var(--tap) var(--ease);
}
.foot-links a:hover{border-bottom-color:var(--accent);}

/* ── the wordmark ──
   Set to span the width, whatever the name is.
 *
 * The size is measured and applied by fitFootMark() in customer.js rather than
 * fixed here: a vw value only fills the screen for a name of one particular
 * length, and this one is whatever the café called itself. The clamp below is
 * just a sane starting value for the instant before that runs.
 *
 * 96vw rather than 100vw — the latter counts the scrollbar's width on desktop
 * and would put the page back into sideways scrolling. */
.foot-mark{
  margin:clamp(34px,6vw,74px) 0 clamp(14px,2vw,22px);
  width:96vw;max-width:none;margin-left:50%;transform:translateX(-50%);
  font-family:'Anton',var(--display),sans-serif;font-weight:400;
  font-size:clamp(38px,15vw,220px);line-height:.92;letter-spacing:-.03em;
  text-transform:uppercase;text-align:center;user-select:none;
  white-space:nowrap;

  /* 2px of ink then 3px of air, repeated down the glyph. -webkit- prefixes
     are still required on Safari for both properties. */
  background-image:repeating-linear-gradient(
    180deg,
    var(--fg) 0 2px,
    transparent 2px 5px
  );
  -webkit-background-clip:text;
  background-clip:text;
  color:transparent;
  opacity:.5;
}

.foot-rule{height:1px;background:var(--line);max-width:1480px;margin:0 auto;}
.foot-tag{
  max-width:1480px;margin:14px auto 0;
  display:flex;gap:10px;flex-wrap:wrap;
}
/* The café's own line and the VAT note are two separate sentences that would
   otherwise read as one run-on. The divider only appears when there is
   actually a second one — :empty covers the case where no VAT is added. */
#taxFoot:not(:empty)::before{content:'·';margin-right:10px;opacity:.45;}

@media (max-width:820px){
  .foot-grid{grid-template-columns:1fr 1fr;gap:26px;}
  .foot-col:first-child{grid-column:1 / -1;}
}
@media (max-width:520px){
  .foot-grid{grid-template-columns:1fr;}
  .foot-tag{flex-direction:column;gap:4px;}
}

/* ══════ ITEM PANEL ══════
   Recovered: these rules sat between the FOOTER and MOBILE markers, and a
   splice that replaced that whole range to rebuild the footer took them
   with it. Nothing threw — the panel simply opened with no styling and so
   had no size, which reads as "the customisation menu is missing". */
.i-back-drop{
  position:fixed;inset:0;z-index:400;
  background:rgba(6,6,8,.52);
  backdrop-filter:blur(16px) saturate(.9);
  -webkit-backdrop-filter:blur(16px) saturate(.9);
  display:grid;place-items:center;padding:20px;
  animation:fade .28s var(--ease);
  overscroll-behavior:contain;
}
:root[data-theme="light"] .i-back-drop{background:rgba(20,20,16,.34);}

.i-card{
  position:relative;width:100%;max-width:520px;max-height:88dvh;overflow-y:auto;
  border-radius:var(--r-xl);
  /* frosted, not solid — the menu stays faintly readable behind it */
  background:color-mix(in srgb,var(--surface) 82%,transparent);
  backdrop-filter:blur(26px) saturate(1.5);
  -webkit-backdrop-filter:blur(26px) saturate(1.5);
  border:1px solid color-mix(in srgb,var(--line-2) 70%,transparent);
  box-shadow:0 26px 70px rgba(0,0,0,.46),inset 0 1px 0 rgba(255,255,255,.07);
  animation:card-up .42s var(--ease);
  overscroll-behavior:contain;
}
@keyframes card-up{from{opacity:0;transform:translateY(24px) scale(.97);}}

.i-close{
  position:absolute;top:14px;right:14px;z-index:5;
  width:34px;height:34px;border-radius:50%;
  display:grid;place-items:center;font-size:.86rem;
  background:rgba(8,8,10,.5);backdrop-filter:blur(10px);
  border:1px solid rgba(255,255,255,.18);color:#fff;
  transition:background var(--tap) var(--ease),transform var(--tap) var(--ease);
}
.i-close:hover{background:rgba(8,8,10,.74);}
.i-close:active{transform:scale(.88);}

.i-shot{
  position:relative;height:186px;background:var(--surface-2);overflow:hidden;
}
.i-shot img{width:100%;height:100%;object-fit:cover;opacity:0;
  transition:opacity .7s var(--ease);}
.i-shot img.ready{opacity:1;}
.i-shot::after{
  content:'';position:absolute;inset:0;
  background:linear-gradient(180deg,transparent 46%,rgba(6,6,8,.78));
}
.i-shot-body{position:absolute;left:0;right:0;bottom:0;z-index:2;padding:16px 18px;}
.i-shot-body .c-tag{position:static;display:inline-block;margin-bottom:9px;}
.i-shot h1{
  font-size:clamp(1.4rem,4.2vw,1.85rem);line-height:1.1;letter-spacing:-.028em;color:#fff;
  text-shadow:0 2px 18px rgba(0,0,0,.45);
}

.i-body{padding:20px 18px 22px;}
.i-block{margin-bottom:20px;}
.i-block:last-child{margin-bottom:0;}
.i-block > .mono{color:var(--fg-3);margin-bottom:10px;display:block;}

.i-ings{display:flex;flex-wrap:wrap;gap:7px;}
.i-ing{
  padding:8px 13px;border-radius:100px;
  background:var(--surface-2);border:1px solid var(--line);
  font-size:.82rem;color:var(--fg-2);
}

.i-facts{display:flex;flex-wrap:wrap;gap:9px;}
.i-fact{
  flex:1;min-width:104px;
  background:var(--surface-2);border:1px solid var(--line);
  border-radius:var(--r-sm);padding:13px 14px;
}
.i-fact .mono{color:var(--fg-3);font-size:.53rem;}
.i-fact b{display:block;margin-top:6px;font-family:var(--display);
  font-size:1.2rem;font-weight:600;letter-spacing:-.025em;}
.i-fact b small{font-size:.58rem;font-family:var(--mono);color:var(--fg-3);
  letter-spacing:.08em;margin-left:3px;font-weight:400;}

.i-opts{display:flex;flex-direction:column;gap:8px;}

/* order footer — sticks to the bottom of the panel while the body scrolls */
.i-order{
  position:sticky;bottom:0;
  border-top:1px solid var(--line);
  background:color-mix(in srgb,var(--surface) 92%,transparent);
  backdrop-filter:blur(20px);
  -webkit-backdrop-filter:blur(20px);
  padding:16px 18px 18px;
}
.i-order-row{display:flex;align-items:center;gap:14px;margin-bottom:14px;}
.i-price{display:flex;align-items:baseline;gap:7px;}
.i-price b{font-family:var(--display);font-size:1.75rem;font-weight:600;letter-spacing:-.03em;}
.i-price span{font-family:var(--mono);font-size:.62rem;color:var(--fg-3);letter-spacing:.1em;}
/* .i-qty is defined in app.css; here it just sits to the right */
.i-order-row .i-qty{margin-left:auto;background:var(--surface);}
.i-cta{width:100%;}

.i-more{margin-top:4px;}
.i-more .c-grid{grid-template-columns:repeat(3,1fr);gap:9px;}
.i-more .c-card{aspect-ratio:3 / 4;border-radius:var(--r);}
.i-more .c-card h3{font-size:.82rem;line-height:1.2;}
.i-more .c-card .c-price{font-size:.8rem;}
.i-more .c-card-body{padding:11px;}
.i-more .c-card-info{gap:5px;}
.i-more .c-card-foot{margin-top:2px;}

/* ══════════════════ MOBILE ══════════════════ */
@media (max-width:760px){
  /* svh so the hero is not cut off by the browser's own chrome */
  .hero{min-height:88svh;padding:0 18px 34px;}
  .hero-top{padding:16px 18px;}
  .c-mark img{width:34px;height:46px;}
  .hero-kicker{margin-bottom:16px;}
  .hero-title{font-size:clamp(2.4rem,11vw,3.4rem);}
  .hero-lede{font-size:.92rem;margin-top:16px;}
  .hero-meta{margin-top:20px;gap:7px;}
  .hero-pill{padding:8px 13px;font-size:.52rem;}

  .c-main{padding:24px 14px 132px;}
  .c-sec{margin-bottom:38px;}
  .c-sec-head{gap:12px;margin-bottom:16px;}

  /* two across — one column is too much scrolling for an 82-item menu */
  .c-grid{grid-template-columns:repeat(2,1fr);gap:10px;}
  .c-card-body{padding:11px 12px 12px;}
  .c-card-info{gap:4px;}
  .c-card h3{font-size:.92rem;}
  .c-card .c-recipe{font-size:.72rem;}
  .c-card-meta{display:none;}
  .c-card-foot{padding-top:9px;}
  .c-price{font-size:1rem;}
  .c-add{width:34px;height:34px;}
  .c-add svg{width:15px;height:15px;}
  .c-kcal{top:7px;right:7px;padding:4px 7px;font-size:.46rem;}

  /* Bottom offset deliberately not set here — it is owned by the one rule
     under .c-bar.up, so there is a single place that decides it. */
  .c-bar{
    left:14px;right:14px;width:auto;gap:10px;
    transform:translateY(180%);padding:8px 8px 8px 16px;
  }
  .c-bar.up{transform:none;}
  .c-bar-info b{font-size:.9rem;}
  .c-bar-info span{font-size:.5rem;}
  .c-bar .btn{padding:10px 16px;font-size:.6rem;}

  /* the item panel becomes a bottom sheet at this size */
  .i-back-drop{padding:0;align-items:flex-end;}
  .i-card{
    max-width:none;max-height:92svh;
    border-radius:var(--r-xl) var(--r-xl) 0 0;
    animation:card-rise .42s var(--ease);
  }
  @keyframes card-rise{from{transform:translateY(100%);}}
  .i-shot{height:158px;}
  .i-body{padding:18px 16px 20px;}
  .i-order{padding:14px 16px calc(16px + env(safe-area-inset-bottom));}
  .i-more .c-grid{grid-template-columns:repeat(3,1fr);gap:8px;}
  .i-more .c-card h3{font-size:.74rem;}
  .i-more .c-card .c-price{font-size:.72rem;}
  .chip-opt{padding:9px 13px;}

  .c-sheet{max-height:92svh;padding:20px 16px calc(24px + env(safe-area-inset-bottom));}
  .c-line-shot{width:50px;height:50px;}
  .foot{padding:30px 18px 40px;}
}

/* very small phones */
@media (max-width:380px){
  .c-grid{grid-template-columns:1fr;}
  .i-more .c-grid{grid-template-columns:repeat(2,1fr);}
}
