/* Faves — design system + components. One file, no build step. */

/* ---------- Design tokens ---------- */
:root {
  color-scheme: light dark;

  /* Warm neutrals + one rich accent (burnt orange / chilli). */
  --bg: #faf5ee;
  --surface: #fffdf9;
  --surface-2: #f3ebe0;
  --ink: #2b2420;
  --ink-soft: #6c5f55;
  --line: #e6dcce;
  --accent: #bd451f;
  --accent-ink: #ffffff;
  --accent-soft: #f6e6dd;
  --warn: #b02a15;
  --warn-bg: #fbe4de;
  --warn-ink: #5c130a;
  --ok: #2f7d32; /* "open" — meets AA on --surface */
  --amber: #9a5b00; /* "closing/opening soon" */
  --focus: #1f6feb;

  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica,
    Arial, sans-serif;

  --step-sub: 0.82rem;
  --step-body: 1rem;
  --step-name: 1.3rem;
  --step-title: 1.9rem;

  --space-1: 0.35rem;
  --space-2: 0.65rem;
  --space-3: 1rem;
  --space-4: 1.5rem;
  --space-5: 2.25rem;

  /* Height of the mobile compact contact bar; the sticky toolbar offsets by
     this while the bar is shown (see .contact-bar-open). */
  --contact-bar-h: 3rem;

  --radius: 14px;
  --radius-chip: 999px;
  --shadow: 0 1px 2px rgba(43, 36, 32, 0.06), 0 6px 18px rgba(43, 36, 32, 0.07);
  --shadow-lift: 0 2px 6px rgba(43, 36, 32, 0.1), 0 14px 32px rgba(43, 36, 32, 0.13);
  --bar-h: 4.6rem;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #171310;
    --surface: #221c17;
    --surface-2: #2c241d;
    --ink: #f3e9dd;
    --ink-soft: #b9a897;
    --line: #382e25;
    --accent: #e87345;
    --accent-ink: #1a1109;
    --accent-soft: #38251b;
    --warn: #ff7a68;
    --warn-bg: #3a1712;
    --warn-ink: #ffd8d0;
    --ok: #7bc47f;
    --amber: #e0a33e;
    --focus: #6ea8ff;
    --shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 6px 18px rgba(0, 0, 0, 0.35);
    --shadow-lift: 0 2px 6px rgba(0, 0, 0, 0.5), 0 14px 32px rgba(0, 0, 0, 0.5);
  }
}

/* ---------- Reset-ish ---------- */
*,
*::before,
*::after {
  box-sizing: border-box;
}
/* The whole app hides/shows via the `hidden` attribute (no inline display
   toggles anywhere). The UA's [hidden]{display:none} loses to any author rule
   that sets display (flex/grid/…) at equal specificity — which silently broke
   the overflow menu and the QR card (they showed when hidden). This guard makes
   the attribute always win, app-wide, so the pattern can't regress again. */
[hidden] {
  display: none !important;
}
html {
  -webkit-text-size-adjust: 100%;
}
body {
  margin: 0;
  font-family: var(--font);
  font-size: var(--step-body);
  line-height: 1.5;
  color: var(--ink);
  background: var(--bg);
  min-height: 100dvh;
  -webkit-font-smoothing: antialiased;
}
h1,
h2,
h3,
p,
ul {
  margin: 0;
}
ul {
  list-style: none;
  padding: 0;
}
a {
  color: inherit;
  text-decoration: none;
}
button {
  font: inherit;
  color: inherit;
}
img {
  max-width: 100%;
}

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

.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;
}

.wrap {
  width: min(100% - 2 * var(--space-3), 60rem);
  margin-inline: auto;
}

/* ---------- Header ---------- */
.app-header {
  padding: var(--space-4) 0 var(--space-3);
}
.app-title {
  font-size: var(--step-title);
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.05;
}
.app-title::first-letter {
  color: var(--accent);
}
.app-sub {
  color: var(--ink-soft);
  font-size: var(--step-sub);
  margin-top: var(--space-1);
}

/* ---------- Main / results ---------- */
main {
  padding-bottom: calc(var(--bar-h) + env(safe-area-inset-bottom) + var(--space-4));
}
.results-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-2);
  margin-bottom: var(--space-3);
  min-height: 1.4rem;
}
.result-count {
  color: var(--ink-soft);
  font-size: var(--step-sub);
  font-weight: 600;
}

/* Shared pill toggles in the results head: "Open now" (filter) and
   "Near me" (distance sort). "Near me" stays hidden until app.js confirms
   geolocation is available. */
.list-toggles {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  align-items: center;
}
.list-toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.3em;
  min-height: 44px;
  padding: 0.35em 0.9em;
  border: 1px solid var(--line);
  border-radius: var(--radius-chip);
  background: var(--surface-2);
  color: var(--ink-soft);
  font-size: var(--step-sub);
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
}
.list-toggle[aria-pressed="true"] {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-ink);
}
.list-toggle:disabled {
  opacity: 0.6;
  cursor: progress;
}
.list-toggle:active {
  transform: scale(0.97);
}
.geo-status {
  color: var(--ink-soft);
  font-size: var(--step-sub);
  margin-bottom: var(--space-3);
}
.tz-note {
  color: var(--ink-soft);
  font-size: var(--step-sub);
  margin-bottom: var(--space-3);
}

/* "Faves" wordmark doubles as a home button. */
.app-home-link {
  color: inherit;
  text-decoration: none;
  display: inline-block;
  transition: color 0.15s ease, transform 0.15s ease;
}
/* Hover cue that it's the way home: the wordmark warms to the accent (the
   "F" is already accent) and lifts a touch — no underline. */
@media (hover: hover) {
  .app-home-link:hover {
    color: var(--accent);
  }
}
@media (hover: hover) and (prefers-reduced-motion: no-preference) {
  .app-home-link:hover {
    transform: translateY(-1px);
  }
}

/* Search / favourites panel header with an explicit way back to the list. */
.panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  margin-bottom: var(--space-2);
}
.panel-title {
  font-size: var(--step-name);
  font-weight: 800;
}
.panel-done {
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  gap: 0.2em;
  padding: 0.4em 0.9em;
  border: 1px solid var(--line);
  border-radius: var(--radius-chip);
  background: var(--surface);
  color: var(--accent);
  font-size: var(--step-sub);
  font-weight: 700;
  white-space: nowrap;
  cursor: pointer;
}
@media (hover: hover) {
  .panel-done:hover {
    border-color: var(--accent);
    background: var(--accent-soft);
  }
}

/* ---------- Global search (home) ---------- */
.search-field {
  position: relative;
  display: flex;
  align-items: center;
  margin-bottom: var(--space-3);
}
.search-icon {
  position: absolute;
  left: 0.85em;
  font-size: 1rem;
  pointer-events: none;
  opacity: 0.7;
}
.search-input {
  width: 100%;
  min-height: 48px;
  /* Right padding reserves room for the clear ✕ so text never underlaps it. */
  padding: 0.6em 3em 0.6em 2.4em;
  border: 1px solid var(--line);
  border-radius: var(--radius-chip);
  background: var(--surface);
  color: var(--ink);
  font-size: var(--step-body);
}
.search-input::placeholder {
  color: var(--ink-soft);
}
/* Suppress the browser's own clear affordance (WebKit only, inconsistent) — we
   ship our own so it's present everywhere, including mobile. */
.search-input::-webkit-search-cancel-button {
  -webkit-appearance: none;
  appearance: none;
}
/* Clear ✕: a 44px tap target holding a small circular badge, iOS-style. */
.search-clear {
  position: absolute;
  right: 0.3em;
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}
.search-clear span {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--surface-2);
  color: var(--ink-soft);
  font-size: 0.72rem;
  line-height: 1;
}
@media (hover: hover) {
  .search-clear:hover span {
    background: var(--line);
    color: var(--ink);
  }
}
.search-clear:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
  border-radius: var(--radius-chip);
}

/* Search / favourites mode: browse view + bottom filter bar + shuffle FAB
   step aside so the results own the screen. */
body.searching .browse-only,
body.searching .filter-bar,
body.searching .pick-fab,
body.faves-view .browse-only,
body.faves-view .filter-bar,
body.faves-view .pick-fab {
  display: none;
}

/* Search box + Favourites toggle share a row above the results. */
.home-tools {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-bottom: var(--space-3);
}
.home-tools .search-field {
  flex: 1;
  margin-bottom: 0;
}
.fav-toggle {
  flex: none;
}
.fav-toggle[aria-pressed="true"] {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-ink);
}
.fav-toggle .favourites-count:not(:empty) {
  min-width: 1.4em;
  padding: 0.05em 0.35em;
  border-radius: var(--radius-chip);
  background: var(--accent);
  color: var(--accent-ink);
  font-variant-numeric: tabular-nums;
  text-align: center;
}
.fav-toggle[aria-pressed="true"] .favourites-count:not(:empty) {
  background: var(--accent-ink);
  color: var(--accent);
}

/* Heart toggle (dish rows, venue/recipe header, favourites view). Larger
   and higher-contrast than a bare glyph so it reads as a real control; the
   unsaved state is a clear outline heart, the saved state a filled accent
   heart. A springy pop on hover/press makes the toggle feel tactile. */
.heart {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  min-height: 48px;
  border: 0;
  border-radius: var(--radius-chip);
  background: transparent;
  color: var(--ink-soft);
  font-size: 1.7rem;
  line-height: 1;
  cursor: pointer;
  transition: transform 0.16s cubic-bezier(0.34, 1.56, 0.64, 1),
    color 0.16s ease, background 0.16s ease;
}
.heart[aria-pressed="true"] {
  color: var(--accent);
}
@media (hover: hover) {
  .heart:hover {
    background: var(--accent-soft);
    color: var(--accent);
    transform: scale(1.18);
  }
}
.heart:active {
  transform: scale(0.86);
}
.heart:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
}
/* A gentle pop when a heart becomes filled (respects reduced-motion via the
   global rule that flattens animation durations). */
.heart[aria-pressed="true"] {
  animation: heart-pop 0.28s cubic-bezier(0.34, 1.56, 0.64, 1);
}
@keyframes heart-pop {
  0% { transform: scale(0.7); }
  60% { transform: scale(1.25); }
  100% { transform: scale(1); }
}
.heart-lg {
  width: 52px;
  height: 52px;
  font-size: 2.1rem;
}
/* In a result row the heart is a full-height tap target on the right. */
.search-row .heart {
  align-self: stretch;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
}

.search-summary {
  color: var(--ink-soft);
  font-size: var(--step-sub);
  font-weight: 600;
  margin-bottom: var(--space-3);
}
.search-group {
  margin-bottom: var(--space-4);
}
.search-group-title {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-2);
  font-size: var(--step-sub);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--ink-soft);
  padding-bottom: var(--space-1);
  border-bottom: 1px solid var(--line);
  margin-bottom: var(--space-2);
}
.search-group-count {
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
}
.search-list {
  display: grid;
  gap: var(--space-1);
}
.search-row {
  display: flex;
  align-items: stretch;
  gap: var(--space-1);
}
.search-link {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 0.15em;
  min-height: 44px;
  justify-content: center;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  transition: border-color 0.14s ease, background 0.14s ease;
}
.search-row-name {
  font-weight: 600;
  color: var(--ink);
}
.search-row-sub {
  font-size: var(--step-sub);
  color: var(--ink-soft);
}
@media (hover: hover) {
  .search-link:hover {
    border-color: var(--accent);
    background: var(--accent-soft);
  }
  .search-link:hover .search-row-name {
    color: var(--accent);
  }
}
.search-link:focus-within,
.search-link:focus-visible {
  border-color: var(--accent);
}

/* Favourites view: hearted dishes nested under their place. The venue is
   the parent (shown even if only a dish of it is hearted); its dishes sit
   on an indented rail beneath, reading like "my usual at each spot". */
.fav-venue-group {
  margin-bottom: var(--space-4);
}
.fav-venue-head .fav-venue-link {
  background: var(--accent-soft);
  border-color: transparent;
}
.fav-venue-head .search-row-name {
  font-weight: 700;
}
.fav-venue-group .search-row:not(.fav-venue-head) {
  margin-left: var(--space-3);
  padding-left: var(--space-3);
  border-left: 2px solid var(--line);
}

.card-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-3);
}
@media (min-width: 34rem) {
  .card-grid {
    grid-template-columns: 1fr 1fr;
  }
}

/* ---------- Cards ---------- */
.card {
  position: relative; /* anchor for the corner heart */
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  overflow: hidden;
  transition: transform 0.14s ease, box-shadow 0.14s ease, border-color 0.14s ease;
}
.card-link,
.card-body {
  display: block;
  padding: var(--space-3);
  height: 100%;
}
.card-link .card-name {
  transition: color 0.14s ease;
}
/* The heart floats in the card's top-right corner, clear of the name. It's a
   sibling of the link (not nested), so it z-stacks above and stays tappable. */
.card-heart {
  position: absolute;
  top: calc(var(--space-2) - 2px);
  right: calc(var(--space-2) - 2px);
  z-index: 1;
}
.card-link .card-name {
  padding-right: 2.5rem; /* reserve the corner the heart occupies */
}

/* Hover response — only for cards that link somewhere (stubs don't), and
   only on devices that truly hover, so touch screens don't get a sticky
   hover state after a tap. The whole card lifts; keyboard focus gets the
   same accent border via :focus-within (the focus ring still shows). */
.card:has(.card-link):focus-within {
  border-color: var(--accent);
}
@media (hover: hover) {
  .card:has(.card-link):hover {
    transform: translateY(-3px);
    box-shadow: var(--shadow-lift);
    border-color: var(--accent);
  }
  .card:has(.card-link):hover .card-name {
    color: var(--accent);
  }
  .card:has(.card-link):active {
    transform: translateY(-1px);
  }
}
@media (prefers-reduced-motion: reduce) {
  .card {
    transition: box-shadow 0.14s ease, border-color 0.14s ease;
  }
  .card:has(.card-link):hover,
  .card:has(.card-link):active {
    transform: none;
  }
}
.card[data-status="stub"] {
  background: var(--surface-2);
}

.card-name {
  font-size: var(--step-name);
  font-weight: 700;
  letter-spacing: -0.01em;
  line-height: 1.15;
}
.card-meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1);
  align-items: center;
  margin-top: var(--space-1);
  color: var(--ink-soft);
  font-size: var(--step-sub);
}
.card-area::after {
  content: "·";
  margin-inline: 0.4em;
  color: var(--line);
}
.card-distance {
  color: var(--accent);
  font-weight: 700;
}
.card-distance::after {
  content: "·";
  margin-inline: 0.4em;
  color: var(--line);
}
.chip-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1);
  margin-top: var(--space-2);
}

/* ---------- Chips ---------- */
.chip {
  display: inline-flex;
  align-items: center;
  gap: 0.3em;
  padding: 0.18em 0.6em;
  border-radius: var(--radius-chip);
  font-size: 0.74rem;
  font-weight: 600;
  line-height: 1.4;
  white-space: nowrap;
}
.chip-cuisine {
  background: var(--accent-soft);
  color: var(--accent);
}
/* Typical price-per-person, derived from the venue's own menu prices. */
.chip-price {
  background: var(--surface-2);
  color: var(--ink-soft);
}
.chip-price .price-band {
  font-weight: 800;
  color: var(--ink);
  letter-spacing: 0.02em;
}
/* Menu-header spend line: "$$ about $28 per person · estimated from the menu" */
.menu-price {
  margin-top: var(--space-2);
  color: var(--ink-soft);
  font-size: var(--step-sub);
}
.menu-price .price-band {
  font-weight: 800;
  color: var(--ink);
  margin-right: 0.15em;
}
.menu-price .price-est {
  color: var(--ink-soft);
  opacity: 0.85;
}
.chip-service {
  background: transparent;
  border: 1px solid var(--line);
  color: var(--ink-soft);
}
.chip-status {
  background: var(--surface);
  border: 1px dashed var(--line);
  color: var(--ink-soft);
}

/* ---------- Live open/closed badge (hours engine) ---------- */
.hours-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--ink-soft);
}
.hours-badge::before {
  content: "";
  width: 0.5em;
  height: 0.5em;
  border-radius: 50%;
  background: currentColor;
  flex: none;
}
.hours-badge[data-state="open"] {
  color: var(--ok);
}
.hours-badge[data-state="closing-soon"],
.hours-badge[data-state="opening-soon"] {
  color: var(--amber);
}
.hours-badge[data-state="closed"] {
  color: var(--ink-soft);
}
.card-hours {
  margin-top: var(--space-2);
}

/* Card photo: full-bleeds to the card edges (cancels the link padding) and
   reserves its box via aspect-ratio so lazy-loading causes no layout shift. */
.card-photo {
  display: block;
  width: calc(100% + 2 * var(--space-3));
  margin: calc(-1 * var(--space-3)) calc(-1 * var(--space-3)) var(--space-3);
  aspect-ratio: 16 / 9;
  object-fit: cover;
  background: var(--surface-2);
}

/* ---------- Empty state ---------- */
.empty {
  padding: var(--space-5) var(--space-3);
  text-align: center;
  color: var(--ink-soft);
}

/* ---------- Fallback (no-JS) list ---------- */
.fallback-note {
  color: var(--ink-soft);
  font-size: var(--step-sub);
  margin-bottom: var(--space-3);
}
.app-ready .fallback-note {
  display: none;
}

/* ---------- Sticky bottom filter bar ---------- */
.filter-bar {
  position: fixed;
  inset-inline: 0;
  bottom: 0;
  z-index: 10;
  display: none;
  gap: var(--space-2);
  align-items: center;
  padding: var(--space-2) var(--space-3);
  padding-bottom: calc(var(--space-2) + env(safe-area-inset-bottom));
  background: color-mix(in srgb, var(--surface) 92%, transparent);
  border-top: 1px solid var(--line);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}
.app-ready .filter-bar {
  display: flex;
}
.filter-bar-inner {
  width: min(100% - 2 * var(--space-3), 60rem);
  margin-inline: auto;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  align-items: center;
}
/* Mobile: the service toggle + two selects won't fit legibly on one row at
   390px (the selects collapsed to ~39px stubs). Give the segmented toggle its
   own full-width row and let the two selects share the row below. --bar-h is
   bumped to match so the body padding and both FABs clear the taller bar in
   lockstep (see body:not(.menu-page) below). At ≥34rem it all fits one row. */
.filter-bar-inner .segmented {
  flex: 1 1 100%;
}
.filter-bar-inner .segmented button {
  flex: 1 1 auto;
}
body:not(.menu-page) {
  --bar-h: 7.6rem;
}

.segmented {
  display: inline-flex;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-chip);
  padding: 2px;
}
.segmented button {
  border: 0;
  background: transparent;
  padding: 0.5em 0.85em;
  min-height: 40px;
  border-radius: var(--radius-chip);
  font-size: var(--step-sub);
  font-weight: 600;
  color: var(--ink-soft);
  cursor: pointer;
  white-space: nowrap;
}
.segmented button[aria-pressed="true"] {
  background: var(--accent);
  color: var(--accent-ink);
}

.select-field {
  position: relative;
  flex: 1;
  min-width: 0;
}
.select-field select {
  width: 100%;
  min-height: 44px;
  padding: 0.5em 2em 0.5em 0.85em;
  border: 1px solid var(--line);
  border-radius: var(--radius-chip);
  background: var(--surface-2);
  color: var(--ink);
  font-size: var(--step-sub);
  font-weight: 600;
  appearance: none;
  cursor: pointer;
  text-overflow: ellipsis;
}
.select-field::after {
  content: "";
  position: absolute;
  right: 0.9em;
  top: 50%;
  width: 0.5em;
  height: 0.5em;
  border-right: 2px solid var(--ink-soft);
  border-bottom: 2px solid var(--ink-soft);
  transform: translateY(-70%) rotate(45deg);
  pointer-events: none;
}
.select-field select:not([data-active="all"]) {
  border-color: var(--accent);
  color: var(--accent);
}

/* Wide enough for the toggle + both selects on one row; undo the mobile
   two-row layout and reset the bar height. */
@media (min-width: 34rem) {
  body:not(.menu-page) {
    --bar-h: 4.6rem;
  }
  .filter-bar-inner {
    flex-wrap: nowrap;
  }
  .filter-bar-inner .segmented {
    flex: 0 0 auto;
  }
  .filter-bar-inner .segmented button {
    flex: 0 0 auto;
  }
}

/* ---------- Pick for us (Phase 4) ---------- */
.pick-fab {
  position: fixed;
  right: var(--space-3);
  bottom: calc(var(--bar-h) + env(safe-area-inset-bottom) + var(--space-3));
  z-index: 11;
  display: none;
  align-items: center;
  gap: 0.45em;
  min-height: 48px;
  padding: 0.6em 1.2em;
  border: 0;
  border-radius: var(--radius-chip);
  background: var(--accent);
  color: var(--accent-ink);
  font-size: var(--step-body);
  font-weight: 700;
  box-shadow: var(--shadow);
  cursor: pointer;
}
.app-ready .pick-fab {
  display: inline-flex;
}
.pick-fab:active {
  transform: scale(0.96);
}
/* Auto-hide on scroll-down (picker.js toggles .is-tucked): slide it off the
   bottom edge so it stops covering the list, then slide back on scroll-up. */
.pick-fab {
  transition: transform 0.22s ease, opacity 0.22s ease;
}
.pick-fab.is-tucked {
  transform: translateY(150%);
  opacity: 0;
  pointer-events: none;
}
@media (prefers-reduced-motion: reduce) {
  .pick-fab {
    transition: opacity 0.2s ease;
  }
  .pick-fab.is-tucked {
    transform: none;
  }
}

.picker {
  width: min(100% - 2rem, 24rem);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--ink);
  padding: 0;
  box-shadow: var(--shadow);
}
.picker::backdrop {
  background: rgba(23, 19, 16, 0.45);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
}
.picker-inner {
  position: relative;
  padding: var(--space-4);
  text-align: center;
}
.picker-close {
  position: absolute;
  top: var(--space-2);
  right: var(--space-2);
  width: 44px;
  height: 44px;
  border: 0;
  border-radius: var(--radius-chip);
  background: transparent;
  color: var(--ink-soft);
  font-size: 1.1rem;
  cursor: pointer;
}
.picker-close:hover {
  background: var(--surface-2);
}
.picker-dice {
  font-size: 2.6rem;
  line-height: 1.2;
}
.picker-dice.rolling {
  animation: dice-roll 0.35s ease-in-out infinite alternate;
}
@keyframes dice-roll {
  from {
    transform: rotate(-14deg);
  }
  to {
    transform: rotate(14deg);
  }
}
.picker-stage {
  min-height: 7.5rem;
  display: grid;
  place-items: center;
  padding: var(--space-2) 0;
}
.picker-cycle {
  font-size: 1.35rem;
  font-weight: 800;
  letter-spacing: -0.01em;
  line-height: 1.2;
}
.picker-eyebrow {
  font-size: var(--step-sub);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--ink-soft);
}
.picker-name {
  font-size: 1.6rem;
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.15;
  margin-top: var(--space-1);
}
.picker-meta {
  color: var(--ink-soft);
  font-size: var(--step-sub);
  margin-top: var(--space-1);
}
.picker-fave-note {
  margin-top: var(--space-1);
  font-size: var(--step-sub);
  font-weight: 700;
  color: var(--accent);
}
.picker-chips {
  justify-content: center;
}
.picker-actions {
  display: grid;
  gap: var(--space-2);
  margin-top: var(--space-3);
}
.picker-go {
  justify-content: center;
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-ink);
}
.picker-again {
  justify-content: center;
  background: var(--surface);
  cursor: pointer;
}

/* ---------- Order tally (Theme 1) ---------- */
/* Dish quantity stepper (shared by the menu row and the order dialog). */
.stepper {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
}
.stepper-add {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0.35em 0.9em;
  border: 1px solid var(--accent);
  border-radius: var(--radius-chip);
  background: var(--accent-soft);
  color: var(--accent);
  font-size: var(--step-sub);
  font-weight: 700;
  white-space: nowrap;
  cursor: pointer;
}
.stepper-btn {
  width: 44px;
  height: 44px;
  border: 1px solid var(--line);
  border-radius: var(--radius-chip);
  background: var(--surface);
  color: var(--ink);
  font-size: 1.25rem;
  line-height: 1;
  cursor: pointer;
}
.stepper-btn:active,
.stepper-add:active {
  transform: scale(0.94);
}
.stepper-count {
  min-width: 1.4em;
  text-align: center;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.dish-actions {
  margin-top: var(--space-2);
  display: flex;
  justify-content: flex-end;
}

/* The floating order button. Bottom-left so it clears the pick FAB (right)
   and, on the home screen, sits above the filter bar like the pick FAB. */
.order-fab {
  position: fixed;
  left: var(--space-3);
  bottom: calc(var(--bar-h) + env(safe-area-inset-bottom) + var(--space-3));
  z-index: 12;
  display: inline-flex;
  align-items: center;
  gap: 0.45em;
  min-height: 48px;
  padding: 0.6em 1.1em;
  border: 0;
  border-radius: var(--radius-chip);
  background: var(--ink);
  color: var(--bg);
  font-size: var(--step-body);
  font-weight: 700;
  box-shadow: var(--shadow-lift);
  cursor: pointer;
}
.menu-page .order-fab {
  bottom: calc(env(safe-area-inset-bottom) + var(--space-3));
}
.order-fab:active {
  transform: scale(0.96);
}

/* Back-to-top for long menus: bottom-right, opposite the bottom-left order FAB.
   Hidden via the [hidden] attribute (global guard) until scrolled down. */
.to-top {
  position: fixed;
  right: var(--space-3);
  bottom: calc(env(safe-area-inset-bottom) + var(--space-3));
  z-index: 12;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: var(--surface);
  color: var(--ink);
  font-size: 1.4rem;
  line-height: 1;
  box-shadow: var(--shadow-lift);
  cursor: pointer;
  transition: transform 0.12s ease, color 0.16s ease, border-color 0.16s ease;
}
@media (hover: hover) {
  .to-top:hover {
    color: var(--accent);
    border-color: var(--accent);
  }
}
.to-top:active {
  transform: scale(0.94);
}
@media (prefers-reduced-motion: reduce) {
  .to-top {
    transition: none;
  }
}
.order-fab-count {
  min-width: 1.5em;
  padding: 0.05em 0.4em;
  border-radius: var(--radius-chip);
  background: var(--accent);
  color: var(--accent-ink);
  font-variant-numeric: tabular-nums;
  text-align: center;
}

/* The order dialog: a bottom sheet on phones, a centred card on wide. */
.order-sheet {
  width: 100%;
  max-width: 34rem;
  max-height: 85vh;
  margin: auto auto 0;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: var(--radius) var(--radius) 0 0;
  background: var(--surface);
  color: var(--ink);
  box-shadow: var(--shadow-lift);
}
@media (min-width: 34rem) {
  .order-sheet {
    margin: auto;
    border-radius: var(--radius);
  }
}
.order-sheet::backdrop {
  background: rgba(23, 19, 16, 0.45);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
}
.order-inner {
  display: flex;
  flex-direction: column;
  max-height: 85vh;
}
.order-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-3);
  border-bottom: 1px solid var(--line);
}
.order-title {
  font-size: var(--step-name);
}
.order-close {
  width: 44px;
  height: 44px;
  border: 0;
  border-radius: var(--radius-chip);
  background: transparent;
  color: var(--ink-soft);
  font-size: 1.1rem;
  cursor: pointer;
}
.order-close:hover {
  background: var(--surface-2);
}
.order-body {
  overflow-y: auto;
  padding: var(--space-3);
  -webkit-overflow-scrolling: touch;
}
.order-empty {
  color: var(--ink-soft);
  text-align: center;
  padding: var(--space-4) var(--space-2);
}
.order-group {
  margin-bottom: var(--space-4);
}
.order-group-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-2);
  margin-bottom: var(--space-2);
}
.order-group-name {
  font-size: var(--step-body);
  font-weight: 700;
}
.order-call {
  min-height: 40px;
  display: inline-flex;
  align-items: center;
  gap: 0.3em;
  padding: 0.3em 0.8em;
  border-radius: var(--radius-chip);
  background: var(--accent-soft);
  color: var(--accent);
  font-size: var(--step-sub);
  font-weight: 700;
  white-space: nowrap;
}
.order-lines {
  display: grid;
  gap: var(--space-2);
}
.order-line {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}
.order-line-name {
  flex: 1;
  min-width: 0;
}
.order-line-price {
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.order-line.collected .order-line-name {
  text-decoration: line-through;
  color: var(--ink-soft);
}
.order-collect-line {
  flex: 1;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-height: 44px;
  cursor: pointer;
}
.order-check {
  width: 22px;
  height: 22px;
  accent-color: var(--accent);
  flex: none;
}
.order-subtotal {
  display: flex;
  justify-content: space-between;
  margin-top: var(--space-2);
  padding-top: var(--space-2);
  border-top: 1px solid var(--line);
  color: var(--ink-soft);
  font-size: var(--step-sub);
}
.order-subtotal-amount {
  font-weight: 700;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.order-foot {
  padding: var(--space-3);
  border-top: 1px solid var(--line);
  background: var(--surface-2);
}
.order-total-row {
  display: flex;
  justify-content: space-between;
  font-size: var(--step-name);
  font-weight: 800;
}
.order-total {
  font-variant-numeric: tabular-nums;
}
.order-caption {
  color: var(--ink-soft);
  font-size: var(--step-sub);
  margin-top: var(--space-1);
}
.order-actions {
  display: flex;
  gap: var(--space-2);
  margin-top: var(--space-3);
}
.order-collect-toggle,
.order-clear {
  flex: 1;
  min-height: 46px;
  border: 1px solid var(--line);
  border-radius: var(--radius-chip);
  background: var(--surface);
  color: var(--ink);
  font-size: var(--step-body);
  font-weight: 600;
  cursor: pointer;
}
.order-collect-toggle[aria-pressed="true"] {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-ink);
}
.order-clear.confirming {
  border-color: var(--warn);
  background: var(--warn-bg);
  color: var(--warn-ink);
}

/* ---------- Group ordering: send + receive (Theme 1b) ---------- */
/* The primary "Send to the orderer" action, and the accent buttons in the
   send/receive dialogs, share this filled-accent look. */
.order-send {
  width: 100%;
  min-height: 46px;
  margin-top: var(--space-2);
  border: 1px solid var(--accent);
  border-radius: var(--radius-chip);
  background: var(--accent);
  color: var(--accent-ink);
  font-size: var(--step-body);
  font-weight: 700;
  cursor: pointer;
}
.order-send:hover {
  filter: brightness(0.96);
}
/* "Share these" sits under the favourites summary, above the grouped list. */
.fav-share {
  margin-bottom: var(--space-3);
}
/* The share + receive sheets reuse .order-sheet's frame. */
.share-sheet,
.recv-sheet {
  width: 100%;
  max-width: 34rem;
  max-height: 85vh;
  margin: auto auto 0;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: var(--radius) var(--radius) 0 0;
  background: var(--surface);
  color: var(--ink);
  box-shadow: var(--shadow-lift);
}
@media (min-width: 34rem) {
  .share-sheet,
  .recv-sheet {
    margin: auto;
    border-radius: var(--radius);
  }
}
.share-sheet::backdrop,
.recv-sheet::backdrop {
  background: rgba(23, 19, 16, 0.45);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
}
.share-body {
  display: grid;
  gap: var(--space-3);
}
.share-name,
.share-link {
  width: 100%;
  min-height: 46px;
  padding: 0 var(--space-3);
  border: 1px solid var(--line);
  border-radius: var(--radius-chip);
  background: var(--surface);
  color: var(--ink);
  font-size: var(--step-body);
}
.share-link {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: var(--step-sub);
}
.share-status {
  min-height: 1.2em;
  margin: 0;
  color: var(--ink-soft);
  font-size: var(--step-sub);
}
.share-qr {
  display: grid;
  justify-items: center;
  gap: var(--space-2);
}
.share-qr-canvas {
  /* Always on a white card so the code scans in dark mode too; the canvas
     already paints its own quiet zone, this just frames it. Radius stays small
     (--radius, not the pill --radius-chip) — a canvas is clipped by its
     border-radius, and a pill radius rounds the QR into an oval, shaving the
     corner finder patterns and making it unscannable. */
  width: min(280px, 80vw);
  height: auto;
  padding: var(--space-2);
  border-radius: var(--radius);
  background: #fff;
  image-rendering: pixelated; /* keep module edges crisp when scaled */
}
/* When .order-send shares an .order-actions row (send + receive dialogs),
   it flexes evenly beside its sibling instead of taking the full width. */
.order-actions .order-send {
  width: auto;
  flex: 1;
  margin-top: 0;
}
.recv-list {
  display: grid;
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
}
.recv-group {
  display: grid;
  gap: 0.15em;
  padding: var(--space-2) 0;
  border-bottom: 1px solid var(--line);
}
.recv-venue {
  font-weight: 700;
}
.recv-lines {
  color: var(--ink-soft);
  font-size: var(--step-sub);
}

/* ---------- Settings (distance dials) ---------- */
.app-header-inner {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-2);
}
.settings-btn {
  flex: none;
  width: 48px;
  height: 48px;
  margin-top: var(--space-1);
  border: 1px solid var(--line);
  border-radius: var(--radius-chip);
  background: var(--surface);
  color: var(--ink-soft);
  font-size: 1.4rem;
  line-height: 1;
  cursor: pointer;
  transition: transform 0.2s ease, color 0.16s ease, border-color 0.16s ease;
}
@media (hover: hover) {
  .settings-btn:hover {
    color: var(--accent);
    border-color: var(--accent);
    transform: rotate(30deg);
  }
}
.settings-btn:active {
  transform: scale(0.94);
}

/* Header overflow ("⋯") menu — Favourites + Settings under one button. */
.overflow {
  position: relative;
  flex: none;
  margin-top: var(--space-1);
}
.overflow-btn {
  width: 48px;
  height: 48px;
  border: 1px solid var(--line);
  border-radius: var(--radius-chip);
  background: var(--surface);
  color: var(--ink-soft);
  font-size: 1.6rem;
  line-height: 1;
  cursor: pointer;
  transition: color 0.16s ease, border-color 0.16s ease, transform 0.12s ease;
}
@media (hover: hover) {
  .overflow-btn:hover {
    color: var(--accent);
    border-color: var(--accent);
  }
}
.overflow-btn:active {
  transform: scale(0.94);
}
.overflow-btn[aria-expanded="true"] {
  color: var(--accent);
  border-color: var(--accent);
}
.overflow-menu {
  position: absolute;
  top: calc(100% + var(--space-1));
  right: 0;
  z-index: 20;
  min-width: 12rem;
  padding: var(--space-1);
  display: flex;
  flex-direction: column;
  gap: 2px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}
.overflow-item {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  width: 100%;
  min-height: 44px;
  padding: 0.5em 0.7em;
  border: 0;
  border-radius: var(--radius-chip);
  background: transparent;
  color: var(--ink);
  font-size: var(--step-body);
  font-weight: 600;
  text-align: left;
  cursor: pointer;
}
@media (hover: hover) {
  .overflow-item:hover {
    background: var(--surface-2);
  }
}
.overflow-item:active {
  background: var(--surface-2);
}
.overflow-item-icon {
  width: 1.4em;
  font-size: 1.1rem;
  text-align: center;
}
/* The favourites count sits at the far edge of its row (the pressed-state
   recolour is inherited from .fav-toggle[aria-pressed] above). */
.overflow-item .favourites-count:not(:empty) {
  margin-left: auto;
  min-width: 1.4em;
  padding: 0.05em 0.4em;
  border-radius: var(--radius-chip);
  background: var(--accent);
  color: var(--accent-ink);
  font-variant-numeric: tabular-nums;
  text-align: center;
}

.settings-sheet {
  width: 100%;
  max-width: 34rem;
  margin: auto auto 0;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: var(--radius) var(--radius) 0 0;
  background: var(--surface);
  color: var(--ink);
  box-shadow: var(--shadow-lift);
}
@media (min-width: 34rem) {
  .settings-sheet {
    margin: auto;
    border-radius: var(--radius);
  }
}
.settings-sheet::backdrop {
  background: rgba(23, 19, 16, 0.45);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
}
.settings-inner {
  padding: var(--space-3);
}
.settings-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: var(--space-2);
}
.settings-title {
  font-size: var(--step-name);
}
.settings-close {
  width: 44px;
  height: 44px;
  border: 0;
  border-radius: var(--radius-chip);
  background: transparent;
  color: var(--ink-soft);
  font-size: 1.1rem;
  cursor: pointer;
}
.settings-close:hover {
  background: var(--surface-2);
}
.settings-note {
  color: var(--ink-soft);
  font-size: var(--step-sub);
  margin-bottom: var(--space-4);
}
.settings-field {
  margin-bottom: var(--space-4);
}
.settings-label {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-2);
  font-weight: 600;
  margin-bottom: var(--space-2);
}
.settings-out {
  color: var(--accent);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.settings-range {
  width: 100%;
  height: 44px;
  accent-color: var(--accent);
  cursor: pointer;
}
.settings-hint {
  color: var(--ink-soft);
  font-size: var(--step-sub);
  margin-top: var(--space-1);
}
.settings-actions {
  display: flex;
  justify-content: flex-end;
}
.settings-reset {
  min-height: 46px;
  padding: 0.5em 1.2em;
  border: 1px solid var(--line);
  border-radius: var(--radius-chip);
  background: var(--surface);
  color: var(--ink);
  font-size: var(--step-body);
  font-weight: 600;
  cursor: pointer;
}

/* Food preferences section of the settings dialog. */
.settings-group-title {
  margin: var(--space-5) 0 var(--space-2);
  font-size: 1.15rem; /* between the dialog title and the body-sized field labels */
  font-weight: 700;
}
.settings-group-title:first-of-type {
  margin-top: 0;
}
/* Field labels ("Your dietary needs", "Allergens to flag"): full-contrast and
   body-sized so they read as real headings, a clear step below the bold
   section titles above them. */
.settings-sub {
  margin: var(--space-3) 0 var(--space-2);
  color: var(--ink);
  font-size: var(--step-body);
  font-weight: 600;
}
/* Language picker: a compact dropdown matching the home Area/Cuisine selects. */
.lang-select {
  position: relative;
  display: inline-block;
  min-width: 12rem;
}
.lang-select-input {
  width: 100%;
  min-height: 44px;
  padding: 0.5em 2.4em 0.5em 0.85em;
  border: 1px solid var(--line);
  border-radius: var(--radius-chip);
  background: var(--surface);
  color: var(--ink);
  font-size: var(--step-body);
  font-weight: 600;
  appearance: none;
  cursor: pointer;
}
.lang-select::after {
  content: "";
  position: absolute;
  right: 0.9em;
  top: 50%;
  width: 0.5em;
  height: 0.5em;
  border-right: 2px solid var(--ink-soft);
  border-bottom: 2px solid var(--ink-soft);
  transform: translateY(-70%) rotate(45deg);
  pointer-events: none;
}
.lang-select-input:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* Heading + its ⓘ caveat share a row; relative so the note anchors to it. The
   row owns the heading's vertical margins so the two align on one baseline. */
.settings-sub-row {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--space-1);
  margin: var(--space-3) 0 var(--space-2);
}
.settings-sub-row .settings-sub {
  margin: 0;
}
/* The caveat ⓘ keeps a 44px tap target but a smaller glyph, sized to the
   heading beside it (the menu's larger 1.45rem ⓘ sits by a big venue name);
   left-aligned so it hugs the heading rather than floating mid-box. */
.settings-sub-row .caveat-btn {
  justify-content: flex-start;
  width: 44px;
  height: 44px;
  margin: 0;
  padding-left: 0.1em;
  font-size: 1.05rem;
}
.pref-chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1);
}
.pref-chip {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0.4em 0.9em;
  border-radius: var(--radius-chip);
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink-soft);
  font-size: var(--step-sub);
  font-weight: 600;
  cursor: pointer;
}
.pref-chip[aria-pressed="true"] {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-ink);
}
/* Avoided allergens signal danger, not preference — red when set. */
.pref-chips-avoid .pref-chip[aria-pressed="true"] {
  background: var(--warn);
  border-color: var(--warn);
  color: var(--surface);
}

/* Collapsible chip group: clamp to one 44px row until "Show all" is tapped, so
   a long allergen list doesn't dominate the dialog. .fits (set by JS when the
   chips don't overflow) drops the clamp and fade entirely. */
.chips-collapsible {
  position: relative;
}
.chips-collapsible.is-collapsed:not(.fits) .pref-chips {
  /* One 44px chip row + half the row-gap, so the clip lands in the gap below
     row 1 (not through a chip's rounded bottom) yet keeps row 2 hidden. */
  max-height: calc(44px + var(--space-1) / 2);
  overflow: hidden;
}
.chips-collapsible.is-collapsed:not(.fits)::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 2.4rem; /* sit just above the toggle */
  height: 1.4rem;
  background: linear-gradient(to bottom, transparent, var(--surface));
  pointer-events: none;
}
.chips-toggle {
  margin-top: var(--space-1);
  padding: 0.35em 0;
  border: 0;
  background: none;
  color: var(--accent);
  font-size: var(--step-sub);
  font-weight: 600;
  cursor: pointer;
}
.chips-toggle:hover {
  text-decoration: underline;
}

@media (prefers-reduced-motion: reduce) {
  * {
    animation-duration: 0.001ms !important;
    transition-duration: 0.001ms !important;
  }
}
/* Only smooth-scroll when the user hasn't asked for reduced motion. An
   unconditional `html { scroll-behavior: smooth }` outranks a reduce-scoped
   override by source order (equal specificity), so gate the smooth rule
   itself rather than trying to override it. */
@media (prefers-reduced-motion: no-preference) {
  html {
    scroll-behavior: smooth;
  }
}

/* ================= Menu screen ================= */
:root {
  --diet: #2f6b3d;
  --diet-bg: #e5f1e8;
  --nav-h: 3.1rem;
}
@media (prefers-color-scheme: dark) {
  :root {
    --diet: #86d79b;
    --diet-bg: #182619;
  }
}

.menu-page {
  padding-bottom: var(--space-5);
}

/* Two-column menu on tablet/desktop: the menu on the left, a sticky info
   column (contact, hours, map link, order buttons) on the right. Opt-in via
   .menu-twocol (set by menu.js only for a venue with a real menu). Mobile
   stays single-column — the grid simply doesn't apply below the breakpoint,
   so the header → aside → main DOM order reads as the familiar stack. */
@media (min-width: 48rem) {
  .menu-twocol {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 18rem;
    grid-template-areas:
      "header header"
      "main   aside";
    column-gap: var(--space-5);
    align-items: start;
  }
  .menu-twocol > .menu-header {
    grid-area: header;
  }
  .menu-twocol > .menu-main {
    grid-area: main;
    min-width: 0; /* let long dish text wrap rather than widen the column */
  }
  .menu-twocol > .menu-aside {
    grid-area: aside;
    position: sticky;
    top: var(--space-3);
    align-self: start; /* don't stretch to row height, or sticky can't work */
  }
  /* First info card sits flush with the top of the menu column beside it. */
  .menu-twocol > .menu-aside > :first-child {
    margin-top: 0;
  }
  /* The narrow column reads better with the order buttons stacked. */
  .menu-twocol > .menu-aside .order-links {
    flex-direction: column;
    align-items: stretch;
  }
}
/* Back-to-list control on the menu/recipe pages. A proper bordered pill
   (not a faint text link) so it reads as a control and is easy to hit —
   it was easy to miss on desktop. */
.skip {
  padding: var(--space-3) var(--space-3) 0;
}
.skip a {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  min-height: 44px;
  padding: 0.4em 1em;
  border: 1px solid var(--line);
  border-radius: var(--radius-chip);
  background: var(--surface);
  color: var(--ink);
  font-size: var(--step-sub);
  font-weight: 700;
}
@media (hover: hover) and (pointer: fine) {
  .skip a:hover {
    border-color: var(--accent);
    color: var(--accent);
  }
}
.menu-status {
  padding: var(--space-5) var(--space-3);
  text-align: center;
  color: var(--ink-soft);
}

/* Header */
.menu-header {
  padding: var(--space-3) 0 var(--space-4);
  border-bottom: 1px solid var(--line);
}
.menu-title-row {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-2);
}
.menu-title-row .heart {
  margin-top: -0.1em;
}
.menu-title {
  font-size: var(--step-title);
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.05;
}
.menu-sub {
  color: var(--ink-soft);
  margin-top: var(--space-1);
}
.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  min-height: 44px;
  padding: 0.5em 1.1em;
  border-radius: var(--radius-chip);
  font-weight: 700;
  font-size: var(--step-sub);
  border: 1px solid var(--line);
}

/* Contact card — phone, pickup, hours, made prominent */
.contact-card {
  margin-top: var(--space-3);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  overflow: hidden;
}
.contact-row {
  display: flex;
  gap: var(--space-2);
  align-items: flex-start;
  padding: var(--space-3);
  border-bottom: 1px solid var(--line);
}
.contact-row:last-child {
  border-bottom: 0;
}
.contact-ico {
  font-size: 1.15rem;
  line-height: 1.4;
  flex: 0 0 auto;
}
.contact-text {
  display: grid;
  gap: 1px;
  min-width: 0;
}
.contact-label {
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--ink-soft);
}
.contact-value {
  font-weight: 600;
  line-height: 1.3;
}
.contact-call {
  background: var(--accent);
}
.contact-call .contact-label {
  /* Full ink, not softened: keeps AA contrast on the lighter dark-mode
     accent. Hierarchy vs the value comes from size + uppercase. */
  color: var(--accent-ink);
}
.contact-call .contact-value,
.contact-call .contact-ico {
  color: var(--accent-ink);
  font-size: 1.25rem;
}
.contact-hours .contact-text {
  width: 100%;
}
.hours-list {
  display: grid;
  gap: 2px;
  margin-top: 2px;
  font-size: 0.95rem;
  color: var(--ink);
  max-width: 24rem;
}
.hours-list li {
  display: flex;
  justify-content: space-between;
  gap: var(--space-3);
}
.hours-list li.is-today {
  font-weight: 700;
  color: var(--ink);
}
.hours-list li.is-today .hours-time {
  color: var(--ink);
}
.contact-hours .hours-badge {
  margin: 4px 0 6px;
  font-size: 0.9rem;
}
.hours-time {
  font-variant-numeric: tabular-nums;
  color: var(--ink-soft);
}

/* Order online */
.order-block {
  margin-top: var(--space-3);
}
.order-head {
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--ink-soft);
  margin-bottom: var(--space-2);
}
.order-links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}
.btn-order {
  background: var(--surface);
  color: var(--ink);
}
.btn-order::after {
  content: "↗";
  font-weight: 700;
  color: var(--ink-soft);
}
.menu-verified {
  margin-top: var(--space-2);
  font-size: 0.78rem;
  color: var(--ink-soft);
}

/* Our picks */
.picks {
  margin-top: var(--space-4);
  padding: var(--space-3);
  background: var(--accent-soft);
  border-radius: var(--radius);
}
.picks-head {
  font-size: 1.05rem;
  font-weight: 700;
  color: var(--accent);
  margin-bottom: var(--space-2);
}
.picks-list {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}
.pick {
  display: inline-flex;
  align-items: baseline;
  gap: 0.5em;
  padding: 0.5em 0.9em;
  min-height: 44px;
  background: var(--surface);
  border: 1px solid var(--accent);
  border-radius: var(--radius-chip);
  font-weight: 600;
}
.pick-price {
  color: var(--ink-soft);
  font-size: var(--step-sub);
  font-variant-numeric: tabular-nums;
}

/* Compact contact bar (mobile only). Once the full contact card scrolls out of
   view, menu.js unhides this slim bar so "call to order" + the open-now status
   stay pinned to the top of a long menu. Desktop keeps the sticky aside column,
   so the bar is suppressed there. Toggled via [hidden]; .contact-bar-open on
   <body> drops the search toolbar below it (calc includes the notch inset). */
.contact-bar {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 7;
  min-height: calc(var(--contact-bar-h) + env(safe-area-inset-top));
  padding-top: env(safe-area-inset-top);
  background: color-mix(in srgb, var(--bg) 92%, transparent);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--line);
}
.contact-bar-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  width: min(100% - 2 * var(--space-3), 60rem);
  min-height: var(--contact-bar-h);
  margin: 0 auto;
}
.contact-bar-status {
  min-width: 0;
  font-size: 0.85rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.contact-bar-call {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  flex: none;
  min-height: 44px;
  padding: 0.3em 1em;
  border-radius: var(--radius-chip);
  background: var(--accent);
  color: var(--accent-ink);
  font-weight: 700;
}
.contact-bar-call .contact-ico {
  font-size: 1.05rem;
}
@media (hover: hover) and (pointer: fine) {
  .contact-bar-call:hover {
    background: var(--accent-strong, var(--accent));
  }
}
/* Desktop has the sticky aside column, so the bar never applies there. */
@media (min-width: 48rem) {
  .contact-bar {
    display: none !important;
  }
  .contact-bar-open .menu-toolbar {
    top: 0;
  }
}
.contact-bar-open .menu-toolbar {
  top: calc(var(--contact-bar-h) + env(safe-area-inset-top));
}

/* Sticky toolbar: search + section nav pinned together (see menu.js). */
.menu-toolbar {
  position: sticky;
  top: 0;
  z-index: 6;
  margin-top: var(--space-4);
  display: grid;
  gap: var(--space-2);
  background: color-mix(in srgb, var(--bg) 92%, transparent);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--line);
}
/* Grid items default to min-width:auto, so the jump-nav strip refuses to
   shrink below its content and pushes the whole menu screen wider than the
   viewport (Fable saw 423px at 390). Let children shrink so the nav's own
   overflow-x scroll takes over instead. */
.menu-toolbar > * {
  min-width: 0;
}
.menu-search {
  width: 100%;
  min-height: 46px;
  padding: 0.6em 0.9em;
  border: 1px solid var(--line);
  border-radius: var(--radius-chip);
  background: var(--surface);
  color: var(--ink);
  font-size: var(--step-body);
}
.diet-chips {
  margin-top: var(--space-3);
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1);
}
.diet-chip {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0.4em 0.9em;
  border-radius: var(--radius-chip);
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink-soft);
  font-size: var(--step-sub);
  font-weight: 600;
  cursor: pointer;
}
.diet-chip[aria-pressed="true"] {
  background: var(--diet);
  border-color: var(--diet);
  color: var(--surface);
}

/* Section jump-nav. Sits inside the sticky .menu-toolbar, which owns the
   pin, background and border — so the nav itself is just the scroll strip. */
.section-nav-scroll {
  display: flex;
  gap: var(--space-1);
  overflow-x: auto;
  scrollbar-width: none;
  padding: var(--space-2) 0;
  scroll-snap-type: x proximity;
}
.section-nav-scroll::-webkit-scrollbar {
  display: none;
}
.section-link {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0.4em 0.85em;
  border-radius: var(--radius-chip);
  font-size: var(--step-sub);
  font-weight: 600;
  color: var(--ink-soft);
  white-space: nowrap;
  scroll-snap-align: start;
}
.section-link.active {
  background: var(--accent);
  color: var(--accent-ink);
}

/* Sections + dishes */
.menu-section {
  scroll-margin-top: calc(var(--toolbar-h, 6.6rem) + var(--space-2));
  padding-top: var(--space-4);
}
.section-title {
  /* Pin the heading just under the sticky toolbar (search + jump-nav), so
     which section you're in stays visible while scrolling its dishes (it's
     pushed up by the next heading). z below the toolbar (6) so it wins. */
  position: sticky;
  top: calc(var(--toolbar-h, 6.6rem) - 1px);
  z-index: 4;
  margin: 0 0 var(--space-1);
  padding: var(--space-2) 0;
  background: color-mix(in srgb, var(--bg) 92%, transparent);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  font-size: 1.25rem;
  font-weight: 700;
  letter-spacing: -0.01em;
}
.dish-list {
  display: grid;
  gap: var(--space-1);
}
.dish {
  /* Clear the sticky toolbar + sticky section heading when a pick or
     "goes well with" link jumps to this dish. */
  scroll-margin-top: calc(var(--toolbar-h, 6.6rem) + 3.2rem);
  padding: var(--space-3) 0;
  border-bottom: 1px solid var(--line);
}
.dish.dimmed {
  opacity: 0.32;
}
.dish-head {
  display: flex;
  gap: var(--space-3);
  align-items: baseline;
  justify-content: space-between;
}
.dish-name {
  font-size: 1.05rem;
  font-weight: 600;
  line-height: 1.25;
}
/* The venue's order-number badge — muted, monospace-numeric, kept visually
   separate from the dish title (it's a code, not part of the name). */
.dish-code {
  display: inline-block;
  margin-right: var(--space-2);
  padding: 0.05em 0.4em;
  border-radius: 6px;
  background: var(--surface-2);
  color: var(--ink-soft);
  font-size: 0.85em;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  vertical-align: baseline;
}
.dish-price {
  flex: 0 0 auto;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.dish-desc {
  margin-top: var(--space-1);
  color: var(--ink-soft);
  font-size: 0.95rem;
}
.dish-tags {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1);
  margin-top: var(--space-2);
}
.dish-photo {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: var(--radius);
  margin-top: var(--space-2);
  background: var(--surface-2);
}

/* "Goes well with" pairings — deep-link chips to other dishes. */
.dish-pairs {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-1);
  margin-top: var(--space-2);
}
.dish-pairs-label {
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--ink-soft);
  margin-right: 0.2em;
}
.pair-chip {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0.25em 0.7em;
  border-radius: var(--radius-chip);
  background: var(--accent-soft);
  color: var(--accent);
  font-size: 0.8rem;
  font-weight: 600;
  text-decoration: none;
}
.pair-chip:hover {
  text-decoration: underline;
}

/* Tag chips */
.tag {
  display: inline-flex;
  align-items: center;
  padding: 0.16em 0.55em;
  border-radius: 7px;
  font-size: 0.72rem;
  font-weight: 700;
  line-height: 1.5;
}
.tag-diet {
  background: var(--diet-bg);
  color: var(--diet);
}
.tag-spicy {
  background: var(--warn-bg);
  color: var(--warn);
}
.tag-allergen {
  background: var(--warn-bg);
  color: var(--warn-ink);
  border: 1.5px solid var(--warn);
  text-transform: uppercase;
  letter-spacing: 0.02em;
}
@media (prefers-color-scheme: dark) {
  .tag-allergen {
    color: var(--warn);
  }
}
/* An allergen the viewer flagged in their preferences — make it shout: filled,
   heavier, and it pulls focus. Surfacing our tag, never a safety claim. */
.tag-allergen.is-flagged {
  background: var(--warn);
  color: var(--surface);
  border-color: var(--warn);
  font-weight: 800;
}
@media (prefers-color-scheme: dark) {
  .tag-allergen.is-flagged {
    color: var(--warn-ink);
  }
}
/* The whole dish row, when it carries a flagged allergen — a warning rail so
   it stands out while scanning a long menu. */
.dish-flagged {
  border-left: 3px solid var(--warn);
  padding-left: var(--space-3);
}

@media (min-width: 40rem) {
  .dish-list {
    gap: var(--space-2);
  }
}

/* ================= Cook at Home (recipes) ================= */

/* Home-screen tile: an accent-tinted pin so it reads as "not a venue". */
.card-recipes {
  background: var(--accent-soft);
  border-color: color-mix(in srgb, var(--accent) 35%, var(--line));
}
.chip-recipes {
  background: var(--accent);
  color: var(--accent-ink);
}

/* Recipe meta (serves · time) sits where a dish price would. */
.dish-meta {
  flex: 0 0 auto;
  color: var(--ink-soft);
  font-size: var(--step-sub);
  font-weight: 600;
  white-space: nowrap;
}

/* Collapsible ingredients + method — keeps the recipe list scannable. */
.recipe-detail {
  margin-top: var(--space-2);
}
.recipe-summary {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  min-height: 40px;
  padding: 0.35em 0.9em;
  border-radius: var(--radius-chip);
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink);
  font-size: var(--step-sub);
  font-weight: 600;
  cursor: pointer;
  list-style: none;
  width: fit-content;
}
.recipe-summary::-webkit-details-marker {
  display: none;
}
.recipe-summary::after {
  content: "▾";
  color: var(--ink-soft);
}
.recipe-detail[open] .recipe-summary::after {
  content: "▴";
}
.recipe-body {
  padding-top: var(--space-3);
}
.recipe-head {
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--ink-soft);
  margin-bottom: var(--space-1);
}

/* Recipe name as a link in the Cook at Home list → its full page. */
.dish-name-link {
  color: inherit;
  text-decoration: none;
}
.dish-name-link:hover {
  color: var(--accent);
  text-decoration: underline;
}

/* Full recipe page (recipe.html) */
.recipe-detail-page {
  padding-top: var(--space-3);
}
.recipe-detail-page .recipe-head {
  margin-top: var(--space-4);
}
.recipe-lede {
  color: var(--ink-soft);
  margin: var(--space-2) 0;
}
.recipe-photo {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: var(--radius);
  margin: var(--space-3) 0;
  background: var(--surface-2);
}
.recipe-detail-page .dish-tags {
  margin-top: var(--space-3);
}
.recipe-body .ingredients {
  display: grid;
  gap: 2px;
  margin-bottom: var(--space-3);
}
.recipe-body .ingredients li {
  padding-left: 1em;
  position: relative;
}
.recipe-body .ingredients li::before {
  content: "•";
  position: absolute;
  left: 0;
  color: var(--accent);
}
.recipe-body .method {
  display: grid;
  gap: var(--space-2);
  counter-reset: step;
  padding: 0;
}
.recipe-body .method li {
  display: grid;
  grid-template-columns: 1.6em 1fr;
  align-items: start;
  counter-increment: step;
}
.recipe-body .method li::before {
  content: counter(step);
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  color: var(--accent);
}

/* "Needs a refresh" note — behind an ⓘ disclosure beside the venue name,
   so the header stays uncluttered until you ask for it. */
.menu-title-group {
  position: relative; /* positioning context for the note popover */
  display: flex;
  align-items: flex-start;
  gap: var(--space-1);
  min-width: 0; /* let a long title wrap rather than shove the heart off */
}
.caveat-btn {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  margin-top: -0.1em; /* sit against the title's cap height */
  font-size: 1.45rem; /* a caution, not a passive hint — noticeable but not loud */
  line-height: 1;
  color: var(--warn); /* orange by default: the note behind it is a warning */
  background: none;
  border: none;
  border-radius: var(--radius-chip);
  cursor: pointer;
}
.caveat-btn:hover,
.caveat-btn[aria-expanded="true"] {
  color: var(--warn);
  background: var(--warn-bg); /* a soft halo on hover/open, so it reads as active */
}
.caveat-note {
  display: none;
  position: absolute;
  top: 100%;
  left: 0;
  z-index: 20;
  width: max-content;
  max-width: min(28rem, 88vw);
  margin-top: var(--space-1);
  padding: var(--space-2) var(--space-3);
  background: var(--warn-bg);
  color: var(--warn-ink);
  border: 1px solid var(--warn);
  border-radius: var(--radius);
  font-size: var(--step-sub);
  font-weight: 600;
  line-height: 1.4;
  box-shadow: 0 8px 24px rgb(0 0 0 / 0.18);
}
.caveat-note.is-open {
  display: block;
}
/* Mouse users get a hover reveal too; touch/keyboard use the click toggle. */
@media (hover: hover) and (pointer: fine) {
  .caveat-btn:hover ~ .caveat-note {
    display: block;
  }
}
@media (prefers-color-scheme: dark) {
  .caveat-note {
    color: var(--warn);
  }
}

/* ---------- Site footer ---------- */
/* The privacy story is genuinely strong for this site, so it earns a plain
   statement. Business attribution only — no contact details (personal-data
   rule). Lives inside <main> so the fixed filter bar's bottom padding keeps
   it clear of the bar. */
.site-footer {
  margin-top: var(--space-5);
  padding-top: var(--space-4);
  border-top: 1px solid var(--line);
  color: var(--ink-soft);
  font-size: var(--step-sub);
  text-align: center;
}
.footer-privacy {
  max-width: 46ch;
  margin-inline: auto;
  line-height: 1.55;
  text-wrap: balance;
}
.footer-made {
  margin-top: var(--space-2);
  font-size: 0.8rem;
}
.footer-brand {
  font-weight: 700;
  color: var(--ink);
}
/* Footer "About & privacy" link — a button styled as a text link (it opens the
   About dialog rather than navigating), sized to a comfortable tap target. */
.footer-link {
  display: inline-block;
  min-height: 44px;
  padding: 0.4em 0.2em;
  border: 0;
  background: none;
  color: var(--ink-soft);
  font: inherit;
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
}
.footer-link:hover {
  color: var(--accent);
}

/* About dialog. Reuses .settings-sheet for the sheet/backdrop/head; these
   style only its prose. */
.about-lede {
  color: var(--ink);
  line-height: 1.55;
  margin-bottom: var(--space-4);
}
.about-group {
  margin-bottom: var(--space-4);
}
.about-group-title {
  font-size: var(--step-sub);
  font-weight: 700;
  margin-bottom: var(--space-1);
}
.about-text {
  color: var(--ink-soft);
  line-height: 1.55;
}
.about-made {
  margin-top: var(--space-4);
  padding-top: var(--space-3);
  border-top: 1px solid var(--line);
  font-size: 0.85rem;
  color: var(--ink-soft);
}

/* Transient status toast (toast.js) — bottom-centre, sits clear of the filter
   bar, fades in/out. Reduced motion keeps the fade but drops the slide. */
.toast {
  position: fixed;
  left: 50%;
  bottom: calc(var(--bar-h) + env(safe-area-inset-bottom) + var(--space-4));
  transform: translate(-50%, 0.75rem);
  z-index: 20;
  max-width: min(90vw, 30rem);
  padding: 0.7em 1.1em;
  border-radius: var(--radius-chip);
  background: var(--ink);
  color: var(--bg);
  font-size: var(--step-sub);
  font-weight: 600;
  text-align: center;
  box-shadow: var(--shadow-lift);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.18s ease, transform 0.18s ease;
}
.toast.is-shown {
  opacity: 1;
  transform: translate(-50%, 0);
}
@media (prefers-reduced-motion: reduce) {
  .toast {
    transform: translate(-50%, 0);
    transition: opacity 0.18s ease;
  }
}
