/* Cup & Cone.
   Built from the client-approved concept deck (concept/pdf-work/head.html),
   rebuilt on 2026-09-19 onto one system: a type scale, a spacing scale, a
   radius set, three elevations and one motion vocabulary. Every size below
   comes from these tokens; a value that does not is a bug.

   Look: calm, vanilla / ink / almond, one espresso band. Type: Gilda Display
   + Parastoo on every line. Glass lives in two places only: the island that
   follows the reader, and the small controls laid over photos and video. */

/* ---------------------------------------------------------------- fonts */
@font-face {
  font-family: "Gilda Display";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/fonts/gilda-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
    U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Gilda Display";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/fonts/gilda-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308,
    U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113,
    U+2C60-2C7F, U+A720-A7FF;
}
/* Parastoo is variable (400 to 700). At one pixel size its letters sit
   smaller than Gilda's; size-adjust evens the two scripts out at the source. */
@font-face {
  font-family: "Parastoo";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  size-adjust: 108%;
  src: url("/fonts/parastoo-arabic.woff2") format("woff2");
  unicode-range: U+0600-06FF, U+0750-077F, U+0870-088E, U+0890-0891, U+0898-08E1, U+08E3-08FF,
    U+200C-200E, U+2010-2011, U+204F, U+2E41, U+FB50-FDFF, U+FE70-FEFF, U+102E0-102FB,
    U+10E60-10E7E, U+10EC2-10EC4, U+10EFC-10EFF, U+1EE00-1EEFF;
}

/* ---------------------------------------------------------------- tokens */
:root {
  /* colour: one neutral ramp, one accent, one ink */
  --bg: #fcf2d3;
  --surface: #fff8e6;
  --fg: #2b2515;
  --muted: #766b4e; /* 4.7:1 on vanilla */
  --line: rgba(43, 37, 21, 0.12);
  --line-strong: rgba(43, 37, 21, 0.22);
  --accent: #a91f39; /* 6.4:1 on vanilla */
  --on-accent: #fcf2d3;
  --ring: #2b2515;
  --open: #3a9a5b;
  --star: #b87c10; /* 3.2:1 on vanilla: the star means the rating, so it has to be seen */
  --studio: #fcf2d3; /* the ground the studio photos are multiplied into */
  --ink: #2b2515; /* the espresso: footer, moments band, the order */
  --cream: #f6eccf; /* text on espresso: 12.9:1 */
  --cream-muted: #b9ae90; /* secondary text on espresso: 7.1:1 */

  /* type: eight steps and two display sizes, nothing in between */
  --sans: "Gilda Display", "Parastoo", serif;
  --t-micro: 12px; /* circle labels, badges, legal */
  --t-caption: 13px; /* second lines, notes, meta */
  --t-small: 14px; /* chips, tabs, small controls */
  --t-ui: 15px; /* prices, list rows, secondary buttons */
  --t-body: 16px; /* reading text, names, primary buttons */
  --t-lead: 18px; /* a line that introduces: the hero's tag, quotes */
  --t-title: 21px; /* group headings inside a section */
  --t-h3: 28px; /* small display: the brand in the footer */
  --t-h2: clamp(2.5rem, 11.2vw, 3rem); /* section titles */
  --t-h1: clamp(2.75rem, 12.4vw, 3.5rem); /* the hero: caps read larger than
    the mixed-case question it replaced, so the step came down with it */
  --lh-tight: 1.15;
  --lh-snug: 1.35;
  --lh-body: 1.6;

  /* space: a 4px scale */
  --s1: 4px;
  --s2: 8px;
  --s3: 12px;
  --s4: 16px;
  --s5: 20px;
  --s6: 24px;
  --s7: 32px;
  --s8: 40px;
  --s9: 48px;
  --s10: 64px;
  --s11: 80px;
  --gut: 20px; /* the deck's side margin */
  --page: 28rem;
  --section: 80px; /* the breath between sections */

  /* shape */
  --r-sm: 12px;
  --r-btn: 16px;
  --r-md: 24px;
  --r-lg: 28px;
  --r-xl: 32px;

  /* elevation: three depths, warm shadows, never grey */
  --sh-1: 0 1px 2px rgba(43, 37, 21, 0.06), 0 4px 14px -6px rgba(43, 37, 21, 0.14);
  --sh-2: 0 2px 6px -2px rgba(43, 37, 21, 0.12), 0 12px 30px -12px rgba(43, 37, 21, 0.38);
  --sh-3: 0 4px 12px -4px rgba(43, 37, 21, 0.14), 0 28px 60px -20px rgba(43, 37, 21, 0.55);

  /* motion */
  --ease: cubic-bezier(0.16, 1, 0.3, 1); /* arrivals: fast out, long settle */
  --ease-io: cubic-bezier(0.65, 0, 0.35, 1); /* things changing in place */
  --ease-icon: cubic-bezier(0.2, 0, 0, 1); /* icon and label swaps */
  --ease-sheet: cubic-bezier(0.32, 0.72, 0, 1);
  /* springs as easing curves (a damped spring leaving with some speed),
     calm on purpose: 2% settle for arrivals, 6% for a tap landing */
  --spring: linear(0, 0.307 4.5%, 0.532 9.1%, 0.693 13.6%, 0.808 18.2%, 0.887 22.7%, 0.94 27.3%,
    0.975 31.8%, 0.997 36.4%, 1.01 40.9%, 1.017 45.5%, 1.02 50%, 1.02 54.5%, 1.019 59.1%, 1.017 63.6%,
    1.015 68.2%, 1.012 72.7%, 1.01 77.3%, 1.008 81.8%, 1.007 86.4%, 1.005 90.9%, 1.004 95.5%, 1);
  --spring-pop: linear(0, 0.18 4.5%, 0.381 9.1%, 0.571 13.6%, 0.732 18.2%, 0.858 22.7%, 0.949 27.3%,
    1.009 31.8%, 1.043 36.4%, 1.058 40.9%, 1.06 45.5%, 1.055 50%, 1.045 54.5%, 1.034 59.1%,
    1.024 63.6%, 1.015 68.2%, 1.008 72.7%, 1.003 77.3%, 1 81.8%, 0.998 86.4%, 0.997 90.9%, 0.997 95.5%, 1);
  --t-press: 160ms;
  --t-state: 240ms;
  --t-enter: 800ms;

  --flow: -1; /* the direction reading continues in: left in Arabic */
  color-scheme: light;
}

html[dir="ltr"] {
  --flow: 1;
}

/* Night (switched off for now, NIGHT_MODE in wrangler.jsonc): the same page,
   dark after sunset in RAK. Kept at token level so it can come back. */
html[data-theme="night"] {
  --bg: #1b170e;
  --surface: #27211a;
  --fg: #f6eccf;
  --muted: #b9ae90;
  --line: rgba(246, 236, 207, 0.14);
  --line-strong: rgba(246, 236, 207, 0.24);
  --accent: #ec6e82;
  --on-accent: #1b170e;
  --ring: #f6eccf;
  color-scheme: dark;
}

/* ---------------------------------------------------------------- base */
*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
  font-synthesis: none; /* Gilda has one weight; never fake bold */
}

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scrollbar-color: var(--muted) var(--bg);
}

@media (prefers-reduced-motion: reduce) {
  .lightbox img,
  .lightbox .lightbox-cap {
    transform: none;
    transition: none;
  }

  html {
    scroll-behavior: auto;
  }
}

[hidden] {
  display: none !important;
}

body {
  background: var(--bg);
  color: var(--fg);
  font-family: var(--sans);
  font-size: var(--t-body);
  line-height: var(--lh-body);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  overflow-x: hidden; /* propagates to the viewport: things waiting to slide in never widen the page */
  caret-color: var(--accent);
  -webkit-tap-highlight-color: transparent;
}

/* Things waiting to slide in sit off to the side; on a phone that would widen
   the layout viewport itself (body overflow does not stop it), so the page's
   content clips its own sideways overflow. clip, not hidden: no scroll box. */
main,
.footer {
  overflow-x: clip;
}

/* while a dialog is open the page stops scrolling; JS keeps the offset */
body.is-locked {
  position: fixed;
  inset-inline: 0;
  width: 100%;
  overflow: hidden;
}

::selection {
  background: var(--accent);
  color: var(--on-accent);
}

/* Weights are chosen here, never inherited. The browser's own rule for b and
   strong is "bolder", which is relative: inside a 600 heading it computes to
   900, a weight neither face has, so it is faked and the serifs smear. Two
   real weights, and the headings name theirs. */
b,
strong {
  font-weight: 600;
}

h1,
h2,
h3,
h4,
h5,
h6 {
  font-size: inherit;
  font-weight: 600;
  line-height: var(--lh-snug);
}

img,
video {
  display: block;
  max-width: 100%;
}

a {
  color: inherit;
  text-decoration: none;
}

button,
input,
select {
  font: inherit;
  color: inherit;
}

button {
  background: none;
  border: 0;
  cursor: pointer;
  text-align: inherit;
}

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 6px;
}

.sr {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.sr:focus-visible {
  position: fixed;
  z-index: 200;
  inset-block-start: var(--s2);
  inset-inline-start: var(--s2);
  width: auto;
  height: auto;
  clip-path: none;
  padding: var(--s3) var(--s4);
  border-radius: var(--r-sm);
  background: var(--fg);
  color: var(--bg);
}

.ico {
  width: 24px;
  height: 24px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
  flex: none;
}

.en {
  direction: ltr;
  unicode-bidi: isolate;
}

.num {
  font-variant-numeric: tabular-nums;
  direction: ltr;
  unicode-bidi: isolate;
}

/* The UAE dirham sign (Central Bank of the UAE, 2025): a D crossed by two
   bars. Neither of the site's fonts has it, and most phones cannot show it
   as a typed character yet, so it is drawn: a mask filled with the text
   colour, as tall as the digits beside it. It always sits to the left of
   the amount, in Arabic and in English. Plain text (the WhatsApp message,
   Excel) keeps "د.إ" / "AED". */
.dh {
  display: inline-block;
  inline-size: 0.92em;
  block-size: 0.72em;
  margin-right: 0.2em;
  vertical-align: -0.02em;
  background: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 26 20'%3E%3Cpath fill-rule='evenodd' d='M6 1h5.5C18.3 1 22.2 4.9 22.2 10S18.3 19 11.5 19H6zM8.2 3.2v13.6h3.3c5.3 0 8.5-2.7 8.5-6.8s-3.2-6.8-8.5-6.8z'/%3E%3Cpath d='M1.5 7.1h21.7v1.5H1.5zM1.5 11.4h21.7v1.5H1.5z'/%3E%3C/svg%3E")
    center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 26 20'%3E%3Cpath fill-rule='evenodd' d='M6 1h5.5C18.3 1 22.2 4.9 22.2 10S18.3 19 11.5 19H6zM8.2 3.2v13.6h3.3c5.3 0 8.5-2.7 8.5-6.8s-3.2-6.8-8.5-6.8z'/%3E%3Cpath d='M1.5 7.1h21.7v1.5H1.5zM1.5 11.4h21.7v1.5H1.5z'/%3E%3C/svg%3E")
    center / contain no-repeat;
}

@media (forced-colors: active) {
  .dh {
    background: CanvasText;
  }
}

.wrap {
  width: 100%;
  max-width: var(--page);
  margin-inline: auto;
  padding-inline: var(--gut);
}

/* ---------------------------------------------------------------- type */
.display {
  font-family: var(--sans);
  font-weight: 600;
  line-height: var(--lh-tight);
  text-wrap: balance;
}

/* Gilda sets wide when it is large; Arabic is never letter-spaced (it would
   break the joins), so only the English page tightens its display lines */
html[lang="en"] .display {
  letter-spacing: -0.015em;
}

/* Every section: a heading that carries its weight and one plain line. */
.sec-head {
  display: grid;
  gap: var(--s1);
  margin-block-end: var(--s6);
}

.sec-head h2 {
  font-size: var(--t-h2);
}

.sub {
  font-size: var(--t-body);
  color: var(--muted);
  text-wrap: pretty;
}

/* the heading's words rise out of a mask (see reveals) */
.mask {
  display: block;
  overflow: hidden;
  padding-block: 0.1em 0.22em;
  margin-block: -0.1em -0.22em;
}

.mask > span {
  display: block;
}

/* ---------------------------------------------------------------- buttons */
.btn {
  height: 52px;
  padding-inline: var(--s5);
  border-radius: var(--r-btn);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s2);
  font-size: var(--t-body);
  font-weight: 600;
  line-height: 1;
  white-space: nowrap;
  transition:
    scale var(--t-press) var(--ease),
    background-color var(--t-state) var(--ease),
    box-shadow var(--t-state) var(--ease);
}

.btn .ico {
  width: 20px;
  height: 20px;
}

.btn:active {
  scale: 0.96;
}

.b1 {
  background: var(--accent);
  color: var(--on-accent);
}

.b2 {
  box-shadow: inset 0 0 0 1.5px var(--fg);
}

@media (hover: hover) {
  .b1:hover {
    background: color-mix(in srgb, var(--accent) 88%, #000);
  }
  .b2:hover {
    background: var(--surface);
  }
}

.stack {
  display: grid;
  margin-block-start: var(--s6);
}

/* toolbar buttons: a glyph in a 44px target, pressed state on the finger */
.tb {
  width: 44px;
  height: 44px;
  flex: none;
  border-radius: 50%;
  display: grid;
  place-items: center;
  transition:
    scale var(--t-press) var(--ease),
    background-color var(--t-state) var(--ease);
}

.tb:active {
  scale: 0.96;
  background: color-mix(in srgb, var(--fg) 6%, transparent);
}

.tb .ico {
  width: 24px;
  height: 24px;
}

/* the language: a small ringed tag in the same 44px target */
.lang span {
  min-width: 30px;
  height: 30px;
  padding-inline: var(--s2);
  border-radius: 15px;
  display: grid;
  place-items: center;
  font-size: var(--t-caption);
  font-weight: 600;
  line-height: 1;
  box-shadow: inset 0 0 0 1.5px currentColor;
}

/* ---------------------------------------------------------------- loader */
/* Once per visit, typographic. It clears itself in CSS too: no script, no wall. */
.loader {
  position: fixed;
  inset: 0;
  z-index: 100;
  background: var(--bg);
  display: grid;
  place-content: center;
  justify-items: center;
  gap: var(--s2);
  text-align: center;
  animation: loader-out 500ms var(--ease) 2.6s forwards;
}

.seen .loader {
  display: none;
}

.loader.is-done {
  animation: loader-out 450ms var(--ease) forwards;
}

/* the lockup writes itself on, left to right, the way script is drawn */
.loader-logo {
  width: min(66vw, 280px);
  height: auto;
  animation: write 1040ms var(--ease-io) 80ms both;
}

@keyframes write {
  from {
    clip-path: inset(0 100% 0 0);
    opacity: 0.4;
  }
  30% {
    opacity: 1;
  }
  to {
    clip-path: inset(0 0 0 0);
    opacity: 1;
  }
}

@keyframes rise {
  from {
    opacity: 0;
    transform: translateY(14px);
    filter: blur(6px);
  }
  to {
    opacity: 1;
    transform: none;
    filter: none;
  }
}

@keyframes loader-out {
  to {
    opacity: 0;
    visibility: hidden;
  }
}

@media (prefers-reduced-motion: reduce) {
  .loader {
    display: none;
  }
}

/* ---------------------------------------------------------------- header */
/* Flat, on the page's ground, scrolls away with the hero. */
.site-header {
  position: relative;
  z-index: 40;
}

.header-in {
  height: 68px;
  max-width: var(--page);
  margin-inline: auto;
  padding-inline: var(--gut) calc(var(--gut) - 10px);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s3);
}

.brand {
  display: flex;
  align-items: center;
  gap: var(--s3);
  min-height: 44px;
}

.brand img {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  box-shadow: 0 0 0 1px var(--line);
}

.brand b {
  font-size: var(--t-title);
  font-weight: 600;
  line-height: 1.2;
}

.d-links {
  display: none;
}

.header-actions {
  display: flex;
  align-items: center;
  gap: 0;
}

.head-order {
  display: none;
}

/* the menu: hangs from whichever bar opened it, solid, above everything */
.nav-sheet {
  position: fixed;
  z-index: 50;
  inset-block-start: calc(env(safe-area-inset-top, 0px) + 76px);
  inset-inline-end: 12px;
  min-width: 14rem;
  padding: var(--s2);
  border-radius: var(--r-md);
  background: var(--surface);
  box-shadow: 0 0 0 1px var(--line), var(--sh-3);
  display: grid;
  gap: 2px;
  transform-origin: calc(50% + var(--flow) * -40%) 0;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-8px) scale(0.96);
  filter: blur(4px);
  transition:
    opacity 180ms var(--ease),
    transform 320ms var(--ease),
    filter 240ms var(--ease),
    visibility 0s 320ms;
}

.nav-sheet.is-open {
  opacity: 1;
  visibility: visible;
  transform: none;
  filter: none;
  transition:
    opacity 200ms var(--ease),
    transform 420ms var(--spring),
    filter 240ms var(--ease),
    visibility 0s;
}

.nav-sheet a {
  min-height: 48px;
  padding-inline: var(--s3);
  border-radius: var(--r-sm);
  display: flex;
  align-items: center;
  gap: var(--s3);
  font-size: var(--t-body);
  font-weight: 600;
  transition: background-color var(--t-state) var(--ease);
}

.nav-sheet a:active {
  background: var(--bg);
}

.nav-sheet .ico {
  width: 20px;
  height: 20px;
  color: var(--muted);
}

.nav-sheet .nav-lang {
  margin-block-start: var(--s1);
  border-block-start: 1px solid var(--line);
  border-radius: 0 0 var(--r-sm) var(--r-sm);
  color: var(--muted);
}

/* ---------------------------------------------------------------- the island */
/* One capsule of liquid glass (radius = half its height). Script brings it in
   once the hero has gone and keeps it; until then it is invisible and inert.
   It changes face: home (name, Instagram, menu) or, over the menu, the menu's
   own categories with a pill that slides to the one on screen. */
.island {
  position: fixed;
  z-index: 44;
  inset-block-start: calc(env(safe-area-inset-top, 0px) + 10px);
  inset-inline: 12px;
  max-width: 30rem;
  margin-inline: auto;
  opacity: 0;
  pointer-events: none;
  transform: translateY(-20px) scale(0.9);
  transform-origin: 50% 0;
  transition:
    opacity 200ms var(--ease-io),
    transform 320ms cubic-bezier(0.4, 0, 1, 1);
}

/* arriving: rises into place on a spring, and the glass itself gives a small
   liquid wobble (wider and flatter, then settling) as it lands */
.island.is-on {
  opacity: 1;
  transform: none;
  pointer-events: auto;
  transition:
    opacity 260ms var(--ease),
    transform 760ms var(--spring-pop);
}

.island.is-on .isl-in {
  animation: liquid 820ms var(--ease) both;
}

@keyframes liquid {
  0% {
    scale: 0.94 0.86;
  }
  38% {
    scale: 1.035 0.95;
  }
  68% {
    scale: 0.992 1.015;
  }
  100% {
    scale: 1 1;
  }
}

.isl-in {
  position: relative;
  height: 56px;
  border-radius: 28px;
  background: color-mix(in srgb, #fff8e6 58%, transparent);
  -webkit-backdrop-filter: blur(22px) saturate(190%) brightness(1.03);
  backdrop-filter: blur(22px) saturate(190%) brightness(1.03);
  box-shadow:
    inset 0 1px 1px rgba(255, 255, 255, 0.9),
    inset 0 -1px 1px rgba(43, 37, 21, 0.05),
    0 0 0 0.5px rgba(43, 37, 21, 0.16),
    var(--sh-2);
  transition:
    background-color 400ms var(--ease-io),
    box-shadow 400ms var(--ease-io),
    color 400ms var(--ease-io);
}

/* the light that catches the top of the glass, and its rim */
.isl-in::before,
.isl-in::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
}

.isl-in::before {
  background:
    radial-gradient(120% 110% at 20% -30%, rgba(255, 255, 255, 0.62), rgba(255, 255, 255, 0) 55%),
    radial-gradient(70% 90% at 92% 130%, rgba(255, 255, 255, 0.3), rgba(255, 255, 255, 0) 60%);
}

.isl-in::after {
  padding: 1px;
  background: linear-gradient(
    175deg,
    rgba(255, 255, 255, 0.95),
    rgba(255, 255, 255, 0.12) 40%,
    rgba(255, 255, 255, 0) 60%,
    rgba(255, 255, 255, 0.45)
  );
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
}

/* over the espresso band the glass turns dark with it */
html.on-dark .isl-in {
  background: color-mix(in srgb, #2b2515 62%, transparent);
  color: var(--cream);
  box-shadow:
    inset 0 1px 1px rgba(255, 255, 255, 0.16),
    inset 0 -1px 1px rgba(0, 0, 0, 0.2),
    0 0 0 0.5px rgba(255, 255, 255, 0.14),
    var(--sh-2);
}

html.on-dark .isl-in::before {
  opacity: 0.25;
}

@media (prefers-reduced-transparency: reduce) {
  .isl-in {
    background: var(--surface);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
  html.on-dark .isl-in {
    background: var(--ink);
  }
}

/* the two faces share the capsule and cross-fade: opacity, scale and blur */
.isl-face {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  transition:
    opacity 280ms var(--ease-icon),
    scale 280ms var(--ease-icon),
    filter 280ms var(--ease-icon),
    visibility 0s;
}

.island.is-tabs .isl-home,
.island:not(.is-tabs) .isl-tabs {
  opacity: 0;
  scale: 0.96;
  filter: blur(4px);
  visibility: hidden;
  pointer-events: none;
  transition:
    opacity 200ms var(--ease-icon),
    scale 200ms var(--ease-icon),
    filter 200ms var(--ease-icon),
    visibility 0s 200ms;
}

.isl-home {
  padding-inline: var(--s2) var(--s1);
  gap: var(--s2);
}

.isl-brand {
  display: flex;
  align-items: center;
  gap: var(--s2);
  min-width: 0;
  min-height: 44px;
  padding-inline-end: var(--s2);
}

.isl-brand img {
  width: 38px;
  height: 38px;
  border-radius: 50%;
  box-shadow: 0 0 0 1px var(--line);
}

.isl-brand b {
  font-size: var(--t-body);
  font-weight: 600;
  line-height: 1.2;
  white-space: nowrap;
}

.isl-links {
  display: none;
}

.isl-acts {
  display: flex;
  align-items: center;
  gap: var(--s1);
  margin-inline-start: auto;
}

/* the one thing the shop is for, always within reach: a filled disc on a
   phone (concentric inside the capsule), the words spelled out on a laptop.
   While the order itself floats over the menu, this steps aside rather than
   filling a second thing in the accent on the same screen. */
/* stepping aside means leaving no gap behind: it closes to nothing and the
   two quiet icons take the space back */
html.order-up .isl-order {
  width: 0;
  margin-inline-start: calc(var(--s1) * -1);
  opacity: 0;
  scale: 0.6;
  pointer-events: none;
}

.isl-order {
  overflow: hidden;
  transition:
    opacity 200ms var(--ease-icon),
    scale 320ms var(--spring),
    width 320ms var(--ease),
    margin-inline-start 320ms var(--ease);
  width: 40px;
  height: 40px;
  padding: 0;
  border-radius: 50%;
  position: relative;
}

.isl-order span {
  display: none;
}

.isl-order .ico {
  width: 20px;
  height: 20px;
}

/* the disc is drawn at 40, but the thumb gets the full 44 */
.isl-order::before {
  content: "";
  position: absolute;
  inset: -2px;
  border-radius: 50%;
}

.isl-tabs {
  padding: var(--s2);
  gap: 2px;
  overflow-x: auto;
  scrollbar-width: none;
  justify-content: space-between;
}

.isl-tabs::-webkit-scrollbar {
  display: none;
}

.isl-tab {
  position: relative;
  z-index: 1;
  flex: 1 0 auto;
  height: 40px;
  padding-inline: var(--s3);
  border-radius: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  font-size: var(--t-small);
  font-weight: 600;
  white-space: nowrap;
  transition:
    color var(--t-state) var(--ease),
    scale var(--t-press) var(--ease);
}

.isl-tab:active {
  scale: 0.96;
}

.isl-tab .ico {
  width: 18px;
  height: 18px;
}

/* the pill under the current category: a full-width shape cut down to the
   current tab with an inset clip (paint only, no layout), eased on a spring */
.isl-ind,
.isl-over {
  position: absolute;
  inset-block-start: var(--s2);
  left: 0;
  right: 0;
  height: 40px;
  pointer-events: none;
  clip-path: inset(0 var(--r, 100%) 0 var(--l, 0px) round 20px);
  transition: clip-path 520ms var(--spring);
}

.isl-ind {
  background: var(--ink);
  transition:
    clip-path 520ms var(--spring),
    background-color 400ms var(--ease-io);
}

/* the same row again, in the pill's colour, showing only where the pill is:
   a label is never half-legible while the pill travels across it */
.isl-over {
  z-index: 1;
  display: flex;
  justify-content: space-between;
  gap: 2px;
  padding-inline: var(--s2);
  color: var(--cream);
}

.isl-tabs.no-anim .isl-ind,
.isl-tabs.no-anim .isl-over {
  transition: none;
}

html.on-dark .isl-ind {
  background: var(--cream);
}

html.on-dark .isl-over {
  color: var(--ink);
}

/* where content meets the island, it fades rather than hitting a line */
.edge {
  position: fixed;
  z-index: 43;
  inset-inline: 0;
  inset-block-start: 0;
  height: calc(env(safe-area-inset-top, 0px) + 84px);
  background: linear-gradient(
    to bottom,
    color-mix(in srgb, var(--bg) 94%, transparent) 25%,
    color-mix(in srgb, var(--bg) 0%, transparent)
  );
  opacity: 0;
  pointer-events: none;
  transition: opacity 360ms var(--ease-io);
}

html.isl-up .edge {
  opacity: 1;
}

html.on-dark .edge {
  background: linear-gradient(to bottom, rgba(43, 37, 21, 0.9) 25%, rgba(43, 37, 21, 0));
}

/* ---------------------------------------------------------------- live status */
.live {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  height: 34px;
  padding-inline: var(--s3) var(--s4);
  border-radius: 17px;
  background: var(--surface);
  box-shadow: inset 0 0 0 1px var(--line);
  font-size: var(--t-small);
  font-weight: 600;
  line-height: 1;
  white-space: nowrap;
}

.live i {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex: none;
}

.live[data-state="open"] i {
  background: var(--open);
  box-shadow: 0 0 0 4px rgba(58, 154, 91, 0.22);
}

.live[data-state="closed"] i {
  background: var(--muted);
}

.live .live-m {
  width: 15px;
  height: 15px;
  stroke-width: 1.6;
  color: var(--muted);
}

/* ---------------------------------------------------------------- hero */
/* Deck p05: status, the question, the cup's line, the swirl, two buttons. */
.hero-copy {
  padding: var(--s2) var(--gut) 0;
}

/* The name, set the way it is on their own cups: caps, lightly tracked. The
   copy stays in its natural case; only the rendering is capital, and Arabic
   is untouched by it. Two words to a line want tighter leading than a
   sentence does. */
.hero-h {
  font-size: var(--t-h1);
  margin-block-start: var(--s5);
  line-height: 1.06;
  text-transform: uppercase;
}

html[lang="en"] .hero-h {
  letter-spacing: 0.02em;
}

.hero-tag {
  margin-block-start: var(--s2);
  font-size: var(--t-lead);
  line-height: var(--lh-snug);
  color: var(--muted);
}

/* The studio shot is multiplied into its own vanilla ground: its white goes,
   its floor shadow stays. */
.hero-stage {
  position: relative;
  aspect-ratio: 390 / 430;
  margin-block-start: var(--s2);
  background: var(--studio);
  isolation: isolate;
  overflow: hidden;
}

html[data-theme="night"] .hero-stage {
  margin-inline: var(--gut);
  border-radius: var(--r-lg);
}

.hero-stage img.poster,
.hero-stage video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 48% 67%;
  mix-blend-mode: multiply;
}

/* "Scroll down, it builds. Scroll up, it sinks." --build (0 to 1) comes from
   the scroll; without script, or with reduced motion, the swirl stays whole. */
.hero-stage img.poster {
  -webkit-mask-image: linear-gradient(to top, transparent 0, #000 9%);
  mask-image: linear-gradient(to top, transparent 0, #000 9%);
}

@media (max-width: 63.99rem) {
  .js .hero-stage img.poster {
    --edge: calc(74% + var(--build, 0) * 34%);
    /* the same scroll that builds the swirl leans the cup in a little */
    transform: scale(calc(1 + var(--build, 0) * 0.035)) translateY(calc(var(--build, 0) * -6px));
    -webkit-mask-image: linear-gradient(to top, transparent 0, #000 9%, #000 var(--edge), transparent calc(var(--edge) + 6%));
    mask-image: linear-gradient(to top, transparent 0, #000 9%, #000 var(--edge), transparent calc(var(--edge) + 6%));
  }
}

@media (prefers-reduced-motion: reduce) {
  .js .hero-stage img.poster {
    -webkit-mask-image: none;
    mask-image: none;
  }
}

.hero-stage video {
  opacity: 0;
  transition: opacity 480ms var(--ease);
}

.hero-stage.film-ready video {
  opacity: 1;
}

.hero-stage.film-ready img.poster {
  opacity: 0;
}

/* side by side while the two labels fit, stacked when they do not: English
   runs longer than Arabic, and at 320px "Directions" was being cut off. The
   order button keeps the larger share of the row wherever both fit. */
.hero-cta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s3);
  padding: var(--s4) var(--gut) 0;
}

.hero-cta .btn {
  flex: 1 1 9.5rem;
}

.hero-cta .b1 {
  flex-grow: 1.35;
}

.hero-cta .btn {
  height: 56px;
}

.hero-cats {
  display: none; /* laptop only: on a phone the circles live with the menu */
}

/* The hero arrives once the loader clears: the words rise in reading order,
   the cup settles, the buttons land last. (Script sets .is-ready; if it never
   runs, everything shows after a moment anyway.) */
@media (prefers-reduced-motion: no-preference) {
  .js .hero-copy > *,
  .js .hero-cta > *,
  .js .hero-stage {
    opacity: 0;
    animation: show-late 0s 3s forwards;
  }

  .js.is-ready .hero-copy > * {
    animation: rise 900ms var(--ease) both;
  }

  /* the question slides up out of its mask, like every title on the page */
  .js.is-ready .hero-copy > .hero-h {
    opacity: 1;
    animation: none;
  }

  .js.is-ready .hero-h .mask > span {
    animation: mask-up 1100ms var(--ease) 80ms both;
  }

  .js.is-ready .hero-copy > :nth-child(3) {
    animation-delay: 180ms;
  }

  .js.is-ready .hero-stage {
    animation: stage-in 1300ms var(--ease) 140ms both;
  }

  .js.is-ready .hero-cta > * {
    animation: land 900ms var(--spring-pop) 420ms both;
  }

  .js.is-ready .hero-cta > :nth-child(2) {
    animation-delay: 500ms;
  }
}

@keyframes mask-up {
  from {
    transform: translateY(108%);
  }
  to {
    transform: none;
  }
}

@keyframes show-late {
  to {
    opacity: 1;
  }
}

@keyframes stage-in {
  from {
    opacity: 0;
    transform: translateY(28px) scale(0.97);
    filter: blur(10px);
  }
  to {
    opacity: 1;
    transform: none;
    filter: none;
  }
}

@keyframes land {
  from {
    opacity: 0;
    transform: translateY(18px) scale(0.94);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* ---------------------------------------------------------------- sections */
.section {
  padding-block-start: var(--section);
}

/* ---------------------------------------------------------------- circles */
/* Deck p06: their Instagram story highlights as the menu's categories. In the
   page they stay where the menu begins; once the menu scrolls, the island
   carries the categories instead, so they never stack on top of each other. */
.cats {
  display: flex;
  gap: var(--s4);
}

.cat {
  display: grid;
  justify-items: center;
  gap: var(--s2);
  width: 68px;
  flex: none;
}

.ring {
  width: 64px;
  height: 64px;
  border-radius: 50%;
  background: var(--bg);
  color: var(--fg);
  display: grid;
  place-items: center;
  box-shadow: 0 0 0 2px var(--bg), 0 0 0 3.5px var(--ring);
  transition:
    box-shadow var(--t-state) var(--ease),
    scale var(--t-press) var(--ease);
}

.cat:active .ring {
  scale: 0.96;
}

.cat[aria-current="true"] .ring {
  box-shadow: 0 0 0 2.5px var(--bg), 0 0 0 5px var(--accent);
}

.ring .ico {
  width: 28px;
  height: 28px;
}

/* a tap: the ring gives and springs back, its icon draws itself */
.cat.drawing .ring {
  animation: ring-pop 640ms var(--spring-pop) both;
}

.cat.drawing .ring .ico path {
  stroke-dasharray: 1;
  animation: draw 1000ms var(--ease-io) 60ms both;
}

@keyframes ring-pop {
  from {
    transform: scale(0.86);
  }
  to {
    transform: scale(1);
  }
}

@keyframes draw {
  from {
    stroke-dashoffset: 1;
  }
  to {
    stroke-dashoffset: 0;
  }
}

.lbl {
  font-size: var(--t-caption);
  font-weight: 500;
  line-height: 1.2;
  white-space: nowrap;
  color: var(--muted);
  transition: color var(--t-state) var(--ease);
}

.cat[aria-current="true"] .lbl {
  color: var(--fg);
}

.cats-bar .cats {
  max-width: var(--page);
  margin-inline: auto;
  padding: var(--s2) var(--gut) var(--s4);
  overflow-x: auto;
  scrollbar-width: none;
  scroll-padding-inline: var(--gut);
}

.cats-bar .cats::-webkit-scrollbar {
  display: none;
}

/* the circles and the island's tabs are one control in two places: as the
   menu reaches the top of the screen the island takes it over, and the
   circles hand it across rather than sitting under it */
.js .cats-bar {
  transition:
    opacity 260ms var(--ease),
    transform 320ms var(--ease);
}

html.isl-tabs .cats-bar {
  opacity: 0;
  transform: translateY(-8px) scale(0.98);
  pointer-events: none;
}

/* ---------------------------------------------------------------- menu */
/* a #cat- link (shared, or without script) lands below the island */
.menu-group {
  scroll-margin-top: 88px;
}

/* a sideways pull belongs to the menu; up and down, and a pinch, stay the
   browser's */
.menu-list {
  touch-action: pan-y pinch-zoom;
}

/* under a finger: nothing eases in between, so the category tracks it 1:1 */
.js .menu-group.is-pull {
  transform: translate3d(var(--pull-x, 0px), 0, 0);
  opacity: calc(1 - var(--pull-p, 0) * 0.26);
  will-change: transform;
}

/* let go: it springs back, or carries the throw on into the handover */
.js .menu-group.is-pull-back {
  transition:
    transform 480ms var(--spring),
    opacity 260ms var(--ease);
}

.grp {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s3);
  margin-block: var(--s6) var(--s4);
}

.grp b {
  font-size: var(--t-title);
  font-weight: 600;
  line-height: var(--lh-snug);
}

.grp span {
  font-size: var(--t-caption);
  font-weight: 400;
  color: var(--muted);
}

/* the other language's name, as a quiet label. Only a Latin one is tracked
   and capitalised: letter-spacing would break the Arabic joins. */
.grp span.en,
.add-h span.en {
  font-size: var(--t-micro);
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

/* The shelf: two cups a row, each standing on its own soft tile. */
.shelf {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--s7) var(--s3);
}

@media (min-width: 48rem) {
  .shelf {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

.card {
  position: relative;
  min-width: 0;
}

.card-open {
  display: grid;
  width: 100%;
  text-align: start;
}

.card-ph {
  position: relative;
  display: grid;
  place-items: center;
  aspect-ratio: 1;
  border-radius: var(--r-md);
  overflow: hidden;
  background: var(--surface);
  isolation: isolate;
  transition: scale var(--t-press) var(--ease);
}

.card-open:active .card-ph {
  scale: 0.96;
}

.card-ph img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  mix-blend-mode: multiply;
}

/* the studio set is cut out and framed alike: whole, with its own shadow */
.card-ph img.cut,
.sheet-photo img.cut {
  object-fit: contain;
  mix-blend-mode: normal;
}

@media (hover: hover) and (pointer: fine) {
  .card-ph img.cut {
    transition: transform 560ms var(--spring);
  }
  .card-open:hover .card-ph img.cut {
    transform: translateY(-4%) scale(1.04);
  }
}

/* no photo yet: the category's line icon on the same tile every other card
   stands on, so the shelf reads as one material and only the icon says the
   photo is still to come */
.thumb-ico {
  width: 40px;
  height: 40px;
  color: color-mix(in srgb, var(--muted) 70%, var(--bg));
  stroke-width: 1.5;
}

.card-tx {
  display: grid;
  gap: 2px;
  margin-block-start: var(--s3);
  padding-inline: 2px;
  min-width: 0;
}

.card-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s2);
}

.card-name {
  min-width: 0;
  font-size: var(--t-body);
  font-weight: 600;
  line-height: var(--lh-snug);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* the price is data, not emphasis: full ink at the real weight of the face
   the digits are set in, rather than a faked bold in a quieter colour */
.card-price {
  flex: none;
  font-size: var(--t-ui);
  font-weight: 400;
  color: var(--fg);
}

.card-sub {
  font-size: var(--t-caption);
  line-height: var(--lh-snug);
  color: var(--muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.card-soldout {
  flex: none;
  font-size: var(--t-caption);
  font-weight: 600;
  color: var(--accent);
}

.card[data-soldout="true"] .card-ph {
  opacity: 0.55;
}

/* The + : a small glass disc in the tile's corner, concentric with it
   (radius 17 + inset 8 = the tile's 24). Its tap target is 44px. */
.add {
  position: absolute;
  inset-block-start: 0;
  inset-inline-end: var(--s2);
  margin-block-start: calc(100% - 42px); /* measured on the card's width = the tile */
  width: 34px;
  height: 34px;
  border-radius: 50%;
  display: none; /* without script the order is the WhatsApp button */
  place-items: center;
  color: var(--accent);
  background: color-mix(in srgb, #ffffff 70%, transparent);
  -webkit-backdrop-filter: blur(12px) saturate(170%);
  backdrop-filter: blur(12px) saturate(170%);
  box-shadow:
    inset 0 1px 1px rgba(255, 255, 255, 0.9),
    0 0 0 0.5px rgba(43, 37, 21, 0.14),
    0 4px 12px -4px rgba(43, 37, 21, 0.35);
  transition:
    scale var(--t-press) var(--ease),
    background-color var(--t-state) var(--ease),
    color var(--t-state) var(--ease);
}

.add::before {
  content: "";
  position: absolute;
  inset: -5px;
  border-radius: 50%;
}

.js .add {
  display: grid;
}

.add:active {
  scale: 0.96;
}

.add .add-plus,
.add .add-n {
  position: absolute;
  transition:
    opacity 220ms var(--ease-icon),
    scale 220ms var(--ease-icon),
    filter 220ms var(--ease-icon);
}

.add .add-plus {
  width: 18px;
  height: 18px;
  stroke-width: 2.2;
}

.add .add-n {
  font-size: var(--t-small);
  font-weight: 700;
  opacity: 0;
  scale: 0.25;
  filter: blur(4px);
}

.add.has {
  background: var(--accent);
  color: var(--on-accent);
}

.add.has .add-n {
  opacity: 1;
  scale: 1;
  filter: none;
}

.add.has .add-plus {
  opacity: 0;
  scale: 0.25;
  filter: blur(4px);
}

.add.is-popping,
.chip.is-popping {
  animation: pop 480ms var(--spring-pop);
}

@keyframes pop {
  from {
    transform: scale(0.8);
  }
  to {
    transform: scale(1);
  }
}

/* toppings and milk choices: chips, each one a line in the order */
.addons {
  margin-block-start: var(--s8);
  padding-block-start: var(--s6);
  border-block-start: 1px solid var(--line);
}

.add-h {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s3);
}

.add-h b {
  font-size: var(--t-title);
  font-weight: 600;
  line-height: var(--lh-snug);
}

.add-h span {
  font-size: var(--t-caption);
  color: var(--muted);
}

.add-grp {
  margin-block-start: var(--s5);
}

.add-t {
  font-size: var(--t-caption);
  font-weight: 600;
  color: var(--muted);
}

.add-grp ul {
  list-style: none;
  margin-block-start: var(--s2);
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2);
}

.chip {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  height: 40px;
  padding-inline: var(--s4);
  border-radius: 20px;
  background: var(--surface);
  box-shadow: inset 0 0 0 1px var(--line);
  font-size: var(--t-small);
  transition:
    background-color var(--t-state) var(--ease),
    box-shadow var(--t-state) var(--ease),
    scale var(--t-press) var(--ease);
}

.chip .num {
  font-size: var(--t-caption);
  font-weight: 600;
  color: var(--muted);
}

.chip:active {
  scale: 0.96;
}

.chip .add-n {
  display: none;
  min-width: 22px;
  height: 22px;
  padding-inline: 6px;
  border-radius: 11px;
  place-items: center;
  background: var(--accent);
  color: var(--on-accent);
  font-size: var(--t-micro);
  font-weight: 700;
}

.chip.has {
  background: color-mix(in srgb, var(--accent) 7%, var(--surface));
  box-shadow: inset 0 0 0 1.5px var(--accent);
}

.chip.has .add-n {
  display: inline-grid;
}

.add-note {
  margin-block-start: var(--s4);
  font-size: var(--t-caption);
  color: var(--muted);
}

html[dir="ltr"] .lnk .ico {
  transform: scaleX(-1);
}

/* ---------------------------------------------------------------- the order */
/* Without script: the deck's one floating button, riding with the menu. */
.basket {
  position: sticky;
  inset-block-end: calc(env(safe-area-inset-bottom, 0px) + var(--s4));
  z-index: 20;
  display: grid;
  width: min(100% - 2 * var(--gut), var(--page) - 2 * var(--gut));
  margin: var(--s6) auto 0;
}

.basket-direct {
  height: 56px;
  border-radius: 28px;
  box-shadow: var(--sh-2);
}

.basket-card {
  display: none;
}

/* With script it floats: the order button while it is empty and the menu is
   on screen, the order itself (everywhere) once something is in it. */
.js .basket {
  position: fixed;
  inset-inline: 12px;
  inset-block-end: calc(env(safe-area-inset-bottom, 0px) + 12px);
  z-index: 40;
  width: auto;
  max-width: 30rem;
  margin: 0 auto;
  opacity: 0;
  transform: translateY(24px) scale(0.96);
  filter: blur(6px);
  pointer-events: none;
  transition:
    opacity 260ms var(--ease),
    transform 620ms var(--spring),
    filter 360ms var(--ease);
}

.js .basket.on {
  opacity: 1;
  transform: none;
  filter: none;
  pointer-events: auto;
}

.js .basket:not([data-state="empty"]) .basket-card {
  display: block;
}

.js .basket:not([data-state="empty"]) .basket-direct {
  display: none;
}

/* nothing ordered yet: a pill the width of its own words, floating clear of
   the cards. Once something is in the order, the espresso capsule takes the
   full width, and the change of size is itself the signal. */
.js .basket[data-state="empty"] {
  justify-items: center;
}

.js .basket[data-state="empty"] .basket-direct {
  height: 52px;
  padding-inline: var(--s6);
  border-radius: 26px;
}

/* a capsule of espresso glass, the same shape as the island */
.basket-card {
  position: relative;
  /* the up-and-down drag on the order is the order's, not the page's;
     without this the browser claims it as a scroll and cancels the pointer
     stream half way through the pull */
  touch-action: pan-x pinch-zoom;
  border-radius: 30px;
  background: color-mix(in srgb, #2b2515 90%, transparent);
  -webkit-backdrop-filter: blur(18px) saturate(160%);
  backdrop-filter: blur(18px) saturate(160%);
  color: var(--cream);
  box-shadow:
    inset 0 1px 1px rgba(255, 255, 255, 0.14),
    0 0 0 0.5px rgba(0, 0, 0, 0.3),
    var(--sh-3);
}

.basket-bar {
  width: 100%;
  height: 60px;
  display: flex;
  align-items: center;
  gap: var(--s3);
  padding-inline: 10px var(--s5);
  color: inherit;
  border-radius: 30px;
}

/* what is in it: the last three cups, overlapping */
.basket-faces {
  display: flex;
  flex: none;
}

.face {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  overflow: hidden;
  display: grid;
  place-items: center;
  background: var(--surface);
  color: var(--muted);
  box-shadow: 0 0 0 2px #2b2515;
  animation: face-in 520ms var(--spring-pop) both;
}

.face + .face {
  margin-inline-start: -14px;
}

.face img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  scale: 1.28; /* the studio frame has air around the cup; fill the disc */
}

.face .ico {
  width: 18px;
  height: 18px;
}

@keyframes face-in {
  from {
    transform: scale(0.4);
    opacity: 0;
    filter: blur(4px);
  }
  to {
    transform: none;
    opacity: 1;
    filter: none;
  }
}

.basket-label {
  flex: 1;
  min-width: 0;
  display: grid;
  text-align: start;
  line-height: 1.25;
}

.basket-label b {
  font-size: var(--t-body);
  font-weight: 600;
}

.basket-count {
  font-size: var(--t-caption);
  color: var(--cream-muted);
}

.basket-sum {
  font-size: var(--t-body);
  font-weight: 600;
}

.basket-sum.is-kicking,
.basket-faces.is-kicking {
  animation: kick 560ms var(--spring-pop);
}

@keyframes kick {
  from {
    transform: scale(1.18);
  }
  to {
    transform: scale(1);
  }
}

.basket-chev {
  width: 20px;
  height: 20px;
  opacity: 0.8;
  transform: rotate(90deg);
  transition: transform 460ms var(--spring);
}

.basket[data-state="open"] .basket-chev {
  transform: rotate(-90deg);
}

/* the list grows out of the bar, from its bottom edge; solid, not glass */
.basket-body {
  position: absolute;
  inset-inline: 0;
  inset-block-end: calc(100% + var(--s3));
  max-height: min(70vh, 36rem);
  display: flex;
  flex-direction: column;
  padding: var(--s5) var(--s4) var(--s4);
  border-radius: var(--r-lg);
  background: var(--bg);
  color: var(--fg);
  box-shadow: 0 0 0 1px var(--line), var(--sh-3);
  transform-origin: 50% 100%;
  opacity: 0;
  transform: translateY(14px) scale(0.95);
  filter: blur(4px);
  visibility: hidden;
  pointer-events: none;
  transition:
    opacity 180ms var(--ease),
    transform 320ms var(--ease),
    filter 240ms var(--ease),
    visibility 0s 320ms;
}

/* under a finger the panel is present and follows it: no transition in the
   way, and the travel drives how open it looks. Pulling it open lifts it out
   of the bar; pushing it closed takes it back down with the thumb. */
.basket.is-pulling .basket-body {
  visibility: visible;
  pointer-events: none;
  transition: none;
}

/* it becomes solid in the first half of the pull, so the order is never a
   sheet of glass with the menu reading through it */
.basket.is-pulling[data-pull="open"] .basket-body {
  opacity: min(1, calc(var(--pull-p, 0) * 2.4));
  filter: blur(calc((1 - var(--pull-p, 0)) * 3px));
  transform: translateY(calc((1 - var(--pull-p, 0)) * 24px)) scale(calc(0.95 + var(--pull-p, 0) * 0.05));
}

.basket.is-pulling[data-pull="close"] .basket-body {
  opacity: calc(1 - var(--pull-p, 0) * 0.85);
  filter: blur(calc(var(--pull-p, 0) * 3px));
  transform: translateY(var(--pull, 0px)) scale(calc(1 - var(--pull-p, 0) * 0.04));
}

/* the capsule itself leans with the pull, so the two read as one piece */
.basket.is-pulling .basket-card {
  transform: translateY(calc(var(--pull, 0px) * 0.06));
}

.basket[data-state="open"] .basket-body {
  opacity: 1;
  transform: none;
  filter: none;
  visibility: visible;
  pointer-events: auto;
  transition:
    opacity 220ms var(--ease),
    transform 560ms var(--spring),
    filter 260ms var(--ease),
    visibility 0s;
}

.basket-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s3);
  padding-inline: var(--s1);
  margin-block-end: var(--s3);
}

.basket-head b {
  font-size: var(--t-title);
  line-height: var(--lh-snug);
}

.basket-head span {
  font-size: var(--t-caption);
  color: var(--muted);
}

/* only the list scrolls; the note, the total and the send button stay put */
.basket-list {
  touch-action: pan-y; /* the list keeps its own scroll */
  list-style: none;
  display: grid;
  align-content: start;
  gap: var(--s1);
  flex: 0 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  margin-inline: calc(var(--s1) * -1);
  padding-inline: var(--s1);
  /* the fade is on whichever edge has more list behind it, and on neither
     when the whole order fits (a fade there reads as a rendering fault) */
  --fade-t: 0px;
  --fade-b: 0px;
  -webkit-mask-image: linear-gradient(
    to bottom,
    transparent 0,
    #000 var(--fade-t),
    #000 calc(100% - var(--fade-b)),
    transparent 100%
  );
  mask-image: linear-gradient(
    to bottom,
    transparent 0,
    #000 var(--fade-t),
    #000 calc(100% - var(--fade-b)),
    transparent 100%
  );
}

.basket-list.can-scroll {
  --fade-b: 20px;
}

.basket-list.can-scroll:not(.at-top) {
  --fade-t: 20px;
}

.basket-list.can-scroll.at-end {
  --fade-b: 0px;
}

.basket-head,
.basket-field,
.basket-total,
.basket-note,
.basket-send {
  flex: none;
}

.basket-row {
  display: grid;
  grid-template-columns: 52px minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--s3);
  padding: var(--s1);
}

.basket.is-opening .basket-row {
  animation: rise 520ms var(--ease) both;
  animation-delay: calc(min(var(--i), 6) * 45ms + 80ms);
}

.basket-row .ph {
  width: 52px;
  height: 52px;
  border-radius: 14px;
  display: grid;
  place-items: center;
  overflow: hidden;
  background: var(--surface);
  color: var(--muted);
}

.basket-row .ph img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  scale: 1.15;
}

.basket-row .ph .ico {
  width: 20px;
  height: 20px;
}

/* the name over its price, both starting at the same edge: the price sets its
   own direction for the numerals, so the grid places it, not text-align */
.basket-row .tx {
  display: grid;
  justify-items: start;
  gap: 2px;
}

.basket-row .nm {
  font-size: var(--t-ui);
  font-weight: 600;
  line-height: var(--lh-snug);
}

.basket-row .pr {
  font-size: var(--t-caption);
  color: var(--muted);
}

/* a line's own add-ons: listed under its name, chosen right under the row */
.basket-row .ad {
  font-size: var(--t-caption);
  line-height: var(--lh-snug);
  color: var(--fg);
}

.bk-add {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  min-height: 32px;
  margin-block-start: 2px;
  padding-inline: 8px 12px;
  border-radius: 999px;
  box-shadow: inset 0 0 0 1.2px var(--line-strong);
  font-size: var(--t-caption);
  font-weight: 600;
  transition-property: background-color, color, box-shadow;
  transition-duration: var(--t-state);
  transition-timing-function: ease-out;
}

.bk-add .ico {
  width: 14px;
  height: 14px;
}

.bk-add.on {
  background: var(--fg);
  color: var(--bg);
  box-shadow: none;
}

.bk-add:active,
.basket-adds button:active {
  scale: 0.96;
}

.basket-adds {
  display: grid;
  gap: var(--s2);
  margin: 2px var(--s1) var(--s3);
  padding: var(--s3);
  border-radius: 18px;
  background: var(--surface);
  box-shadow: inset 0 0 0 1px var(--line);
  animation: rise 360ms var(--ease) both;
}

.basket-adds h4 {
  font-size: var(--t-ui);
  font-weight: 600;
}

.basket-adds .ga {
  margin-block-start: var(--s1);
  font-size: var(--t-caption);
  color: var(--muted);
}

.basket-adds .chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.basket-adds .chips button {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 38px;
  padding-inline: 12px;
  border-radius: 999px;
  background: var(--bg);
  box-shadow: inset 0 0 0 1px var(--line-strong);
  font-size: var(--t-small);
  transition-property: background-color, color, box-shadow;
  transition-duration: var(--t-state);
  transition-timing-function: ease-out;
}

.basket-adds .chips button[aria-pressed="true"] {
  background: var(--accent);
  color: var(--on-accent);
  box-shadow: none;
}

.basket-adds .chips small {
  font-size: var(--t-caption);
  opacity: 0.8;
}

.basket-adds .done {
  justify-self: end;
  min-height: 40px;
  margin-block-start: var(--s1);
  padding-inline: var(--s5);
  border-radius: 12px;
  background: var(--fg);
  color: var(--bg);
  font-size: var(--t-ui);
  font-weight: 600;
}

@media (prefers-reduced-motion: reduce) {
  .basket-adds {
    animation: none;
  }
}

.qty {
  display: flex;
  align-items: center;
  gap: 2px;
  padding: 3px;
  border-radius: 20px;
  background: var(--surface);
  box-shadow: inset 0 0 0 1px var(--line);
}

.qty button {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  transition: scale var(--t-press) var(--ease), background-color var(--t-state) var(--ease);
}

.qty button:active {
  scale: 0.96;
  background: var(--bg);
}

.qty .ico {
  width: 16px;
  height: 16px;
}

.qty output {
  min-width: 20px;
  text-align: center;
  font-size: var(--t-small);
  font-weight: 700;
}

/* a line for the shop: "no ice", a pickup time */
.basket-field {
  display: grid;
  gap: var(--s1);
  margin-block-start: var(--s4);
  padding-inline: var(--s1);
}

.basket-field span {
  font-size: var(--t-caption);
  font-weight: 600;
  color: var(--muted);
}

.basket-field input {
  height: 48px;
  padding-inline: var(--s4);
  border: 0;
  border-radius: var(--r-sm);
  background: var(--surface);
  box-shadow: inset 0 0 0 1px var(--line);
  font-size: var(--t-body); /* 16px: iOS does not zoom the page */
  transition: box-shadow var(--t-state) var(--ease);
}

.basket-field input::placeholder {
  color: color-mix(in srgb, var(--muted) 75%, transparent);
}

.basket-field input:focus {
  outline: none;
  box-shadow: inset 0 0 0 1.5px var(--fg);
}

.basket-total {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin-block-start: var(--s4);
  padding: var(--s4) var(--s1) var(--s3);
  border-block-start: 1px solid var(--line);
  font-weight: 600;
}

.basket-total b {
  font-size: var(--t-h3);
  font-weight: 400;
  line-height: var(--lh-tight);
}

.basket-note {
  padding: 0 var(--s1) var(--s3);
  font-size: var(--t-caption);
  color: var(--muted);
}

.basket-send {
  width: 100%;
  height: 56px;
  border-radius: 28px;
}

/* the cup on its way into the order (physical coordinates: measured on screen) */
.flyer {
  position: fixed;
  z-index: 70;
  top: 0;
  left: 0;
  pointer-events: none;
  will-change: transform;
}

.flyer img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  will-change: transform, opacity;
}

/* ---------------------------------------------------------------- almond */
/* Deck p07: their photo, their caption word for word, then what customers said. */
.al-photo {
  border-radius: var(--r-lg);
  overflow: hidden;
  background: var(--surface);
}

.al-photo img {
  width: 100%;
  height: auto;
  aspect-ratio: 7 / 6;
  object-fit: cover;
}

.al-photo img.cut {
  object-fit: contain;
  padding-block: var(--s4) var(--s1);
}

.al-h {
  font-size: var(--t-h2);
  margin-block-start: var(--s6);
}

.al-q {
  margin-block-start: var(--s3);
  padding-inline-end: var(--s8);
}

.al-q p {
  font-size: var(--t-lead);
  font-weight: 500;
  line-height: var(--lh-body);
  text-wrap: pretty; /* the closing guillemet never lands alone on a line */
}

.al-q small {
  display: block;
  margin-block-start: var(--s1);
  font-size: var(--t-caption);
  color: var(--muted);
}

.rvh {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s3);
  margin-block-start: var(--s7);
}

.rvh h3 {
  font-size: var(--t-title);
  font-weight: 600;
}

.rate-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 32px;
  padding-inline: var(--s3);
  border-radius: 16px;
  background: var(--surface);
  box-shadow: inset 0 0 0 1px var(--line);
  font-size: var(--t-caption);
  font-weight: 600;
}

.rate-pill .ico,
.rate .ico {
  width: 15px;
  height: 15px;
  fill: var(--star);
  stroke: none;
}

.rvs {
  display: flex;
  gap: var(--s3);
  margin-block-start: var(--s3);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
}

.rv {
  flex: 0 0 min(268px, 80%);
  scroll-snap-align: start;
  padding: var(--s4);
  border-radius: var(--r-md);
  background: var(--surface);
  box-shadow: inset 0 0 0 1px var(--line);
  font-size: var(--t-ui);
}

.rv figcaption {
  margin-block-start: var(--s2);
  font-size: var(--t-caption);
  color: var(--muted);
}

/* ---------------------------------------------------------------- new + collabs */
/* Deck p08: their posters as they made them, one at a time; the one in the
   middle of the strip is in focus, its neighbours step back. */
.car {
  display: flex;
  gap: var(--s3);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-padding-inline: var(--gut);
  padding: var(--s1) var(--gut) var(--s2);
  scrollbar-width: none;
}

.car::-webkit-scrollbar {
  display: none;
}

/* button.poster: the hero's photo also carries the class "poster" */
button.poster {
  flex: 0 0 min(300px, 76vw);
  aspect-ratio: 290 / 362;
  border-radius: var(--r-md);
  overflow: hidden;
  scroll-snap-align: start;
  background: var(--surface);
  outline: 1px solid rgba(0, 0, 0, 0.08);
  outline-offset: -1px;
  transition: scale var(--t-press) var(--ease);
}

button.poster:active,
.collab:active {
  scale: 0.96;
}

button.poster img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    button.poster img {
      animation: in-focus linear both;
      animation-timeline: view(inline);
      animation-range: cover 0% cover 100%;
    }
  }
}

@keyframes in-focus {
  0% {
    scale: 1.12;
    opacity: 0.55;
  }
  40%,
  60% {
    scale: 1;
    opacity: 1;
  }
  100% {
    scale: 1.12;
    opacity: 0.55;
  }
}

.dots {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 6px;
  height: 32px;
}

.dots i {
  width: 7px;
  height: 7px;
  border-radius: 4px;
  background: var(--line-strong);
  transition: background-color var(--t-state) var(--ease);
}

.dots i.on {
  width: 22px;
  background: var(--accent);
}

.collabs {
  display: grid;
  gap: var(--s3);
  margin-block-start: var(--s3);
}

.collab {
  position: relative;
  display: block;
  width: 100%;
  height: 220px;
  border-radius: var(--r-md);
  overflow: hidden;
  background: var(--surface);
  transition: scale var(--t-press) var(--ease);
}

.collab img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 62%;
}

.collab .ov {
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgba(20, 16, 10, 0.84), rgba(20, 16, 10, 0) 64%);
}

.collab .ct {
  position: absolute;
  inset-inline: var(--s5);
  inset-block-end: var(--s4);
  color: #fcf2d3;
  direction: ltr;
  text-align: left;
  display: grid;
  gap: 2px;
}

.collab .ct b {
  font-size: var(--t-title);
  font-weight: 400;
  line-height: var(--lh-tight);
  letter-spacing: -0.01em;
}

.collab .ct span {
  font-size: var(--t-ui);
  opacity: 0.88;
}

/* ---------------------------------------------------------------- boxes */
.bx-photo {
  border-radius: var(--r-md);
  overflow: hidden;
  background: var(--surface);
}

.bx-photo img {
  width: 100%;
  height: auto;
  aspect-ratio: 35 / 29;
  object-fit: cover;
  object-position: 50% 66%;
}

.form {
  display: grid;
  gap: var(--s3);
  margin-block-start: var(--s4);
}

.fld {
  min-height: 56px;
  padding-inline: var(--s4);
  border-radius: var(--r-btn);
  background: var(--surface);
  box-shadow: inset 0 0 0 1px var(--line);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s3);
  font-size: var(--t-body);
}

.fld > b {
  font-weight: 600;
  flex: none;
}

.fld input,
.fld select {
  flex: 1;
  min-width: 0;
  font-size: var(--t-body);
  background: none;
  border: 0;
  text-align: end;
}

.fld input::placeholder {
  color: var(--muted);
}

.step {
  display: flex;
  align-items: center;
  gap: var(--s3);
}

.step button {
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
}

.step button .ico {
  width: 32px;
  height: 32px;
  padding: 7px;
  border-radius: 50%;
  box-shadow: inset 0 0 0 1.5px var(--fg);
}

.step output {
  min-width: 2ch;
  text-align: center;
  font-size: var(--t-lead);
  font-weight: 600;
}

.note {
  font-size: var(--t-small);
  color: var(--muted);
}

/* ---------------------------------------------------------------- moments: the espresso band */
/* One dark peak in the scroll. Tokens are scoped, so everything inside reads
   its colours from the band. */
#moments {
  --fg: var(--cream);
  --muted: var(--cream-muted);
  --line: rgba(246, 236, 207, 0.14);
  --line-strong: rgba(246, 236, 207, 0.24);
  --surface: #352b1f;
  margin-block-start: var(--section);
  padding-block: var(--s10) var(--s9);
  border-radius: var(--r-xl);
  background: var(--ink);
  color: var(--fg);
}

#moments .b2 {
  color: var(--fg);
}

/* reels: their own short videos, tall, silent, looping only while seen */
.reels {
  display: flex;
  gap: var(--s3);
  margin-inline: calc(var(--gut) * -1);
  padding: var(--s1) var(--gut) var(--s6);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-padding-inline: var(--gut);
  scrollbar-width: none;
  overscroll-behavior-x: contain;
}

.reels::-webkit-scrollbar {
  display: none;
}

.reel {
  position: relative;
  flex: 0 0 min(46vw, 13rem);
  aspect-ratio: 9 / 16;
  border-radius: var(--r-md);
  overflow: hidden;
  scroll-snap-align: start;
  background: var(--surface);
  outline: 1px solid rgba(255, 255, 255, 0.1);
  outline-offset: -1px;
}

.reel-v {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* the pause control every playing video needs: a glass disc */
.reel-toggle {
  position: absolute;
  inset-block-start: var(--s2);
  inset-inline-end: var(--s2);
  width: 36px;
  height: 36px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  color: #fff;
  background: rgba(20, 16, 10, 0.3);
  -webkit-backdrop-filter: blur(12px) saturate(160%);
  backdrop-filter: blur(12px) saturate(160%);
  box-shadow: inset 0 1px 1px rgba(255, 255, 255, 0.28), 0 0 0 0.5px rgba(255, 255, 255, 0.18);
  transition: scale var(--t-press) var(--ease);
}

.reel-toggle::before {
  content: "";
  position: absolute;
  inset: -4px;
  border-radius: 50%;
}

.reel-toggle:active {
  scale: 0.96;
}

.reel-toggle .ico {
  position: absolute;
  width: 16px;
  height: 16px;
  fill: currentColor;
  stroke: none;
  transition:
    opacity 220ms var(--ease-icon),
    scale 220ms var(--ease-icon),
    filter 220ms var(--ease-icon);
}

.reel-toggle .i-pause,
.is-playing > .reel-toggle .i-play {
  opacity: 0;
  scale: 0.25;
  filter: blur(4px);
}

.is-playing > .reel-toggle .i-pause {
  opacity: 1;
  scale: 1;
  filter: none;
}

html:not(.js) .reel-toggle {
  display: none;
}

/* the reels that show a menu item end in it */
.reel-chip {
  position: absolute;
  inset-inline: var(--s2);
  inset-block-end: var(--s2);
  height: 44px;
  padding-inline: var(--s3) 6px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s2);
  border-radius: 22px;
  color: var(--ink);
  background: color-mix(in srgb, #fcf2d3 80%, transparent);
  -webkit-backdrop-filter: blur(16px) saturate(170%);
  backdrop-filter: blur(16px) saturate(170%);
  box-shadow: inset 0 1px 1px rgba(255, 255, 255, 0.8), 0 8px 20px -10px rgba(0, 0, 0, 0.6);
  font-size: var(--t-small);
  font-weight: 600;
  transition: scale var(--t-press) var(--ease);
}

.reel-chip:active {
  scale: 0.96;
}

.reel-chip span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.reel-chip .ico {
  width: 32px;
  height: 32px;
  padding: 7px;
  border-radius: 50%;
  flex: none;
  background: var(--accent);
  color: var(--on-accent);
  stroke-width: 2.2;
}

/* the photo mosaic: two columns, the second set lower */
.mas {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--s3);
  align-items: start;
}

.moment {
  display: block;
  width: 100%;
  border-radius: var(--r-md);
  overflow: hidden;
  background: var(--surface);
  outline: 1px solid rgba(255, 255, 255, 0.1);
  outline-offset: -1px;
  transition: scale var(--t-press) var(--ease);
}

.moment:active {
  scale: 0.96;
}

.moment img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.moment:nth-child(4n + 1) {
  aspect-ratio: 170 / 300;
}
.moment:nth-child(4n + 2) {
  aspect-ratio: 170 / 250;
  margin-block-start: var(--s8);
}
.moment:nth-child(4n + 3) {
  aspect-ratio: 170 / 220;
}
.moment:nth-child(4n + 4) {
  aspect-ratio: 170 / 240;
  margin-block-start: calc(var(--s3) * -1);
}

/* ---------------------------------------------------------------- lightbox */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 70;
  background: #0f0c07;
  color: var(--cream);
  display: grid;
  grid-template-rows: 1fr auto;
  opacity: 0;
  visibility: hidden;
  transition: opacity 260ms var(--ease), visibility 0s 260ms;
}

.lightbox.is-open {
  opacity: 1;
  visibility: visible;
  transition: opacity 260ms var(--ease), visibility 0s;
}

.lightbox img {
  width: 100%;
  height: 100%;
  min-height: 0;
  object-fit: contain;
}

/* the photo under a finger: sideways to the next one, down to put it away.
   The gesture is the lightbox's, so the browser is told to keep only the
   pinch. Nothing eases while the finger is down; the release springs. */
.lightbox {
  touch-action: pinch-zoom;
}

.lightbox img,
.lightbox .lightbox-cap {
  transform: translate3d(var(--slide, 0px), var(--lift, 0px), 0);
  transition: transform 420ms var(--spring);
}

.lightbox.is-dragging img,
.lightbox.is-dragging .lightbox-cap {
  transition: none;
}

.lightbox.is-dragging {
  background: color-mix(in srgb, #0f0c07 calc(var(--dim, 1) * 100%), transparent);
}

.lightbox-cap {
  padding: var(--s5) var(--s6) calc(env(safe-area-inset-bottom, 0px) + var(--s6));
  display: grid;
  gap: var(--s2);
}

.lightbox-cap p {
  font-size: var(--t-title);
  font-weight: 600;
  line-height: var(--lh-snug);
}

.lightbox-cap p:empty {
  display: none;
}

#lightbox-meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s1) var(--s3);
  font-size: var(--t-small);
  color: var(--cream-muted);
}

.lightbox-close {
  position: absolute;
  z-index: 2;
  inset-block-start: calc(env(safe-area-inset-top, 0px) + var(--s4));
  inset-inline-end: var(--gut);
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: rgba(246, 236, 207, 0.14);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  display: grid;
  place-items: center;
  transition: scale var(--t-press) var(--ease);
}

/* A finger swipes and a keyboard has its arrows; a mouse had neither, so on
   a pointer device the two steps are spelled out at the edges. */
.lightbox-step {
  position: absolute;
  z-index: 2;
  inset-block-start: 50%;
  width: 48px;
  height: 48px;
  margin-block-start: -24px;
  border-radius: 50%;
  display: none;
  place-items: center;
  background: rgba(246, 236, 207, 0.14);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  transition: scale var(--t-press) var(--ease), opacity var(--t-state) var(--ease);
}

.lightbox-step:active {
  scale: 0.96;
}

.lb-prev {
  inset-inline-start: var(--s3);
}

.lb-next {
  inset-inline-end: var(--s3);
}

/* Each chevron points the way it travels. The icon is drawn pointing left,
   so in Arabic "next" (on the left) keeps it and "previous" (on the right)
   turns; in English it is the other way round. */
.lb-prev .ico {
  rotate: 180deg;
}

html[dir="ltr"] .lb-prev .ico {
  rotate: 0deg;
}

html[dir="ltr"] .lb-next .ico {
  rotate: 180deg;
}

@media (hover: hover) {
  .lightbox-step {
    display: grid;
  }
}

.lightbox-close:active {
  scale: 0.96;
}

.lightbox-close .ico {
  width: 20px;
  height: 20px;
}

/* ---------------------------------------------------------------- visit */
/* Deck p11: the storefront edge to edge, fading into the page; the heading
   sits in the fade. */
.visit {
  padding-block-start: var(--section);
}

.v-photo {
  position: relative;
  height: min(400px, 100vw);
  overflow: hidden;
}

.v-photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 30%;
}

/* the fade reaches 2px past the photo's edge, so no sub-pixel row of the
   picture shows below it */
.v-photo .grad {
  position: absolute;
  inset: 0 0 -2px;
  background: linear-gradient(to top, var(--bg) 7%, color-mix(in srgb, var(--bg) 0%, transparent) 58%);
}

.v-body {
  position: relative;
  margin-block-start: calc(var(--s10) * -1);
}

.v-h {
  font-size: var(--t-h2);
}

.v-body .live {
  margin-block-start: var(--s3);
}

.addr {
  display: grid;
  gap: var(--s2);
  margin-block-start: var(--s5);
}

.addr p {
  display: flex;
  align-items: center;
  gap: var(--s3);
  min-height: 32px;
  font-size: var(--t-body);
}

.addr .ico {
  width: 22px;
  height: 22px;
  color: var(--muted);
}

.acts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(6.5rem, 1fr));
  gap: var(--s2);
  margin-block-start: var(--s5);
}

.acts .btn {
  height: 52px;
  padding-inline: var(--s2);
  gap: 6px;
  font-size: var(--t-ui);
}

.acts .btn .ico {
  width: 19px;
  height: 19px;
}

.hours {
  margin-block-start: var(--s4);
  border-radius: var(--r-btn);
  background: var(--surface);
  box-shadow: inset 0 0 0 1px var(--line);
  overflow: hidden;
}

.hours div {
  display: flex;
  justify-content: space-between;
  gap: var(--s3);
  padding: var(--s3) var(--s4);
  font-size: var(--t-ui);
}

.hours div + div {
  border-block-start: 1px solid var(--line);
}

.hours div[data-today="true"] {
  font-weight: 600;
}

.rate {
  margin-block-start: var(--s4);
  min-height: 60px;
  padding-inline: var(--s4);
  border-radius: var(--r-btn);
  background: var(--surface);
  box-shadow: inset 0 0 0 1px var(--line);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s3);
}

.rate b {
  display: flex;
  align-items: center;
  gap: var(--s2);
  font-size: var(--t-body);
  font-weight: 600;
}

.rate .ico {
  width: 18px;
  height: 18px;
}

.rate a {
  min-height: 44px;
  display: grid;
  place-items: center;
  color: var(--accent);
  font-size: var(--t-ui);
  font-weight: 600;
}

/* ---------------------------------------------------------------- cta + footer */
.cta {
  margin-block-start: var(--section);
  padding: var(--s7) var(--s6) var(--s6);
  border-radius: var(--r-lg);
  background: var(--surface);
  box-shadow: inset 0 0 0 1px var(--line);
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: var(--s6);
}

.cta h2 {
  font-size: clamp(2.25rem, 10vw, 2.75rem);
}

.cta .btn {
  width: 100%;
  height: 56px;
}

.footer {
  margin-block-start: var(--section);
  background: var(--ink);
  color: var(--cream);
  border-radius: var(--r-xl) var(--r-xl) 0 0;
  padding: var(--s8) var(--s6) calc(env(safe-area-inset-bottom, 0px) + var(--s8));
}

.footer-in {
  max-width: var(--page);
  margin-inline: auto;
}

.f-brand {
  display: flex;
  align-items: center;
  gap: var(--s4);
}

.f-brand img {
  width: 60px;
  height: 60px;
  border-radius: 50%;
}

.f-brand b {
  display: block;
  font-weight: 400;
  font-size: var(--t-h3);
  line-height: var(--lh-tight);
}

.f-brand span {
  font-size: var(--t-caption);
  color: var(--cream-muted);
}

.f-links {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0 var(--s4);
  margin-block-start: var(--s6);
  font-size: var(--t-body);
  font-weight: 500;
}

.f-links a {
  min-height: 48px;
  display: flex;
  align-items: center;
}

.f-soc {
  display: grid;
  margin-block-start: var(--s5);
  padding-block-start: var(--s5);
  border-block-start: 1px solid rgba(246, 236, 207, 0.16);
}

.f-soc a {
  min-height: 48px;
  display: flex;
  align-items: center;
  gap: var(--s3);
  font-size: var(--t-ui);
  font-weight: 500;
}

.f-soc .ico {
  width: 22px;
  height: 22px;
  color: var(--cream-muted);
}

.f-bot {
  display: flex;
  justify-content: space-between;
  gap: var(--s3);
  margin-block-start: var(--s7);
  font-size: var(--t-micro);
  color: var(--cream-muted);
  direction: ltr;
}

/* ---------------------------------------------------------------- item sheet */
/* Deck p06: photo, name + share, the other language, the way to what
   customers said, then the order. Dragged with the finger, springs back or
   closes; the backdrop follows. */
.sheet-scrim {
  position: fixed;
  inset: 0;
  z-index: 60;
  background: rgba(12, 9, 5, 0.55); /* dim to focus; no blur: it follows the finger every frame */
  opacity: 0;
  pointer-events: none;
}

.sheet-scrim.is-open {
  pointer-events: auto;
}

.sheet {
  position: fixed;
  z-index: 61;
  inset-inline: 0;
  inset-block-end: 0;
  margin-inline: auto;
  width: 100%;
  max-width: 32rem;
  max-height: 92svh;
  background: var(--bg);
  border-radius: var(--r-xl) var(--r-xl) 0 0;
  padding: 0 var(--gut) calc(env(safe-area-inset-bottom, 0px) + var(--s5));
  display: flex;
  flex-direction: column;
  transform: translateY(100%);
  visibility: hidden;
  touch-action: none;
  will-change: transform;
  box-shadow: 0 -24px 60px -24px rgba(0, 0, 0, 0.4);
}

.sheet.is-open {
  visibility: visible;
}

.grab {
  flex: none;
  align-self: center;
  width: 96px;
  height: 28px;
  display: grid;
  place-items: center;
  cursor: grab;
}

.grab span {
  width: 40px;
  height: 5px;
  border-radius: 3px;
  background: var(--line-strong);
}

.sheet-photo {
  position: relative;
  flex: none;
  aspect-ratio: 35 / 29;
  border-radius: var(--r-md);
  overflow: hidden;
  background: var(--studio);
  isolation: isolate;
}

.sheet-photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  mix-blend-mode: multiply;
}

.sheet-photo video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.sheet-body {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  display: flex;
  flex-direction: column;
}

.sh-name {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--s3);
  margin-block-start: var(--s5);
}

.sh-name h3 {
  font-size: clamp(2rem, 9.4vw, 2.5rem);
}

.share {
  width: 44px;
  height: 44px;
  margin-block-start: 2px;
  display: grid;
  place-items: center;
  flex: none;
  border-radius: 50%;
  background: var(--surface);
  box-shadow: inset 0 0 0 1px var(--line);
  color: var(--muted);
  transition:
    scale var(--t-press) var(--ease),
    color var(--t-state) var(--ease);
}

.share:active {
  scale: 0.96;
}

.share .ico {
  width: 20px;
  height: 20px;
}

.en-n {
  margin-block-start: var(--s1);
  font-size: var(--t-lead);
  color: var(--muted);
}

.en-n:empty {
  display: none;
}

.lnk {
  display: inline-flex;
  align-items: center;
  gap: var(--s1);
  align-self: start;
  min-height: 44px;
  margin-block-start: var(--s1);
  color: var(--accent);
  font-size: var(--t-ui);
  font-weight: 600;
}

.lnk .ico {
  width: 18px;
  height: 18px;
}

.price {
  margin-block-start: auto;
  padding-block-start: var(--s5);
  align-self: start;
  font-size: var(--t-title);
  font-weight: 600;
}

.price:empty {
  display: none;
}

#sheet-cta {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--s3);
  margin-block-start: var(--s4);
}

#sheet-cta .btn {
  height: 56px;
}

#sheet-cta .b1:only-child {
  grid-column: 1 / -1;
}

.sheet-wa {
  width: 56px;
  padding: 0;
}

/* opening: the cup drops onto its tile, the words follow it in */
.sheet.is-open .sheet-photo img {
  animation: sheet-cup 780ms var(--spring-pop) 80ms both;
}

.sheet.is-open .sheet-body > * {
  animation: rise 600ms var(--ease) both;
}

.sheet.is-open .sheet-body > :nth-child(1) { animation-delay: 140ms; }
.sheet.is-open .sheet-body > :nth-child(2) { animation-delay: 190ms; }
.sheet.is-open .sheet-body > :nth-child(3) { animation-delay: 230ms; }
.sheet.is-open .sheet-body > :nth-child(4) { animation-delay: 260ms; }
.sheet.is-open .sheet-body > :nth-child(5) { animation-delay: 290ms; }

@keyframes sheet-cup {
  from {
    opacity: 0;
    transform: translateY(-10%) scale(0.88);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* ---------------------------------------------------------------- toast */
/* It rises clear of whatever action is at the bottom of the screen: the only
   thing that raises a toast is the share button inside the item sheet, and
   covering that sheet's own "add to order" button is the one place it must
   not land. */
.toast {
  position: fixed;
  z-index: 80;
  inset-inline: 0;
  inset-block-end: calc(env(safe-area-inset-bottom, 0px) + 104px);
  width: max-content;
  max-width: calc(100% - 2 * var(--gut));
  margin-inline: auto;
  padding: var(--s3) var(--s5);
  border-radius: 999px;
  background: var(--fg);
  color: var(--bg);
  font-size: var(--t-ui);
  font-weight: 600;
  box-shadow: var(--sh-2);
  opacity: 0;
  transform: translateY(10px) scale(0.96);
  pointer-events: none;
  transition: opacity 200ms var(--ease), transform 420ms var(--spring);
}

.toast.on {
  opacity: 1;
  transform: none;
}

/* ---------------------------------------------------------------- reveals */
/* Things arrive as they scroll in. Script adds .is-in; without it, or with
   reduced motion, nothing is ever hidden.
   - default: rises into focus
   - head: the title's words slide up out of a mask, the line follows
   - photo: opens from its bottom edge while the picture settles
   - slide / slide-start: in from the side the row continues to / starts on
   - pop: small things, with a little give
   - cards: the two columns come in from opposite sides, then the cup lands */
.js [data-reveal] {
  opacity: 0;
  transform: translateY(24px);
  filter: blur(8px);
  transition:
    opacity 700ms var(--ease) var(--d, 0ms),
    transform var(--t-enter) var(--ease) var(--d, 0ms),
    filter 700ms var(--ease) var(--d, 0ms);
}

.js [data-reveal].is-in {
  opacity: 1;
  transform: none;
  filter: none;
}

.js [data-reveal="head"] {
  opacity: 1;
  transform: none;
  filter: none;
}

.js [data-reveal="head"] .mask > span {
  transform: translateY(108%);
  transition: transform 1000ms var(--ease);
}

.js [data-reveal="head"] > :not(h2) {
  opacity: 0;
  transform: translateY(12px);
  filter: blur(6px);
  transition:
    opacity 700ms var(--ease) 180ms,
    transform 800ms var(--ease) 180ms,
    filter 700ms var(--ease) 180ms;
}

.js [data-reveal="head"].is-in .mask > span,
.js [data-reveal="head"].is-in > :not(h2) {
  opacity: 1;
  transform: none;
  filter: none;
}

.js [data-reveal="photo"] {
  opacity: 1;
  transform: none;
  filter: none;
  clip-path: inset(18% 0 0 0);
  transition: clip-path 1100ms var(--ease-io) var(--d, 0ms);
}

.js [data-reveal="photo"].is-in {
  clip-path: inset(0);
}

.js [data-reveal="photo"] img {
  transform: scale(1.14);
  transition: transform 1600ms var(--ease) var(--d, 0ms);
}

.js [data-reveal="photo"].is-in img {
  transform: none;
}

.js [data-reveal="slide"] {
  transform: translateX(calc(var(--flow) * 64px));
}

.js [data-reveal="slide-start"] {
  transform: translateX(calc(var(--flow) * -48px));
}

.js [data-reveal="pop"] {
  transform: translateY(24px) scale(0.9);
  transition:
    opacity 520ms var(--ease) var(--d, 0ms),
    transform 800ms var(--spring-pop) var(--d, 0ms),
    filter 520ms var(--ease) var(--d, 0ms);
}

/* the menu's cards: odd ones from the reading start, even ones from its end
   (in Arabic: the right column from the right, the left one from the left) */
.card:nth-child(odd) {
  --col: calc(var(--flow) * -1);
}

.card:nth-child(even) {
  --col: var(--flow);
}

/* no blur here: blurring nineteen photo tiles at once costs frames */
.js .card {
  opacity: 0;
  transform: translate(calc(var(--col) * 44px + var(--enter-x, 0px)), 28px) scale(0.96);
  transition:
    opacity 480ms var(--ease) var(--d, 0ms),
    transform 900ms var(--spring) var(--d, 0ms);
}

.js .card.is-in {
  opacity: 1;
  transform: none;
}

.js .card .card-ph > img,
.js .card .card-ph > .thumb-ico {
  transition: transform 1000ms var(--spring-pop) calc(var(--d, 0ms) + 120ms);
}

.js .card:not(.is-in) .card-ph > img,
.js .card:not(.is-in) .card-ph > .thumb-ico {
  transform: translateY(-16%) scale(0.88);
}

/* a category leaving: a short, quiet step toward the side it came from */
.js .menu-group.is-leaving .card,
.js .menu-group.is-leaving .addons {
  opacity: 0;
  transform: translateX(var(--exit-x, 0px));
  transition-duration: 180ms;
  transition-delay: 0ms;
}

/* ---------------------------------------------------------------- reduced motion */
@media (prefers-reduced-motion: reduce) {
  .js [data-reveal],
  .js [data-reveal] img,
  .js [data-reveal] .mask > span,
  .js [data-reveal] > *,
  .js .card,
  .js .card .card-ph > img,
  .js .card .card-ph > .thumb-ico {
    opacity: 1 !important;
    transform: none !important;
    filter: none !important;
    clip-path: none !important;
    transition: none !important;
  }

  .add.is-popping,
  .chip.is-popping,
  .basket-sum.is-kicking,
  .basket-faces.is-kicking,
  .basket.is-opening .basket-row,
  .face,
  .sheet.is-open .sheet-photo img,
  .sheet.is-open .sheet-body > *,
  .cat.drawing .ring,
  .cat.drawing .ring .ico path {
    animation: none;
  }

  .js .basket,
  .basket-body,
  .basket[data-state="open"] .basket-body,
  .basket-chev,
  .nav-sheet,
  .nav-sheet.is-open,
  .card-ph img.cut {
    transition: opacity 160ms linear !important;
  }

  .js .basket,
  .basket-body,
  .nav-sheet,
  .island {
    transform: none !important;
    filter: none !important;
  }

  .island,
  .island.is-on {
    transition: opacity 160ms linear !important;
  }

  .island.is-on .isl-in {
    animation: none;
  }

  .isl-ind,
  .isl-over {
    transition: none;
  }
}

/* ---------------------------------------------------------------- laptop */
/* Deck p12: links spelled out, a standing order button, the swirl filling its
   half of the screen, the circles under the buttons. */
@media (min-width: 64rem) {
  :root {
    --page: 72rem;
    --gut: 44px;
    --section: 128px;
    --t-h2: 3.75rem;
    /* caps run wider than mixed case: sized so the name breaks as CUP AND /
       CONE in its column, never one word to a line */
    --t-h1: clamp(4.5rem, 6.2vw, 5.5rem);
  }

  .header-in {
    height: 88px;
    padding-inline: var(--gut);
  }

  .brand img {
    width: 46px;
    height: 46px;
  }

  .brand b {
    font-size: var(--t-h3);
  }

  .d-links,
  .isl-links {
    display: flex;
    gap: var(--s7);
    font-size: var(--t-body);
    font-weight: 500;
  }

  .d-links a,
  .isl-links a {
    min-height: 44px;
    display: flex;
    align-items: center;
    transition: color var(--t-state) var(--ease);
  }

  .d-links a:hover,
  .d-links a[aria-current="true"],
  .isl-links a:hover {
    color: var(--accent);
  }

  .d-links a[aria-current="true"] {
    font-weight: 700;
  }

  .header-actions {
    gap: var(--s2);
  }

  .head-order,
  .isl-order {
    width: auto;
    height: 44px;
    padding-inline: var(--s5);
    font-size: var(--t-ui);
    border-radius: 22px;
  }

  .isl-order span {
    display: inline;
  }

  .menu-btn,
  .isl-menu,
  .nav-sheet {
    display: none;
  }

  .island {
    max-width: 64rem;
  }

  .isl-in {
    height: 64px;
    border-radius: 32px;
  }

  .isl-home {
    padding-inline: var(--s3) 10px;
    gap: var(--s6);
  }

  .isl-links {
    margin-inline-start: auto;
  }

  .isl-acts {
    margin-inline-start: 0;
    gap: var(--s2);
  }

  .isl-tabs {
    justify-content: center;
    gap: var(--s2);
    padding: 10px;
  }

  .isl-tab {
    flex: 0 0 auto;
    height: 44px;
    padding-inline: var(--s5);
    border-radius: 22px;
    font-size: var(--t-ui);
  }

  .isl-ind,
  .isl-over {
    inset-block-start: 10px;
    height: 44px;
    clip-path: inset(0 var(--r, 100%) 0 var(--l, 0px) round 22px);
  }

  .isl-over {
    gap: var(--s2);
    padding-inline: 10px;
    justify-content: center;
  }

  .edge {
    height: 96px;
  }

  .hero {
    display: grid;
    grid-template-columns: minmax(0, 46%) minmax(0, 1fr);
    grid-template-areas:
      "copy stage"
      "cta  stage"
      "cats stage";
    grid-template-rows: auto auto 1fr;
    height: clamp(580px, calc(100svh - 88px), 780px);
  }

  .hero-copy {
    grid-area: copy;
    padding: var(--s10) var(--gut) 0;
    padding-inline-start: max(var(--gut), calc((100vw - 72rem) / 2 + var(--gut)));
  }

  .hero-h {
    line-height: 1.08;
    margin-block-start: var(--s6);
  }

  .hero-tag {
    font-size: var(--t-title);
  }

  .hero-stage {
    grid-area: stage;
    aspect-ratio: auto;
    height: 100%;
    margin: 0;
  }

  html[data-theme="night"] .hero-stage {
    margin: 0 var(--gut) var(--gut) 0;
    border-radius: 0 0 var(--r-lg) var(--r-lg);
  }

  .hero-cta {
    grid-area: cta;
    display: flex;
    gap: var(--s3);
    padding: var(--s7) var(--gut) 0;
    padding-inline-start: max(var(--gut), calc((100vw - 72rem) / 2 + var(--gut)));
  }

  .hero-cta .b1 {
    min-width: 13rem;
  }

  .hero-cta .b2 {
    min-width: 10rem;
  }

  .hero-cats {
    grid-area: cats;
    display: block;
    padding: var(--s8) var(--gut) 0;
    padding-inline-start: max(var(--gut), calc((100vw - 72rem) / 2 + var(--gut)));
  }

  .hero-cats .cats {
    gap: var(--s5);
  }

  .sec-head {
    margin-block-end: var(--s8);
  }

  .sub {
    font-size: var(--t-lead);
  }

  .shelf {
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: var(--s9) var(--s6);
  }

  .card-name {
    font-size: var(--t-body);
  }

  /* the header already carries a standing order button */
  .basket-direct,
  html:not(.js) .basket {
    display: none;
  }

  .js .basket[data-state="empty"] {
    visibility: hidden;
  }

  .js .basket {
    inset-inline: auto var(--gut);
    width: 26rem;
    max-width: none;
    margin: 0;
  }

  /* words on the reading side, the photo beside them, as in the hero */
  #almond .wrap,
  .visit {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: var(--s10);
    align-items: center;
  }

  .al-text,
  .v-body {
    grid-column: 1;
    grid-row: 1;
  }

  .al-photo,
  .v-photo {
    grid-column: 2;
    grid-row: 1;
  }

  .al-photo img {
    aspect-ratio: 1 / 1;
  }

  .al-h {
    margin-block-start: 0;
  }

  .car {
    max-width: var(--page);
    margin-inline: auto;
  }

  .collabs {
    grid-template-columns: repeat(auto-fit, minmax(22rem, 1fr));
  }

  .collab {
    height: 280px;
  }

  #moments {
    max-width: calc(var(--page) + 2 * var(--s8));
    margin-inline: auto;
    padding-block: var(--s11) var(--s10);
  }

  .reels {
    margin-inline: 0;
    padding-inline: 0;
  }

  .reel {
    flex-basis: calc((100% - 3 * var(--s3)) / 4);
  }

  .mas {
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: var(--s4);
  }

  #moments .stack {
    justify-items: start;
  }

  .visit {
    max-width: var(--page);
    margin-inline: auto;
    padding-inline: var(--gut);
  }

  .v-photo {
    height: 34rem;
    border-radius: var(--r-xl);
  }

  .v-photo .grad {
    display: none;
  }

  .v-body {
    margin: 0;
    padding: 0;
    max-width: 30rem;
  }

  .cta {
    flex-direction: row;
    align-items: center;
    padding: var(--s8) var(--s9);
  }

  .cta .btn {
    width: auto;
    min-width: 16rem;
  }

  .footer {
    border-radius: 40px 40px 0 0;
    padding: var(--s10) var(--gut) var(--s8);
  }

  .footer-in {
    display: grid;
    grid-template-columns: 1.2fr 1fr 1fr;
    gap: var(--s7) var(--s9);
    align-items: start;
  }

  .f-links,
  .f-soc {
    margin: 0;
    padding: 0;
    border: 0;
  }

  .f-bot {
    grid-column: 1 / -1;
    padding-block-start: var(--s5);
    border-block-start: 1px solid rgba(246, 236, 207, 0.16);
  }

  .sheet {
    max-height: 88svh;
  }
}
