/* Tacos Ay Ay Ay, Boulder. Hero study.
   The opening is ONE continuous drone take, not a sequence of plates: the camera
   flies down the center aisle and turns into the archway booth in a single shot.
   Resting state is the settled page: last frame held, logo visible, page scrollable.
   The html.cine class is what adds the shot and the scroll lock, and main.js takes
   it off again. If the JS never runs, the page is simply already settled. */

:root {
  --adobe: #b9774c;
  --clay: #7a4428;
  --tile: #e4c9a8;
  --ink: #1b1310;
  --cream: #f5ece1;
  --neon: #ffd23f;

  /* One step off the ink for every raised surface, one hairline, one muted text.
     Three values instead of a dozen one-off browns is what makes the page read
     as a single brand rather than a stack of sections. */
  --ink-2: #140e0b;
  --rule: rgba(233,203,170,.14);
  --muted: #c9a079;

  --wrap: 1180px;
  --radius: 14px;

  /* Motion kit v2 tokens. State changes are fast, entrances are slow on a long
     tail, and entrances only ever use --ease. */
  --duration-fast: 150ms;
  --duration-slow: 300ms;
  --duration-reveal: 900ms;
  --ease: cubic-bezier(.22, 1, .36, 1);
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: #0a0706;
  color: var(--cream);
  font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}

/* The lock. overflow:hidden alone still permits programmatic scrolls, so the
   scrollable extent is collapsed to the viewport instead. */
html.cine, html.cine body {
  height: 100%;
  overflow: hidden;
}

img { display: block; width: 100%; height: auto; }

/* ---------- hero ---------- */

/* Sticky, not relative, and that single word is the whole curtain: the hero
   holds still at the top of the viewport while everything after it drags up
   over the shot. Pure scroll position, no JS, nothing to throttle. At rest
   (y = 0) sticky renders pixel for pixel the same as relative, so the opening
   is untouched. Unpinned under reduced motion, further down. */
.hero {
  position: sticky;
  top: 0;
  height: 100svh;
  min-height: 420px;
  overflow: hidden;
  /* The poster sits on the hero itself, not only on the video and the picture.
     Both of those need JS: the clip's source is attached from data-src, and
     .still is display:none above 600px. With scripting off on a desktop that
     left the whole hero flat black. This is the floor under both of them. */
  background: #0a0706 url(assets/hero-poster.jpg) center 52% / cover no-repeat;
}

/* The shot. It holds its last frame when it ends, which IS the resting hero,
   so nothing has to be swapped in behind it. */
.shot {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 52%;
}

/* Phones get the framed still instead. A 16:9 clip cover-crops to a sliver on a
   tall viewport, and they never download the 5MB. */
.still { display: none; }

@media (max-width: 600px) {
  .shot { display: none; }
  .still {
    display: block;
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: 52% 55%;
  }
}

/* Vignette and the pool of shade the logo sits in. Always present. */
.veil {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    radial-gradient(ellipse 70% 55% at 50% 56%, rgba(0,0,0,.52) 0%, rgba(0,0,0,.30) 55%, rgba(0,0,0,0) 100%),
    radial-gradient(ellipse 120% 100% at 50% 50%, rgba(0,0,0,0) 45%, rgba(0,0,0,.58) 100%);
}

.blackout {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: #000;
  opacity: 0;
}

.grain {
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: .16;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 160px 160px;
}

/* The source art is neon on solid black, so screen drops the black and keeps the glow.
   The blend has to sit on the element that shares a stacking context with the photo.
   Put it on the img and it composites against .mark's own empty backdrop instead,
   and the logo renders as a black tile. */
.mark {
  position: absolute;
  left: 50%;
  top: 50%;
  width: min(56vw, 360px);
  transform: translate(-50%, -52%);
  pointer-events: none;
  mix-blend-mode: screen;
}

.mark img {
  will-change: transform, opacity;
}

.skip {
  display: none;
  position: absolute;
  top: 18px;
  right: 18px;
  z-index: 5;
  padding: 15px 20px;
  border: 1px solid rgba(255,255,255,.45);
  border-radius: 999px;
  background: rgba(10,7,6,.72);
  color: #fff;
  font: 500 13px/1 ui-sans-serif, system-ui, sans-serif;
  letter-spacing: .04em;
  cursor: pointer;
}

.skip:hover { background: rgba(10,7,6,.9); }
.skip:focus-visible { outline: 3px solid var(--neon); outline-offset: 3px; }

html.cine .skip { display: block; }

.cue {
  position: absolute;
  left: 50%;
  bottom: 26px;
  width: 1px;
  height: 56px;
  transform: translateX(-50%);
  overflow: hidden;
  background: rgba(255,255,255,.22);
  pointer-events: none;
}

.cue span {
  display: block;
  width: 1px;
  height: 20px;
  background: var(--neon);
  animation: cueRun 2.4s cubic-bezier(.6,0,.3,1) infinite;
}

@keyframes cueRun {
  0%   { transform: translateY(-24px); }
  100% { transform: translateY(60px); }
}

/* ---------- the opening ---------- */

/* Only two things animate now. The shot itself carries the camera move, so the
   CSS has no business touching it. */

@keyframes markIn {
  0%   { transform: scale(.88); opacity: 0; filter: brightness(1.6); }
  60%  { opacity: 1; }
  100% { transform: scale(1); opacity: 1; filter: brightness(1); }
}

@keyframes blackOut {
  0%   { opacity: 1; }
  100% { opacity: 0; }
}

@keyframes cueIn {
  0%   { opacity: 0; }
  100% { opacity: 1; }
}

/* The mark and the cue are timed off the VIDEO, not off page load, so they land
   on the settle whether or not playback started on time. main.js adds .ending. */
html.cine .mark img { opacity: 0; }
html.cine .cue { opacity: 0; }

html.cine.ending .mark img {
  animation: markIn 1.2s cubic-bezier(.2,.7,.3,1) both;
}

html.cine.ending .cue {
  animation: cueIn .6s ease-out .9s both;
}

html.cine .blackout {
  animation: blackOut .9s ease-out both;
}

/* ---------- below the fold ---------- */

/* Everything after the hero rides OVER it, so every covering layer is opaque
   and above. The shadow is cast upward, onto the pinned shot, which is what
   makes the page read as a panel lifting instead of a seam. */
main {
  position: relative;
  z-index: 1;
  background: var(--ink);
  box-shadow: 0 -26px 64px rgba(0,0,0,.66);
}

:focus-visible { outline: 3px solid var(--neon); outline-offset: 3px; }

.skiplink {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 20;
  padding: 15px 20px;
  background: var(--neon);
  color: var(--ink);
  font: 600 15px/1 ui-sans-serif, system-ui, sans-serif;
  text-decoration: none;
}

.skiplink:focus { left: 0; }

/* ---------- header ---------- */

/* The measured height of .topbar. The menu rail sticks directly under it and
   anchors scroll to clear it, so both read this one number. Verified against
   the rendered bar at 1440 and 375, not estimated. */
:root { --bar: 63px; }
@media (max-width: 760px) { :root { --bar: 91px; } }

/* Sticky, not fixed. main begins where the hero ends, so a sticky child can
   never sit over the opening shot and needs no hiding rule while html.cine
   holds the page. The scroll lock does collapse stickiness, which is correct:
   during the lock there is nothing to stick to. */
.topbar {
  position: sticky;
  top: 0;
  z-index: 30;
  background: rgba(20,14,11,.72);
  border-bottom: 1px solid transparent;
  -webkit-backdrop-filter: saturate(1.3) blur(12px);
          backdrop-filter: saturate(1.3) blur(12px);
  transition: background var(--duration-slow) var(--ease),
              border-color var(--duration-slow) var(--ease);
}

/* The solid state is a predicate on scroll position, set by a scroll listener
   and an equality check. Never an IntersectionObserver: a sticky bar never
   stops intersecting anything, and IO samples at frame boundaries, so one
   wheel flick steps clean over a thin root. */
.topbar.is-solid {
  background: var(--ink-2);
  border-bottom-color: var(--rule);
}

.topbar-in {
  display: flex;
  align-items: center;
  gap: 14px 26px;
  max-width: var(--wrap);
  margin: 0 auto;
  padding: 10px 24px;
}

.topbar-name {
  flex: none;
  margin: 0;
  font-size: 16px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--neon);
}

/* The wordmark is a standalone link, not a link inside a sentence, so the
   inline exception to the 24px minimum target does not cover it. Padding, not
   a bigger font, so the bar height does not move. */
.topbar-name a { display: inline-block; padding: 4px 0; color: inherit; text-decoration: none; }

.topbar nav { flex: 1 1 auto; }

.topbar ul {
  display: flex;
  flex-wrap: wrap;
  gap: 2px 24px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.topbar nav a {
  position: relative;
  display: inline-block;
  padding: 12px 1px;
  color: #e3d3c2;
  font-size: 15px;
  letter-spacing: .03em;
  text-decoration: none;
}

/* Transform only, so the underline costs no layout. */
.topbar nav a::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 6px;
  height: 2px;
  background: var(--neon);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--duration-slow) var(--ease);
}

.topbar nav a:hover::after { transform: scaleX(1); }

.topbar-order {
  flex: none;
  padding: 11px 18px;
  border: 1px solid rgba(255,210,63,.55);
  border-radius: 999px;
  color: var(--neon);
  font: 600 15px/1 ui-sans-serif, system-ui, sans-serif;
  text-decoration: none;
  transition: background var(--duration-fast) var(--ease);
}

.topbar-order:hover { background: rgba(255,210,63,.14); }

/* Anchors land below BOTH sticky bars instead of under them. The 60px is the
   measured rail height (59px) plus a hairline of breathing room. */
[id] { scroll-margin-top: calc(var(--bar) + 60px); }

@media (max-width: 760px) {
  .topbar-in { flex-wrap: wrap; justify-content: center; padding: 8px 16px; gap: 2px 18px; }
  .topbar nav { flex: 1 1 100%; order: 3; }
  .topbar ul { justify-content: center; gap: 0 18px; }
  .topbar nav a { font-size: 14px; padding: 8px 1px; }
  .topbar-name { font-size: 15px; }
}

/* ---------- motion ---------- */

/* Scroll reveal. Rise and fade, once, at 8% visible.
   The resting state is VISIBLE, and the html.js gate is what makes that true
   rather than merely claimed. Only the pre-paint bootstrap adds .js, so with
   scripting off, or that block blocked, these 56 elements never hide at all.
   Hiding is the enhancement; it is applied only once JS has proved it is
   there to undo it. Gated the other way round, a page with no JS rendered as
   the hero photo and nothing else. */
html.js .rv {
  opacity: 0;
  transform: translateY(26px);
  transition: opacity var(--duration-reveal) var(--ease),
              transform var(--duration-reveal) var(--ease);
  transition-delay: var(--d, 0s);
}

/* Needs the html.js prefix too, or it loses on specificity to the rule above
   and .in stops un-hiding anything. */
html.js .rv.in { opacity: 1; transform: none; }

/* Native scroll-driven easing on photos, no JS at all. Browsers without
   animation-timeline see the finished frame, which is the correct picture. */
@supports (animation-timeline: view()) {
  .sd-scale {
    animation: ay-scale var(--ease) both;
    animation-timeline: view();
    animation-range: entry 0% entry 85%;
  }
  @keyframes ay-scale { from { transform: scale(1.07); } to { transform: scale(1); } }

  .sd-par {
    animation: ay-par linear both;
    animation-timeline: view();
    animation-range: entry 0% exit 100%;
  }
  @keyframes ay-par {
    from { transform: translateY(5%) scale(1.12); }
    to   { transform: translateY(-5%) scale(1.12); }
  }

  /* The curtain's wash drifts and opens up as the panel clears the hero.
     Browsers without animation-timeline get the finished frame, which is the
     glow sitting where it is drawn. */
  .curtain .glow {
    animation: ay-glow linear both;
    animation-timeline: view();
    animation-range: entry 0% exit 60%;
  }
  @keyframes ay-glow {
    from { transform: translate(-50%, 7%) scale(.86); opacity: .55; }
    to   { transform: translate(-50%, -9%) scale(1.06); opacity: 1; }
  }
}

/* ---------- bands ---------- */

.band {
  max-width: var(--wrap);
  margin: 0 auto;
  padding: 84px 24px 96px;
  text-align: center;
}

.intro { max-width: 820px; padding-bottom: 72px; }

/* ---------- the curtain panel ---------- */

/* The first band after the hero. It is full bleed and fully opaque on purpose:
   this is the sheet that slides up over the pinned shot, and any transparency
   here would put the film behind the copy. */
.curtain {
  position: relative;
  overflow: hidden;
  background:
    radial-gradient(118% 84% at 50% -8%, rgba(185,119,76,.26), rgba(185,119,76,0) 62%),
    radial-gradient(74% 58% at 94% 110%, rgba(122,68,40,.24), rgba(122,68,40,0) 72%),
    var(--ink-2);
  border-bottom: 1px solid var(--rule);
}

/* A warm wash that drifts as the panel passes. Decorative, so it sits at
   z-index 0 with the copy lifted above it rather than at -1, which would
   paint behind the panel's own background and vanish. */
.curtain .glow {
  position: absolute;
  z-index: 0;
  left: 50%;
  top: -22%;
  width: min(900px, 120%);
  aspect-ratio: 1;
  transform: translateX(-50%);
  background: radial-gradient(closest-side, rgba(255,210,63,.13), rgba(255,210,63,0) 70%);
  pointer-events: none;
}

.curtain .band { position: relative; z-index: 1; }

/* Both addresses, one shape each. Identical frames, so the eye compares the
   cities and not the boxes. */
.spots {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  max-width: 620px;
  margin: 0 auto 28px;
  text-align: left;
}

.spot {
  padding: 18px 20px 14px;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: rgba(10,7,6,.46);
}

.spot-city {
  margin: 0 0 7px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--neon);
}

.spot-addr {
  margin: 0 0 8px;
  font-size: 16px;
  line-height: 1.5;
  color: var(--cream);
}

.spot-map {
  display: inline-block;
  padding: 7px 0 6px;
  font-size: 14px;
  color: #e3d3c2;
  text-decoration: none;
  border-bottom: 1px solid rgba(227,211,194,.4);
  transition: color var(--duration-fast) var(--ease),
              border-color var(--duration-fast) var(--ease);
}

.spot-map:hover { color: var(--neon); border-bottom-color: var(--neon); }

@media (max-width: 560px) {
  .spots { grid-template-columns: 1fr; max-width: 420px; }
}

.kicker {
  margin: 0 0 14px;
  font-size: 13px;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: #c9a079;
}

.band h1 {
  margin: 0 0 18px;
  font-size: clamp(34px, 6vw, 60px);
  line-height: 1.05;
  font-weight: 700;
  color: var(--cream);
}

.band h2 {
  margin: 0 0 16px;
  font-size: clamp(28px, 4.4vw, 42px);
  line-height: 1.1;
  font-weight: 700;
  color: var(--cream);
}

.lede {
  max-width: 640px;
  margin: 0 auto 36px;
  font-size: clamp(17px, 2.2vw, 20px);
  line-height: 1.6;
  color: #e3d3c2;
}

.call a {
  display: inline-block;
  padding: 11px 0 9px;
  color: var(--neon);
  font-size: 20px;
  font-weight: 600;
  text-decoration: none;
  border-bottom: 2px solid rgba(255,210,63,.5);
}

.call a:hover { border-bottom-color: var(--neon); }

.btn {
  display: inline-block;
  padding: 15px 26px;
  border-radius: 999px;
  background: var(--neon);
  color: var(--ink);
  font: 600 16px/1 ui-sans-serif, system-ui, sans-serif;
  letter-spacing: .02em;
  text-decoration: none;
  transition: background var(--duration-fast) var(--ease),
              transform var(--duration-fast) var(--ease);
}

.btn:hover { background: #ffdd68; }
.btn:active { transform: scale(.98); }

/* The light sweep, on exactly ONE button on the page. A second sweeping CTA in
   the same viewport stops being a focal point and starts being noise, so the
   header, Maps and Visit buttons deliberately stay plain. */
@property --spin { syntax: '<angle>'; inherits: false; initial-value: 0deg; }

.btn--sweep {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  --spin: 0deg;
}

.btn--sweep::before {
  content: "";
  position: absolute;
  inset: -40%;
  z-index: -2;
  background: conic-gradient(from var(--spin),
    transparent 0deg, transparent 268deg,
    #fff0b8 300deg, #fff 322deg, #fff0b8 344deg, transparent 360deg);
  animation: ay-spin 3.2s linear infinite;
}

.btn--sweep::after {
  content: "";
  position: absolute;
  inset: 2px;
  z-index: -1;
  border-radius: inherit;
  background: var(--neon);
  transition: background var(--duration-fast) var(--ease);
}

.btn--sweep:hover::after { background: #ffdd68; }

@keyframes ay-spin { to { --spin: 360deg; } }

.note {
  max-width: 640px;
  margin: 34px auto 0;
  font-size: 15px;
  line-height: 1.6;
  color: #c9a079;
}

.cta { margin: 36px 0 0; }

/* ---------- marquee ---------- */

/* The meat list, moving. The track's children are duplicated once in the
   markup with aria-hidden on the copy, so a screen reader reads the list
   exactly once and the loop still has something to scroll into. */
.marquee {
  overflow: hidden;
  border-top: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
  background: var(--ink-2);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}

.marquee-track {
  display: flex;
  width: max-content;
  padding: 15px 0;
  animation: ay-glide 58s linear infinite;
}

.marquee:hover .marquee-track { animation-play-state: paused; }

.marquee-track span {
  flex: none;
  padding: 0 22px;
  font-size: 14px;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--muted);
  white-space: nowrap;
}

.marquee-track span::after { content: ""; }
.marquee-track span + span { border-left: 1px solid var(--rule); }

@keyframes ay-glide { to { transform: translateX(-50%); } }

/* ---------- full width plate ---------- */

/* A room photograph is 3:2 and no dish frame can hold it, so it gets its own
   element instead of a worse crop. The copy sits on solid ink, never over the
   photo, which is why this band needs no scrim and no media contrast pass. */
.plate {
  display: grid;
  grid-template-columns: 1fr;
  align-items: stretch;
  gap: 0;
  border-top: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
  background: var(--ink-2);
}

/* The clip frame the parallax needs. Without it the drifting image paints
   outside the band and shoves the layout. */
.plate-frame { overflow: hidden; }

.plate img {
  display: block;
  width: 100%;
  height: 100%;
  aspect-ratio: 3 / 2;
  object-fit: cover;
}

.plate-cap {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 56px 24px 64px;
  text-align: center;
}

.plate-cap h2 {
  margin: 0 0 14px;
  font-size: clamp(26px, 4vw, 38px);
  line-height: 1.1;
  color: var(--cream);
}

.plate-cap p {
  max-width: 420px;
  margin: 0 auto;
  font-size: 17px;
  line-height: 1.6;
  color: #e3d3c2;
}

@media (min-width: 860px) {
  .plate { grid-template-columns: 1.15fr 1fr; }
  .plate-cap { padding: 48px 56px; text-align: left; }
  .plate-cap p { margin: 0; }
}

/* ---------- menu ---------- */

/* No painted wall behind this section any more. A tiling brick fill at this
   scale reads as clip art on a phone, and the thing it was hiding was that the
   menu had no photographs in it. The photographs are the texture now. */

.rail-wrap {
  position: sticky;
  top: var(--bar, 63px);
  z-index: 20;
  background: var(--ink-2);
  border-top: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
}

.rail {
  display: flex;
  gap: 8px;
  max-width: var(--wrap);
  margin: 0 auto;
  padding: 10px 24px;
  overflow-x: auto;
  scrollbar-width: none;
  /* The page must always scroll vertically from inside a horizontal strip. */
  touch-action: pan-x pan-y;
}

.rail::-webkit-scrollbar { display: none; }

.rail a {
  flex: none;
  padding: 9px 15px;
  border: 1px solid var(--rule);
  border-radius: 999px;
  color: #e3d3c2;
  font-size: 14px;
  letter-spacing: .02em;
  text-decoration: none;
  white-space: nowrap;
  transition: background var(--duration-fast) var(--ease),
              border-color var(--duration-fast) var(--ease),
              color var(--duration-fast) var(--ease);
}

.rail a:hover { border-color: rgba(255,210,63,.5); color: var(--cream); }

/* Which chip is current is a predicate on scroll position, so it is set by the
   same scroll listener that solidifies the header, not by an observer. */
.rail a.is-here {
  background: var(--neon);
  border-color: var(--neon);
  color: var(--ink);
  font-weight: 600;
}

.mgroup { max-width: var(--wrap); margin: 0 auto; padding: 56px 24px 8px; }
.mgroup:last-of-type { padding-bottom: 24px; }

.mhead {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px 16px;
  padding-bottom: 20px;
  border-bottom: 1px solid var(--rule);
  text-align: left;
}

.mhead h3 {
  margin: 0;
  font-size: clamp(22px, 3vw, 30px);
  line-height: 1.1;
  color: var(--cream);
}

.mnote {
  margin: 16px 0 0;
  font-size: 15px;
  line-height: 1.6;
  text-align: left;
  color: var(--muted);
}

/* One frame shape and one ratio across every dish, with all the variation in
   the photographs themselves. Column count follows the RENDERED width of a
   card, not the number of dishes in the group: below 560 a 3:2 card at two up
   is a thumbnail, and above 920 a two up card is a billboard. */
.dishes {
  display: grid;
  grid-template-columns: 1fr;
  gap: 30px 22px;
  margin: 28px 0 0;
  padding: 0;
  list-style: none;
}

@media (min-width: 560px) { .dishes { grid-template-columns: 1fr 1fr; } }
@media (min-width: 920px) { .dishes { grid-template-columns: repeat(3, 1fr); } }

.dish { margin: 0; text-align: left; }

.dish-frame {
  overflow: hidden;
  border-radius: var(--radius);
  background: var(--ink-2);
}

.dish img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 3 / 2;
  object-fit: cover;
  transition: transform var(--duration-slow) var(--ease);
}

.dish:hover img { transform: scale(1.045); }

.dish h4 {
  margin: 14px 0 0;
  font-size: 18px;
  line-height: 1.3;
  font-weight: 600;
  color: var(--cream);
}

.dish p {
  margin: 5px 0 0;
  font-size: 14.5px;
  line-height: 1.55;
  color: var(--muted);
}

/* The items with no photograph still have to be on the page, so each group
   ends with its own plain line rather than quietly losing half the board. */
.also {
  margin: 26px 0 0;
  font-size: 15.5px;
  line-height: 1.75;
  text-align: left;
  color: #e3d3c2;
}

.also b {
  display: block;
  margin-bottom: 2px;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--muted);
}

.menu-end { max-width: var(--wrap); margin: 0 auto; padding: 40px 24px 88px; text-align: center; }

/* ---------- drinks ---------- */

/* Their own 6:5 frame. The bottles are natively taller than the plates and a
   3:2 crop takes the caps off the back row, so the shape changes rather than
   the crop getting worse. */
.drinks .dish img { aspect-ratio: 6 / 5; }

/* ---------- bar boards ---------- */

.boards {
  display: grid;
  grid-template-columns: 1fr;
  align-items: start;
  gap: 24px;
  margin-top: 30px;
  text-align: left;
}

@media (min-width: 680px) { .boards { grid-template-columns: 1fr 1fr; gap: 28px 34px; } }
@media (min-width: 1000px) { .boards { grid-template-columns: repeat(4, 1fr); gap: 34px 28px; } }

/* Flat, no panel, no border box. A gradient or an image here would make every
   line unmeasurable by the contrast sweep for a few levels of brown. */
.board h3 {
  margin: 0 0 14px;
  padding-bottom: 12px;
  border-bottom: 2px solid var(--adobe);
  font-size: 17px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--neon);
}

.board ul { margin: 0; padding: 0; list-style: none; }

.board li {
  padding: 9px 0;
  border-top: 1px solid var(--rule);
  font-size: 15.5px;
  line-height: 1.45;
  color: var(--cream);
}

.board li:first-child { border-top: 0; }
.board li span { display: block; margin-top: 3px; font-size: 13.5px; color: var(--muted); }

/* ---------- section heads on the left ---------- */

/* A centered heading over a left aligned grid is the single thing that made the
   old page read as unfinished, so the bands that hold grids say so. */
.band-left { text-align: left; }
.band-left .lede { margin-left: 0; margin-right: 0; }
.band-left .note { margin-left: 0; margin-right: 0; }

/* Full bleed tint, so the band's own max-width does not draw an inset panel
   edge down the middle of the page. */
.bar { background: var(--ink-2); border-top: 1px solid var(--rule); border-bottom: 1px solid var(--rule); }

.catering { background: var(--ink-2); border-top: 1px solid var(--rule); border-bottom: 1px solid var(--rule); }

/* ---------- visit ---------- */

.visit-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 32px;
  text-align: left;
  margin-top: 8px;
}

@media (min-width: 760px) { .visit-grid { grid-template-columns: repeat(3, 1fr); } }

.vcol h3 {
  margin: 0 0 12px;
  font-size: 15px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: #c9a079;
}

.addr, .contact, .hours {
  margin: 0 0 20px;
  font-size: 18px;
  line-height: 1.7;
  color: var(--cream);
}

/* A real two column grid, not an inline-block with a guessed min-width. The old
   rule sized the label column to "Tuesday to Sunday" and then let the longest
   value wrap under it, so one row lined up and the other did not. */
.hours {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 6px 18px;
  font-size: 16px;
  line-height: 1.5;
}

.hours .day { color: var(--muted); white-space: nowrap; }
.hours .hrs { color: var(--cream); }

/* Below this the two columns no longer both fit, so stack every row rather
   than letting one wrap and the other not. */
@media (max-width: 430px) {
  .hours { grid-template-columns: 1fr; gap: 2px; }
  .hours .hrs { margin-bottom: 10px; }
}

.contact { line-height: 1.2; }

.contact a {
  display: inline-block;
  padding: 12px 0 10px;
  color: var(--neon);
  text-decoration: none;
  border-bottom: 1px solid rgba(255,210,63,.45);
}

.contact a:hover { border-bottom-color: var(--neon); }

.small {
  margin: 0;
  font-size: 14px;
  line-height: 1.6;
  color: #c9a079;
}

/* ---------- footer ---------- */

.foot {
  position: relative;
  z-index: 1;
  padding: 44px 24px 56px;
  border-top: 1px solid rgba(233,203,170,.16);
  background: var(--ink);
  text-align: center;
}

.foot-name {
  margin: 0 0 8px;
  font-size: 17px;
  font-weight: 700;
  letter-spacing: .04em;
  color: var(--cream);
}

.foot-line { margin: 0 0 10px; font-size: 15px; color: #c9a079; }

/* The number stands on its own line now that both addresses share the one
   above it, so it is a standalone target and the inline-link exception to the
   24px minimum no longer covers it. Padding, not a larger font. */
.foot-line a {
  display: inline-block;
  padding: 6px 2px;
  color: #e3d3c2;
  text-decoration: none;
  border-bottom: 1px solid rgba(227,211,194,.4);
}

.foot-links { margin: 0; display: flex; justify-content: center; gap: 24px; }
.foot-links a { padding: 13px 2px; font-size: 15px; color: #e3d3c2; text-decoration: none; border-bottom: 1px solid rgba(227,211,194,.4); }

/* ---------- mobile call bar ---------- */

/* Phones only, and phones never run the opening sequence, so this can never
   collide with the scroll lock. */
.callbar { display: none; }

@media (max-width: 600px) {
  .callbar {
    display: grid;
    grid-template-columns: 1fr 1fr;
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 10;
    gap: 1px;
    background: rgba(233,203,170,.2);
    border-top: 1px solid rgba(233,203,170,.2);
  }
  .callbar a {
    padding: 17px 10px;
    background: #241a15;
    color: var(--cream);
    font: 600 16px/1 ui-sans-serif, system-ui, sans-serif;
    text-align: center;
    text-decoration: none;
  }
  .callbar-order { background: var(--neon) !important; color: var(--ink) !important; }
  .foot { padding-bottom: 104px; }
}

/* ---------- documents ---------- */

/* The legal pages are pages, not an afterthought with a different look. They
   get the same header, the same rules and the same type scale as the rest of
   the site, plus a measure wide enough to read and narrow enough to scan. */
.doc {
  max-width: 720px;
  margin: 0 auto;
  padding: 72px 24px 110px;
  text-align: left;
}

.doc-kicker {
  margin: 0 0 12px;
  font-size: 13px;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--muted);
}

.doc h1 {
  margin: 0 0 10px;
  font-size: clamp(32px, 5vw, 46px);
  line-height: 1.05;
  color: var(--cream);
}

/* A numbered rule above each heading gives the page a visible spine, which is
   what a wall of policy prose is missing. */
.doc h2 {
  margin: 46px 0 14px;
  padding-top: 22px;
  border-top: 1px solid var(--rule);
  font-size: 20px;
  letter-spacing: .01em;
  color: var(--neon);
}

.doc p, .doc li { font-size: 17px; line-height: 1.75; color: #e3d3c2; }
.doc ul { padding-left: 20px; }
.doc li { margin-bottom: 12px; }
.doc li::marker { color: var(--adobe); }
.doc strong { color: var(--cream); }
.doc a { color: var(--neon); }

.doc-updated {
  display: inline-block;
  margin: 0 0 8px;
  padding: 7px 14px;
  border: 1px solid var(--rule);
  border-radius: 999px;
  font-size: 13.5px !important;
  letter-spacing: .04em;
  color: var(--muted) !important;
}

.doc-back {
  display: inline-block;
  margin-top: 48px;
  padding: 14px 22px;
  border: 1px solid rgba(255,210,63,.55);
  border-radius: 999px;
  color: var(--neon);
  font-size: 15px;
  text-decoration: none;
  transition: background var(--duration-fast) var(--ease);
}

.doc-back:hover { background: rgba(255,210,63,.12); }

/* ---------- reduced motion ---------- */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
  /* Every block lands on its finished state rather than simply going faster.
     Carries the html.js prefix to match the hiding rule's specificity, or it
     loses to it and reduced motion starts waiting on the observer. */
  html.js .rv { opacity: 1; transform: none; }
  .sd-scale, .sd-par { animation: none; transform: none; }

  /* The curtain is scroll coupled movement, which is exactly what this
     preference is asking us not to do. Unpinned, the hero simply scrolls away
     and every band below it is an ordinary stacked section. */
  .hero { position: relative; }
  main { box-shadow: none; }
  .curtain .glow { animation: none; transform: translateX(-50%); }

  .dish:hover img { transform: none; }
  .btn--sweep::before { animation: none; opacity: 0; }
  .marquee { overflow-x: auto; -webkit-mask-image: none; mask-image: none; }
  .marquee-track { animation: none; }
  .marquee-track > [aria-hidden="true"] { display: none; }

  .shot { display: none; }
  .still {
    display: block;
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: 52% 55%;
  }
  .cue span { animation: none; }
  html.cine .mark img,
  html.cine .cue,
  html.cine .blackout { animation: none; opacity: 1; }
  html.cine .blackout { opacity: 0; }
}
