/* Teow Tem Toh — Thai street screenprint.
   Flat inks, heavy rules, hard offset shadows. No blur, no gradients-as-decoration. */

/* ---------------------------------------------------------------- base */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
}

body {
  margin: 0;
  background: var(--surface-dark);
  color: var(--text-on-dark);
  font-family: var(--font-body);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* height:auto keeps the intrinsic ratio when only the width is constrained;
   components that size both axes override it. */
img {
  max-width: 100%;
  height: auto;
}

a {
  color: inherit;
  text-decoration: none;
}

h1,
h2,
h3,
h4 {
  font-family: var(--font-display);
  font-weight: 400;
  text-transform: uppercase;
  margin: 0;
}

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

.skip-link {
  position: absolute;
  left: var(--gutter);
  top: -100%;
  z-index: 100;
  background: var(--accent);
  color: var(--green-700);
  font-weight: 900;
  font-size: 13px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 12px 18px;
}

.skip-link:focus-visible {
  top: 12px;
}

.container {
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

/* Keep in-page jumps clear of the sticky header. */
:target,
[id] {
  scroll-margin-top: calc(var(--header-h) + 16px);
}

.thai {
  font-family: var(--font-thai);
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

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

/* Reveals only hide themselves once JS is present to bring them back. */
.has-reveal [data-reveal] {
  opacity: 0;
  transform: translateY(26px);
  transition:
    opacity var(--duration-slow) var(--ease-reveal),
    transform var(--duration-slow) var(--ease-reveal);
  transition-delay: var(--delay, 0ms);
}

.has-reveal [data-reveal].is-revealed {
  opacity: 1;
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  .has-reveal [data-reveal] {
    opacity: 1;
    transform: none;
    transition: none;
  }
}

/* ---------------------------------------------------------- intro seal */

/* A fixed overlay, not a section of the document: the hero sits directly under
   it and the page loses no height to the splash. The whole sequence is CSS;
   main.js only ends it, and the inline head script decides whether it runs at
   all. Hidden by default so no-JS and reduced-motion never see it. */

.intro {
  display: none;
}

.intro-pending .intro {
  display: flex;
  position: fixed;
  inset: 0;
  z-index: 200;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  background: var(--surface-dark);
  /* Never the hit target. The skip listeners live on window, so a tap still
     ends the splash — and also lands on whatever is beneath it, instead of
     being spent dismissing a logo. */
  pointer-events: none;
  animation: intro-exit 340ms var(--ease-out-expo) 2560ms both;
}

.intro__stage {
  position: relative;
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}

.intro-pending .intro__seal {
  position: relative;
  width: min(66vw, 63svh);
  aspect-ratio: 695 / 668;
  transform-origin: 50.4% 47.2%;
  will-change: transform;
  animation: intro-zoom 1450ms cubic-bezier(0.5, 0, 0.75, 0.3) 450ms both;
}

.intro__logo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: fill;
  /* Feather the outer rim so the seal stays clean as it scales up. */
  -webkit-mask-image: radial-gradient(ellipse closest-side at 50% 50%, #000 0 98%, transparent 99.5%);
  mask-image: radial-gradient(ellipse closest-side at 50% 50%, #000 0 98%, transparent 99.5%);
}

/* Photo revealed inside the counter of the Thai letter "ต". */
.intro-pending .intro__inner {
  position: absolute;
  left: 28.78%;
  top: 22.46%;
  width: 43.17%;
  height: 49.4%;
  overflow: hidden;
  -webkit-mask-image: url("../assets/logo-tor-mask.png");
  mask-image: url("../assets/logo-tor-mask.png");
  -webkit-mask-size: 100% 100%;
  mask-size: 100% 100%;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  animation: intro-fade 650ms linear 700ms both;
}

.intro__inner img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 46%;
}

/* The seal opens onto the full frame in the last beat. */
.intro-pending .intro__full {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 46%;
  pointer-events: none;
  animation: intro-fade 450ms linear 1800ms both;
}

.intro-pending .intro__wordmark {
  position: absolute;
  top: clamp(20px, 4vw, 38px);
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(14px, 2vw, 19px);
  letter-spacing: var(--tracking-widest);
  text-shadow: 2px 2px 0 var(--green-900);
  animation: intro-fade 600ms linear 500ms reverse both;
}

@keyframes intro-zoom {
  from {
    transform: scale(1);
  }
  to {
    transform: scale(3.4);
  }
}

@keyframes intro-fade {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

@keyframes intro-exit {
  to {
    opacity: 0;
    visibility: hidden;
  }
}

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

.site-header {
  position: sticky;
  top: 0;
  z-index: 60;
  background: var(--surface-dark);
  border-bottom: var(--border-heavy) solid var(--accent);
}

.site-header__inner {
  max-width: none;
  padding-inline: clamp(24px, 2.4vw, 40px);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
  padding-block: 12px;
  min-height: calc(var(--header-h) - var(--border-heavy));
}

.site-header__mark {
  font-family: var(--font-display);
  font-size: clamp(19px, 2.4vw, 24px);
  letter-spacing: 0.03em;
}

.site-nav {
  display: flex;
  align-items: center;
  gap: clamp(12px, 2vw, 26px);
  flex-wrap: wrap;
  font-weight: 800;
  font-size: 12px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.site-nav a {
  transition: color var(--duration-fast), transform var(--duration-fast);
}

.site-nav a:hover {
  color: var(--accent);
  transform: translateY(-2px);
}

/* -------------------------------------------------------------- button */

.btn {
  display: inline-block;
  font-weight: 900;
  font-size: 13.5px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.btn--primary {
  background: var(--action);
  color: var(--cream-100);
  padding: 16px 26px;
  box-shadow: var(--shadow-button);
  transition: transform var(--duration-fast), box-shadow var(--duration-fast);
}

.btn--primary:hover {
  transform: translate(-3px, -3px);
  box-shadow: var(--shadow-button-hover);
}

.btn--ghost {
  border: var(--border-heavy) solid var(--cream-100);
  color: var(--cream-100);
  padding: 13px 24px;
  transition: background var(--duration-normal), color var(--duration-normal);
}

.btn--ghost:hover {
  background: var(--cream-100);
  color: var(--green-700);
}

.btn--compact {
  background: var(--action);
  color: var(--cream-100);
  padding: 10px 18px;
  letter-spacing: 0.08em;
  font-size: 12px;
  transition: transform var(--duration-fast), box-shadow var(--duration-fast);
}

.site-nav .btn--compact:hover {
  color: var(--cream-100);
  transform: translate(-2px, -2px);
  box-shadow: 4px 4px 0 var(--green-900);
}

@media (max-width: 720px) {
  /* Hiding these left the narrow viewport with one control on a 15,397px
     page — and the narrow viewport is the primary one. They wrap to a second
     row instead, sized to clear the 24px target minimum. */
  .site-header__inner {
    flex-wrap: wrap;
    row-gap: 2px;
    padding-block: 8px 0;
  }

  .site-header__mark {
    font-size: 20px;
  }

  .site-nav {
    order: 3;
    width: 100%;
    gap: 0;
    justify-content: space-between;
    border-top: 1px solid rgb(244 239 225 / 0.18);
  }

  .site-nav > a:not(.btn--compact) {
    font-size: 10.5px;
    letter-spacing: 0.04em;
    padding-block: 9px;
  }

  /* The pickup button stays on the first row, beside the wordmark. */
  .site-nav .btn--compact {
    position: absolute;
    top: 8px;
    right: clamp(24px, 2.4vw, 40px);
  }

  .site-header__inner {
    position: relative;
  }

  .btn--compact {
    padding: 9px 12px;
    font-size: 11px;
  }

}

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

.hero {
  position: relative;
  overflow: hidden;
  min-height: calc(100svh - var(--header-h));
}

/* Halftone dot texture — the only "texture" the system allows. */
.hero__dots {
  position: absolute;
  inset: 0;
  background-image: radial-gradient(rgb(224 160 46 / 0.1) 1.3px, transparent 1.7px);
  background-size: 10px 10px;
  pointer-events: none;
}

.hero__photo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
}

.hero__photo img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}

/* Keep the complete bowl arrangement in view on wide screens; the hero's
   dark surface fills the small side margin created by the image ratio. */
@media (min-width: 721px) {
  /* Sized to the artwork's own ratio and pinned bottom-right, so the space
     around it reads as deliberate margin rather than a letterbox seam. */
  .hero__photo {
    inset: auto 0 0 auto;
    width: min(82vw, 1380px);
    height: auto;
    aspect-ratio: 1641 / 958;
    max-height: 100%;
  }

  .hero__photo img {
    object-fit: cover;
    object-position: right bottom;
  }
}

/* Horizontal scrim so the headline keeps contrast over the photo. */
.hero__scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(
    90deg,
    rgb(11 36 28 / 0.97) 0 30%,
    rgb(20 59 47 / 0.88) 40%,
    rgb(20 59 47 / 0.46) 55%,
    rgb(20 59 47 / 0.06) 70%
  );
  pointer-events: none;
}

.hero__inner {
  position: relative;
  max-width: none;
  padding-inline: clamp(24px, 2.4vw, 40px);
  display: flex;
  align-items: center;
  min-height: calc(100svh - var(--header-h));
  padding-block: clamp(30px, 5vw, 52px) clamp(36px, 5vw, 64px);
}

.hero__copy {
  width: 100%;
  max-width: min(520px, 100%);
}

.hero__eyebrow {
  display: inline-block;
  background: var(--accent);
  color: var(--green-700);
  padding: 6px 13px;
  font-weight: 900;
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  margin-bottom: 16px;
}

.hero__thai {
  font-weight: 900;
  font-size: clamp(24px, 3vw, 32px);
  color: var(--accent);
  line-height: 1;
  margin-bottom: 10px;
}

.hero__title {
  font-size: var(--text-hero);
  line-height: 0.86;
  letter-spacing: 0.004em;
  text-shadow: 6px 6px 0 var(--action-display);
}

.hero__lede {
  max-width: 430px;
  margin: 24px 0 26px;
  font-size: var(--text-body);
  line-height: 1.6;
  color: rgb(244 239 225 / 0.85);
}

.hero__actions {
  display: flex;
  gap: 12px;
  align-items: center;
  flex-wrap: wrap;
}

.hero__badge {
  position: absolute;
  bottom: clamp(24px, 4vw, 52px);
  right: clamp(16px, 4vw, 32px);
  width: clamp(96px, 12vw, 124px);
  height: clamp(96px, 12vw, 124px);
  border-radius: 50%;
  background: var(--accent);
  color: var(--green-700);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  line-height: 1;
  box-shadow: 6px 6px 0 var(--green-900);
  transform: rotate(11deg);
  animation: bob 5s ease-in-out infinite;
}

.hero__badge b {
  font-weight: 400;
  font-size: clamp(22px, 3vw, 30px);
}

.hero__badge span {
  font-size: 11px;
  letter-spacing: 0.06em;
}

.hero__badge span:last-child {
  font-size: 10px;
}

/* The stamp is a link now. `bob` owns transform, so the press-shift lands on
   the shadow alone; and the global gold focus ring would vanish on gold. */
.hero__badge:hover,
.hero__badge:focus-visible {
  /* Settle the bob while it is being aimed at; a target that never stops
     moving is harder to hit, and worst for anyone with a motor impairment. */
  animation-play-state: paused;
  box-shadow: 9px 9px 0 var(--green-900);
}

.hero__badge:focus-visible {
  outline-color: var(--green-900);
}

@keyframes bob {
  0%,
  100% {
    transform: rotate(11deg) translateY(0);
  }
  50% {
    transform: rotate(11deg) translateY(-8px);
  }
}

/* --------------------------------------------------------- service strip */

.service-strip {
  position: relative;
  background: var(--action);
  color: var(--cream-100);
  border-block: var(--border-heavy) solid var(--green-700);
  font-size: 11px;
  font-weight: 900;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.service-strip__link {
  color: inherit;
  border-bottom: 2px solid rgb(244 239 225 / 0.55);
  padding-block: 3px;
}

.service-strip__link:hover {
  border-bottom-color: var(--cream-100);
}

.service-strip .container {
  min-height: 48px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  padding-block: 10px;
}

@media (max-width: 720px) {
  .hero__photo {
    width: 100%;
  }

  .hero__photo img {
    object-position: 60% 48%;
  }

  .hero__scrim {
    background: linear-gradient(
      90deg,
      rgb(20 59 47 / 0.97) 0 42%,
      rgb(20 59 47 / 0.9) 64%,
      rgb(20 59 47 / 0.56) 100%
    );
  }

  /* Close on the content instead of holding a full viewport of scrimmed
     photo, so the address strip lands inside the first screen. */
  .hero,
  .hero__inner {
    min-height: 0;
  }

  .hero__inner {
    padding-block: clamp(26px, 7vw, 40px) clamp(30px, 8vw, 48px);
  }

  /* The Crowding Rule: below ~44px the 6px offset lands on the line beneath. */
  .hero__title {
    text-shadow: 3px 3px 0 var(--action-display);
  }

  .hero__eyebrow {
    letter-spacing: 0.1em;
    font-size: 10px;
    padding: 6px 10px;
  }

  /* Measured 3.73:1 over the scrimmed photo at this width. A solid ground is
     the only guarantee here: the backdrop is a photograph, so no token-level
     check can prove it. */
  .hero .btn--ghost {
    background: var(--green-700);
  }

  .hero__actions {
    gap: 10px;
  }

  .hero__badge {
    position: static;
    align-self: flex-end;
    margin-top: -18px;
    transform: rotate(-7deg);
    animation: none;
  }

  .hero__inner {
    flex-direction: column;
    align-items: stretch;
  }

  .service-strip .container {
    justify-content: center;
    gap: 6px 16px;
  }
}

/* The remaining ticker is used once, as a transition into the story. */
.marquee {
  display: flex;
  align-items: center;
  overflow: hidden;
  font-family: var(--font-display);
  text-transform: uppercase;
}

.marquee__track {
  display: flex;
  white-space: nowrap;
  /* Three passes, then it rests. The track is two identical halves and the
     loop ends on -50%, so the final frame is pixel-identical to the first —
     it settles rather than stopping somewhere arbitrary.

     This does NOT satisfy WCAG 2.2.2: three passes is 135 seconds and the
     criterion exempts only motion under five. It is less motion, not
     conformant motion. See PRODUCT.md. */
  animation: marquee 45s linear 3 forwards;
}

/* The loop translates by exactly half the track, so each half must be wider
   than the viewport in ACTUAL CONTENT. `min-width: 100%` looked like it
   guaranteed that and did the opposite: it resolves against the track, so it
   doubled the box while the spans stayed put and half of every group was bare.
   Five repeats measure ~4,114px, which clears any real display. */
.marquee__group {
  display: flex;
  flex: 0 0 auto;
}

.marquee__track span {
  padding-inline: 22px;
}

.marquee--gold {
  height: 44px;
  background: var(--accent);
  color: var(--green-700);
  border-block: var(--border-heavy) solid var(--green-700);
  font-size: 15px;
  letter-spacing: 0.1em;
}

/* JS-only: hold the run until the band is actually on screen, so the beat is
   not spent while the reader is still in the hero. */
.has-marquee-gate .marquee__track {
  animation-play-state: paused;
}

.has-marquee-gate .marquee__track.is-running {
  animation-play-state: running;
}

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

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

/* ---------------------------------------------------- signature bowls */

.signature {
  background: var(--surface-muted);
  color: var(--text-on-light);
  padding-block: clamp(40px, 6vw, 66px);
}

.signature__head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 30px;
  flex-wrap: wrap;
}

.signature__head h2 {
  font-size: var(--text-h2);
  letter-spacing: 0.01em;
  line-height: 0.95;
}

.signature__note {
  font-weight: 900;
  font-size: var(--text-meta);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--action);
  text-align: right;
  padding-bottom: 8px;
}

.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(270px, 100%), 1fr));
  gap: clamp(16px, 2.4vw, 26px);
}

.card {
  position: relative;
  background: var(--surface-light);
  border: var(--border-heavy) solid var(--green-700);
  overflow: hidden;
  box-shadow: var(--shadow-card);
  transition: transform var(--duration-normal), box-shadow var(--duration-normal);
}

.card:hover {
  transform: translate(-4px, -6px);
  box-shadow: var(--shadow-card-hover);
}

.card__media {
  position: relative;
  height: clamp(200px, 22vw, 230px);
  overflow: hidden;
  background: var(--surface-placeholder);
}

.card__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 500ms var(--ease-out-expo);
}

.card:hover .card__media img {
  transform: scale(1.05);
}

.card__tag {
  position: absolute;
  top: 0;
  left: 0;
  background: var(--action);
  color: var(--cream-100);
  font-family: var(--font-display);
  font-size: 14px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 6px 14px;
}

.card__body {
  padding: 18px 20px 22px;
  border-top: var(--border-heavy) solid var(--green-700);
}

.card__title {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
}

/* The card lifted and zoomed on hover while being an <article> with no link —
   an affordance it could not honour. The heading carries the link and a
   stretched ::after makes the whole card the target, so the accessible name
   stays the dish rather than becoming "read more". */
.card__title h3 a::after {
  content: "";
  position: absolute;
  inset: 0;
}

.card__go {
  margin: 10px 0 0;
  font-weight: 900;
  font-size: 11.5px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--action);
}

.card__title h3 {
  font-size: 21px;
  letter-spacing: 0.01em;
}

.card__thai {
  font-size: 14px;
  color: rgb(20 59 47 / 0.75);
  margin: 3px 0 8px;
}

.card__desc {
  font-size: 14px;
  line-height: 1.55;
  color: rgb(20 59 47 / 0.75);
  margin: 0;
}

/* --------------------------------------------------------------- tower */

.tower {
  position: relative;
  background: var(--action);
  color: var(--cream-100);
  overflow: hidden;
}

.tower__grid {
  max-width: var(--container);
  margin-inline: auto;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr));
  align-items: center;
}

.tower__copy {
  padding: clamp(44px, 6vw, 72px) clamp(16px, 4vw, 34px);
}

.tower__eyebrow {
  display: inline-block;
  background: var(--accent);
  color: var(--green-700);
  font-family: var(--font-display);
  font-size: 14px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding: 6px 14px;
  margin-bottom: 20px;
}

.tower__title {
  font-size: clamp(46px, 7.4vw, 80px);
  line-height: 0.85;
  text-shadow: 5px 5px 0 var(--green-700);
}

.tower__lede {
  font-size: clamp(15px, 1.6vw, 16.5px);
  line-height: 1.7;
  max-width: 460px;
  margin: 24px 0;
  color: rgb(244 239 225 / 0.92);
}

.stats {
  display: flex;
  border: var(--border-heavy) solid var(--cream-100);
  flex-wrap: wrap;
}

.stats > div {
  flex: 1;
  min-width: 100px;
  padding: 15px 17px;
  border-right: var(--border-heavy) solid var(--cream-100);
}

.stats > div:last-child {
  border-right: 0;
  background: var(--accent);
  color: var(--green-700);
}

.stats dt {
  font-family: var(--font-display);
  font-size: 34px;
  line-height: 1;
}

.stats dd {
  margin: 0;
  font-weight: 900;
  font-size: 10.5px;
  letter-spacing: var(--tracking-meta);
  text-transform: uppercase;
  color: rgb(244 239 225 / 0.92);
}

.stats > div:last-child dd {
  color: inherit;
}

/* The section that carries the whole argument used to end on the stats and
   offer nothing to press. */
.tower__cta {
  display: inline-block;
  margin-top: clamp(20px, 3vw, 28px);
}

/* The bowl-stack artwork carries its own callout copy near the left and right
   edges, so the panel takes the artwork's ratio rather than cropping to fill. */
.tower__media {
  position: relative;
  aspect-ratio: 1400 / 797;
  background: var(--red-700);
  overflow: hidden;
}

/* Vertical overscan only — enough headroom for the parallax shift, shallow
   enough that the side crop stays clear of the callout bubbles. */
.tower__media img {
  position: absolute;
  inset: -4% 0;
  width: 100%;
  height: 108%;
  object-fit: cover;
  object-position: 50% 50%;
}

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

.menu {
  background: var(--surface-light);
  color: var(--text-on-light);
  padding-block: clamp(44px, 6vw, 70px) clamp(50px, 7vw, 80px);
}

.menu__rule {
  border-top: 6px solid var(--green-700);
  border-bottom: var(--border-heavy) solid var(--green-700);
  padding-block: 14px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  margin-bottom: 12px;
  flex-wrap: wrap;
  font-weight: 900;
  font-size: var(--text-meta);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
}

.menu__rule .thai {
  font-weight: 700;
  font-size: 15px;
  letter-spacing: normal;
  text-transform: none;
  color: rgb(20 59 47 / 0.75);
}

.menu__title {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: clamp(72px, 14vw, 160px);
  margin: 10px 0 4px;
  font-size: var(--text-display);
  line-height: 0.86;
  text-align: center;
  letter-spacing: -0.01em;
  text-shadow: 3px 3px 0 var(--action-display);
}

.menu__promise {
  text-align: center;
  text-wrap: balance;
  font-weight: 900;
  font-size: 11px;
  letter-spacing: var(--tracking-widest);
  text-transform: uppercase;
  color: var(--action);
  border-bottom: var(--border-heavy) solid var(--green-700);
  padding-bottom: 22px;
  margin-bottom: clamp(28px, 4vw, 44px);
}

/* Eleven sections is a long scroll. The chips are plain anchors, so they work
   with JS off and cost the page nothing.

   One row that scrolls, not five that wrap: wrapped, this cost a third of the
   first screen on a phone before any food appeared. It sticks under the header
   so the accelerator is still there after it has been used once. */
.menu__jump {
  display: flex;
  gap: 8px;
  /* Wraps at every width. It used to scroll below 900px, which hid nine of the
     eleven sections behind an invisible scrollbar and clipped BEEF NOODLES to
     "BE" — the exact failure the desktop branch was written to avoid. */
  flex-wrap: wrap;
  justify-content: center;
  background: var(--surface-light);
  border-bottom: var(--border-heavy) solid var(--green-700);
  padding-block: 10px;
  margin-bottom: clamp(24px, 3vw, 34px);
}

.menu__jump a {
  display: flex;
  align-items: center;
  flex: 0 0 auto;
  min-height: 44px;
  scroll-snap-align: start;
  font-weight: 900;
  font-size: var(--text-meta);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--text-on-light);
  border: 2px solid var(--green-700);
  padding: 5px 13px;
  transition: background-color var(--duration-fast), color var(--duration-fast);
}

/* Narrow screens tighten the chips so the index is three or four rows, not ten.
   This has to sit after `.menu__jump a`: a media query adds no specificity, so
   source order is what decides. */
@media (max-width: 720px) {
  .menu__jump {
    gap: 6px;
  }

  .menu__jump a {
    letter-spacing: 0.02em;
    font-size: 11px;
    padding: 5px 8px;
  }
}

.menu__jump a:hover,
.menu__jump a:focus-visible {
  background: var(--gold-500);
}

/* Sits under the last section, above the footnote, where the small print is. */
.menu__legend {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 8px 14px;
  margin: 4px 0 0;
}

.menu__legend span {
  font-weight: 700;
  font-size: 12px;
  color: rgb(20 59 47 / 0.8);
}

/* The marks sit in the description line, so they ride the text baseline rather
   than opening a row of their own on the handful of dishes that carry them. */
.menu__marks {
  white-space: nowrap;
}

.menu__mark {
  vertical-align: -2px;
  margin-left: 3px;
}

.menu__mark--peanut {
  color: var(--green-700);
}

.menu__mark--spicy {
  color: var(--action);
}

/* The one argument a competitor cannot copy, printed at the size of an
   argument rather than as rows 3 and 4 of a list. */
.menu__lead {
  display: grid;
  grid-template-columns: minmax(0, 280px) minmax(0, 1fr);
  align-items: center;
  gap: clamp(18px, 3vw, 40px);
  background: var(--surface-dark);
  color: var(--text-on-dark);
  padding: clamp(18px, 2.6vw, 30px);
  margin-bottom: clamp(30px, 4vw, 46px);
}

@media (max-width: 720px) {
  .menu__lead {
    grid-template-columns: minmax(0, 1fr);
  }

  .menu__lead-photo {
    max-height: 210px;
  }
}

.menu__lead-photo {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 1;
  object-fit: cover;
}

.menu__lead-copy h3 {
  font-size: clamp(30px, 4.4vw, 50px);
  line-height: 0.88;
  text-transform: uppercase;
  margin: 0 0 12px;
  text-shadow: var(--border-heavy) var(--border-heavy) 0 var(--action-display);
}

.menu__lead-copy > p {
  font-size: 15px;
  line-height: 1.55;
  margin: 0 0 16px;
  max-width: 52ch;
}

.menu__lead-price {
  display: flex;
  align-items: baseline;
  gap: 10px;
  font-family: var(--font-display);
  font-size: clamp(17px, 2vw, 20px);
  text-transform: uppercase;
  margin: 0 0 2px;
}

.menu__lead-price::after {
  content: "";
  order: 1;
  flex: 1;
  min-width: 24px;
  border-bottom: 2px dotted rgb(244 239 225 / 0.45);
  transform: translateY(-5px);
}

.menu__lead-price .menu__price {
  color: var(--accent);
}

.menu__lead-bowls {
  list-style: none;
  margin: 0 0 14px;
  padding: 0;
  border-top: 1px solid rgb(244 239 225 / 0.35);
}

.menu__lead-bowls li {
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding-block: 9px;
  border-bottom: 1px solid rgb(244 239 225 / 0.35);
  font-family: var(--font-display);
  font-size: clamp(17px, 2vw, 20px);
  text-transform: uppercase;
}

.menu__lead-bowls .menu__price {
  color: var(--text-on-dark);
}

.menu__lead-tag {
  font-weight: 900;
  font-size: var(--text-meta);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--accent);
  margin: 0;
}

/* The same intrinsic grid as every other region. Multi-column flowed the
   sections column-major, so the jump chips and the reading order disagreed:
   pressing Desserts landed section nine in column three while the reader's eye
   went to the top-left and found Recommended. A ragged column bottom is the
   cheaper problem, and it is the one this keeps. */
/* Columns, not a grid. An intrinsic grid sizes every row to its tallest member,
   so eleven sections of wildly different lengths left 1,441px of blank
   newsprint — 563px of it beside Beef Noodles, the section people come for.
   Columns fill in sequence instead, so the only empty space left is the ragged
   bottom of the last column, which is what a printed menu looks like anyway. */
.menu__groups {
  /* Longhand: the `columns` shorthand rejects `min()` as a column-width, and an
     invalid shorthand silently collapses the whole menu into one column. */
  column-width: 310px;
  column-gap: clamp(28px, 4vw, 56px);
}

.menu__groups > * {
  break-inside: avoid;
}

.menu__figure {
  margin: 0 0 clamp(30px, 4vw, 44px);
  align-self: start;
}

.menu__figure img {
  display: block;
  width: 100%;
  height: auto;
  /* The assets are 2:3. Framing them at 3:4 is a deliberate crop: it costs a
     long menu less height than the full frame, and every figure then matches. */
  aspect-ratio: 3 / 4;
  object-fit: cover;
}

/* The menu used to end on the grid's leftover cell. It ends on the order. */
.menu__order {
  align-self: start;
  background: var(--surface-dark);
  color: var(--text-on-dark);
  padding: clamp(20px, 2.4vw, 28px);
  margin-bottom: clamp(30px, 4vw, 44px);
}

.menu__order h3 {
  font-size: clamp(30px, 3.4vw, 44px);
  line-height: 0.88;
  margin: 0 0 12px;
  text-shadow: var(--border-heavy) var(--border-heavy) 0 var(--action-display);
}

.menu__order p {
  font-size: 14px;
  line-height: 1.55;
  margin: 0 0 18px;
}

.menu__order-alt {
  display: inline-block;
  margin-top: 14px;
  font-weight: 900;
  font-size: var(--text-meta);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  border-bottom: 2px solid var(--accent);
  /* A bare text link measured 21px tall, under SC 2.5.8's 24px floor. Set
     after the border rule, or the shorthand below it wins on the bottom. */
  padding: 7px 0 5px;
}

.menu__group {
  margin-bottom: clamp(30px, 4vw, 44px);
  scroll-margin-top: calc(var(--header-h) + 78px);
}

/* Pop and juice are names on a list — the menu prints no description and no
   price for them, so neither does the page. */
.menu__compact {
  padding-block: 11px;
  border-bottom: 1px solid rgb(20 59 47 / 0.22);
}

.menu__compact h4 {
  display: flex;
  align-items: baseline;
  gap: 10px;
  font-family: var(--font-display);
  font-size: 15px;
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  margin: 0 0 4px;
}

.menu__compact h4::after {
  content: "";
  order: 1;
  flex: 1;
  border-bottom: 2px dotted rgb(20 59 47 / 0.3);
  transform: translateY(-4px);
  min-width: 14px;
}

.menu__compact .menu__price {
  font-size: clamp(18px, 2.2vw, 21px);
}

.menu__compact p {
  font-size: 14px;
  line-height: 1.6;
  color: rgb(20 59 47 / 0.8);
  margin: 0;
}

.menu__group-head {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 16px;
  flex-wrap: wrap;
}

.menu__group-head h3 {
  font-size: var(--text-h3);
  background: var(--green-700);
  color: var(--cream-100);
  padding: 4px 12px;
}

.menu__group-head .thai {
  font-size: 15px;
  color: rgb(20 59 47 / 0.75);
}

.menu__group-head::after {
  content: "";
  flex: 1;
  height: var(--border-heavy);
  background: var(--green-700);
  min-width: 16px;
}

.menu__item {
  padding-block: 11px;
  border-bottom: 1px solid rgb(20 59 47 / 0.22);
}

.menu__item-line {
  display: flex;
  align-items: baseline;
  gap: 10px;
  font-family: var(--font-display);
  font-size: clamp(18px, 2.2vw, 21px);
  text-transform: uppercase;
  letter-spacing: 0.01em;
}

.menu__item-line::after {
  content: "";
  order: 1;
  flex: 1;
  border-bottom: 2px dotted rgb(20 59 47 / 0.3);
  transform: translateY(-5px);
  min-width: 40px;
}

/* Rows whose prices live in the sub-list have nothing to point at — and rows
   whose name fills the column have nowhere to point: a two-dot leader reads as
   an ellipsis on the end of a dish name. The renderer knows the name length,
   so the decision is made there rather than left to flex to approximate. */
/* Rows whose prices live in the sub-list have nothing to point at. */
.menu__item-line--bare::after {
  content: none;
}

/* The leader is a pointing device; what it points at is the price. */
.menu__price {
  order: 2;
  /* When the row wraps, the leader keeps the first line and the price takes
     the second — where nothing would otherwise push it to the right edge. */
  margin-left: auto;
  color: var(--text-on-light);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

/* Options price the same dish more than once, so they hang under the name
   rather than fighting it for the one leader line. */
.menu__options {
  list-style: none;
  margin: 6px 0 0;
  padding: 0;
}

.menu__options li {
  display: flex;
  align-items: baseline;
  gap: 10px;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.02em;
  padding-block: 2px;
  color: rgb(20 59 47 / 0.8);
}

.menu__options li::after {
  content: "";
  order: 1;
  flex: 1;
  border-bottom: 1px dotted rgb(20 59 47 / 0.3);
  transform: translateY(-4px);
  min-width: 14px;
}

.menu__options .menu__price {
  font-family: var(--font-display);
  font-size: 15px;
}

.menu__item p {
  font-size: 14px;
  line-height: 1.5;
  color: rgb(20 59 47 / 0.8);
  margin: 2px 0 0;
}

/* The name row is a `p` inside `.menu__item` too, so the rule above outranks
   `.menu__item-line` on specificity and flattens the row to one size — the
   dish name then reads smaller than its own description, because Anton is
   condensed. Restate the row's own type at a weight that wins. */
.menu__item p.menu__item-line {
  font-size: clamp(18px, 2.2vw, 21px);
  line-height: 1.15;
  color: var(--text-on-light);
  margin: 0;
}

.menu__footnote {
  max-width: 62ch;
  margin-inline: auto;
  text-align: center;
  font-weight: 700;
  font-size: 13px;
  letter-spacing: 0.04em;
  color: rgb(20 59 47 / 0.8);
  margin: 20px 0 0;
}

.menu__footnote-jump {
  display: inline-block;
  margin-left: 14px;
  padding-block: 4px;
  color: var(--text-on-light);
  border-bottom: 2px solid rgb(20 59 47 / 0.4);
}

.menu__footnote-link {
  display: inline-block;
  margin-left: 6px;
  padding-block: 4px;
  color: var(--action);
  border-bottom: 2px solid var(--action);
}

/* --------------------------------------------------------------- story */

.story {
  background: var(--surface-dark);
  padding-block: clamp(48px, 7vw, 78px);
}

.story__head {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: clamp(10px, 2vw, 20px);
  margin-bottom: clamp(30px, 4vw, 48px);
}

.story__head::before,
.story__head::after {
  content: "";
  height: var(--border-heavy);
  background: var(--rule-on-dark);
}

.story__head h2 {
  font-size: clamp(32px, 5vw, 56px);
  text-shadow: 4px 4px 0 var(--action-display);
}

.story__steps {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr));
  gap: clamp(24px, 3vw, 34px);
  margin-bottom: clamp(34px, 5vw, 52px);
  counter-reset: step;
}

.story__step {
  counter-increment: step;
}

.story__step::before {
  content: "0" counter(step);
  display: block;
  font-family: var(--font-display);
  font-size: 60px;
  line-height: 0.9;
  color: var(--accent);
}

.story__step h3 {
  font-size: 24px;
  margin-bottom: 12px;
  line-height: 1.05;
}

.story__step h3::before {
  content: "";
  display: block;
  height: var(--border-heavy);
  background: var(--action-display);
  margin: 12px 0 16px;
}

.story__step p {
  font-size: 15px;
  line-height: 1.7;
  color: var(--text-muted-dark);
  margin: 0;
}

.story__quote {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
  gap: clamp(24px, 3vw, 40px);
  align-items: center;
  border-top: var(--border-heavy) solid rgb(244 239 225 / 0.2);
  padding-top: clamp(30px, 4vw, 44px);
  margin: 0;
}

.story__quote blockquote {
  font-family: var(--font-display);
  font-size: clamp(30px, 4.4vw, 46px);
  line-height: 1.02;
  text-transform: uppercase;
  color: var(--accent);
  margin: 0;
}

.story__quote p {
  font-size: 15.5px;
  line-height: 1.7;
  color: var(--text-muted-dark);
  margin: 20px 0 0;
  max-width: 520px;
}

.story__quote img {
  width: 100%;
  border: 6px solid var(--cream-100);
  box-shadow: 14px 14px 0 rgb(11 36 28 / 0.35);
  display: block;
  transition: transform 350ms var(--ease-out-expo);
}

.story__quote img:hover {
  transform: rotate(-1.5deg) scale(1.02);
}

/* --------------------------------------------------------------- order */

.order {
  background: var(--surface-muted);
  color: var(--text-on-light);
  padding-block: var(--space-section);
}

.order h2 {
  font-size: var(--text-h2);
  margin-bottom: 8px;
  text-align: center;
}

.order__lede {
  text-align: center;
  font-size: 15.5px;
  color: var(--text-muted-light);
  margin: 0 0 34px;
}

.order__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(250px, 100%), 1fr));
  gap: 20px;
}

.order-card {
  border: var(--border-heavy) solid var(--green-700);
  padding: 28px 24px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  min-height: 190px;
  box-shadow: 8px 8px 0 rgb(20 59 47 / 0.25);
  transition: transform var(--duration-normal), box-shadow var(--duration-normal);
}

.order-card:hover {
  transform: translate(-4px, -5px);
  box-shadow: 13px 13px 0 rgb(20 59 47 / 0.3);
}

.order-card h3 {
  font-size: 25px;
  letter-spacing: 0.02em;
}

.order-card p {
  font-size: 14.5px;
  line-height: 1.6;
  margin: 0;
  flex: 1;
}

.order-card span {
  font-weight: 900;
  font-size: 12.5px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* The colour is the categorization (DESIGN.md), so it has to say what the
   business wants: the restaurant's own channel loudest, the commission-taking
   marketplace second, walk-in third. */
.order-card--pickup {
  background: var(--action);
  border-color: var(--action);
  color: var(--cream-100);
}

.order-card--pickup p {
  color: rgb(244 239 225 / 0.92);
}

.order-card--delivery {
  background: var(--surface-light);
  border-color: var(--green-700);
}

.order-card--delivery h3 {
  color: var(--action);
}

.order-card--delivery p {
  color: rgb(20 59 47 / 0.75);
}

.order-card--dinein {
  background: var(--green-700);
  color: var(--cream-100);
}

.order-card--dinein h3 {
  color: var(--accent);
}

.order-card--dinein p {
  color: rgb(244 239 225 / 0.86);
}

/* ------------------------------------------------------------- gallery */

.gallery {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(150px, 100%), 1fr));
  gap: 4px;
  background: var(--surface-dark);
}

.gallery li {
  aspect-ratio: 1;
  overflow: hidden;
  background: var(--surface-placeholder);
}

/* Five silent squares before this: no name, no price, no destination. */
.gallery__link {
  display: block;
  position: relative;
  height: 100%;
}

.gallery__name {
  position: absolute;
  inset: auto 0 0;
  padding: 24px 12px 10px;
  background: linear-gradient(rgb(11 36 28 / 0), rgb(11 36 28 / 0.9));
  color: var(--cream-100);
  font-weight: 900;
  font-size: 11.5px;
  letter-spacing: 0.06em;
  line-height: 1.25;
  text-transform: uppercase;
}

.gallery img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 500ms var(--ease-out-expo);
}

.gallery img:hover {
  transform: scale(1.07);
}

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

.site-footer {
  background: var(--surface-darkest);
  padding: var(--space-section) var(--gutter) 0;
  border-top: 6px solid var(--accent);
}

.site-footer__inner {
  max-width: var(--container);
  margin-inline: auto;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
  gap: clamp(28px, 4vw, 56px);
  align-items: start;
}

.site-footer__mark {
  font-family: var(--font-display);
  font-size: clamp(26px, 4vw, 34px);
  letter-spacing: 0.03em;
  margin-bottom: 20px;
}

.site-footer__cols {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(150px, 100%), 1fr));
  gap: 26px 24px;
}

.site-footer h2 {
  font-family: var(--font-body);
  font-weight: 900;
  font-size: var(--text-meta);
  letter-spacing: var(--tracking-meta);
  color: var(--accent);
  margin-bottom: 8px;
}

.site-footer address {
  font-style: normal;
  font-size: 15px;
  line-height: 1.6;
}

.site-footer__link {
  display: inline-block;
  margin-top: 6px;
  padding-block: 6px;
  font-weight: 800;
  font-size: 13px;
  letter-spacing: 0.04em;
  color: var(--accent);
  border-bottom: 1px solid var(--accent);
  padding-bottom: 2px;
}

.hours {
  font-size: 15px;
  line-height: 1.9;
  margin: 0;
}

.hours div {
  display: flex;
  justify-content: space-between;
  gap: 16px;
}

.hours dt,
.hours dd {
  margin: 0;
}

.hours dd {
  color: rgb(244 239 225 / 0.7);
}

.socials {
  display: flex;
  gap: 12px;
  margin-top: 2px;
}

.socials a {
  width: 38px;
  height: 38px;
  border: 2px solid rgb(244 239 225 / 0.35);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background var(--duration-normal);
}

.socials a:hover {
  background: var(--accent);
}

.socials svg {
  width: 18px;
  height: 18px;
  fill: var(--cream-100);
}

.socials a:hover svg {
  fill: var(--green-700);
}

.site-footer__map {
  border: 5px solid var(--cream-100);
  overflow: hidden;
  box-shadow: 10px 10px 0 rgb(11 36 28 / 0.35);
  min-height: 300px;
  background: var(--green-600);
}

.site-footer__map iframe {
  display: block;
  width: 100%;
  height: 100%;
  min-height: 300px;
  border: 0;
  filter: grayscale(0.2) contrast(1.05);
}

.site-footer__legal {
  max-width: var(--container);
  margin: 40px auto 0;
  border-top: 1px solid rgb(244 239 225 / 0.15);
  padding-block: 20px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  font-size: 12px;
  color: rgb(244 239 225 / 0.55);
  flex-wrap: wrap;
}

.site-footer__legal b {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 16px;
  letter-spacing: 0.05em;
  color: rgb(244 239 225 / 0.8);
}
