/* ==========================================================================
   Tapioca House — Houston, TX
   Palette pulled from the brand: the logo's orange, the charcoal their food
   is photographed on, and the cream of milk tea. Pearls are the recurring
   motif because the logo already puts four of them in the base of the cup.
   ========================================================================== */

:root {
  /* Colour ------------------------------------------------------------- */
  --ink:        #0E0C0B;   /* warm near-black, biased brown not blue      */
  --ink-2:      #151110;   /* section alternate                           */
  --pearl:      #1C1613;   /* tapioca pearl brown, used for card lift     */
  --orange:     #FE6600;   /* exact logo orange                           */
  --orange-dim: #C24E00;
  --tea:        #C9873F;   /* brewed amber, second accent                 */
  --milk:       #F3E7D8;   /* milk tea cream, foreground only             */
  --milk-dim:   #A99C8E;
  --jade:       #6E8F6B;   /* veggie marker, used sparingly               */
  --line:       rgba(243, 231, 216, 0.14);

  /* Type --------------------------------------------------------------- */
  --display: "Fraunces", Georgia, serif;
  --body:    "Manrope", system-ui, -apple-system, sans-serif;
  --mono:    "JetBrains Mono", ui-monospace, monospace;

  --step--1: clamp(0.78rem, 0.75rem + 0.15vw, 0.86rem);
  --step-0:  clamp(0.98rem, 0.94rem + 0.2vw, 1.06rem);
  --step-1:  clamp(1.2rem, 1.1rem + 0.5vw, 1.5rem);
  --step-2:  clamp(1.6rem, 1.35rem + 1.2vw, 2.4rem);
  --step-3:  clamp(2.2rem, 1.6rem + 2.8vw, 4rem);
  --step-4:  clamp(3rem, 1.8rem + 5.6vw, 7.5rem);

  /* Space -------------------------------------------------------------- */
  --gutter: clamp(1.15rem, 4vw, 3.5rem);
  --section: clamp(4.5rem, 10vw, 9rem);
  --max: 1320px;
  --radius: 18px;

}

/* Reset -------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }
html { -webkit-text-size-adjust: 100%; }
body {
  background: var(--ink);
  color: var(--milk);
  font-family: var(--body);
  font-size: var(--step-0);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}
/* height:auto is load-bearing. The width/height attributes on each <img> are
   presentational hints that set CSS height, which silently beats aspect-ratio
   and stretched every feature photo to its intrinsic height. */
img { max-width: 100%; height: auto; display: block; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }

:focus-visible {
  outline: 2px solid var(--orange);
  outline-offset: 3px;
  border-radius: 4px;
}

.wrap { width: min(100% - var(--gutter) * 2, var(--max)); margin-inline: auto; }
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* Skip link so keyboard users are not trapped in the nav ------------- */
.skip {
  position: absolute; left: 50%; translate: -50% -120%;
  background: var(--orange); color: #000; padding: 0.65rem 1.2rem;
  border-radius: 0 0 12px 12px; z-index: 200; font-weight: 700;
  transition: translate 0.2s;
}
.skip:focus { translate: -50% 0; }

/* ==========================================================================
   Type
   ========================================================================== */
.display {
  font-family: var(--display);
  font-weight: 600;
  font-variation-settings: "SOFT" 40, "WONK" 1, "opsz" 100;
  line-height: 0.95;
  letter-spacing: -0.02em;
}
h1, h2, h3 { font-family: var(--display); font-weight: 600; line-height: 1.02; }
h1 { font-size: var(--step-4); }
h2 { font-size: var(--step-3); }
h3 { font-size: var(--step-1); }

.eyebrow {
  font-family: var(--mono);
  font-size: var(--step--1);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--orange);
  display: flex; align-items: center; gap: 0.7rem;
}
/* A single pearl instead of a rule: the motif does the labelling. */
.eyebrow::before {
  content: ""; width: 7px; height: 7px; border-radius: 50%;
  background: var(--orange); flex: none;
}

.lede { font-size: var(--step-1); color: var(--milk-dim); max-width: 46ch; line-height: 1.5; }
.muted { color: var(--milk-dim); }

/* ==========================================================================
   Navigation — floating pill, active item marked with a pearl
   ========================================================================== */
.nav {
  position: fixed; inset-inline: 0; top: clamp(0.6rem, 2vw, 1.4rem);
  z-index: 100; display: flex; justify-content: center;
  padding-inline: var(--gutter); pointer-events: none;
}
.nav-inner {
  pointer-events: auto;
  display: flex; align-items: center; gap: clamp(0.5rem, 2vw, 2rem);
  background: rgba(14, 12, 11, 0.72);
  backdrop-filter: blur(18px) saturate(1.3);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 0.5rem 0.6rem 0.5rem 0.9rem;
  /* Wider since Catering joined: five links plus the wordmark plus the call
     button had the wordmark and the first link touching. */
  width: min(100%, 940px);
}
.nav-logo { display: flex; align-items: center; gap: 0.6rem; margin-right: auto; padding-right: 0.8rem; }
.nav-logo img { width: 38px; height: 38px; }
.nav-logo span {
  font-family: var(--display); font-size: 1.05rem; letter-spacing: -0.01em;
  white-space: nowrap;
}
.nav-links { display: flex; align-items: center; gap: clamp(0.2rem, 1.4vw, 0.5rem); }
.nav-links a {
  font-size: var(--step--1); letter-spacing: 0.08em; text-transform: uppercase;
  font-weight: 600; padding: 0.55rem 0.7rem; border-radius: 999px;
  color: var(--milk-dim); transition: color 0.25s, background 0.25s;
  position: relative;
}
.nav-links a:hover { color: var(--milk); }
.nav-links a[aria-current="page"] { color: var(--milk); }

/* A single pill slides between the links rather than each one lighting its
   own background, so the pointer is followed by one continuous object instead
   of a row of things blinking on and off. It is positioned from measurements
   taken in script; until then it stays transparent, so a failed script leaves
   plain links rather than a stray shape. */
.nav-ind {
  position: absolute; z-index: -1; left: 0; top: 50%;
  height: 2.05rem; width: 0; translate: 0 -50%;
  border-radius: 999px; opacity: 0;
  background: rgba(243, 231, 216, 0.09);
  transition: transform 0.42s cubic-bezier(0.22, 0.61, 0.36, 1),
              width 0.42s cubic-bezier(0.22, 0.61, 0.36, 1),
              opacity 0.3s ease, background 0.4s ease;
}
.nav.is-light .nav-ind,
.nav-boot-light .nav .nav-ind { background: rgba(26, 21, 18, 0.08); }
.nav-links { position: relative; }

/* The dot under the current page lifts into the pill on hover instead of
   sitting on top of it. */
.nav-links a[aria-current="page"]::after { transition: opacity 0.3s, translate 0.3s; }
.nav-links:hover a[aria-current="page"]::after { opacity: 0; }
.nav-links a[aria-current="page"]::after {
  content: ""; position: absolute; left: 50%; translate: -50% 0; bottom: 0.18rem;
  width: 5px; height: 5px; border-radius: 50%; background: var(--orange);
}
.nav-call {
  display: inline-flex; align-items: center; gap: 0.45rem;
  background: var(--orange); color: #14100D; font-weight: 800;
  font-size: var(--step--1); padding: 0.6rem 1.05rem; border-radius: 999px;
  white-space: nowrap; transition: transform 0.25s, background 0.25s;
}
.nav-call:hover { background: #FF7A1F; transform: translateY(-1px); }

.nav-toggle { display: none; padding: 0.5rem; border-radius: 999px; }

/* The fly-through opens on warm white, and a near-black pill sitting on that
   reads as a hole punched in the page. The nav therefore starts light and
   crosses to the dark theme as the aperture reaches it, driven by the
   fly-through's own progress rather than by a scroll distance, so the two
   always change together. Only applied when the aperture is actually running:
   the static fallbacks open on ink, where the dark nav is already right. */
.nav-inner { transition: background 0.45s ease, border-color 0.45s ease; }
.nav-logo span { transition: color 0.45s ease; }
.nav-toggle { transition: color 0.45s ease; }

/* Two ways in. .is-light is what the fly-through drives while scrolling;
   .nav-boot-light is set on <html> by a tiny blocking script in the head, so
   the pill is already light on the very first paint. Without it the dark
   default is painted first and the bar visibly flips to white once the
   deferred script runs. The boot class is handed over to .is-light the moment
   that script takes charge. */
/* No container in the light theme. On the dark page the bar's own pill is
   nearly the colour of the page, so you read one pill - the orange button.
   Drawn against the warm white opening it became a second, competing pill.
   The links sit straight on the hero instead; there is nothing behind them
   there but flat colour, so they need no backdrop to stay legible. */
.nav.is-light .nav-inner,
.nav-boot-light .nav .nav-inner {
  background: transparent;
  border-color: transparent;
  box-shadow: none;
}
.nav.is-light .nav-logo span,
.nav.is-light .nav-toggle,
.nav.is-light .nav-links a[aria-current="page"],
.nav-boot-light .nav .nav-logo span,
.nav-boot-light .nav .nav-toggle,
.nav-boot-light .nav .nav-links a[aria-current="page"] { color: #1A1512; }
.nav.is-light .nav-links a,
.nav-boot-light .nav .nav-links a { color: #6B5C50; }
/* Colour only. The background here was left over from before the sliding
   pill existed, and the two drew one shape each - the link's own box and the
   pill, which is a fixed height and so a different size - giving the doubled
   outline on hover. The pill is the background now. The dark theme had
   already lost this rule; the light one had not. */
.nav.is-light .nav-links a:hover,
.nav-boot-light .nav .nav-links a:hover { color: #1A1512; }

/* ==========================================================================
   Hero — the cup is the thesis; pearls settle into it on load
   ========================================================================== */
.hero {
  position: relative; min-height: 100svh; display: grid; align-items: center;
  /* Top padding only has to clear the floating nav; the grid centres the rest. */
  padding-block: clamp(6rem, 12vh, 8.5rem) var(--section);
  overflow: hidden;
}
.hero-grid {
  display: grid; gap: clamp(2rem, 5vw, 4rem);
  grid-template-columns: 1fr;
  align-items: center;
}
@media (min-width: 900px) {
  .hero-grid { grid-template-columns: 1.05fr 0.95fr; }
}
.hero-copy { position: relative; z-index: 2; }
.hero h1 { margin-block: 1.1rem 1.4rem; }
.hero h1 em {
  font-style: normal; color: var(--orange); display: block;
  font-variation-settings: "SOFT" 60, "WONK" 1, "opsz" 144;
}
.hero-actions { display: flex; flex-wrap: wrap; gap: 0.8rem; margin-top: 2rem; }

.btn {
  display: inline-flex; align-items: center; gap: 0.55rem;
  padding: 0.95rem 1.6rem; border-radius: 999px; font-weight: 700;
  font-size: var(--step-0); transition: transform 0.25s, background 0.25s, border-color 0.25s;
}
.btn-primary { background: var(--orange); color: #14100D; }
.btn-primary:hover { background: #FF7A1F; transform: translateY(-2px); }
.btn-ghost { border: 1px solid var(--line); color: var(--milk); }
.btn-ghost:hover { border-color: var(--orange); transform: translateY(-2px); }

/* Specular rim -----------------------------------------------------------
   A hairline of light along the button's own edge that points at the cursor
   and fades in as it comes near. Built out of a rotating conic gradient
   clipped to a one-pixel ring, so it costs no canvas, no WebGL context and
   no library: the reference does this with a shader, but the shape is a
   rounded rectangle we already have a border-radius for, and everything the
   shader computes per pixel we can state once as a gradient.

   The gradient carries two lobes 180 degrees apart because the highlight is
   symmetric: the edge facing the light and the edge facing away both catch
   it. --sa is where the light is coming from and --sg is how close the
   pointer is; the script writes both.

   The ring itself is the standard padding-box exclusion: fill the whole box,
   then mask out everything except a --sw wide band at the edge. inherit on
   the radius keeps it true on the pill buttons and the square ones alike. */
.spec { position: relative; isolation: isolate; }
.spec > * { position: relative; z-index: 1; }
.spec::after {
  content: ""; position: absolute; inset: 0; z-index: 0;
  border-radius: inherit; padding: var(--sw, 1.2px);
  pointer-events: none;
  background: conic-gradient(from calc(var(--sa, 0) * 1deg) at 50% 50%,
    rgba(255, 255, 255, 0.96) 0deg,
    rgba(255, 255, 255, 0.10) 26deg,
    transparent 62deg,
    transparent 118deg,
    rgba(255, 255, 255, 0.10) 154deg,
    rgba(255, 255, 255, 0.96) 180deg,
    rgba(255, 255, 255, 0.10) 206deg,
    transparent 242deg,
    transparent 298deg,
    rgba(255, 255, 255, 0.10) 334deg,
    rgba(255, 255, 255, 0.96) 360deg);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
          mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
  opacity: var(--sg, 0);
  /* Only a fallback for the first frame and for a page with no script; the
     script drives --sg every frame once it is running. */
  transition: opacity 0.25s linear;
}
/* On the solid orange the white hairline is too cold, and on the dark ones a
   warm line reads as a reflection of the room rather than a stroke. */
.btn-primary.spec::after { --sw: 1.4px; filter: saturate(0) brightness(1.25); }
.spec.btn-ghost::after, .nav-call.spec::after { --sw: 1.2px; }

@media (prefers-reduced-motion: reduce) {
  .spec::after { display: none; }
}

/* Full-bleed photographic plate, the way the reference uses roasted beans. */
.hero-bg { position: absolute; inset: 0; z-index: 0; overflow: hidden; }
.hero-bg img { width: 100%; height: 100%; object-fit: cover; }
.hero-veil {
  position: absolute; inset: 0; z-index: 1;
  background:
    radial-gradient(70% 90% at 72% 45%, rgba(254, 102, 0, 0.16), transparent 62%),
    linear-gradient(100deg, var(--ink) 18%, rgba(14, 12, 11, 0.72) 48%, rgba(14, 12, 11, 0.34) 100%);
}
.hero .wrap { position: relative; z-index: 2; }

/* Stage the cups sit on. They overlap and break the column, so the cluster
   reads as one object rather than three pictures in a row. */
.hero-stage { position: relative; aspect-ratio: 520 / 620; }
.hero-stage .cup {
  position: absolute; width: auto; filter: drop-shadow(0 26px 40px rgba(0,0,0,0.6));
  will-change: transform;
}
.cup-front { height: 78%; left: 26%; bottom: 2%;  z-index: 3; }
.cup-mid   { height: 63%; left: 2%;  bottom: 10%; z-index: 2; }
.cup-back  { height: 40%; right: 0;  top: 8%;     z-index: 1; }

.scatter { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; z-index: 0; }
.scatter .pip { fill: var(--orange); opacity: 0.85; transform-box: fill-box; transform-origin: center; }

.hero-scroll {
  position: absolute; left: 50%; translate: -50% 0; bottom: 1.6rem; z-index: 3;
  font-family: var(--mono); font-size: 0.68rem; letter-spacing: 0.24em;
  text-transform: uppercase; color: var(--milk-dim);
  display: flex; align-items: center; gap: 0.6rem;
}
.hero-scroll span {
  width: 1px; height: 34px;
  background: linear-gradient(var(--orange), transparent);
}

@media (max-width: 899px) {
  .hero-stage { aspect-ratio: 5 / 4; margin-top: 1rem; }
  .cup-front { height: 96%; left: 30%; }
  .cup-mid   { height: 78%; left: 4%; }
  .cup-back  { height: 50%; }
}

/* ==========================================================================
   Marquee — a night-market signboard, carrying real menu items
   ========================================================================== */
.marquee {
  border-block: 1px solid var(--line);
  background: var(--ink-2);
  padding-block: 0.9rem;
  overflow: hidden;
  display: flex;
  user-select: none;
}
.marquee-track {
  display: flex; gap: 2.6rem; flex: none; min-width: 100%;
  animation: slide 46s linear infinite;
}
.marquee span {
  font-family: var(--mono); font-size: var(--step--1);
  text-transform: uppercase; letter-spacing: 0.16em; color: var(--milk-dim);
  display: flex; align-items: center; gap: 2.6rem; white-space: nowrap;
}
.marquee span::after {
  content: ""; width: 6px; height: 6px; border-radius: 50%;
  background: var(--orange); opacity: 0.8;
}
@keyframes slide { to { transform: translateX(-100%); } }

/* ==========================================================================
   Sections
   ========================================================================== */
.section { padding-block: var(--section); position: relative; }
/* One continuous photographic ground for the page, faint, so sections read as
   one surface rather than alternating flat blocks. */
body::before {
  content: ""; position: fixed; inset: 0; z-index: -2;
  background: url("../img/bg-leaf.webp") center / cover no-repeat;
  opacity: 0.5;
}
body::after {
  content: ""; position: fixed; inset: 0; z-index: -1;
  background: linear-gradient(var(--ink) 0%, rgba(14,12,11,0.90) 40%, var(--ink) 100%);
}
.section-alt { overflow-x: clip; background: rgba(21, 17, 16, 0.72); }
.section-head { margin-bottom: clamp(2.2rem, 5vw, 3.6rem); }
/* Only the prose is measure-limited; the display line sets its own width so a
   short heading is not forced to wrap mid-phrase. */
.section-head .lede, .section-head > p:not(.eyebrow) { max-width: 58ch; }
.section-head h2 { margin-block: 0.9rem 1rem; max-width: 20ch; }

/* The counter — drinks and snacks stand on the page as objects, not inside
   boxes. Cutouts on a shared background is what makes the reference read as
   a composition rather than a grid of product tiles. */
.counter {
  display: grid; gap: clamp(2.5rem, 4vw, 3rem) clamp(1rem, 2.5vw, 2rem);
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  align-items: end;
}
.pour { margin: 0; position: relative; text-align: center; }
/* Alternate the baseline so the row is a skyline, not a shelf. */
.pour:nth-child(even) { transform: translateY(clamp(1rem, 3vw, 2.6rem)); }

.pour-img {
  height: clamp(190px, 22vw, 290px); width: auto; margin: 0 auto 1.2rem;
  filter: drop-shadow(0 22px 30px rgba(0,0,0,0.55));
  transition: transform 0.5s cubic-bezier(.22,1,.36,1), filter 0.5s;
}
.pour:hover .pour-img {
  transform: translateY(-14px) rotate(-3deg) scale(1.04);
  filter: drop-shadow(0 34px 44px rgba(254,102,0,0.28));
}
.pour h3 { font-size: var(--step-1); margin-bottom: 0.3rem; }
.pour p { font-size: var(--step--1); color: var(--milk-dim); line-height: 1.55; max-width: 30ch; margin-inline: auto; }
.pour .price {
  font-family: var(--mono); color: var(--orange); font-size: var(--step-0);
  font-weight: 700; display: block; margin-bottom: 0.35rem;
}

/* Feature rows — big photography, alternating */
.feature { display: grid; gap: clamp(1.8rem, 5vw, 4rem); align-items: center; }
@media (min-width: 880px) {
  .feature { grid-template-columns: 1fr 1fr; }
  .feature.reverse .feature-media { order: 2; }
}
.feature + .feature { margin-top: var(--section); }
.feature-media img {
  width: 100%; border-radius: var(--radius); aspect-ratio: 5 / 4; object-fit: cover;
}
.feature h2 { margin-block: 0.9rem 1rem; }
.feature p + p { margin-top: 0.9rem; }

/* Accordion gallery -------------------------------------------------------
   flex-grow is the only animated property: the panels share the row, and the
   one under the pointer takes the room from the rest. Widths are never
   measured, so nothing needs recalculating on resize, and because each photo
   is cropped by its own panel it stays put while the panel changes width
   instead of sliding about.

   min-width: 0 matters. Flex items default to min-width:auto, which refuses
   to shrink below the image's own width and would stop the collapse dead. */
.acc {
  display: flex; gap: 0.55rem; margin-top: clamp(2rem, 4vw, 3rem);
  height: clamp(340px, 54vh, 540px);
}
.acc-item {
  position: relative; flex: 1 1 0; min-width: 0;
  border-radius: 14px; overflow: hidden; cursor: pointer;
  transition: flex-grow 0.75s cubic-bezier(0.22, 0.61, 0.36, 1),
              filter 0.55s ease;
}
.acc-item img {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover;
  /* Nudged off centre: the subject of these photographs sits low, and the
     collapsed strip is cut from the middle. */
  object-position: 50% 42%;
  transition: transform 0.75s cubic-bezier(0.22, 0.61, 0.36, 1);
}
/* Scrim, so the label holds against a bright photo. */
.acc-item::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(to top,
    rgba(14, 12, 11, 0.92) 0%, rgba(14, 12, 11, 0.45) 34%, transparent 62%);
}

/* Once the pointer is anywhere in the row the others step back. Written as
   two rules of equal specificity, so the hovered one must come second. */
.acc:hover .acc-item, .acc:focus-within .acc-item {
  flex-grow: 0.62; filter: grayscale(1) brightness(0.5);
}
.acc .acc-item:hover, .acc .acc-item:focus-within {
  flex-grow: 3.9; filter: none;
}
.acc .acc-item:hover img, .acc .acc-item:focus-within img { transform: scale(1.05); }

.acc-face {
  position: absolute; left: 0; bottom: 0; z-index: 2;
  padding: clamp(1rem, 1.8vw, 1.6rem);
  width: max-content; max-width: 34ch;
}
.acc-no {
  font-family: var(--mono); font-size: 0.66rem; letter-spacing: 0.24em;
  color: var(--orange); display: block; margin-bottom: 0.5rem;
}
.acc-face h3 {
  font-size: clamp(1.05rem, 1.6vw, 1.5rem); line-height: 1.05;
  white-space: nowrap;
  /* The rule the whole thing hangs on: a nowrap heading in a panel that is
     currently a narrow strip would otherwise force the strip wide. */
}
/* A collapsed panel is narrower than its own title, and the title cannot wrap,
   so it would be sliced mid-word against the panel's clip. The caption is
   dropped from the panels that are standing back and belongs to whichever one
   has the room for it. At rest, with the widths even, they all keep theirs. */
.acc-face { transition: opacity 0.32s ease; }
.acc:hover .acc-item .acc-face,
.acc:focus-within .acc-item .acc-face { opacity: 0; }
.acc .acc-item:hover .acc-face,
.acc .acc-item:focus-within .acc-face { opacity: 1; }

.acc-face p {
  color: var(--milk-dim); font-size: var(--step--1); margin-top: 0.55rem;
  opacity: 0; transform: translateY(8px);
  transition: opacity 0.4s ease 0.12s, transform 0.4s ease 0.12s;
}
.acc .acc-item:hover .acc-face p,
.acc .acc-item:focus-within .acc-face p { opacity: 1; transform: none; }

.acc-actions { margin-top: clamp(1.8rem, 3vw, 2.6rem); }

/* No hover to answer on a touch screen, and five strips side by side would be
   unreadable at this width anyway, so it becomes a stack with every caption
   already showing. */
@media (max-width: 860px) {
  .acc { flex-direction: column; height: auto; gap: 0.7rem; }
  .acc-item { flex: 0 0 auto; height: clamp(190px, 34vw, 260px); }
  .acc:hover .acc-item, .acc:focus-within .acc-item,
  .acc .acc-item:hover, .acc .acc-item:focus-within {
    flex-grow: 0; filter: none;
  }
  .acc .acc-item:hover img, .acc .acc-item:focus-within img { transform: none; }
  .acc-face h3 { white-space: normal; }
  .acc-face p { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .acc-item, .acc-item img, .acc-face p { transition: none; }
}

/* ==========================================================================
   Menu — grouped by price, numerals aligned like a market board
   ========================================================================== */
.tabs { display: flex; gap: 0.5rem; flex-wrap: wrap; margin-bottom: 2.6rem; }
.tab {
  font-family: var(--mono); font-size: var(--step--1); letter-spacing: 0.14em;
  text-transform: uppercase; padding: 0.65rem 1.3rem; border-radius: 999px;
  border: 1px solid var(--line); color: var(--milk-dim);
  transition: color 0.25s, border-color 0.25s, background 0.25s;
}
.tab:hover { color: var(--milk); border-color: var(--milk-dim); }
.tab[aria-selected="true"] { background: var(--orange); border-color: var(--orange); color: #14100D; font-weight: 700; }

.menu-group + .menu-group { margin-top: clamp(2.6rem, 5vw, 4rem); }
.menu-group-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 1rem; padding-bottom: 0.8rem; border-bottom: 1px solid var(--line);
  margin-bottom: 1.4rem; flex-wrap: wrap;
}
.menu-group-head h3 {
  font-family: var(--mono); font-size: var(--step-0); font-weight: 700;
  letter-spacing: 0.16em; text-transform: uppercase; color: var(--milk);
}
/* Prices are grouped, so the price sits on the group, not each row. */
.menu-group-price { font-family: var(--mono); color: var(--orange); font-weight: 700; font-size: var(--step-1); }
.menu-note { font-size: var(--step--1); color: var(--milk-dim); margin-bottom: 1.2rem; }

.menu-items { display: grid; gap: 0.55rem 2rem; grid-template-columns: repeat(auto-fill, minmax(255px, 1fr)); list-style: none; padding: 0; }
.menu-items li { display: flex; align-items: center; gap: 0.6rem; padding: 0.32rem 0; font-size: var(--step-0); }
.menu-items li::before {
  content: ""; width: 5px; height: 5px; border-radius: 50%;
  background: var(--tea); flex: none; opacity: 0.75;
}
.tag-veg { font-family: var(--mono); font-size: 0.66rem; letter-spacing: 0.1em; color: var(--jade); border: 1px solid currentColor; border-radius: 4px; padding: 0.05rem 0.32rem; }

/* ==========================================================================
   Info panels — hours, address, contact
   ========================================================================== */
.panels { display: grid; gap: 1.2rem; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); }
.panel { background: var(--pearl); border: 1px solid var(--line); border-radius: var(--radius); padding: 1.7rem; }
.panel h3 { font-family: var(--mono); font-size: var(--step--1); letter-spacing: 0.16em; text-transform: uppercase; color: var(--orange); margin-bottom: 0.9rem; }
.panel p, .panel li { color: var(--milk-dim); }
.panel a:hover { color: var(--orange); }
.hours { list-style: none; padding: 0; display: grid; gap: 0.5rem; }
.hours li { display: flex; justify-content: space-between; gap: 1rem; font-size: var(--step-0); }
.hours span:last-child { font-family: var(--mono); color: var(--milk); }

.map-embed { border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; aspect-ratio: 16 / 10; background: var(--pearl); }
.map-embed iframe { width: 100%; height: 100%; border: 0; display: block; filter: grayscale(0.35) contrast(1.05); }

/* ==========================================================================
   Footer
   ========================================================================== */
.footer { background: var(--ink-2); border-top: 1px solid var(--line); padding-block: clamp(3rem, 6vw, 4.5rem) 2rem; }
.footer-grid { display: grid; gap: 2.2rem; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); }
.footer-brand img { width: 68px; margin-bottom: 1rem; }
.footer h4 { font-family: var(--mono); font-size: var(--step--1); letter-spacing: 0.16em; text-transform: uppercase; color: var(--orange); margin-bottom: 0.9rem; font-weight: 700; }
.footer ul { list-style: none; padding: 0; display: grid; gap: 0.55rem; }
.footer a { color: var(--milk-dim); }
.footer a:hover { color: var(--milk); }
.footer-base { margin-top: 2.6rem; padding-top: 1.4rem; border-top: 1px solid var(--line); display: flex; justify-content: space-between; gap: 1rem; flex-wrap: wrap; font-size: var(--step--1); color: var(--milk-dim); }

/* ==========================================================================
   Motion — scroll reveals. Everything is visible without JS.
   ========================================================================== */
.reveal { opacity: 1; }
html.js .reveal { opacity: 0; transform: translateY(26px); }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
  html.js .reveal { opacity: 1; transform: none; }
  .marquee-track { animation: none; }
}

/* ==========================================================================
   Mobile nav
   ========================================================================== */
@media (max-width: 780px) {
  .nav-toggle { display: inline-flex; }
  .nav-links {
    position: absolute; top: calc(100% + 0.6rem); left: 0; right: 0;
    flex-direction: column; align-items: stretch; gap: 0.2rem;
    background: rgba(14, 12, 11, 0.96); backdrop-filter: blur(18px);
    border: 1px solid var(--line); border-radius: 20px; padding: 0.6rem;
    display: none;
  }
  .nav-links.open { display: flex; }
  /* The sliding pill tracks a horizontal row; in the stacked dropdown there
     is no row for it to travel along, and it is a hover affordance on a
     surface with no hover. */
  .nav-ind { display: none; }
  .nav-links a { padding: 0.85rem 1rem; text-align: center; }
  .nav-links a[aria-current="page"]::after { display: none; }
  .nav-inner { position: relative; }
  .nav-logo span { display: none; }
}

/* ==========================================================================
   Pick your side — the reference's card composition, in our palette
   Light section on purpose: white cards need a light ground to read, and the
   page has been unrelieved dark up to here.
   ========================================================================== */
.eyebrow-plain::before { display: none; }

.pick {
  /* The scattered cards are rotated and one of their chips lands a few pixels
     outside the column, which was enough to give the whole page a 10px
     sideways drag. Clipped here rather than at the root: clipping the root
     stops the scroll but also stops position:sticky working, and both the
     fly-through stage and the menu index depend on it. */
  overflow-x: clip;
  position: relative; z-index: 1;
  background: var(--ink-2); color: var(--milk);
  /* Exactly one screen: head, stage and tabs are rows of a full-height grid
     so the section never needs its own scroll. */
  height: 100svh; min-height: 640px;
  display: grid; grid-template-rows: auto 1fr auto;
  align-content: center; gap: clamp(0.75rem, 2vh, 1.6rem);
  padding-block: clamp(5.5rem, 11vh, 7rem) clamp(1.5rem, 4vh, 2.5rem);
  background-image: radial-gradient(rgba(243,231,216,0.055) 1px, transparent 1px);
  background-size: 26px 26px;
}
.pick > .wrap { display: contents; }
.pick-head { text-align: center; }
.pick-head h2 { margin-top: 0.5rem; font-size: clamp(1.9rem, 4.2vh, 3.2rem); }
.pick-head .eyebrow { justify-content: center; }

.pick-stage {
  position: relative; display: grid; place-items: center;
  min-height: 0; height: 100%;
  perspective: 1100px;
}

/* Centre card ------------------------------------------------------------ */
.pick-card {
  position: relative; z-index: 5;
  width: min(92%, 380px); max-height: 100%;
  display: flex; flex-direction: column;
  background: var(--pearl); border: 1px solid var(--line);
  border-radius: 20px; padding: 0.75rem 0.75rem 1.15rem;
  box-shadow: 0 30px 70px rgba(0,0,0,0.55);
}
.pick-media { position: relative; border-radius: 14px; overflow: hidden; }
.pick-media img { width: 100%; height: clamp(150px, 30vh, 280px); object-fit: cover; }
/* Vertical spine label, exactly the device in the reference. */
.pick-spine {
  position: absolute; left: 0.45rem; top: 50%;
  transform: translateY(-50%) rotate(180deg); writing-mode: vertical-rl;
  font-family: var(--mono); font-size: 0.6rem; letter-spacing: 0.24em;
  text-transform: uppercase; color: rgba(255,255,255,0.9); z-index: 2;
  text-shadow: 0 1px 6px rgba(0,0,0,0.5);
}
.pick-card h3 {
  font-size: clamp(1.3rem, 2.8vh, 1.9rem); color: var(--milk); margin: 0.85rem 0.5rem 0.35rem;
}
.pick-card p {
  font-size: var(--step--1); line-height: 1.55; color: var(--milk-dim); margin-inline: 0.5rem;
}

/* Satellites ------------------------------------------------------------- */
.sat {
  /* Outer shell never transforms. It owns the hover target, so the card can
     lift and turn without sliding out from under the pointer, which was
     making hover toggle on and off and the flip stutter. */
  position: absolute; margin: 0;
  width: clamp(112px, 13vw, 176px);
}
.sat-card {
  background: var(--pearl); border: 1px solid var(--line); border-radius: 14px;
  padding: 0.5rem; box-shadow: 0 18px 40px rgba(0,0,0,0.5);
  transform-style: preserve-3d;
  transition: transform .9s cubic-bezier(.3,.85,.3,1), box-shadow .4s;
  position: relative;
}
.sat img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; border-radius: 9px; }
/* The whole card turns: photo, chip, border and shadow together. */
.sat:hover { z-index: 8; }
.sat:hover .sat-card, .sat:focus-within .sat-card {
  transform: rotateY(360deg) translateY(-12px) scale(1.05);
  box-shadow: 0 30px 60px rgba(0,0,0,0.62);
}

.chip {
  position: absolute; top: -0.7rem; right: -0.5rem; z-index: 3;
  background: var(--orange); color: #14100D;
  font-family: var(--mono); font-size: 0.62rem; font-weight: 700;
  letter-spacing: 0.08em; padding: 0.32rem 0.6rem; border-radius: 7px;
  white-space: nowrap; box-shadow: 0 6px 16px rgba(36,28,22,0.22);
}

.sat-1 { left: 0;     top: 3%;    rotate: -8deg; width: clamp(120px, 14.5vw, 194px); }
.sat-2 { right: 7%;   top: 17%;   rotate: 5deg;  width: clamp(100px, 11.5vw, 150px); }
.sat-3 { left: 11%;   bottom: 2%; rotate: 7deg;  width: clamp(108px, 12.5vw, 164px); }
.sat-4 { right: 0;    bottom: 21%; rotate: -3deg; width: clamp(116px, 13.5vw, 178px); }

/* Tabs, underneath, in a raised pill ------------------------------------- */
.pick-tabs {
  position: relative;
  display: flex; gap: 0.3rem; flex-wrap: wrap; justify-content: center;
  margin-inline: auto; width: fit-content;
  background: var(--pearl); border: 1px solid var(--line);
  border-radius: 999px; padding: 0.35rem;
  box-shadow: 0 16px 40px rgba(0,0,0,0.45);
}
/* The same moving pill the bar uses. The selection used to jump from one tab
   to the next because each drew its own background; one pill that travels
   carries the eye with it instead. Positioned from script, and transparent
   until it has been, so a page with no script is left with plain tabs rather
   than a stray shape. */
.rtab-ind {
  position: absolute; z-index: 0; left: 0; top: 50%;
  height: 0; width: 0; translate: 0 -50%;
  border-radius: 999px; background: var(--orange); opacity: 0;
  transition: transform 0.42s cubic-bezier(0.22, 0.61, 0.36, 1),
              width 0.42s cubic-bezier(0.22, 0.61, 0.36, 1),
              height 0.42s cubic-bezier(0.22, 0.61, 0.36, 1),
              opacity 0.3s ease;
}
.rtab {
  position: relative; z-index: 1;
  font-family: var(--body); font-size: var(--step--1); font-weight: 600;
  padding: 0.6rem 1.2rem; border-radius: 999px; color: var(--milk-dim);
  transition: color .25s;
}
/* Whatever the pill is under reads as dark-on-orange: the hovered tab while
   you are in the row, the selected one the moment you leave. */
.rtab[aria-selected="true"], .rtab:hover { color: #14100D; }
.pick-tabs:hover .rtab[aria-selected="true"] { color: var(--milk-dim); }
.pick-tabs:hover .rtab:hover { color: #14100D; }
/* No script, no pill: fall back to the tab drawing its own. */
.no-js-tabs .rtab[aria-selected="true"] { background: var(--orange); }

@media (max-width: 900px) {
  /* Below this the satellites cannot orbit without collisions, so the stage
     becomes a simple stack and the section is allowed its natural height. */
  .pick { height: auto; padding-block: var(--section); }
  .pick-stage { display: grid; grid-template-columns: repeat(2, 1fr); gap: 0.9rem; }
  .sat { position: relative; inset: auto; rotate: 0deg !important; width: 100%; }
  .pick-card { grid-column: 1 / -1; order: -1; width: 100%; }
}

/* ==========================================================================
   Popular items — one circular stage, four dishes passing through it
   ========================================================================== */
/* One screen, deliberately. Everything that answers a hover - the dish, the
   ring and the caption - has to be in view at the same time as the names you
   are hovering, or you point at a row and the thing that changed is off the
   top of the window. So the whole section is bounded by the viewport and the
   pieces inside it are measured in vh rather than vw: it is the height that
   runs out first, and sizing on width would overflow a short laptop. */
.signature {
  position: relative; overflow: hidden; background: var(--ink);
  min-height: 100svh;
  display: grid; align-content: center;
  padding-block: clamp(4.6rem, 11vh, 7rem) clamp(1.1rem, 4vh, 2.5rem);
}
.signature .section-head { margin-bottom: clamp(1rem, 2.5vh, 2rem); }

/* Below this there is genuinely not room for a ring, four names, a caption
   and two buttons at a readable size, so it stops pretending and lets the
   section be as tall as it needs. Cramming would cost legibility, which is
   the thing the one-screen rule exists to protect. */
@media (max-height: 640px) {
  .signature { min-height: auto; padding-block: clamp(5rem, 9vh, 6rem) 2.5rem; }
}
.signature .section-head h2 { font-size: clamp(1.9rem, 4.6vh, 3.4rem); }
.signature .section-head .lede { display: none; }

.sig-inner { display: grid; gap: clamp(1.5rem, 4vw, 3.5rem); align-items: center; }
@media (min-width: 940px) { .sig-inner { grid-template-columns: minmax(0, 0.85fr) minmax(0, 1fr); } }

.sig-stage {
  position: relative; aspect-ratio: 1;
  width: min(100%, 52vh, 460px);
  margin-inline: auto; display: grid; place-items: center;
}
.sig-glow {
  position: absolute; inset: 8%;
  background: radial-gradient(circle at 50% 52%,
    rgba(254,102,0,0.30) 0%, rgba(254,102,0,0.12) 38%, transparent 68%);
  filter: blur(14px);
}
.sig-ring {
  position: absolute; inset: 0; width: 100%; height: 100%;
  animation: sig-turn 26s linear infinite; overflow: visible;
}
.sig-ring text {
  font-family: var(--mono); font-size: 11.5px; letter-spacing: 0.34em;
  text-transform: uppercase; fill: var(--orange-dim);
}
@keyframes sig-turn { to { transform: rotate(360deg); } }
.sig-stage:hover .sig-ring { animation-play-state: paused; }

/* All four are stacked on the same cell and only one is shown. Kept in the
   document rather than swapping a single src, so every dish is decoded before
   it is needed and the change cannot show a blank frame. */
/* Bounded on both axes. Sizing on width alone assumed every dish was
   landscape: the milk tea is 357x668, so at 78% width it came out 359x671 on
   a 460px stage and stood straight out of the ring. Constraining both and
   letting the other axis follow fits any of them inside the circle.

   No transition or animation here on purpose. These are moved by GSAP alone,
   because a CSS transition on transform plus a CSS keyframe on the same
   property is two writers, and switching quickly left both dishes on screen
   at once - the flicker between items. */
.sig-cut {
  /* Taken out of flow and centred by auto margins. As a grid item its
     percentage max-height resolved against the stage's own auto height, so
     the tall milk tea pushed the square stage out to 460x654 and then sized
     itself against that. Against an out-of-flow box the percentages resolve
     against the square, and the dish cannot alter it. */
  position: absolute; inset: 0; margin: auto; z-index: 1;
  width: auto; height: auto;
  max-width: 72%; max-height: 66%;
  object-fit: contain;
  filter: drop-shadow(0 26px 40px rgba(0,0,0,0.65));
  opacity: 0;
}
/* The first dish is visible in the stylesheet, so the ring is never empty on
   a page where the script did not run. The script takes it from here. */
.sig-cut:first-of-type { opacity: 1; }

/* A fixed floor, because the panels are stacked and only one is in flow:
   without it the column's height follows whichever caption is showing and
   the buttons below it move every time the dish changes. */
.sig-panels {
  position: relative;
  min-height: clamp(84px, 15vh, 150px);
  margin-top: clamp(0.9rem, 2.2vh, 1.6rem);
}
.sig-panel {
  position: absolute; inset: 0; opacity: 0; pointer-events: none;
  transform: translateY(14px);
  transition: opacity 0.4s ease, transform 0.5s cubic-bezier(0.22,0.61,0.36,1);
}
.sig-panel.is-on { position: relative; opacity: 1; transform: none; pointer-events: auto; }
.sig-panel h3 { font-size: clamp(1.8rem, 3.6vw, 3rem); line-height: 1.02; }
.sig-panel h3 em {
  font-style: normal; color: var(--orange); display: block;
  font-variation-settings: "SOFT" 60, "WONK" 1, "opsz" 144;
}
.sig-panel .muted { margin-top: 0; max-width: 46ch; font-size: var(--step--1); }

.sig-facts { display: flex; flex-wrap: wrap; gap: 0.4rem; margin: 0.9rem 0 0; padding: 0; list-style: none; }
.sig-facts li {
  font-family: var(--mono); font-size: 0.66rem; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--milk-dim);
  border: 1px solid var(--line); border-radius: 999px; padding: 0.45rem 0.85rem;
}

.sig-picker { display: grid; gap: 0.15rem; margin: clamp(1.6rem, 3vw, 2.4rem) 0 1.8rem; }
.sig-pick {
  display: flex; align-items: baseline; gap: 0.9rem; width: 100%;
  padding: 0.75rem 0.9rem; border-radius: 12px; text-align: left;
  color: var(--milk-dim); background: transparent;
  border: 1px solid transparent;
  transition: color 0.3s, background 0.3s, border-color 0.3s;
}
.sig-pick:hover { color: var(--milk); background: rgba(243,231,216,0.05); }
.sig-pick.is-on { color: var(--milk); border-color: rgba(254,102,0,0.45); background: rgba(254,102,0,0.07); }
.sig-no { font-family: var(--mono); font-size: 0.68rem; letter-spacing: 0.18em; color: var(--orange); }
.sig-label { font-family: var(--display); font-size: clamp(1rem, 1.7vw, 1.25rem); }

/* Flowing menu — the four names, filled from the edge the pointer crossed
   ========================================================================== */
.fm { border-top: 1px solid var(--line); }
.fm-row {
  position: relative; display: flex; align-items: center; justify-content: flex-start;
  /* Taller than strictly needed for the text. The band's whole travel is one
     row height, so a short row makes a 0.6s slide look like a cut; the
     reference's rows are around 150px and that is why it reads as motion. */
  height: clamp(48px, 8.6vh, 98px);
  border-bottom: 1px solid var(--line);
  overflow: hidden; padding-inline: clamp(0.8rem, 1.6vw, 1.4rem);
}
.fm-label {
  font-family: var(--display); font-weight: 700;
  font-size: clamp(1.05rem, 2.9vh, 1.9rem); line-height: 1;
  letter-spacing: -0.02em; color: var(--milk);
  transition: color 0.35s ease;
}
.fm-row.is-on .fm-label { color: var(--orange); }
/* No fade on the label. The band is opaque and covers it, which is how the
   reference does it; fading the text as well meant that any moment the band
   had not yet arrived showed an empty row with its name gone. */

/* The band. GSAP owns its Y, and that is the only vertical motion in here. */
.fm-marquee {
  position: absolute; inset: 0; overflow: hidden;
  background: var(--milk); pointer-events: none;
  transform: translate3d(0, 101%, 0);
}
.fm-inner { display: block; height: 100%; overflow: hidden; }
/* The horizontal travel, and nothing else on this element. Two identical
   halves, so translating exactly -50% returns to an identical frame and the
   loop has no seam. It runs continuously rather than starting on hover, so
   the strip is already in motion the moment the band uncovers it instead of
   visibly starting from a standstill. */
.fm-track {
  display: flex; align-items: center; height: 100%; width: max-content;
  animation: fm-scroll 22s linear infinite;
  will-change: transform;
}
@keyframes fm-scroll { to { transform: translateX(-50%); } }

/* Each row is started at a different point in the same loop, and every other
   one runs the other way. Without this all four strips sit at the same
   offset, so moving between rows lines the photographs up one under another
   and the change reads as the same band redrawn rather than a different dish.
   A negative delay starts a loop already part-way through instead of waiting.
   Reversing is seamless here because the strip is two identical halves, so
   both ends of the travel are the same frame. */
.fm-row:nth-child(1) .fm-track { animation-delay: -1.5s; }
.fm-row:nth-child(2) .fm-track { animation-delay: -7s;  animation-direction: reverse; }
.fm-row:nth-child(3) .fm-track { animation-delay: -13s; }
.fm-row:nth-child(4) .fm-track { animation-delay: -18.5s; animation-direction: reverse; }

.fm-part {
  display: flex; align-items: center; flex-shrink: 0;
  font-family: var(--display); font-weight: 700;
  font-size: clamp(1.05rem, 2.9vh, 1.9rem); line-height: 1;
  letter-spacing: -0.02em; color: var(--ink);
  white-space: nowrap; padding-left: 1.4vw;
}
.fm-part i {
  display: block; flex-shrink: 0;
  width: clamp(74px, 9vh, 130px); height: clamp(36px, 5vh, 62px);
  margin-inline: 1.1vw; border-radius: 999px;
  background-size: cover; background-position: 50% 50%;
  box-shadow: 0 6px 16px rgba(14, 12, 11, 0.22);
}

@media (prefers-reduced-motion: reduce) {
  .fm-track { animation: none; }
  .fm-row:hover .fm-label { opacity: 1; }
  .fm-marquee { display: none; }
}

/* ==========================================================================
   Word of mouth — their own Google and Yelp reviews
   ========================================================================== */
.proof {
  position: relative; background: var(--ink-2); padding-block: var(--section);
  background-image: radial-gradient(rgba(243,231,216,0.055) 1px, transparent 1px);
  background-size: 26px 26px;
}
.proof-head {
  display: flex; flex-wrap: wrap; justify-content: space-between;
  align-items: flex-end; gap: clamp(1rem, 3vw, 2.4rem);
}
.proof h2 { font-size: var(--step-4); line-height: 1.02; margin-top: 0.4rem; }
.proof h2 em { font-style: normal; color: var(--milk-dim); display: block; }
.proof-num { display: flex; align-items: baseline; gap: 0.7rem; }
.proof-num span {
  font-family: var(--display); font-weight: 700; line-height: 0.8;
  font-size: clamp(3.4rem, 8vw, 6.5rem); letter-spacing: -0.04em;
  color: var(--orange); font-variant-numeric: tabular-nums;
}
.proof-num small {
  font-family: var(--mono); font-size: 0.66rem; letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--milk-dim); max-width: 9ch; line-height: 1.4;
}

/* Three columns that travel at slightly different rates as the section
   passes, so the wall reads as alive rather than as a table of quotes. Each
   column is moved by exactly one tween; the cards themselves are never
   touched by script, so a card's own hover cannot fight the column. */
.rv-wall {
  display: grid; gap: clamp(0.7rem, 1.4vw, 1rem);
  grid-template-columns: 1fr; margin-top: clamp(2.4rem, 5vw, 3.6rem);
}
@media (min-width: 720px)  { .rv-wall { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1040px) { .rv-wall { grid-template-columns: repeat(3, 1fr); } }
.rv-col { display: grid; gap: clamp(0.7rem, 1.4vw, 1rem); align-content: start; will-change: transform; }
@media (min-width: 1040px) { .rv-wall > .rv-col:nth-child(2) { margin-top: 2.4rem; } }

.rv {
  margin: 0; padding: clamp(1.1rem, 2vw, 1.5rem);
  border: 1px solid var(--line); border-radius: 16px;
  background: rgba(243,231,216,0.035);
  transition: transform 0.4s cubic-bezier(0.22,0.61,0.36,1),
              border-color 0.4s ease, background 0.4s ease;
}
.rv:hover {
  transform: translateY(-4px);
  border-color: rgba(254,102,0,0.4); background: rgba(254,102,0,0.05);
}
.rv-stars { color: var(--orange); font-size: 0.85rem; letter-spacing: 0.16em; display: block; }
.rv blockquote {
  margin: 0.8rem 0 1rem; padding: 0; border: 0;
  font-size: var(--step--1); line-height: 1.62; color: var(--milk);
}
.rv figcaption { display: flex; flex-direction: column; gap: 0.2rem; }
.rv-who { font-family: var(--display); font-size: 1rem; color: var(--milk); }
.rv-src {
  font-family: var(--mono); font-size: 0.62rem; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--milk-dim);
}

.proof-links {
  display: grid; gap: clamp(0.8rem, 2vw, 1.2rem);
  margin-top: clamp(2rem, 4vw, 3rem);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
  perspective: 900px;
}
.plat {
  position: relative; overflow: hidden;
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 1rem; padding: clamp(1.4rem, 2.6vw, 2.1rem);
  border: 1px solid var(--line); border-radius: 16px;
  background: rgba(243,231,216,0.03); transform-style: preserve-3d;
  transition: border-color 0.35s ease, background 0.35s ease;
}
.plat:hover { border-color: rgba(254,102,0,0.5); background: rgba(254,102,0,0.06); }
.plat::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(circle 240px at var(--px, 50%) var(--py, 50%),
    rgba(255,201,138,0.16), transparent 70%);
  opacity: 0; transition: opacity 0.35s ease;
}
.plat:hover::after { opacity: 1; }
.plat-name { font-family: var(--display); font-size: clamp(1.6rem, 3.4vw, 2.4rem); line-height: 1; }
.plat-go {
  font-family: var(--mono); font-size: 0.68rem; letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--orange); white-space: nowrap;
}

@media (prefers-reduced-motion: reduce) {
  .sig-ring, .sig-cut, .sig-cut.is-on { animation: none; }
  .sig-cut, .sig-panel, .rv { transition: none; }
}

/* ==========================================================================
   Wordmark — colour appears only inside the letters, under the cursor
   ========================================================================== */
.wordmark {
  position: relative; overflow: hidden;
  padding-block: clamp(6rem, 12vw, 11rem) clamp(9rem, 18vw, 15rem);
  background: var(--ink-2);
}
.wm-type {
  position: absolute; inset: auto 0 -4%; text-align: center;
  pointer-events: none; user-select: none; line-height: 0.78;
  /* Sits behind the panel; the panel's own z-index lifts it clear. */
  z-index: 0;
}
.wm-base, .wm-glow {
  font-family: var(--display); font-weight: 700;
  font-size: clamp(4rem, 16vw, 15rem); letter-spacing: -0.03em;
  white-space: nowrap; display: block;
}
.wm-base { color: rgba(243, 231, 216, 0.045); }
/* The lit copy sits exactly on top and is clipped to the glyphs, so the
   radial highlight can never spill outside the letterforms. */
.wm-glow {
  position: absolute; inset: 0;
  /* Soft and diffuse, not a torch beam. A three-stop gradient with hard
     edges read as a flashlight disc; the light in the reference falls off
     gradually over a wide radius and never reaches full opacity, so it sits
     inside the letters rather than burning through them. */
  background-image: radial-gradient(
    circle 300px at var(--mx, 50%) var(--my, 50%),
    rgba(255, 201, 138, 0.92) 0%,
    rgba(254, 102, 0, 0.70) 16%,
    rgba(220, 96, 20, 0.44) 32%,
    rgba(170, 80, 30, 0.24) 48%,
    rgba(120, 60, 30, 0.10) 64%,
    transparent 82%);
  animation: wm-hue 8s linear infinite;
  will-change: filter;
  /* Hidden until the pointer is actually over the type. */
  opacity: 0;
  transition: opacity .55s ease;
  -webkit-background-clip: text; background-clip: text;
  color: transparent;
  transition: opacity .4s;
}
@keyframes wm-hue {
  from { filter: hue-rotate(0deg) saturate(0.92); }
  to   { filter: hue-rotate(360deg) saturate(0.92); }
}

/* Without a pointer there is nothing to follow, so warm the whole word.
   background-image, never the `background` shorthand: the shorthand resets
   background-clip to border-box, which unclips the gradient and paints a
   solid bar across the section. */
/* No pointer to follow, so light the word gently and leave it visible. */
/* On a laptop the wordmark is deliberately wider than the screen and runs off
   both edges. On a phone that stops being a device and becomes a bug: at
   407px only the middle of one word survives the crop, which says nothing.
   Below this width it wraps to two lines and is sized to fit the column, so
   the whole name is legible; nowrap is what was forcing the overflow. */
@media (max-width: 760px) {
  /* Inset rather than padded. The lit copy is positioned inset:0, which
     resolves against the padding box, so padding here would make the glow
     wider than the base underneath it: the two would then wrap at different
     points and the word would appear twice, offset. */
  .wm-type { inset: auto var(--gutter) clamp(1.5rem, 5vw, 3rem); }
  .wm-base, .wm-glow {
    white-space: normal;
    font-size: clamp(2.5rem, 13.5vw, 5rem);
    line-height: 0.92; letter-spacing: -0.02em;
  }
  .wordmark { padding-bottom: clamp(11rem, 34vw, 15rem); }
}

@media (hover: none) {
  .wm-glow {
    background-image: linear-gradient(100deg,
      rgba(254,102,0,0.75), rgba(201,135,63,0.45) 55%, transparent);
    animation-duration: 16s;
    opacity: 1;
  }
}
@media (prefers-reduced-motion: reduce) {
  .wm-glow { animation: none; filter: none; }
}

.wm-panel {
  position: relative; z-index: 2;
  display: grid; gap: clamp(2rem, 5vw, 4rem);
  grid-template-columns: 1fr;
}
@media (min-width: 860px) { .wm-panel { grid-template-columns: 1.1fr 1fr; } }
.wm-lead h2 { margin-block: 0.8rem 0.8rem; }
.wm-lead .hero-actions { margin-top: 1.6rem; }

.wm-cols { display: grid; gap: 1.8rem; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); }
.wm-cols h4 {
  font-family: var(--mono); font-size: var(--step--1); letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--orange); margin-bottom: 0.9rem; font-weight: 700;
}
.wm-cols ul { list-style: none; padding: 0; display: grid; gap: 0.55rem; }
.wm-cols li { display: flex; justify-content: space-between; gap: 1rem; color: var(--milk-dim); font-size: var(--step--1); }
.wm-cols a:hover { color: var(--milk); }

/* One footer, not two: the wordmark section already carries the address,
   hours and ordering, so all that is left is the legal line. */
.wm-base-row {
  background: var(--ink-2); border-top: 1px solid var(--line);
  padding-block: 1.3rem; font-size: var(--step--1); color: var(--milk-dim);
}
.wm-base-row .wrap {
  display: flex; justify-content: space-between; gap: 1rem; flex-wrap: wrap;
}

/* ==========================================================================
   Fly-through — the logo is an aperture that opens onto the corridor
   ========================================================================== */
.flythrough { height: 460vh; position: relative; }

.fly-stage {
  position: sticky; top: 0; height: 100svh; overflow: hidden;
  display: grid; grid-template-rows: 1fr auto;
  align-items: center; justify-items: center;
  padding: clamp(5.5rem, 12vh, 7.5rem) var(--gutter) clamp(4rem, 9vh, 6rem);
}
/* Warm white sits behind everything; the aperture opening over it is what
   turns the page dark, so no colour tween is needed. */
.fly-sky { position: absolute; inset: 0; background: #F5F2EC; z-index: 0; }

/* Full-screen and masked. The aperture is animated through mask-size rather
   than by scaling the element, because scaling would enlarge the photographs
   inside it too and they have to stay at corridor scale. */
.fly-window {
  position: absolute; inset: 0; z-index: 1;
  /* Two masks unioned. The mark alone is a thin stroke drawing, so once it
     is enlarged the openings are narrow bands and the photographs fall in the
     gaps between them. The iris opens from the centre of the mark and takes
     over, which is what makes it read as going inside rather than past. */
  /* The iris is centred by moving the circle *inside* its gradient, not by
     moving the layer. mask-position shifts the whole box, and this box is
     exactly 100% x 100% with no-repeat, so offsetting it by --cy left a strip
     at the top of the screen with no mask layer over it at all: that strip
     stayed the warm white of .fly-sky for the whole scroll. */
  -webkit-mask-image: var(--mark-mask), radial-gradient(circle at 50% calc(50% + var(--cy, 0px)),
      #000 0, #000 var(--iris, 0px), transparent var(--iris, 0px));
          mask-image: var(--mark-mask), radial-gradient(circle at 50% calc(50% + var(--cy, 0px)),
      #000 0, #000 var(--iris, 0px), transparent var(--iris, 0px));
  -webkit-mask-size: var(--ap, 300px) auto, 100% 100%;
          mask-size: var(--ap, 300px) auto, 100% 100%;
  /* Only the mark is repositioned. The iris layer stays at center so its box
     always covers the whole element; its circle is already offset by the same
     --cy inside the gradient above, so the two remain concentric. */
  -webkit-mask-position: center calc(50% + var(--cy, 0px)), center;
          mask-position: center calc(50% + var(--cy, 0px)), center;
  -webkit-mask-repeat: no-repeat, no-repeat; mask-repeat: no-repeat, no-repeat;
  -webkit-mask-composite: source-over; mask-composite: add;
  /* 1200, not 900: a panel blows up as its z approaches the perspective
     distance and inverts once it passes, which is what made the photographs
     flicker near the end of the flight. The travel is now capped so the
     nearest panel never gets closer than a third of this. */
  perspective: 1200px; perspective-origin: 50% 50%;
}
.fly-void { position: absolute; inset: 0; background: var(--ink); }

/* Aurora ------------------------------------------------------------------
   Four soft lights drifting behind the corridor, so the dark the photographs
   fly through has some depth in it instead of being flat black at the edges.

   The reference does this with a WebGL noise field; this is four radial
   gradients, heavily blurred and slowly moved along paths that do not share
   a period, so they never return to the same arrangement twice. There is no
   canvas, no GL context and nothing in script: it is CSS keyframes on four
   elements nothing else touches, which is also why it cannot end up fighting
   the corridor the way two writers on one property would.

   Colours are from the counter rather than the usual green and violet: burnt
   orange, an amber, a deep rust, and one cool jade for the tea to keep the
   warm ones from turning muddy where they cross. */
.aurora {
  position: absolute; inset: -25%; z-index: 0;
  pointer-events: none; overflow: hidden;
  filter: blur(88px) saturate(1.1);
  /* Enough to feel lit, not enough to read as a colour wash: the photographs
     are the subject and the light is the room they are in. */
  opacity: 0.38;
}
.aurora i {
  position: absolute; display: block; border-radius: 50%;
  /* screen, so where two lights cross they add rather than one covering the
     other, which is what stops it looking like drifting cut-outs. */
  mix-blend-mode: screen;
  will-change: transform;
}
.au-1 {
  width: 58%; height: 62%; left: -8%; top: -6%;
  background: radial-gradient(circle, rgba(254,102,0,0.55), rgba(254,102,0,0) 68%);
  animation: au-a 27s ease-in-out infinite;
}
.au-2 {
  width: 52%; height: 56%; right: -10%; top: 4%;
  background: radial-gradient(circle, rgba(255,168,64,0.42), rgba(255,168,64,0) 66%);
  animation: au-b 34s ease-in-out infinite;
}
.au-3 {
  width: 64%; height: 58%; left: 6%; bottom: -14%;
  background: radial-gradient(circle, rgba(178,44,12,0.50), rgba(178,44,12,0) 70%);
  animation: au-c 23s ease-in-out infinite;
}
.au-4 {
  width: 44%; height: 48%; right: 2%; bottom: -8%;
  background: radial-gradient(circle, rgba(46,138,110,0.34), rgba(46,138,110,0) 68%);
  animation: au-d 31s ease-in-out infinite;
}
/* Deliberately different periods and paths: with matching ones the four would
   line up on a cycle and the movement would start to read as a loop. */
@keyframes au-a {
  0%,100% { transform: translate3d(0,0,0) scale(1); }
  33%     { transform: translate3d(14%, 10%, 0) scale(1.12); }
  66%     { transform: translate3d(-8%, 16%, 0) scale(0.94); }
}
@keyframes au-b {
  0%,100% { transform: translate3d(0,0,0) scale(1.05); }
  40%     { transform: translate3d(-16%, 12%, 0) scale(0.92); }
  70%     { transform: translate3d(-6%, -10%, 0) scale(1.16); }
}
@keyframes au-c {
  0%,100% { transform: translate3d(0,0,0) scale(0.98); }
  45%     { transform: translate3d(12%, -14%, 0) scale(1.18); }
  75%     { transform: translate3d(20%, -4%, 0) scale(1.02); }
}
@keyframes au-d {
  0%,100% { transform: translate3d(0,0,0) scale(1.1); }
  50%     { transform: translate3d(-18%, -12%, 0) scale(0.9); }
}

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

.corridor-row { position: absolute; inset: 0; transform-style: preserve-3d; will-change: transform; }
.corridor-row .panel {
  position: absolute; top: 50%; left: 50%;
  width: clamp(150px, 15vw, 240px); aspect-ratio: 3 / 4;
  margin: 0; border-radius: 10px; overflow: hidden;
  box-shadow: 0 30px 60px rgba(0,0,0,0.6);
  transform-style: preserve-3d; backface-visibility: hidden;
}
.corridor-row .panel img { width: 100%; height: 100%; object-fit: cover; }

.fly-copy {
  position: relative; z-index: 3; grid-row: 2; text-align: center;
  width: min(100%, 760px); color: #1A1512;
}
.fly-copy .eyebrow { justify-content: center; color: var(--orange-dim); }
.fly-copy h1 { font-size: clamp(2.1rem, 5.6vw, 4.4rem); margin-block: 0.6rem 0.7rem; }
.fly-copy h1 em {
  font-style: normal; color: var(--orange); display: block;
  font-variation-settings: "SOFT" 60, "WONK" 1, "opsz" 144;
}
.fly-lede { font-size: var(--step-0); color: #6B5C50; max-width: 46ch; margin-inline: auto; }

/* Arrives once you are inside, over the corridor. */
.corridor-copy {
  position: absolute; z-index: 4; text-align: center; pointer-events: none;
  padding-inline: var(--gutter); opacity: 0;
}
.corridor-copy h2 {
  font-size: var(--step-4); line-height: 0.92;
  text-shadow: 0 6px 40px rgba(14,12,11,0.95), 0 2px 14px rgba(14,12,11,0.9);
}

.fly-cue {
  position: absolute; z-index: 3; bottom: 1.4rem; left: 50%; translate: -50% 0;
  font-family: var(--mono); font-size: 0.66rem; letter-spacing: 0.24em;
  text-transform: uppercase; color: #8A7A6C;
  display: flex; align-items: center; gap: 0.6rem;
}
.fly-cue span { width: 1px; height: 30px; background: linear-gradient(var(--orange), transparent); }

/* The mark is tall and centred, so its lower stroke hangs straight over a
   centred headline. Given the room, the copy moves out beside it instead.
   Narrower than this there is no room for a column, so it stays underneath
   and the aperture lifts (--cy in the script) to clear it. */
@media (min-width: 1200px) {
  .fly-stage { grid-template-rows: 1fr; }
  .fly-copy {
    grid-row: 1; align-self: center; justify-self: start;
    text-align: left; width: min(32%, 25rem);
  }
  .fly-copy .eyebrow { justify-content: flex-start; }
  .fly-copy h1 { font-size: clamp(2rem, 3.4vw, 3.1rem); }
  .fly-lede { margin-inline: 0; max-width: 32ch; }
}

/* Under this height the nav, a stacked mark and a headline cannot all fit,
   and fitting the mark to what is left leaves it too small to read as a logo.
   Rather than let them collide, the section falls back to the same static
   arrangement used for reduced motion. */
@media (max-height: 560px) and (max-width: 1199px) {
  .flythrough { height: auto; }
  .fly-stage { position: relative; height: auto; padding-block: 7rem 3.5rem; }
  .fly-sky { background: var(--ink); }
  .fly-window { position: relative; height: 62svh; -webkit-mask-image: none; mask-image: none; }
  .fly-copy { color: var(--milk); margin-top: 2rem; }
  .fly-lede { color: var(--milk-dim); }
  .fly-cue { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .flythrough { height: auto; }
  .fly-stage { position: relative; height: auto; padding-block: 8rem 4rem; }
  .fly-sky { background: var(--ink); }
  .fly-window { position: relative; height: 60svh; -webkit-mask-image: none; mask-image: none; }
  .fly-copy { color: var(--milk); margin-top: 2rem; }
  .fly-lede { color: var(--milk-dim); }
  .fly-cue { display: none; }
}


/* ==========================================================================
   Menu page
   A list this long is only useful if you can find your way around it, so the
   page is an index and eleven sections rather than one running list. The
   index is sticky on a wide window and a scrolling rail of chips on a narrow
   one, and it follows you down the page either way.
   ========================================================================== */
.mhero {
  position: relative; overflow: hidden;
  min-height: 92svh; display: grid; align-content: center;
  padding-block: clamp(7rem, 15vh, 10rem) clamp(3rem, 8vh, 5rem);
  background: var(--ink);
}
.mhero-in { position: relative; z-index: 1; max-width: 62rem; }
.mhero-title {
  font-family: var(--display); font-weight: 700; line-height: 0.94;
  font-size: clamp(2.6rem, 8.5vw, 6.5rem); letter-spacing: -0.03em;
  margin-block: 0.5rem 1.1rem;
}
.mhero-title em {
  font-style: normal; color: var(--orange); display: block;
  font-variation-settings: "SOFT" 60, "WONK" 1, "opsz" 144;
}
.mhero-lede { font-size: var(--step-1); color: var(--milk-dim); max-width: 46ch; }
.mhero-figs {
  display: flex; flex-wrap: wrap; gap: clamp(1.4rem, 4vw, 3rem);
  margin: clamp(1.8rem, 4vh, 2.8rem) 0 clamp(1.6rem, 3vh, 2.2rem);
}
.mhero-figs span {
  font-family: var(--mono); font-size: 0.68rem; letter-spacing: 0.2em;
  text-transform: uppercase; color: var(--milk-dim);
  display: flex; align-items: baseline; gap: 0.5rem;
}
.mhero-figs b {
  font-family: var(--display); font-weight: 700; font-size: clamp(2rem, 4.6vw, 3.2rem);
  color: var(--milk); letter-spacing: -0.03em; font-variant-numeric: tabular-nums;
}

/* Index + sections ------------------------------------------------------- */
.mwrap {
  /* --max, not --maxw. The name I used does not exist, and an undefined
     variable makes the whole min() invalid, so the width was dropped and this
     ran edge to edge at every size - which is why the index sat hard against
     the left of the screen. */
  width: min(100% - var(--gutter) * 2, var(--max));
  margin-inline: auto;
  display: grid; gap: clamp(2rem, 5vw, 4rem);
  padding-block: var(--section);
}
@media (min-width: 1040px) {
  .mwrap { grid-template-columns: minmax(0, 15rem) minmax(0, 1fr); align-items: start; }
  .mx { position: sticky; top: 7.5rem; }
}
.mx { display: flex; flex-direction: column; gap: 0.1rem; }
.mx-link {
  display: grid; grid-template-columns: auto 1fr auto; align-items: baseline;
  gap: 0.7rem; padding: 0.6rem 0.7rem; border-radius: 10px;
  color: var(--milk-dim); border: 1px solid transparent;
  transition: color 0.3s, background 0.3s, border-color 0.3s;
}
.mx-link:hover { color: var(--milk); background: rgba(243,231,216,0.05); }
.mx-link.is-here {
  color: var(--milk); border-color: rgba(254,102,0,0.4);
  background: rgba(254,102,0,0.07);
}
.mx-no { font-family: var(--mono); font-size: 0.62rem; letter-spacing: 0.14em; color: var(--orange); }
.mx-name { font-family: var(--display); font-size: 1rem; line-height: 1.15; }
.mx-count { font-family: var(--mono); font-size: 0.62rem; color: var(--milk-dim); }

/* Below the breakpoint it becomes a rail you can swipe, pinned under the bar */
@media (max-width: 1039px) {
  .mx {
    flex-direction: row; gap: 0.4rem; overflow-x: auto; scrollbar-width: none;
    overscroll-behavior-x: contain;      /* no page-swipe out of the rail */
    position: sticky; top: 4.6rem; z-index: 20;
    /* Bleeds to both screen edges so the chips can run off the side, but its
       contents start at the gutter like everything else. */
    padding: 0.55rem var(--gutter);
    margin-inline: calc(var(--gutter) * -1);
    background: linear-gradient(var(--ink) 72%, transparent);
    /* Faded at both ends, so a chip cut off by the edge reads as more to
       scroll to rather than as a chip that has been clipped. */
    -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 var(--gutter),
      #000 calc(100% - var(--gutter)), transparent 100%);
            mask-image: linear-gradient(90deg, transparent 0, #000 var(--gutter),
      #000 calc(100% - var(--gutter)), transparent 100%);
  }
  .mx::-webkit-scrollbar { display: none; }
  .mx-link {
    flex: 0 0 auto; border: 1px solid var(--line); border-radius: 999px;
    padding: 0.5rem 0.9rem; background: var(--ink-2);
  }
  .mx-count { display: none; }
}

.msections { display: grid; gap: clamp(3rem, 8vh, 6rem); }
.ms { scroll-margin-top: 7.5rem; }

/* The heading, its photograph and its note are one column and the list is
   the other. They were stacked before, with the photograph sticky inside a
   short block, so it travelled down past its own section and came to rest
   beside the next one's heading. Keeping them in the same column means the
   picture cannot drift away from the name of the thing it is a picture of. */
.ms-body { display: grid; gap: clamp(1.2rem, 3vw, 2.4rem); align-items: start; }
@media (min-width: 860px) {
  .ms { display: grid; grid-template-columns: minmax(0, 21rem) minmax(0, 1fr);
        gap: clamp(1.6rem, 4vw, 3.2rem); align-items: start; }
  .ms-head { position: sticky; top: 7.5rem; margin-bottom: 0; }
  .ms-body { grid-template-columns: 1fr; }
}
.ms-head { margin-bottom: clamp(1rem, 2.5vh, 1.6rem); }
.ms-no {
  font-family: var(--mono); font-size: 0.66rem; letter-spacing: 0.22em;
  text-transform: uppercase; color: var(--orange);
}
.ms-no span { color: var(--milk-dim); margin-left: 0.6rem; }
.ms-head h2 { font-size: clamp(1.7rem, 3.4vw, 2.6rem); line-height: 1.0; margin-top: 0.4rem; }
.ms-head h2 em {
  font-style: normal; color: var(--orange); display: block;
  font-variation-settings: "SOFT" 60, "WONK" 1, "opsz" 144;
}
.ms-note { color: var(--milk-dim); margin-top: 0.7rem; max-width: 34ch; font-size: var(--step--1); }

.ms-shot {
  position: relative; margin: 1.2rem 0 0; border-radius: 14px; overflow: hidden;
  aspect-ratio: 4 / 3; background: var(--ink-2);
  /* Bounded, because on a narrow window it is no longer in a column that
     limits it and a full-width slab of photograph would push the list off
     the screen. */
  max-width: 21rem;
}
.ms-shot > img:first-child { width: 100%; height: 100%; object-fit: cover; }
.ms-shot::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(to top, rgba(14,12,11,0.72), transparent 60%);
}
.ms-cut {
  position: absolute; z-index: 2; left: 50%; bottom: -8%;
  width: 46%; translate: -50% 0;
  filter: drop-shadow(0 16px 26px rgba(0,0,0,0.6));
}
/* Where the rows carry their own photographs the section one is redundant,
   and two pictures of the same food fight each other. Only applied when most
   of the section is covered, so one lone photograph does not cost the others
   their picture. */
.ms-has-shots .ms-shot { display: none; }

.ms-list { list-style: none; margin: 0; padding: 0; }
.mi {
  display: grid; grid-template-columns: auto 1fr auto; align-items: center;
  gap: 0.8rem; padding: 0.5rem 0.6rem; border-radius: 10px;
  /* Capped, so the leader stays a join between two things rather than a rule
     across the whole window. */
  max-width: 46rem;
  transition: background 0.25s;
}
/* Per row, not per section. A section can hold a mix - Milk Tea has a
   photograph for Tiger Milk Boba and for nothing else - and giving every row
   in it a column for a picture left the other twenty-one with an empty slot,
   which collapsed the leader and pushed the price off on its own. */
.mi:has(.mi-shot) { grid-template-columns: auto auto 1fr auto; }
.mi:hover { background: rgba(243,231,216,0.05); }
.mi:hover .mi-price { color: var(--orange); }
.mi + .mi { border-top: 1px solid rgba(243,231,216,0.06); }
.mi-shot {
  display: block; width: clamp(38px, 4.4vw, 52px); aspect-ratio: 1;
  border-radius: 9px; overflow: hidden; flex: none; background: var(--ink-2);
}
.mi-shot img { width: 100%; height: 100%; object-fit: cover; display: block; }
.mi-name { color: var(--milk); font-size: var(--step--1); }
.mi-dots {
  height: 1px; align-self: center; min-width: 1.5rem;
  background-image: radial-gradient(circle, rgba(243,231,216,0.34) 1px, transparent 1px);
  background-size: 6px 1px; background-repeat: repeat-x;
}
.mi-price {
  font-family: var(--mono); font-size: var(--step--1); color: var(--milk-dim);
  font-variant-numeric: tabular-nums; transition: color 0.25s;
  /* Fixed width so every price in a section lines up on its decimal point
     instead of each one ending where its own digits happen to stop. */
  min-width: 4.2em; text-align: right;
}
.mi-price::before { content: "$"; opacity: 0.55; margin-right: 0.1em; }

.ms-addon .ms-body { grid-template-columns: 1fr; }
.ms-addon .ms-shot { display: none; }
.ms-addon .ms-list {
  display: grid; gap: 0.5rem; max-width: none;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 14rem), 1fr));
}
.ms-addon .mi { border: 1px solid var(--line); border-radius: 999px; padding: 0.55rem 1rem; max-width: none; }
.ms-addon .mi + .mi { border-top: 1px solid var(--line); }
.ms-addon .mi-dots { display: none; }
.ms-addon .mi-price { min-width: 0; }

.mfoot { margin-top: clamp(2rem, 5vh, 3.5rem); }
.mfoot a { color: var(--orange); }

/* Page transition ---------------------------------------------------------
   Going from the white hero straight into the dark menu was a hard cut. A
   sheet of ink covers the change instead: it is opaque on arrival and clears
   itself, and the script draws it back over before it follows a link.

   The clearing is a CSS animation, not script, on purpose. It runs on every
   load whether or not the JS arrives, so a failure can never leave the page
   behind a black sheet - the worst case is a cut, which is what we had. */
.page-veil {
  position: fixed; inset: 0; z-index: 9999;
  background: var(--ink); pointer-events: none; opacity: 1;
  animation: veil-clear 0.62s cubic-bezier(0.22, 0.61, 0.36, 1) forwards;
}
@keyframes veil-clear { to { opacity: 0; visibility: hidden; } }

@media (prefers-reduced-motion: reduce) {
  .page-veil { display: none; }
}

/* The corridor photographs answer to a pointer -------------------------- */
.corridor-row .panel { cursor: default; }
.panel-name {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 2;
  padding: 2.2rem 0.7rem 0.6rem;
  font-family: var(--mono); font-size: 0.58rem; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--milk); text-align: center;
  background: linear-gradient(to top, rgba(14,12,11,0.92), transparent);
  opacity: 0; translate: 0 40%;
  transition: opacity 0.32s ease, translate 0.42s cubic-bezier(0.22,0.61,0.36,1);
  pointer-events: none;
}
.corridor-row .panel.is-named .panel-name { opacity: 1; translate: 0 0; }
/* A hairline of the house orange, so the one under the pointer is obvious
   even at the far end of the corridor where the name is small. */
.corridor-row .panel::after {
  content: ""; position: absolute; inset: 0; z-index: 1;
  border-radius: inherit; border: 1px solid transparent;
  transition: border-color 0.32s ease;
}
.corridor-row .panel.is-named::after { border-color: rgba(254, 102, 0, 0.85); }

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

/* Faded out of the way: no longer in the way of the pointer either. */
.fly-copy.is-gone { pointer-events: none; }
.fly-cue { pointer-events: none; }

/* ==========================================================================
   About
   No cover panel. The page opens on the first thing they say about
   themselves, and reading it is what carries you down: the words light one
   after another as you scroll, so the sentence is the scroll rather than
   something laid on top of it.
   ========================================================================== */
.lit-block {
  position: relative; overflow: hidden; background: var(--ink);
  min-height: 100svh; display: grid; align-content: center;
  padding-block: clamp(7rem, 15vh, 10rem) clamp(4rem, 10vh, 7rem);
}
.lit-alt { background: var(--ink-2); }
.lit-close { background: var(--ink); }
.lit-block > .wrap { position: relative; z-index: 1; }

/* The year, set behind the sentence at the size of the thing it stands for. */
.lit-mark {
  position: absolute; z-index: 0; inset: auto 0 -6% 0; text-align: center;
  font-family: var(--display); font-weight: 700; line-height: 0.75;
  font-size: clamp(9rem, 34vw, 30rem); letter-spacing: -0.05em;
  color: rgba(243, 231, 216, 0.035); pointer-events: none; user-select: none;
}

.lit {
  font-family: var(--display); font-weight: 400;
  font-size: clamp(1.7rem, 5.2vw, 4.4rem); line-height: 1.14;
  letter-spacing: -0.025em; max-width: 22ch;
}
.lit-close .lit { max-width: 20ch; }
/* Each word starts dim and is brought up by the scroll. Set here rather than
   in script so a page with no JS shows the sentence at full strength instead
   of a paragraph of ghosts. */
.js .lit .lw { color: rgba(243, 231, 216, 0.16); transition: none; }
.lit .lw { display: inline-block; }

.lit-visit {
  display: grid; gap: clamp(1.2rem, 3vw, 2.4rem);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 12rem), 1fr));
  margin-block: clamp(2rem, 5vh, 3rem) clamp(1.4rem, 3vh, 2rem);
  max-width: 46rem;
}
.lit-visit h4 {
  font-family: var(--mono); font-size: 0.62rem; letter-spacing: 0.2em;
  text-transform: uppercase; color: var(--orange); margin-bottom: 0.7rem;
}
.lit-visit ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.4rem; }
.lit-visit li { display: flex; justify-content: space-between; gap: 1rem; color: var(--milk-dim); font-size: var(--step--1); }
.lit-visit a { color: var(--milk-dim); }
.lit-visit a:hover { color: var(--orange); }

/* The counts, as a strip that runs sideways while the section holds still.
   Pinned, so the whole set is read without leaving the screen - the same rule
   the popular items follow. */
.hstrip {
  position: relative; background: var(--ink-2); overflow: hidden;
  min-height: 100svh; display: grid; align-content: center;
  padding-block: clamp(6rem, 12vh, 8rem);
}
.hstrip-head { width: min(100% - var(--gutter) * 2, var(--max)); margin-inline: auto; }
.hstrip-rail {
  display: flex; gap: clamp(0.8rem, 2vw, 1.4rem);
  padding-inline: var(--gutter); margin-top: clamp(1.5rem, 4vh, 2.5rem);
  width: max-content; will-change: transform;
}
.hcard {
  flex: 0 0 auto; width: clamp(240px, 30vw, 380px);
  border: 1px solid var(--line); border-radius: 18px;
  padding: clamp(1.2rem, 2.4vw, 1.8rem);
  background: rgba(243, 231, 216, 0.03);
  display: flex; flex-direction: column;
}
.hcard b {
  font-family: var(--display); font-weight: 700; line-height: 0.88;
  font-size: clamp(2.8rem, 6vw, 4.4rem); color: var(--orange);
  letter-spacing: -0.03em; font-variant-numeric: tabular-nums;
}
.hcard > span {
  margin-top: 0.5rem; font-family: var(--mono); font-size: 0.62rem;
  letter-spacing: 0.18em; text-transform: uppercase; color: var(--milk);
}
.hcard p { margin-top: 0.8rem; color: var(--milk-dim); font-size: var(--step--1); }
.hcard img {
  margin-top: auto; width: 100%; aspect-ratio: 16 / 10; object-fit: cover;
  border-radius: 12px; padding-top: 1.2rem;
}
.hcard-end { justify-content: space-between; }
.hcard-end .btn { margin-top: 1.4rem; align-self: flex-start; }

/* Nothing to pin against on a narrow window, so it becomes a normal stack. */
@media (max-width: 780px) {
  .hstrip { min-height: 0; padding-block: var(--section); }
  .hstrip-rail { width: auto; flex-direction: column; }
  .hcard { width: auto; }
}

.aroom { padding-block: var(--section); }
.aroom-grid { display: grid; gap: clamp(1.6rem, 4vw, 3.2rem); align-items: center; }
@media (min-width: 880px) { .aroom-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); } }
.aroom-shot { margin: 0; border-radius: 18px; overflow: hidden; aspect-ratio: 4 / 5; }
.aroom-shot img { width: 100%; height: 100%; object-fit: cover; }
.aroom-copy h2 { font-size: var(--step-3); line-height: 1.02; margin-top: 0.5rem; }
.aroom-copy h2 em {
  font-style: normal; color: var(--orange); display: block;
  font-variation-settings: "SOFT" 60, "WONK" 1, "opsz" 144;
}
.aroom-copy .muted { margin-top: 1rem; }
/* Theirs, not ours: set apart so it reads as a quotation and not as copy. */
.aroom-quote {
  margin: clamp(1.4rem, 3vh, 2rem) 0 0; padding-left: 1.1rem;
  border-left: 2px solid rgba(254,102,0,0.55);
}
.aroom-quote blockquote {
  margin: 0; border: 0; padding: 0;
  font-size: var(--step-0); line-height: 1.55; color: var(--milk);
}
.aroom-quote figcaption {
  display: flex; gap: 0.7rem; align-items: baseline; margin-top: 0.6rem;
  font-family: var(--mono); font-size: 0.6rem; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--milk-dim);
}
.aroom-quote figcaption span:first-child { color: var(--milk); }

.avisit-grid {
  display: grid; gap: clamp(1.2rem, 3vw, 2.4rem);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 12rem), 1fr));
  margin-block: clamp(1.6rem, 4vw, 2.6rem);
}
.avisit-grid h4 {
  font-family: var(--mono); font-size: 0.64rem; letter-spacing: 0.2em;
  text-transform: uppercase; color: var(--orange); margin-bottom: 0.8rem;
}
.avisit-grid ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.45rem; }
.avisit-grid li { display: flex; justify-content: space-between; gap: 1rem; color: var(--milk-dim); font-size: var(--step--1); }
.avisit-grid a { color: var(--milk-dim); }
.avisit-grid a:hover { color: var(--orange); }

/* About: the sentence and what it is about, side by side ------------------ */
.lit-row { display: grid; gap: clamp(2rem, 5vw, 4rem); align-items: center; }
@media (min-width: 980px) {
  .lit-row { grid-template-columns: minmax(0, 1fr) minmax(0, 0.85fr); }
  .lit-row-wide { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
}
.lit-row .lit { max-width: 20ch; }

/* Three photographs at different depths. Scattered rather than stacked in a
   column, so the half of the screen the sentence leaves has a composition in
   it and not a list. */
.lit-stack { position: relative; aspect-ratio: 1 / 1; }
.ls { position: absolute; margin: 0; border-radius: 14px; overflow: hidden;
      box-shadow: 0 26px 50px rgba(0,0,0,0.55); will-change: transform; }
.ls img { width: 100%; height: 100%; object-fit: cover; display: block; }
.ls-1 { left: 2%;  top: 4%;  width: 58%; aspect-ratio: 4 / 3;  rotate: -3deg; z-index: 2; }
.ls-2 { right: 0;  top: 26%; width: 42%; aspect-ratio: 3 / 4;  rotate: 4deg;  z-index: 3; }
.ls-3 { left: 14%; bottom: 2%; width: 50%; aspect-ratio: 4 / 3; rotate: 2deg;  z-index: 1; }

/* One picture per thing the sentence names. */
.lit-four {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: clamp(0.7rem, 1.6vw, 1.1rem);
  grid-template-columns: repeat(2, 1fr);
}
.lit-four li { position: relative; will-change: transform; }
.lit-four img {
  width: 100%; aspect-ratio: 4 / 5; object-fit: cover;
  border-radius: 14px; display: block;
}
.lit-four li:nth-child(even) { margin-top: clamp(1rem, 4vw, 2.6rem); }
.lit-four span {
  display: block; margin-top: 0.6rem;
  font-family: var(--mono); font-size: 0.58rem; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--milk-dim);
}

/* The room ---------------------------------------------------------------- */
.room { position: relative; background: var(--ink-2); padding-block: var(--section); }
.room-head { margin-bottom: clamp(1.6rem, 4vh, 2.6rem); }
.room-head h2 { font-size: var(--step-3); line-height: 1.02; margin-top: 0.4rem; }
.room-head h2 em {
  font-style: normal; color: var(--orange); display: block;
  font-variation-settings: "SOFT" 60, "WONK" 1, "opsz" 144;
}
.room-stage { position: relative; }
@media (min-width: 900px) { .room-stage { padding-right: 22%; } }

.room-main { position: relative; margin: 0; border-radius: 20px; overflow: hidden; will-change: transform; }
.room-main img { width: 100%; aspect-ratio: 16 / 10; object-fit: cover; display: block; }
/* The quotation sits on the photograph because it is about the photograph. */
.room-main figcaption {
  position: absolute; inset: auto 0 0 0;
  padding: clamp(3rem, 8vw, 5rem) clamp(1.2rem, 3vw, 2.4rem) clamp(1.2rem, 2.5vw, 1.8rem);
  background: linear-gradient(to top, rgba(14,12,11,0.94) 30%, transparent);
}
.room-main blockquote {
  margin: 0; border: 0; padding: 0; max-width: 44ch;
  font-family: var(--display); font-size: clamp(1rem, 1.8vw, 1.5rem);
  line-height: 1.35; color: var(--milk);
}
.room-main figcaption span {
  display: block; margin-top: 0.7rem;
  font-family: var(--mono); font-size: 0.58rem; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--milk-dim);
}
.room-main figcaption b { color: var(--orange); font-weight: 400; margin-right: 0.5rem; }

.room-side { position: absolute; margin: 0; border-radius: 14px; overflow: hidden;
             box-shadow: 0 24px 44px rgba(0,0,0,0.6); will-change: transform; }
.room-side img { width: 100%; height: 100%; object-fit: cover; display: block; }
.room-side-a { right: 0; top: -6%; width: 26%; aspect-ratio: 3 / 4; rotate: 3deg; }
.room-side-b { right: 6%; bottom: -8%; width: 22%; aspect-ratio: 4 / 3; rotate: -4deg; }
@media (max-width: 899px) {
  .room-side { display: none; }
}
.room-note {
  margin-top: clamp(1.2rem, 3vh, 2rem); max-width: 46ch;
  color: var(--milk-dim); font-size: var(--step-0);
}

/* ==========================================================================
   Contact
   Their own page puts the phone number above everything, because calling is
   how the shop actually takes orders. So does this one.
   ========================================================================== */
.call {
  position: relative; overflow: hidden; background: var(--ink);
  min-height: 100svh; display: grid; align-content: center;
  padding-block: clamp(7rem, 14vh, 9rem) clamp(4rem, 9vh, 6rem);
}
.call-in { position: relative; z-index: 1; }

/* Open or closed, worked out from the clock in Houston. */
.call-status {
  display: inline-flex; align-items: center; gap: 0.55rem;
  padding: 0.4rem 0.9rem 0.4rem 0.7rem; border-radius: 999px;
  border: 1px solid var(--line); background: rgba(243,231,216,0.04);
  font-family: var(--mono); font-size: 0.62rem; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--milk-dim);
  margin-bottom: clamp(1rem, 3vh, 1.6rem);
}
.call-status b { color: var(--milk); font-weight: 400; }
.call-status .dot {
  width: 7px; height: 7px; border-radius: 50%; background: var(--milk-dim);
  box-shadow: 0 0 0 0 rgba(126, 217, 87, 0.5);
}
.call-status.is-open .dot { background: #7ED957; animation: pulse 2.4s ease-out infinite; }
.call-status.is-shut .dot { background: #C0563A; }
@keyframes pulse {
  0%   { box-shadow: 0 0 0 0 rgba(126, 217, 87, 0.45); }
  70%  { box-shadow: 0 0 0 9px rgba(126, 217, 87, 0); }
  100% { box-shadow: 0 0 0 0 rgba(126, 217, 87, 0); }
}

/* The number, at the size of the thing it is for. */
.call-num {
  display: inline-flex; align-items: baseline; gap: 0.12em;
  font-family: var(--display); font-weight: 700; line-height: 0.86;
  font-size: clamp(2.6rem, 11.5vw, 9rem); letter-spacing: -0.045em;
  color: var(--milk); margin-block: 0.3rem 0.1rem;
  padding: 0.06em 0.1em; border-radius: 18px;
}
.call-num i { color: var(--orange); font-style: normal; }
.call-num span { transition: color 0.3s ease; }
.call-num:hover span { color: var(--orange); }
.call-lede { font-size: var(--step-1); color: var(--milk-dim); max-width: 40ch; margin-top: 1rem; }

.call-ways {
  display: grid; gap: 0.5rem; margin-top: clamp(1.8rem, 4vh, 2.6rem);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
  max-width: 62rem;
}
.way {
  display: grid; gap: 0.3rem; padding: clamp(0.9rem, 2vw, 1.2rem);
  border: 1px solid var(--line); border-radius: 14px;
  background: rgba(243,231,216,0.03);
  transition: border-color 0.35s ease, background 0.35s ease, transform 0.35s ease;
}
.way:hover { border-color: rgba(254,102,0,0.45); background: rgba(254,102,0,0.06); transform: translateY(-2px); }
.way-k {
  font-family: var(--mono); font-size: 0.6rem; letter-spacing: 0.2em;
  text-transform: uppercase; color: var(--orange);
}
.way-v { color: var(--milk); font-size: var(--step--1); overflow-wrap: anywhere; }

/* The form ---------------------------------------------------------------- */
.say { background: var(--ink-2); padding-block: var(--section); }
.say-grid { display: grid; gap: clamp(2rem, 5vw, 4rem); align-items: start; }
@media (min-width: 900px) { .say-grid { grid-template-columns: minmax(0, 0.85fr) minmax(0, 1fr); } }
.say-head h2 { font-size: var(--step-3); line-height: 1.02; margin-top: 0.4rem; }
.say-head h2 em {
  font-style: normal; color: var(--orange); display: block;
  font-variation-settings: "SOFT" 60, "WONK" 1, "opsz" 144;
}
.say-head .muted { margin-top: 1rem; max-width: 40ch; }
.say-hours { list-style: none; margin: 1.6rem 0 0; padding: 0; display: grid; gap: 0.4rem; max-width: 20rem; }
.say-hours li {
  display: flex; justify-content: space-between; gap: 1rem;
  padding-bottom: 0.4rem; border-bottom: 1px solid var(--line);
  color: var(--milk-dim); font-size: var(--step--1);
}

.say-form { display: grid; gap: 0.9rem; }
/* The label sits in the field and rises out of it once there is something to
   read, so the form reads as four lines rather than eight. */
.fld { position: relative; }
.fld input, .fld textarea {
  width: 100%; background: rgba(243,231,216,0.03);
  border: 1px solid var(--line); border-radius: 14px;
  padding: 1.5rem 1rem 0.7rem; color: var(--milk);
  font-family: var(--body); font-size: var(--step-0); line-height: 1.4;
  transition: border-color 0.3s ease, background 0.3s ease;
}
.fld textarea { resize: vertical; min-height: 8rem; }
.fld label {
  position: absolute; left: 1rem; top: 1.05rem;
  font-family: var(--body); font-size: var(--step-0); color: var(--milk-dim);
  pointer-events: none; transform-origin: 0 0;
  transition: transform 0.25s cubic-bezier(0.22,0.61,0.36,1), color 0.25s ease;
}
.fld label i { font-style: normal; opacity: 0.6; font-size: 0.8em; }
.fld input:focus, .fld textarea:focus {
  outline: none; border-color: rgba(254,102,0,0.6); background: rgba(254,102,0,0.05);
}
.fld input:focus + label, .fld textarea:focus + label,
.fld input:not(:placeholder-shown) + label, .fld textarea:not(:placeholder-shown) + label {
  transform: translateY(-0.72rem) scale(0.72); color: var(--orange);
}
.fld.is-bad input, .fld.is-bad textarea { border-color: #C0563A; }
.fld-error { color: #E08B6F; font-size: var(--step--1); }
.say-form .btn { justify-self: start; margin-top: 0.4rem; }
.say-fine { color: var(--milk-dim); font-size: 0.72rem; max-width: 40ch; }

/* Sent ------------------------------------------------------------------- */
.say-done { display: grid; gap: 0.8rem; place-items: start; padding: clamp(1.4rem, 3vw, 2rem) 0; }
.say-done h3 { font-size: var(--step-2); }
.say-done p { color: var(--milk-dim); max-width: 40ch; }
.say-tick {
  width: 44px; height: 44px; border-radius: 50%;
  border: 1px solid rgba(126,217,87,0.5); display: grid; place-items: center;
  color: #7ED957; font-size: 1.2rem;
}

/* The map ---------------------------------------------------------------- */
.find { position: relative; background: var(--ink); padding-bottom: var(--section); }

.find-map {
  position: relative; overflow: hidden;
  height: clamp(340px, 62vh, 620px);
  border-radius: 0 0 clamp(18px, 3vw, 28px) clamp(18px, 3vw, 28px);
  /* A light backdrop, deliberately. The layer above inverts whatever is
     behind it, and until the frame has painted that is the page itself -
     inverting near-black gave a sheet of cream, which is the white flash on
     load. Standing in a map-coloured grey behind it means the empty frame
     inverts to the same dark the loaded map does. */
  background: #f1efeb;
}
.find-map iframe { width: 100%; height: 100%; border: 0; display: block; }

/* Google's tiles are light and this page is not. The first layer inverts
   them, the second puts a warm hue back. Blend layers rather than a filter on
   the frame: a filter on a cross-origin iframe stops applying once Chrome
   gives it its own compositing layer - which it does the moment you interact
   with it - and the map snaps back to daylight. Blending has to read the
   backdrop, so the frame is painted in place. Both are pointer-transparent,
   so the map still drags, zooms and street-views underneath them. */
.find-flip, .find-warm { position: absolute; inset: 0; pointer-events: none; }
.find-flip { background: #ffffff; mix-blend-mode: difference; }
.find-warm { background: #3a2416; mix-blend-mode: color; }

.find-veil {
  position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(to bottom, rgba(14,12,11,0.72), transparent 18%,
              transparent 60%, rgba(14,12,11,0.94));
}

/* Above the blend layers so it is not inverted with the map. */
.map-wait {
  position: absolute; z-index: 5; left: 50%; top: 50%; translate: -50% -50%;
  display: inline-flex; align-items: center; gap: 0.6rem;
  font-family: var(--mono); font-size: 0.6rem; letter-spacing: 0.2em;
  text-transform: uppercase; color: var(--milk-dim);
  pointer-events: none; transition: opacity 0.5s ease;
}
.map-wait i {
  width: 9px; height: 9px; border-radius: 50%; background: var(--orange);
  animation: wait-beat 1.3s ease-in-out infinite;
}
@keyframes wait-beat { 0%, 100% { opacity: 0.25; } 50% { opacity: 1; } }
.find-map.is-ready .map-wait { opacity: 0; }

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

.find-card {
  position: relative; z-index: 3; margin-top: clamp(-7rem, -9vw, -4rem);
  background: var(--ink-2); border: 1px solid var(--line); border-radius: 20px;
  padding: clamp(1.4rem, 3.5vw, 2.4rem);
  width: min(100% - var(--gutter) * 2, 34rem);
  box-shadow: 0 30px 70px rgba(0,0,0,0.55);
}
.find-card h2 { font-size: var(--step-2); margin-top: 0.4rem; }
.find-card .muted { margin-top: 0.7rem; }
.find-card .hero-actions { margin-top: 1.4rem; }
.find { padding-bottom: var(--section); }

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

/* ==========================================================================
   Catering
   The hero answers the question people arrive with - how much, for how many -
   rather than announcing that catering exists.
   ========================================================================== */
.cater {
  position: relative; overflow: hidden; background: var(--ink);
  min-height: 100svh; display: grid; align-content: center;
  padding-block: clamp(7rem, 14vh, 9rem) clamp(4rem, 9vh, 6rem);
}
.cater-in { position: relative; z-index: 1; display: grid; gap: clamp(2rem, 5vw, 4rem); align-items: center; }
@media (min-width: 960px) { .cater-in { grid-template-columns: minmax(0, 1fr) minmax(0, 0.9fr); } }

.cater-h {
  font-family: var(--display); font-weight: 700; line-height: 0.96;
  font-size: clamp(2.1rem, 5.6vw, 4.2rem); letter-spacing: -0.03em;
  margin-block: 0.4rem 1.6rem;
}
.cater-h em {
  font-style: normal; color: var(--orange); display: block;
  font-variation-settings: "SOFT" 60, "WONK" 1, "opsz" 144;
}
.cater-q {
  font-family: var(--mono); font-size: 0.64rem; letter-spacing: 0.2em;
  text-transform: uppercase; color: var(--milk-dim);
}
.cater-dial { display: flex; align-items: baseline; gap: 0.7rem; margin-top: 0.2rem; }
.cater-n {
  font-family: var(--display); font-weight: 700; line-height: 0.85;
  font-size: clamp(3.6rem, 11vw, 7rem); letter-spacing: -0.045em;
  color: var(--milk); font-variant-numeric: tabular-nums;
}
.cater-u {
  font-family: var(--mono); font-size: 0.68rem; letter-spacing: 0.2em;
  text-transform: uppercase; color: var(--orange);
}

/* The slider, drawn rather than left to the browser: the default control is
   the one thing on the page that would look like every other website. */
.cater-range {
  -webkit-appearance: none; appearance: none;
  width: min(100%, 30rem); height: 34px; margin-top: 0.8rem;
  background: transparent; cursor: grab;
}
.cater-range:active { cursor: grabbing; }
.cater-range::-webkit-slider-runnable-track {
  height: 3px; border-radius: 3px;
  background: linear-gradient(to right, var(--orange) var(--fill, 22%), rgba(243,231,216,0.16) var(--fill, 22%));
}
.cater-range::-moz-range-track { height: 3px; border-radius: 3px; background: rgba(243,231,216,0.16); }
.cater-range::-moz-range-progress { height: 3px; border-radius: 3px; background: var(--orange); }
.cater-range::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 22px; height: 22px; margin-top: -10px; border-radius: 50%;
  background: var(--orange); border: 3px solid var(--ink);
  box-shadow: 0 0 0 5px rgba(254,102,0,0.18), 0 8px 18px rgba(0,0,0,0.6);
  transition: box-shadow 0.25s ease, transform 0.25s ease;
}
.cater-range:hover::-webkit-slider-thumb { transform: scale(1.1); box-shadow: 0 0 0 9px rgba(254,102,0,0.14), 0 8px 18px rgba(0,0,0,0.6); }
.cater-range::-moz-range-thumb {
  width: 22px; height: 22px; border-radius: 50%; border: 3px solid var(--ink);
  background: var(--orange); box-shadow: 0 0 0 5px rgba(254,102,0,0.18);
}
.cater-range:focus-visible { outline: none; }
.cater-range:focus-visible::-webkit-slider-thumb { box-shadow: 0 0 0 9px rgba(254,102,0,0.3); }
.cater-marks {
  display: flex; justify-content: space-between; width: min(100%, 30rem);
  font-family: var(--mono); font-size: 0.56rem; letter-spacing: 0.14em;
  color: var(--milk-dim); margin-top: -0.2rem;
}

.cater-out {
  display: flex; align-items: baseline; flex-wrap: wrap; gap: 0.5rem;
  margin-top: clamp(1.2rem, 3vh, 1.8rem);
  font-family: var(--mono); font-size: 0.66rem; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--milk-dim);
}
.cater-out b {
  font-family: var(--display); font-weight: 700; font-size: clamp(1.4rem, 3vw, 2rem);
  letter-spacing: -0.02em; color: var(--milk); font-variant-numeric: tabular-nums;
}
.cater-out i { color: var(--orange); font-style: normal; }
.cater-out span { width: 100%; color: rgba(243,231,216,0.4); letter-spacing: 0.12em; }
.cater-fine { margin-top: 1rem; max-width: 44ch; color: var(--milk-dim); font-size: 0.74rem; line-height: 1.6; }

/* One tray, counted rather than repeated. */
.cater-tray {
  position: relative; margin: 0; width: min(100%, 30rem); margin-inline: auto;
}
.cater-shot {
  position: relative; display: block; border-radius: 20px; overflow: hidden;
  aspect-ratio: 4 / 3; box-shadow: 0 30px 60px rgba(0,0,0,0.6);
}
.cater-shot img {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  transition: opacity 0.6s ease;
}
.cater-shot img[data-tray-b] { opacity: 0; }
.cater-tray.is-b .cater-shot img[data-tray-a] { opacity: 0; }
.cater-tray.is-b .cater-shot img[data-tray-b] { opacity: 1; }

/* The figure sits on the tray, where a number on an order would. */
.cater-badge {
  position: absolute; right: -0.6rem; top: -0.9rem; z-index: 2;
  display: flex; align-items: baseline; gap: 0.15rem;
  background: var(--orange); color: #14100D;
  padding: 0.5rem 0.9rem 0.55rem; border-radius: 999px;
  box-shadow: 0 14px 30px rgba(0,0,0,0.5);
}
.cater-badge i { font-style: normal; font-family: var(--mono); font-size: 0.8rem; opacity: 0.75; }
.cater-badge b {
  font-family: var(--display); font-weight: 700; font-size: clamp(1.4rem, 3vw, 2.1rem);
  line-height: 1; letter-spacing: -0.02em; font-variant-numeric: tabular-nums;
}

/* One mark per tray, so the number is also something you can see at a glance
   without reading it. */
.cater-marks-row {
  display: flex; flex-wrap: wrap; gap: 0.32rem; margin-top: 0.9rem;
}
.cater-marks-row i {
  display: block; width: 26px; height: 15px; border-radius: 3px;
  border: 1px solid rgba(243,231,216,0.28);
  background: rgba(243,231,216,0.06);
  transition: background 0.3s ease, border-color 0.3s ease, transform 0.3s ease;
}
.cater-marks-row i.on { background: var(--orange); border-color: var(--orange); }
.cater-marks-row i.more {
  width: auto; padding: 0 0.4rem; border: 0; background: none;
  font-family: var(--mono); font-size: 0.58rem; letter-spacing: 0.12em;
  color: var(--milk-dim); line-height: 15px;
}

/* The two trays --------------------------------------------------------- */
.trays { background: var(--ink-2); padding-block: var(--section); }
.trays .section-head h2 em {
  font-style: normal; color: var(--orange); display: block;
  font-variation-settings: "SOFT" 60, "WONK" 1, "opsz" 144;
}
.tray-grid {
  display: grid; gap: clamp(1rem, 2.5vw, 1.6rem);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr));
  margin-top: clamp(1.8rem, 4vw, 2.8rem);
}
.tray {
  border: 1px solid var(--line); border-radius: 18px; overflow: hidden;
  background: rgba(243,231,216,0.03);
  transition: border-color 0.35s ease, transform 0.35s ease;
}
.tray:hover { border-color: rgba(254,102,0,0.4); transform: translateY(-3px); }
.tray figure { margin: 0; }
.tray img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; display: block; }
.tray-body { padding: clamp(1.1rem, 2.4vw, 1.6rem); }
.tray-body h3 { font-size: var(--step-1); }
.tray-body .muted { margin-top: 0.6rem; font-size: var(--step--1); }
.tray-price {
  margin-top: 1rem; font-family: var(--mono); color: var(--orange);
  font-size: var(--step-0); font-variant-numeric: tabular-nums;
}

.cater-steps {
  list-style: none; margin: clamp(2.4rem, 6vh, 4rem) 0 clamp(1.6rem, 4vh, 2.4rem); padding: 0;
  display: grid; gap: clamp(1rem, 2.5vw, 1.6rem);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
  counter-reset: step;
}
.cater-steps li { border-top: 1px solid var(--line); padding-top: 1rem; }
.cater-steps b {
  font-family: var(--mono); font-size: 0.62rem; letter-spacing: 0.2em; color: var(--orange);
  display: block;
}
.cater-steps span { display: block; margin-top: 0.5rem; font-family: var(--display); font-size: var(--step-1); }
.cater-steps p { margin-top: 0.5rem; color: var(--milk-dim); font-size: var(--step--1); }

/* ==========================================================================
   Phones
   Two things a desktop hides. The small mono labels that read as a fine
   detail on a monitor land at nine or ten pixels of wide-tracked uppercase on
   a phone, which is a squint; and the list links are text on a line, giving a
   twenty-pixel target where a fingertip is nearer forty-five.
   ========================================================================== */
@media (max-width: 780px) {
  /* A floor under the small labels. Tracking comes down with the size going
     up, or the words start to come apart. */
  .panel-name, .mx-no, .mx-count, .rv-src, .acc-no, .chip,
  .tag-veg, .way-k, .sig-no, .ms-no, .cater-u, .cater-marks,
  .map-credit, .map-open, .fm-part i, .hcard > span, .afact > span,
  .lit-visit h4, .avisit-grid h4, .say-hours li, .cater-steps b {
    font-size: 0.7rem;
    letter-spacing: 0.14em;
  }
  .rv-src, .mx-count, .map-credit { font-size: 0.68rem; }
  /* The rest of the labels that fell under ten pixels once measured on a
     phone rather than eyeballed on a monitor. */
  .lit-four span, .room-main figcaption span, .call-status,
  .cater-q, .cater-out span, .say-fine, .cater-fine { font-size: 0.7rem; letter-spacing: 0.13em; }
  .cater-fine, .say-fine { letter-spacing: 0; line-height: 1.65; }
  .pick-spine { font-size: 0.66rem; }
  .mi-name, .mi-price, .muted, .lede { font-size: 0.95rem; }

  /* Links stacked in a list get a fingertip's worth of height without
     pushing the lists apart: the padding is inside the line box. */
  .footer-grid li a, .wm-cols li a, .lit-visit li a,
  .avisit-grid li a, .say-hours li a, .menu-note a {
    display: inline-block; padding-block: 0.72rem; line-height: 1.15;
  }
  .footer-grid li, .wm-cols li, .lit-visit li, .avisit-grid li { padding-block: 0; }
}

/* The line you came for, pointed out on arrival. Fades by itself: a row left
   highlighted for the rest of the visit reads as selected, not as found. */
.mi.is-found {
  animation: mi-found 2.6s ease-out forwards;
}
@keyframes mi-found {
  0%   { background: rgba(254,102,0,0.28); box-shadow: inset 2px 0 0 var(--orange); }
  60%  { background: rgba(254,102,0,0.16); box-shadow: inset 2px 0 0 var(--orange); }
  100% { background: transparent; box-shadow: inset 2px 0 0 transparent; }
}
@media (prefers-reduced-motion: reduce) {
  .mi.is-found { animation: none; background: rgba(254,102,0,0.16); }
}
