:root {
    --bg: #fafafa;
    --card: #ffffff;
    --ink: #1f2937;
    --muted: #6b7280;
    --line: #e5e7eb;
    /* ── Brand ramp (F-136) — mirrors TmaBrand in Tma.Surface.Components/Theme ────────────────────
       Two tokens for one hue, and which one you reach for is decided by what the colour has to do,
       not by taste. Measured 2026-07-30 against this sheet's own surfaces; PatronBrandRampCssTests
       re-measures on every build so the split cannot quietly collapse back into one token.

       --accent is the IDENTITY hue (TmaBrand.Blue) and carries the brand read. At 4.12:1 on --bg and
       4.30:1 on --card it clears the 3:1 WCAG non-text floor but NOT the 4.5:1 floor for normal text,
       so it is legal for borders, focus rings, dividers, icon fills and large text (≥24px, or
       ≥18.66px bold) — and illegal as a normal-size text colour or as a fill under a label.

       --accent-fg is the AA FOREGROUND (TmaBrand.PrimaryOnLight): the same hue, darker. 5.62:1 on
       --bg, 5.87:1 on --card and 5.39:1 on #eff6ff — the darkest surface any accent text sits on,
       the blue chip tint — while white on it is 5.87:1. Every normal-size accent text and every
       white-label accent fill uses this.

       Only two sites deliberately keep the identity hue as text — `.home-hero h1 em` (1.9rem/800) and
       `.nearby-title em` (1.5rem/800). Both are large text, where 3:1 governs and 4.12:1 passes, and
       both are the "*your* menu" brand moment the ramp exists to preserve rather than flatten.

       No dark end is declared: this sheet has no dark surface, and an unused token drifts. The
       measurements for the one that is coming are recorded instead — against Variant B's surfaces
       (#111B28 / #0B131D / #182535 / #1E2E42), --accent-fg falls to 1.87–3.18:1 and --ink to
       1.06–1.34:1, so the light end does NOT carry over; TmaBrand.PrimaryOnDark #8CCBEE holds
       6.22–10.57:1 there. Note also that all four verdict colours below drop to 1.70–3.86:1 on those
       surfaces, so Variant B needs a dark end for the safety palette before it ships, not after. */
    --accent: #2980b9;
    --accent-fg: #1f6a99;
    --safe: #15803d;       /* shared safety palette — mirrors TmaBrand.Safe */
    --unsafe: #b91c1c;     /* mirrors TmaBrand.Unsafe */
    --removable: #b45309;  /* mirrors TmaBrand.Removable */
    --unverified: #6b7280; /* mirrors TmaBrand.Unverified */
    --filter-section-gap: 0.75rem; /* FB-84: one shared rhythm between the drawer's stacked sections */
}

* { box-sizing: border-box; }

body {
    margin: 0;
    font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
    color: var(--ink);
    background: var(--bg);
    line-height: 1.5;
}

.app-loading, .menu-empty {
    padding: 2rem 1.25rem;
    color: var(--muted);
}

/* ── Mobile-first touch-target floor ──────────────────────────────────────────────
   The patron surface is used one-handed on a phone (a guest scanning the QR at the table),
   so every tappable control meets the 44×44px minimum (WCAG 2.5.5 / iOS HIG). This is the
   phone-first BASE — a floor under the specific control styles below (min-* wins over a
   smaller explicit height), not a desktop-down patch. */
.filter-drawer-close, .add-to-list, .share-link, .cart-tip-btn,
.cart-send, .cart-track, .order-status-refresh, .reserve-submit, .menu-tab,
.order-status-giftcard-apply, .order-status-loyalty-apply, .order-status-loyalty-check,
.cart-mod-add-btn, .prefs-forget,
.search-summary-edit, .concept-switcher-location, .concept-switcher-menu {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
.cart-qty button, .fav-toggle, .cart-close, .cart-remove, .cart-mod-remove {
    min-width: 44px;
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
.filter-option { min-height: 44px; }
.filter-other > summary { padding: 0.6rem 0; }

/* ── App bar / nav ─────────────────────────────────────────────────────────────────
   Rendered on every patron route by both paths (MainLayout / the server prerender) — a scanned printed QR
   code included (USERfb.2026072312.2), which supersedes the earlier chromeless-QR rule.
   Mobile-first: a single sticky top row sized to the 44px touch floor, brand left + links right. */
.patron-appbar {
    position: sticky;
    top: 0;
    z-index: 40;
    display: flex;
    align-items: center;
    gap: 1rem;
    min-height: 48px;
    padding: 0.4rem 1rem;
    background: var(--card);
    border-bottom: 1px solid var(--line);
}
.patron-appbar-brand {
    font-weight: 700;
    color: var(--accent-fg);
    text-decoration: none;
    margin-right: auto; /* push the nav links to the right on every width */
}
.patron-appbar-link {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    color: var(--ink);
    text-decoration: none;
}
.patron-appbar-link:hover, .patron-appbar-brand:hover { text-decoration: underline; }
.patron-appbar-brand { white-space: nowrap; }

/* The one top-right control (USERfb.2026072312.1): the TMA logo mark beside the session word, backed by the
   UXD.5 checkbox panel. Visible at rest: brand, Discover, and that control. Everything else — the auth entry,
   the two funnel entries, and the UXD.5 patron routes below a separator — lives in the CSS-only panel, so there
   is zero script and the server prerender behaves identically before Blazor boots.

   The panel behaves the SAME at every width on purpose. Its previous shape had two regimes — a dropdown below
   900px and an inline row above it — and the reveal rule, being three classes to the wide branch's one, outranked
   the inline layout wherever it was declared at the top level. That is what broke the desktop bar. With one
   regime there is nothing for the reveal to outrank, and PatronNavDisclosureCssTests keeps it that way by
   forbidding any width branch from touching the disclosure at all. */
.patron-nav-toggle { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.patron-nav-button { display: inline-flex; align-items: center; gap: 0.4rem; min-height: 44px; padding: 0 0.25rem; font-weight: 600; color: var(--ink); cursor: pointer; user-select: none; }
/* The mark ships white-on-transparent (it is the same asset the share card and branded mail use), so it needs
   the accent chip under it to read at all on the light bar. The chip takes the ramp token rather than the
   identity hue because the signed-in state below draws a white LETTER in this same circle — text, at 4.5:1,
   not the 3:1 a logo mark would have been allowed to sit at. */
.patron-guest-mark { width: 28px; height: 28px; flex: none; padding: 3px; border-radius: 999px; background: var(--accent-fg); object-fit: contain; }
/* The signed-in avatar reuses that chip and only swaps what is drawn inside it — the patron's initial instead of
   the mark — so the two states are the same size and shape at every width, including the 480px branch below. */
.patron-guest-initial { display: inline-flex; align-items: center; justify-content: center; padding: 0; color: #fff; font-size: 0.95rem; font-weight: 700; line-height: 1; text-transform: uppercase; }
/* A picked food/beverage icon (USERfb.2026072313.2) sits in the SAME chip, but on the card colour with an accent
   ring: an emoji carries its own colours, and those read as mud on the filled accent circle the mark needs. */
.patron-guest-icon { display: inline-flex; align-items: center; justify-content: center; padding: 0; background: var(--card); box-shadow: inset 0 0 0 2px var(--accent); font-size: 0.95rem; line-height: 1; }
.patron-guest-name { white-space: nowrap; }
/* The label is not focusable — the checkbox is, and it is visually hidden — so the focus ring has to be drawn
   on the label the keyboard user is actually aiming at. */
.patron-nav-toggle:focus-visible ~ .patron-nav-button { outline: 2px solid var(--accent); outline-offset: 2px; }
.patron-nav-list { display: none; list-style: none; margin: 0; padding: 0.25rem 0; position: absolute; top: 100%; right: 0.5rem; min-width: 13rem; background: var(--card); border: 1px solid var(--line); border-radius: 0 0 0.6rem 0.6rem; box-shadow: 0 8px 20px rgba(0, 0, 0, 0.08); z-index: 41; }
.patron-nav-list .patron-appbar-link { display: flex; padding: 0 1rem; }
.patron-nav-toggle:checked ~ .patron-nav-list { display: block; }
.patron-nav-sep { margin: 0.25rem 0; border: 0; border-top: 1px solid var(--line); }
/* The sign-in entry keeps its emphasis inside the panel — it is the row a guest is most likely to want — but
   not the pill it wore in the bar, which would read as a stray button in a list of links. */
.patron-appbar-auth.is-signin { color: var(--accent-fg); font-weight: 700; }
/* 375-clean: tighten the row so brand + Discover + the Guest control share one line on the smallest phones. */
@media (max-width: 480px) {
    .patron-appbar { gap: 0.55rem; padding: 0.4rem 0.6rem; font-size: 0.9rem; }
    .patron-guest-mark { width: 24px; height: 24px; }
}

.patron-shell {
    max-width: 720px;
    margin: 0 auto;
    padding: 1rem 1rem 4rem;
}

/* Loading skeleton — the layout appears instantly with an animated shimmer while a page's data loads, so the
   wait feels fast (perceived performance). Greys are static-image neutral; the menu first-load is prerendered
   (real content) and never shows this — it's for client-side fetch gaps (SPA nav, discover). */
.skeleton {
    background: linear-gradient(90deg, #ececec 25%, #f5f5f5 37%, #ececec 63%);
    background-size: 400% 100%;
    animation: skeleton-shimmer 1.4s ease-in-out infinite;
    border-radius: 0.4rem;
}
@keyframes skeleton-shimmer { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }
@media (prefers-reduced-motion: reduce) { .skeleton { animation: none; } }
.skeleton-title { height: 1.9rem; width: 60%; margin: 0.5rem 0 0.6rem; }
.skeleton-tagline { width: 80%; max-width: 22rem; height: 0.9rem; margin-bottom: 1.25rem; }
.skeleton-card { border: 1px solid var(--line); border-radius: 0.6rem; padding: 0.85rem 1rem; margin: 0.5rem 0; }
.skeleton-line { height: 0.85rem; margin: 0.45rem 0; }
.skeleton-line.skeleton-name { width: 45%; height: 1.05rem; }
.skeleton-line.short { width: 70%; }

.menu-header h1 { font-size: 1.75rem; margin: 0.5rem 0 0.25rem; }
.menu-venue { margin: 0 0 0.4rem; font-weight: 600; color: var(--text, inherit); }
.menu-checking { display: flex; align-items: center; gap: 0.5rem; margin: 0 0 1rem; padding: 0.5rem 0.75rem; background: #eff6ff; border: 1px solid #bfdbfe; border-radius: 0.4rem; font-size: 0.85rem; color: #1e40af; }

/* Concept branding (PD.4) — the concept's name and/or logo above the menu title, per its PublicHeaderDisplay
   election. A capped logo height keeps a tall/odd-aspect mark from dominating the phone-first header. */
.concept-brand { display: flex; align-items: center; gap: 0.5rem; margin: 0.25rem 0; }
.concept-logo { max-height: 40px; max-width: 100%; width: auto; object-fit: contain; }
.concept-name { font-weight: 700; color: var(--accent-fg); font-size: 1rem; }

/* Menus / Reservations / Contact tabs (PD.4) — an equal-width row that never overflows even at 375px (each tab
   shares the row via flex:1 rather than scrolling); all three toggle the panel below in place, so the header above
   them never leaves the screen. Meets the 44px touch floor via the shared selector above. */
.menu-tabs { display: flex; gap: 0.4rem; margin: 0.5rem 0 0.75rem; }
.menu-tab {
    flex: 1 1 0; min-width: 0; padding: 0.5rem 0.4rem;
    border: 1px solid var(--line); background: var(--card); color: var(--ink); border-radius: 0.5rem;
    font-weight: 600; font-size: 0.85rem; text-decoration: none; cursor: pointer;
    text-align: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.menu-tab.is-active { border-color: var(--accent-fg); background: var(--accent-fg); color: #fff; }
.menu-tab:not(.is-active):hover { background: #eff6ff; }

/* Location + menu switcher (PD.5) — "showing locations nearby". Mobile-first: pills WRAP onto extra lines
   rather than scroll horizontally (an arbitrary number of locations/menus, unlike the fixed 3-tab row above),
   meeting the 44px touch floor via the shared selector above. Renders nothing at all for a single-location,
   single-menu concept (the common QR case), so the header looks unchanged for most guests. */
.concept-switcher { margin: 0.25rem 0 0.5rem; }
.concept-switcher-caption { margin: 0 0 0.35rem; font-size: 0.8rem; color: var(--muted); }
.concept-switcher-locations { display: flex; flex-wrap: wrap; gap: 0.4rem; margin: 0 0 0.5rem; }
.concept-switcher-location {
    flex-direction: column; align-items: flex-start; gap: 0.05rem; padding: 0.4rem 0.75rem;
    border: 1px solid var(--line); background: var(--card); color: var(--ink); border-radius: 0.6rem;
    text-align: left; cursor: pointer;
}
.concept-switcher-location.is-active { border-color: var(--accent-fg); background: var(--accent-fg); color: #fff; }
.concept-switcher-location-name { font-weight: 600; font-size: 0.88rem; }
.concept-switcher-location-sub { font-size: 0.75rem; opacity: 0.85; }
.concept-switcher-menus { display: flex; flex-wrap: wrap; gap: 0.4rem; margin: 0 0 0.5rem; }
.concept-switcher-menu {
    padding: 0.4rem 0.85rem; border: 1px solid var(--line); background: var(--card); color: var(--ink);
    border-radius: 999px; font-weight: 600; font-size: 0.85rem; text-decoration: none; cursor: pointer;
}
.concept-switcher-menu.is-active { border-color: var(--accent-fg); background: var(--accent-fg); color: #fff; }
.concept-switcher-menu:not(.is-active):hover { background: #eff6ff; }

/* The Contact tab's location block (reuses OrderLocationHeader, otherwise only shown in the order panel). */
.cart-location-header { display: flex; flex-direction: column; gap: 0.3rem; margin: 0 0 1rem; padding: 0.85rem 1rem;
    border: 1px solid var(--line); border-radius: 0.6rem; background: var(--card); }
.cart-location-concept { font-size: 1.05rem; }
.cart-location-name { font-weight: 600; }
.cart-location-address { color: var(--muted); font-size: 0.9rem; }
.cart-location-phone { color: var(--accent-fg); font-weight: 600; text-decoration: none; min-height: 44px; display: inline-flex; align-items: center; }

/* Search & filter — a slide-in drawer (replaces the old inline expansion panel), opened from the
   page's single "Search & filter" control: the sticky FAB below. */
.menu-header-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; margin: 0.25rem 0 0.5rem; }

/* Share control in the menu header (mirrors the drawer's share button; both call the same share path). */
.menu-share {
    display: inline-flex; align-items: center; gap: 0.4rem; min-height: 44px; padding: 0.45rem 0.9rem;
    border: 1px solid var(--accent); background: var(--card); color: var(--accent-fg); border-radius: 999px;
    font-weight: 600; font-size: 0.9rem; cursor: pointer;
}
.menu-share:hover { background: #eff6ff; }

/* Menu language picker (UXD.6) — renders only when the server's translation seam is enabled; styled to sit
   beside Share/Save as a compact pill. Display strings only; safety copy always stays source-language. */
.menu-translate-select {
    min-height: 44px; padding: 0.45rem 0.9rem; border: 1px solid var(--accent); background: var(--card);
    color: var(--accent-fg); border-radius: 999px; font-weight: 600; font-size: 0.9rem; cursor: pointer;
}

/* The page's ONE "Search & filter" control — always reachable while scrolling. It rides a position:sticky rail
   whose negative top margin (button height 44px + the actions row's 0.5rem bottom margin, via margin collapse)
   pulls it up onto the actions row's own line, so at rest it reads as that row's right end — Share left, filter
   right — and PINS to the top-right as the guest scrolls the menu (UI1.1: the header renders no duplicate). The
   rail's net flow height is zero, so hiding it while the drawer is open never shifts the layout; pointer-events
   pass through its empty area to the row beneath. Same 44px height as every other action button. */
.menu-fab-rail {
    position: sticky; top: 0.5rem; z-index: 20;
    display: flex; justify-content: flex-end;
    margin: calc(-44px - 0.5rem) 0 0.5rem; pointer-events: none;
}
.menu-filter-fab {
    pointer-events: auto;
    display: inline-flex; align-items: center; gap: 0.4rem; min-height: 44px; padding: 0.45rem 1.1rem;
    border: none; background: var(--accent-fg); color: #fff; border-radius: 999px;
    font-weight: 700; font-size: 0.9rem; cursor: pointer; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
}
.menu-filter-fab:hover { filter: brightness(0.96); }

.filter-drawer-scrim { position: fixed; inset: 0; background: rgba(0, 0, 0, 0.5); z-index: 40; }
/* Slides in from the RIGHT (thumb-reachable on a phone; leaves the menu visible on the left as it opens). */
.filter-drawer {
    position: fixed; top: 0; right: 0; height: 100%; width: min(90vw, 360px); z-index: 41;
    background: var(--card); box-shadow: -2px 0 18px rgba(0, 0, 0, 0.18);
    display: flex; flex-direction: column;
    transform: translateX(100%); transition: transform 0.2s ease; visibility: hidden;
}
.filter-drawer.is-open { transform: translateX(0); visibility: visible; }
.filter-drawer-head {
    display: flex; align-items: center; justify-content: space-between; flex: none;
    padding: 0.85rem 1rem; border-bottom: 1px solid var(--line);
}
.filter-drawer-head strong { font-size: 1.05rem; }
.filter-drawer-close {
    border: 1px solid var(--accent); background: none; color: var(--accent-fg);
    border-radius: 999px; padding: 0.3rem 0.95rem; font-weight: 600; cursor: pointer;
}
.filter-drawer-body { overflow-y: auto; flex: 1; padding: 0.5rem 1rem 1.5rem; }
@media (prefers-reduced-motion: reduce) { .filter-drawer { transition: none; } }
.filter-group { border: none; margin: 0.75rem 0 0; padding: 0; display: flex; flex-direction: column; gap: 0.35rem; }
.filter-group legend { font-weight: 600; padding: 0; margin-bottom: 0.25rem; }
.filter-option { display: flex; align-items: center; gap: 0.5rem; }
.filter-option > span { user-select: none; }
.filter-cc { display: inline-flex; align-items: center; gap: 0.35rem; margin-left: 0.75rem; font-size: 0.8rem; color: var(--muted); }

/* "I have allergies": the entry affordance for the allergen picker, inside the exclude term module. It borrows the
   "Avoid Allergens" pill wholesale (one disclosure vocabulary in the drawer, no parallel style) and only differs by
   sitting flush with the module above it. Nested one level in, so the inner pill indents to read as its child. */
.filter-allergen-entry { margin: 0.5rem 0 0; }
.filter-allergen-entry > summary {
    min-height: 44px; display: flex; align-items: center; justify-content: space-between; gap: 0.5rem;
    list-style: none; font-weight: 600; cursor: pointer;
    border: 1px solid var(--accent); border-radius: 0.5rem; padding: 0 0.85rem; color: var(--accent-fg);
}
.filter-allergen-entry > summary::-webkit-details-marker { display: none; }
.filter-allergen-entry > summary::after { content: "\25be"; font-size: 0.75rem; transition: transform 0.15s ease; }
.filter-allergen-entry[open] > summary::after { transform: rotate(180deg); }
.filter-allergen-entry > .filter-allergens { margin-left: 0.5rem; }

/* "Avoid Allergens" as a collapsible category (collapsed by default). The summary reads as its own button (a
   bordered, rounded pill matching the drawer's other buttons) while still toggling the native disclosure; a
   chevron stands in for the suppressed default marker so the open/closed state stays legible. 44px tap target. */
.filter-allergens { margin: var(--filter-section-gap) 0 0; }
.filter-allergens > summary {
    min-height: 44px; display: flex; align-items: center; justify-content: space-between; gap: 0.5rem;
    list-style: none; font-weight: 600; cursor: pointer;
    border: 1px solid var(--accent); border-radius: 0.5rem; padding: 0 0.85rem; color: var(--accent-fg);
}
.filter-allergens > summary::-webkit-details-marker { display: none; }
.filter-allergens > summary::after { content: "\25be"; font-size: 0.75rem; transition: transform 0.15s ease; }
.filter-allergens[open] > summary::after { transform: rotate(180deg); }
.filter-allergens-help { margin: 0.5rem 0 0.25rem; font-size: 0.85rem; color: var(--muted); }

/* FB-51 dietary preferences: its OWN collapsible box (mobile-first, 44px targets), a child diet indented one
   level under its parent. Preference styling only — never the allergen verdict palette. */
.filter-dietary { margin: 0.5rem 0 0; }
.filter-dietary > summary { min-height: 44px; display: flex; align-items: center; font-weight: 600; cursor: pointer; }
.filter-dietary-help { margin: 0 0 0.25rem; font-size: 0.85rem; color: var(--muted); }
.filter-dietary-group { display: flex; flex-direction: column; gap: 0.35rem; }
.filter-dietary-option { min-height: 44px; }
.filter-dietary-depth-1 { margin-left: 1rem; }

/* Allergen LOCK (KW.5 / PM-16): while the order list is non-empty the options grey out + disable, and a
   "change allergens" link opens the apply-forward confirmation. The disabled fieldset dims its own controls. */
.filter-allergens.is-locked .filter-group { opacity: 0.55; }
.filter-allergens-locked-note { margin: 0 0 0.4rem; font-size: 0.85rem; color: var(--muted); }
.filter-change-allergens {
    min-height: 44px; display: inline-flex; align-items: center; margin: 0 0 0.35rem; padding: 0 0.2rem;
    border: 0; background: none; color: var(--accent-fg); font-weight: 600; text-decoration: underline; cursor: pointer;
}

/* Collapsible allergen families (KW.2, collapsed by default): the family summary is a 44px tap target and the
   "All [Family] Types Listed" checkbox tops the indented member list. */
.filter-family > summary { min-height: 44px; display: flex; align-items: center; font-weight: 600; cursor: pointer; }
.filter-family-body { display: flex; flex-direction: column; gap: 0.35rem; margin-left: 0.75rem; }
.filter-family-all > span { font-weight: 600; }

/* Cross-contact confirmation modal — centered dialog over a dimming overlay (page content darkened). */
.cc-modal-overlay { position: fixed; inset: 0; background: rgba(0, 0, 0, 0.5); z-index: 60; display: flex; align-items: center; justify-content: center; padding: 1rem; }
.cc-modal { background: var(--card); width: 100%; max-width: 26rem; border-radius: 0.75rem; padding: 1.1rem 1.25rem 1.25rem; box-shadow: 0 12px 32px rgba(0, 0, 0, 0.3); }
.cc-modal-text { margin: 0 0 1rem; font-size: 0.9rem; line-height: 1.5; color: var(--ink, inherit); }
.cc-modal-actions { display: flex; flex-direction: column; gap: 0.5rem; }
.cc-modal-agree { min-height: 44px; border: 0; border-radius: 0.5rem; background: var(--accent-fg); color: #fff; font-weight: 600; cursor: pointer; }
.cc-modal-cancel { min-height: 44px; border: 1px solid var(--line); border-radius: 0.5rem; background: #fff; color: var(--muted); font-weight: 600; cursor: pointer; }

/* The inline SVG button glyphs (search / reserve / share / heart) — one consistent size, brand-coloured via the
   button's currentColor, non-shrinking so the icon never squashes next to its label. Replaces the old emoji glyphs
   so the whole action-button row reads as one designed system (no icon fonts / no CDN — fast-load). */
.btn-icon, .share-icon { vertical-align: -0.15em; flex: 0 0 auto; }

/* Persistent, non-blocking allergen disclaimer, shown with the filter UI (safety text is never hidden).
   The color-scheme verdict legend is retired (KV.3) — unsafe items are hidden, not color-coded. */
.allergen-notes { margin: 0 0 0.5rem; }
.allergen-disclaimer { margin: 0 0 0.6rem; padding: 0.6rem 0.75rem; background: #fff7ed; border: 1px solid #fed7aa; border-radius: 0.5rem; font-size: 0.8rem; color: #7c2d12; line-height: 1.45; }

/* KV.4 allergen agree-gate — the WHOLE drawer is gated behind agreeing to the disclaimer (fail-closed). Until then
   only the disclaimer + this "I agree" button render. */
.allergen-agree-gate { margin: 0.25rem 0 0.5rem; }
.allergen-agree-confirm { min-height: 44px; width: 100%; border: 0; border-radius: 0.5rem; background: var(--accent-fg); color: #fff; font-weight: 600; font-size: 0.95rem; cursor: pointer; }

/* Once agreed, the disclaimer collapses to the bottom of the drawer, reviewable on demand. */
.allergen-notice-review { margin: 1rem 0 0; border-top: 1px solid var(--line); padding-top: 0.5rem; }
.allergen-notice-review > summary { min-height: 44px; display: flex; align-items: center; font-size: 0.85rem; font-weight: 600; color: var(--muted); cursor: pointer; }

/* KV.4 first-visit Terms & Privacy consent gate — a global, non-blocking overlay shown on hydrate to a first-time
   browser (fail-closed). Mobile-first: full-bleed card, 44px tap target. */
.terms-consent-overlay { position: fixed; inset: 0; background: rgba(0, 0, 0, 0.5); z-index: 80; display: flex; align-items: flex-end; justify-content: center; padding: 1rem; }
.terms-consent-card { background: var(--card); width: 100%; max-width: 30rem; border-radius: 0.9rem; padding: 1.1rem 1.25rem 1.25rem; box-shadow: 0 12px 32px rgba(0, 0, 0, 0.3); }
.terms-consent-title { margin: 0 0 0.5rem; font-size: 1.05rem; }
.terms-consent-body { margin: 0 0 1rem; font-size: 0.9rem; line-height: 1.5; color: var(--ink, inherit); }
.terms-consent-link { color: var(--accent-fg); text-decoration: underline; }
.terms-consent-agree { min-height: 44px; width: 100%; border: 0; border-radius: 0.5rem; background: var(--accent-fg); color: #fff; font-weight: 600; font-size: 0.95rem; cursor: pointer; }
@media (min-width: 640px) { .terms-consent-overlay { align-items: center; } }
/* UXC.4 consent gate v2: both documents inline in ONE scroll container (Terms → Privacy) with a scroll-to-end
   sentinel gating Accept. The card flexes so short viewports keep the buttons on screen and the documents scroll. */
.terms-consent-card { display: flex; flex-direction: column; max-height: calc(100vh - 2rem); max-height: calc(100dvh - 2rem); }
.terms-consent-scroll { flex: 1 1 auto; min-height: 6rem; overflow-y: auto; border: 1px solid rgba(0, 0, 0, 0.12); border-radius: 0.5rem; padding: 0.75rem; margin-bottom: 0.75rem; -webkit-overflow-scrolling: touch; }
.terms-consent-doc-heading { margin: 0 0 0.5rem; font-size: 0.95rem; }
.terms-consent-doc + .terms-consent-doc { margin-top: 1rem; padding-top: 1rem; border-top: 1px solid rgba(0, 0, 0, 0.12); }
.terms-consent-end { height: 1px; }
.terms-consent-loading { margin: 0; font-size: 0.9rem; }
.terms-consent-hint { margin: 0 0 0.5rem; font-size: 0.8rem; color: var(--muted, #666); }
/* CG.3: the allergen notice is the gate's third document — same body treatment as the fetched documents. */
.terms-consent-allergen { margin: 0; font-size: 0.9rem; line-height: 1.5; }
/* CG.2: the fallback affirmation, shown only when the scroll sentinel could not attach in a real browser. The
   44px min-height keeps the whole row a comfortable tap target on the phones this gate is scanned from. */
.terms-consent-affirm { display: flex; align-items: flex-start; gap: 0.5rem; min-height: 44px; margin: 0 0 0.5rem; font-size: 0.8rem; line-height: 1.4; color: var(--muted, #666); cursor: pointer; }
.terms-consent-affirm input { flex: 0 0 auto; width: 1.1rem; height: 1.1rem; margin-top: 0.1rem; }
.terms-consent-agree[disabled] { opacity: 0.5; cursor: not-allowed; }
.terms-consent-decline { min-height: 44px; width: 100%; margin-top: 0.5rem; border: 0; border-radius: 0.5rem; background: transparent; color: var(--muted, #666); font-size: 0.9rem; cursor: pointer; text-decoration: underline; }
.prefs-remembered { display: flex; align-items: center; gap: 0.5rem; margin: 0 0 0.75rem; padding: 0.4rem 0.6rem; background: #ecfdf5; border: 1px solid #a7f3d0; border-radius: 0.4rem; font-size: 0.85rem; }
.prefs-forget { margin-left: auto; background: none; border: 0; color: var(--accent-fg); cursor: pointer; font-size: 0.85rem; text-decoration: underline; padding: 0; }
.filter-other { margin-top: 0.75rem; }
.filter-other > summary { cursor: pointer; color: var(--accent-fg); }
.filter-mode { display: flex; align-items: center; gap: 0.5rem; margin-top: var(--filter-section-gap); font-size: 0.9rem; }
.filter-refine { margin-top: var(--filter-section-gap); border-top: 1px solid var(--line); padding-top: var(--filter-section-gap); }
.filter-kinds { display: flex; gap: 1rem; flex-wrap: wrap; }
.filter-display { margin-top: var(--filter-section-gap); border-top: 1px solid var(--line); padding-top: var(--filter-section-gap); display: flex; align-items: center; gap: 1rem; flex-wrap: wrap; }
.filter-display-sort { display: inline-flex; align-items: center; gap: 0.4rem; }
.filter-display-sort select { padding: 0.25rem 0.4rem; border: 1px solid var(--line); border-radius: 0.35rem; }
.filter-text { width: 100%; padding: 0.4rem 0.6rem; border: 1px solid var(--line); border-radius: 0.4rem; font-size: 0.9rem; }
.filter-price { display: flex; align-items: center; gap: 0.5rem; font-size: 0.9rem; }
.filter-price input { width: 5rem; padding: 0.3rem 0.4rem; border: 1px solid var(--line); border-radius: 0.4rem; }

/* PD T1.9: the Drinks / Food / Favourites row, sitting ON the results instead of behind the filter drawer.
   Mobile-first and breakpoint-free: one flex line of 44px tap targets that WRAPS (never scrolls sideways), so at
   375px it stacks onto as many lines as it needs and at 768/1280 it simply settles onto one — nothing to keep in
   sync per width. Neutral chrome on purpose: the row shapes the list, it never signals safety. */
.results-kind-row {
    display: flex; flex-wrap: wrap; align-items: center; gap: 0 1rem;
    margin: 0 0 0.75rem; padding: 0 0.6rem;
    background: var(--card); border: 1px solid var(--line); border-radius: 0.5rem;
}
.results-kind-option { display: flex; align-items: center; gap: 0.4rem; min-height: 44px; font-size: 0.9rem; cursor: pointer; }
.results-kind-option > span { display: inline-flex; align-items: center; gap: 0.25rem; user-select: none; white-space: nowrap; }
.results-kind-option input { accent-color: var(--accent); }

/* Sections + items */
.menu-section {
    font-size: 1.25rem;
    margin: 1.5rem 0 0.5rem;
    padding-bottom: 0.25rem;
    border-bottom: 2px solid var(--line);
}
.menu-items { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.5rem; }
.menu-item {
    background: var(--card);
    border: 1px solid var(--line);
    border-left: 4px solid var(--line);
    border-radius: 0.5rem;
    padding: 0.75rem 1rem;
}
.menu-item.verdict-safe { border-left-color: var(--safe); }
.menu-item.verdict-unsafe { border-left-color: var(--unsafe); }
.menu-item.verdict-removable { border-left-color: var(--removable); }
.menu-item.verdict-unverified { border-left-color: var(--unverified); }
.menu-item.verdict-checking { border-left-color: var(--muted, #9ca3af); }
.menu-item-head { display: flex; justify-content: space-between; align-items: baseline; gap: 0.75rem; }
.menu-item-head-right { display: inline-flex; align-items: baseline; gap: 0.5rem; flex: none; }
/* Let a long dish name shrink + wrap instead of pushing the (nowrap) verdict badge off a 375px screen. It is a
   click-through button into the detail view — reset to look like text, with a generous tap area + focus ring. */
.menu-item-name { font-weight: 600; flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere;
    background: none; border: 0; margin: 0; padding: 0.35rem 0; font: inherit; font-weight: 600; text-align: left;
    color: inherit; cursor: pointer; }
.menu-item-open:hover, .menu-item-open:focus-visible { text-decoration: underline; }
.menu-item-open:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.menu-item-photo { display: block; width: 100%; padding: 0; border: 0; background: none; cursor: pointer; }
.menu-item-photo:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.menu-item-price { font-variant-numeric: tabular-nums; color: var(--ink); font-weight: 600; }
.menu-item-desc { margin: 0.35rem 0 0; color: var(--muted); font-size: 0.9rem; }
.menu-item-why { margin: 0.35rem 0 0; font-size: 0.85rem; }

/* FB-51: the honest "Not verified for <diet>" chips on a dish that does not verifiably meet an elected diet.
   Neutral/preference styling — deliberately NOT the allergen verdict colours, so a diet never reads as a safety
   verdict. */
.menu-item-diet-unverified { margin: 0.3rem 0 0; display: flex; flex-wrap: wrap; gap: 0.3rem; }
.diet-unverified-chip {
    display: inline-flex; align-items: center; padding: 0.15rem 0.5rem; border: 1px solid var(--line);
    border-radius: 0.75rem; background: var(--surface, #f4f4f5); color: var(--muted); font-size: 0.78rem;
}

/* FB-54: the "must request / NO <ingredient>" hint — a modification cue, wrapping cleanly on a 375px phone. */
.menu-item-must-request { margin: 0.3rem 0 0; display: flex; flex-wrap: wrap; align-items: center; gap: 0.3rem; }
.must-request-lead { font-size: 0.78rem; font-weight: 700; color: var(--muted); }
.must-request-chip {
    display: inline-flex; align-items: center; padding: 0.15rem 0.5rem; border: 1px solid var(--line);
    border-radius: 0.75rem; background: var(--surface, #f4f4f5); color: var(--text, #1f2937); font-size: 0.78rem;
}

.verdict-badge {
    flex: none;
    font-size: 0.75rem;
    font-weight: 700;
    padding: 0.15rem 0.5rem;
    border-radius: 999px;
    white-space: nowrap;
}
.verdict-badge.verdict-safe { background: #dcfce7; color: var(--safe); }
.verdict-badge.verdict-unsafe { background: #fee2e2; color: var(--unsafe); }
.verdict-badge.verdict-removable { background: #fef3c7; color: var(--removable); }
.verdict-badge.verdict-unverified { background: #f3f4f6; color: var(--unverified); }
.verdict-badge.verdict-checking { background: #eff6ff; color: #1d4ed8; }

/* FB-84: right-aligned so "Share this menu" lines up with the drawer head's "Done" button — every other
   section in the drawer stays left-aligned. */
.filter-share { margin-top: var(--filter-section-gap); border-top: 1px solid var(--line); padding-top: var(--filter-section-gap); display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: 0.5rem; }
.share-link { background: none; border: 1px solid var(--accent); color: var(--accent-fg); font-weight: 600; font-size: 0.85rem; padding: 0.35rem 0.7rem; border-radius: 999px; cursor: pointer; }
.share-link:hover { background: var(--accent-fg); color: #fff; }
.share-copied { font-size: 0.8rem; color: var(--safe); }
.menu-item-image { display: block; width: 100%; max-height: 13rem; object-fit: cover; border-radius: 0.5rem; margin: 0.5rem 0; background: #f3f4f6; }
.menu-item-pairs { margin: 0.35rem 0 0; font-size: 0.85rem; color: var(--accent-fg); }
.fav-toggle { flex: none; background: none; border: 0; cursor: pointer; font-size: 1.15rem; line-height: 1; color: var(--muted); padding: 0 0.15rem; }
.fav-toggle.is-fav { color: #e11d48; }
.soldout-badge { flex: none; font-size: 0.7rem; font-weight: 700; padding: 0.15rem 0.5rem; border-radius: 999px; white-space: nowrap; background: #f3f4f6; color: var(--unverified); text-transform: uppercase; letter-spacing: 0.03em; }
.featured-badge { flex: none; font-size: 0.7rem; font-weight: 700; padding: 0.15rem 0.5rem; border-radius: 999px; white-space: nowrap; background: #fef3c7; color: #92400e; text-transform: uppercase; letter-spacing: 0.03em; }
.menu-item.is-sold-out { opacity: 0.62; }
.menu-item.is-sold-out .menu-item-name { text-decoration: line-through; }
.add-to-list[disabled] { opacity: 0.55; cursor: not-allowed; border-color: var(--line); background: var(--bg); color: var(--muted); }

.safety-disclaimer {
    display: block;
    margin-top: 2rem;
    padding: 0.75rem 1rem;
    background: #fff7ed;
    border: 1px solid #fed7aa;
    border-radius: 0.5rem;
    font-size: 0.85rem;
    color: #7c2d12;
}
/* Lead line is the action; the caveat stays fully visible beneath it (safety text is never hidden). */
.safety-disclaimer-lead {
    display: block;
    margin-bottom: 0.25rem;
}

/* Patron app front door (/app/) — the value prop + a route into browse-local discovery */
.home-hero { max-width: 32rem; margin: 2rem auto; text-align: center; }
.home-hero h1 { font-size: 1.9rem; margin: 0 0 0.75rem; }
/* "your" is the whole point — the menu is curated for the guest — so emphasize it (brand blue, italic). */
.home-hero h1 em { font-style: italic; font-weight: 800; color: var(--accent); }
.home-lead { color: var(--muted); margin: 0 0 1.5rem; line-height: 1.5; }
.home-cta { display: inline-block; padding: 0.7rem 1.4rem; border-radius: 0.6rem; background: var(--accent-fg); color: #fff; font-weight: 600; text-decoration: none; }
.home-cta:hover { filter: brightness(0.95); }
.home-hint { color: var(--muted); font-size: 0.85rem; margin: 1rem 0 0; }
.home-recent { max-width: 32rem; margin: 2rem auto; }
.home-recent h2 { font-size: 1.1rem; margin: 0 0 0.6rem; }
.home-recent-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.5rem; }
.home-recent-link { display: flex; flex-direction: column; gap: 0.1rem; padding: 0.6rem 0.8rem; border: 1px solid var(--line); border-radius: 0.5rem; text-decoration: none; color: inherit; }
.home-recent-link:hover { border-color: var(--accent); }
.home-recent-name { font-weight: 600; }
.home-recent-venue { color: var(--muted); font-size: 0.85rem; }

/* "Build your menu" — the item-first front door. Single column, generous 44px targets: it is filled one-handed
   on a phone. Chips are the profile made visible; the optional block stays collapsed so first paint is short. */
.ym-builder, .ym-summary { max-width: 32rem; margin: 1.5rem auto; }
.ym-title { font-size: 1.25rem; margin: 0 0 0.25rem; }
.ym-sub { color: var(--muted); margin: 0 0 1.25rem; }
.ym-field { margin: 0 0 1rem; }
.ym-label { display: block; font-weight: 600; margin: 0 0 0.4rem; }
.ym-chip-input { display: flex; gap: 0.5rem; }
.ym-add-input { flex: 1; min-height: 44px; padding: 0.5rem 0.7rem; border: 1px solid var(--line); border-radius: 0.5rem; font: inherit; }
.ym-add { min-height: 44px; min-width: 44px; padding: 0 1rem; border: 1px solid var(--accent); border-radius: 0.5rem; background: #fff; color: var(--accent-fg); font-weight: 600; }
.ym-chips, .ym-summary-chips { list-style: none; margin: 0.6rem 0 0; padding: 0; display: flex; flex-wrap: wrap; gap: 0.4rem; }
.ym-chip { display: inline-flex; align-items: center; gap: 0.35rem; padding: 0.3rem 0.6rem; border-radius: 999px; background: #eef2f7; color: var(--ink); font-size: 0.9rem; }
.ym-chip.is-avoid { background: #fdecec; color: var(--unsafe); }
.ym-chip-remove { min-width: 44px; min-height: 44px; margin: -0.5rem -0.4rem -0.5rem 0; border: 0; background: none; color: inherit; font-size: 1.1rem; line-height: 1; cursor: pointer; display: inline-flex; align-items: center; justify-content: center; }
.ym-optional { margin: 0.5rem 0 1.25rem; }
.ym-optional > summary { min-height: 44px; display: flex; align-items: center; color: var(--accent-fg); font-weight: 600; cursor: pointer; }
.ym-price { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
.ym-price .ym-label { flex-basis: 100%; margin-bottom: 0.4rem; }
.ym-price input, .ym-distance { min-height: 44px; width: 6rem; padding: 0.5rem 0.7rem; border: 1px solid var(--line); border-radius: 0.5rem; font: inherit; }
.ym-distance { width: 8rem; }
.ym-check { min-height: 44px; display: inline-flex; align-items: center; gap: 0.4rem; }
.ym-actions { display: flex; flex-direction: column; gap: 0.6rem; margin: 1.5rem 0 0; }
.ym-save { min-height: 44px; padding: 0.7rem 1.4rem; border: 0; border-radius: 0.6rem; background: var(--accent-fg); color: #fff; font-weight: 600; cursor: pointer; }
.ym-cancel { min-height: 44px; padding: 0.6rem 1.4rem; border: 1px solid var(--line); border-radius: 0.6rem; background: #fff; color: var(--muted); cursor: pointer; }
/* Structured avoid-list: the allergen-canon picker in the builder. Mobile-first — a single stacked column of
   44px tap targets; the "why" disclaimer rides above the options. Depth indent is set inline from the hierarchy. */
.ym-allergens { margin: 0 0 1.25rem; }
.ym-allergen-group { border: 0; margin: 0; padding: 0; display: flex; flex-direction: column; }
.ym-allergen-option { min-height: 44px; display: flex; align-items: center; gap: 0.5rem; }
.ym-allergen-option > span { user-select: none; }
.ym-allergen-other > summary { min-height: 44px; display: flex; align-items: center; color: var(--accent-fg); font-weight: 600; cursor: pointer; }

/* FB-42 "treat this avoid term as an allergen" affordance. Mobile-first — a single stacked card per matched term,
   full-width 44px tap targets that wrap on wider screens. Reads as a helpful prompt, never a safety claim. */
.ym-allergen-convert { display: flex; flex-direction: column; gap: 0.6rem; margin: 0.6rem 0 0; }
.ym-convert-row { border: 1px solid var(--line); border-radius: 0.6rem; padding: 0.7rem 0.8rem; background: #f7f9fc; }
.ym-convert-msg { margin: 0 0 0.6rem; font-size: 0.92rem; color: var(--ink); }
.ym-convert-term { font-weight: 600; }
.ym-convert-actions { display: flex; flex-direction: column; gap: 0.5rem; }
.ym-convert-yes, .ym-consent-yes { min-height: 44px; padding: 0 1rem; border: 1px solid var(--accent-fg); border-radius: 0.5rem; background: var(--accent-fg); color: #fff; font-weight: 600; cursor: pointer; }
.ym-convert-keep, .ym-consent-no { min-height: 44px; padding: 0 1rem; border: 1px solid var(--line); border-radius: 0.5rem; background: #fff; color: var(--muted); cursor: pointer; }
@media (min-width: 30rem) { .ym-convert-actions { flex-direction: row; } }

/* FB-43 "did you mean" picker: a light card naming the typed term, a wrapped row of single-select suggestion
   buttons (44px targets), and Submit/Cancel. Mobile-first — one clean column, actions stack until there is room. */
.ym-didyoumean { border: 1px solid var(--line); border-radius: 0.6rem; padding: 0.7rem 0.8rem; margin: 0.6rem 0 0; background: #f7f9fc; }
.ym-didyoumean-msg { margin: 0 0 0.6rem; font-size: 0.92rem; color: var(--ink); }
.ym-didyoumean-term { font-weight: 600; }
.ym-didyoumean-options { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 0.7rem; }
.ym-didyoumean-option { min-height: 44px; padding: 0 0.9rem; border: 1px solid var(--line); border-radius: 999px; background: #fff; color: var(--ink); font-size: 0.92rem; cursor: pointer; }
.ym-didyoumean-option.is-selected { border-color: var(--accent-fg); background: var(--accent-fg); color: #fff; font-weight: 600; }
.ym-didyoumean-actions { display: flex; flex-direction: column; gap: 0.5rem; }
.ym-didyoumean-submit { min-height: 44px; padding: 0 1rem; border: 1px solid var(--accent-fg); border-radius: 0.5rem; background: var(--accent-fg); color: #fff; font-weight: 600; cursor: pointer; }
.ym-didyoumean-submit:disabled { opacity: 0.5; cursor: default; }
.ym-didyoumean-cancel { min-height: 44px; padding: 0 1rem; border: 1px solid var(--line); border-radius: 0.5rem; background: #fff; color: var(--muted); cursor: pointer; }
@media (min-width: 30rem) { .ym-didyoumean-actions { flex-direction: row; } }

/* "What to include?" / "What to exclude?" grouping boxes — a light card each so the two intents read as distinct. */
.ym-box { border: 1px solid var(--line); border-radius: 0.7rem; padding: 1rem 0.9rem 0.25rem; margin: 0 0 1.25rem; background: #fff; }
.ym-box-title { font-size: 1.05rem; margin: 0 0 0.9rem; }
.ym-exclude { background: #fcfcfd; }
/* "Do you have any allergies?" yes/no gate for the allergen picker. */
.ym-radio-row { display: flex; gap: 1.25rem; }
.ym-radio { min-height: 44px; display: inline-flex; align-items: center; gap: 0.4rem; cursor: pointer; }
.ym-radio > span { user-select: none; }
/* A top-level allergen as a collapsible section (collapsed by default); the master checkbox lives in the summary. */
.ym-allergen-master { border-bottom: 1px solid var(--line); }
.ym-allergen-master > summary { min-height: 44px; display: flex; align-items: center; cursor: pointer; list-style-position: inside; }
.ym-allergen-masterlabel { flex: 1; margin: 0; font-weight: 600; }
.ym-allergen-child { margin-left: 1.5rem; }

.ym-summary-title { font-size: 1.25rem; margin: 0 0 0.75rem; }
.ym-see-nearby { display: block; text-align: center; margin: 1.25rem 0 0.75rem; }
.ym-edit { min-height: 44px; width: 100%; padding: 0.6rem 1.4rem; border: 1px solid var(--line); border-radius: 0.6rem; background: #fff; color: var(--accent-fg); font-weight: 600; cursor: pointer; }

/* Moods — the shared preferences engine's named moods, surfaced as a tap-through to "your items nearby" in that mood.
   Mobile-first: a single-column stack of full-width tap targets, widening to a two-up grid on larger screens. */
.ym-moods { max-width: 32rem; margin: 1.5rem auto; }
.ym-moods-title { font-size: 1.1rem; margin: 0 0 0.25rem; }
.ym-moods-hint { margin: 0 0 0.75rem; color: var(--muted, #64748b); font-size: 0.9rem; }
.ym-moods-list { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: 1fr; gap: 0.6rem; }
.ym-mood { display: flex; flex-direction: column; gap: 0.15rem; min-height: 44px; justify-content: center; padding: 0.7rem 0.9rem; border: 1px solid var(--line); border-radius: 0.7rem; background: #fff; text-decoration: none; color: var(--ink); }
.ym-mood:hover, .ym-mood:focus { border-color: var(--accent); }
.ym-mood-name { font-weight: 600; }
.ym-mood-search { color: var(--muted, #64748b); font-size: 0.9rem; }
@media (min-width: 32rem) { .ym-moods-list { grid-template-columns: 1fr 1fr; } }

/* The signed-out destination (PATRfb.2026072308.1): one collapsible "My Menu Preferences" drawer sitting above
   the guest's items nearby. Mobile-first and viewport-independent — the head is a full-width 44px tap target and
   the body simply flows, so 375 / 768 / 1280 differ only in the shared 32rem centring the rest of the front door
   already uses. Collapsed by default: the dish cards are the primary content. */
.ym-prefs-drawer { max-width: 32rem; margin: 1.5rem auto; border: 1px solid var(--line); border-radius: 0.7rem; background: #fff; overflow: hidden; }
.ym-prefs-drawer-head { margin: 0; font-size: 1.1rem; }
.ym-prefs-drawer-toggle { display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; width: 100%; min-height: 44px; padding: 0.7rem 0.9rem; border: none; background: none; color: var(--ink); font: inherit; font-weight: 600; text-align: left; cursor: pointer; }
.ym-prefs-drawer-toggle:hover, .ym-prefs-drawer-toggle:focus { color: var(--accent-fg); }
.ym-prefs-drawer-title { min-width: 0; }
.ym-prefs-drawer-chevron { flex: none; color: var(--muted, #64748b); font-size: 1.2rem; line-height: 1; }
.ym-prefs-drawer.is-open { border-color: var(--accent); }
.ym-prefs-drawer-body { padding: 0 0.9rem 0.9rem; border-top: 1px solid var(--line); }
.ym-signin-line { max-width: 32rem; margin: -0.75rem auto 1.5rem; color: var(--muted, #64748b); font-size: 0.9rem; text-align: center; }

/* The items-nearby block on that destination — the SAME result cards /nearby renders (one shared component), so
   only its heading and its footer link are styled here. */
.home-nearby { max-width: 32rem; margin: 1.5rem auto; }
.home-nearby-title { font-size: 1.1rem; margin: 0 0 0.6rem; }
.home-nearby-empty { color: var(--muted, #64748b); }
.home-nearby-all { display: block; min-height: 44px; padding: 0.7rem 0.9rem; text-align: center; color: var(--accent-fg); font-weight: 600; }

/* Quick-tap rows (M2.2): small thumb-reachable chip rails on the front door — recent searches (anonymous)
   and popular-nearby. Mobile-first: a wrapping row of 44px-tall pill taps, one tap → that term's results. */
.home-quicktap { max-width: 32rem; margin: 1.5rem auto; }
.home-quicktap-title { font-size: 1.1rem; margin: 0 0 0.6rem; display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; }
.home-quicktap-clear { min-height: 44px; padding: 0.2rem 0.75rem; border: none; background: none; color: var(--muted, #667085); font-size: 0.85rem; font-weight: 400; cursor: pointer; text-decoration: underline; }
.home-quicktap-clear:hover, .home-quicktap-clear:focus { color: var(--accent-fg); }
.home-quicktap-list { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 0.5rem; }
.home-quicktap-chip { display: inline-flex; align-items: center; min-height: 44px; padding: 0.3rem 0.9rem; border: 1px solid var(--line); border-radius: 999px; background: #eef2f7; color: var(--ink); font-size: 0.95rem; text-decoration: none; }
.home-quicktap-chip:hover, .home-quicktap-chip:focus { border-color: var(--accent); }
.home-quicktap.is-popular .home-quicktap-chip { background: #fff; }

/* FB-137 landing pass: the one always-visible search bar (type + go = results), and the plain-English
   always-on preferences entry. Mobile-first: 44px targets, the same 32rem centered column as the rest. */
.home-search { max-width: 32rem; margin: 1rem auto 1.5rem; }
.home-search-label { display: block; font-weight: 600; margin: 0 0 0.4rem; }
.home-search-row { display: flex; gap: 0.5rem; }
.home-search-input { flex: 1; min-width: 0; min-height: 44px; padding: 0.4rem 0.8rem; border: 1px solid var(--line); border-radius: 0.6rem; font-size: 1rem; }
.home-search-input:focus { outline: 2px solid var(--accent); outline-offset: 1px; }
.home-search-go { min-height: 44px; padding: 0.4rem 1.2rem; border: 0; border-radius: 0.6rem; background: var(--accent-fg); color: #fff; font-weight: 600; cursor: pointer; }
.ym-prefs-label { font-size: 0.95rem; font-weight: 600; color: var(--muted); margin: 0.8rem 0 0.2rem; }
.ym-prefs-note { color: var(--muted); font-size: 0.9rem; margin: 0.8rem 0 0; }
a.ym-edit { display: block; box-sizing: border-box; text-align: center; text-decoration: none; }

/* Sign-in/out affordances (BFF): plain link + plain form post — full-page navigations out of the SPA. */
.ym-signin { color: var(--accent-fg); font-weight: 600; text-decoration: underline; padding: 0.4rem 0.15rem; }
.ym-moods-head { display: flex; align-items: baseline; justify-content: space-between; gap: 0.75rem; margin-bottom: 0.75rem; }
.ym-moods-head .ym-moods-title { margin: 0; }
.ym-signout { margin: 0; }
.ym-signout-btn { min-height: 44px; padding: 0.4rem 0.9rem; border: 1px solid var(--line); border-radius: 0.6rem; background: #fff; color: var(--muted); font-size: 0.85rem; cursor: pointer; }

/* End-of-journey "save your preferences" upsell — a dismissible, non-blocking card (never a modal wall). Mobile-first:
   full-width within the same 32rem column as the menu summary, a light accent panel that reads as a nudge, not a gate. */
.ym-save-upsell { position: relative; max-width: 32rem; margin: 1.5rem auto; padding: 1rem 1.1rem; border: 1px solid #bfdbfe; border-radius: 0.7rem; background: #eff6ff; }
.ym-save-upsell-dismiss { position: absolute; top: 0.35rem; right: 0.35rem; min-width: 44px; min-height: 44px; border: 0; background: none; color: var(--muted, #64748b); font-size: 1.4rem; line-height: 1; cursor: pointer; }
.ym-save-upsell-title { margin: 0 0 0.35rem; font-size: 1.05rem; font-weight: 700; color: var(--ink); }
.ym-save-upsell-body { margin: 0 0 0.85rem; color: var(--muted, #64748b); font-size: 0.9rem; }
.ym-save-upsell-cta { display: block; text-align: center; min-height: 44px; padding: 0.6rem 1.4rem; border-radius: 0.6rem; background: var(--accent-fg); color: #fff; font-weight: 700; text-decoration: none; }
.ym-save-upsell-cta:hover, .ym-save-upsell-cta:focus { filter: brightness(0.95); }

/* The signed-in "save this craving as a mood" nudge — same mobile-first card language (≤32rem, 44px targets) as
   the anonymous save-preferences upsell, kept a distinct class so the two affordances never collide. */
.ym-save-mood { position: relative; max-width: 32rem; margin: 1.5rem auto; padding: 1rem 1.1rem; border: 1px solid #bfdbfe; border-radius: 0.7rem; background: #eff6ff; }
.ym-save-mood-dismiss { position: absolute; top: 0.35rem; right: 0.35rem; min-width: 44px; min-height: 44px; border: 0; background: none; color: var(--muted, #64748b); font-size: 1.4rem; line-height: 1; cursor: pointer; }
.ym-save-mood-title { margin: 0 0 0.35rem; font-size: 1.05rem; font-weight: 700; color: var(--ink); }
.ym-save-mood-body, .ym-save-mood-done { margin: 0 0 0.85rem; color: var(--muted, #64748b); font-size: 0.9rem; }
.ym-save-mood-error { margin: 0 0 0.6rem; color: #b91c1c; font-size: 0.85rem; }
.ym-save-mood-cta { display: block; width: 100%; text-align: center; min-height: 44px; padding: 0.6rem 1.4rem; border: 0; border-radius: 0.6rem; background: var(--accent-fg); color: #fff; font-weight: 700; cursor: pointer; }
.ym-save-mood-cta[disabled] { opacity: 0.7; cursor: default; }

/* "Safe for you" tally — shown once the guest selects allergies; honest, neutral (never a reassuring green) */
.verdict-summary { margin: 0 0 1rem; padding: 0.6rem 0.9rem; border-radius: 0.5rem; background: #f8fafc; border: 1px solid var(--line); }
.verdict-summary strong { display: block; }
.verdict-summary-extras { color: var(--muted); font-size: 0.85rem; }

/* "Matching your search for:" — active search/filter terms as chips above the dishes.
   Inclusions plain (blue), exclusions prefixed "NO " (red); overflow collapses behind a clickable +N. */
.search-summary { margin: 0 0 1.1rem; }
.search-summary-lead { display: block; font-size: 0.9rem; font-weight: 600; color: var(--ink); margin-bottom: 0.4rem; }
.search-summary-chips { display: flex; flex-wrap: wrap; align-items: center; gap: 0.4rem; }
.search-chip {
    display: inline-flex; align-items: center; white-space: nowrap;
    padding: 0.2rem 0.65rem; border-radius: 999px; font-size: 0.8rem; font-weight: 600;
    background: #eff6ff; color: var(--accent-fg); border: 1px solid #bfdbfe;
}
.search-chip.is-exclusion { background: #fef2f2; color: var(--unsafe); border-color: #fecaca; }
.search-chip-more { cursor: pointer; background: var(--card); color: var(--ink); border: 1px solid var(--line); }
.search-summary-edit {
    background: none; border: 0; cursor: pointer; padding: 0.2rem 0.3rem;
    color: var(--accent-fg); font-size: 0.8rem; font-weight: 600; text-decoration: underline;
}

/* Tappable Crave/Avoid suggestion chips sourced from the menu's knowledge graph. Mobile-first: they wrap freely and
   each chip is a full 44px tap target. Crave = brand blue, Avoid = red; a selected chip fills in so its state reads
   at a glance. Reuses the search-chip pill vocabulary so the two surfaces feel like one system. */
.suggestion-chips { margin: 0 0 0.6rem; }
.suggestion-chips-label { display: block; font-size: 0.85rem; font-weight: 600; color: var(--ink); margin-bottom: 0.4rem; }
.suggestion-chip-list { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 0.4rem; }
.suggestion-chip {
    display: inline-flex; align-items: center; min-height: 44px; cursor: pointer; white-space: nowrap;
    padding: 0.35rem 0.8rem; border-radius: 999px; font-size: 0.85rem; font-weight: 600;
    background: #eff6ff; color: var(--accent-fg); border: 1px solid #bfdbfe;
}
.suggestion-chips.is-crave .suggestion-chip.is-selected { background: var(--accent-fg); color: #fff; border-color: var(--accent-fg); }
.suggestion-chips.is-avoid .suggestion-chip { background: #fef2f2; color: var(--unsafe); border-color: #fecaca; }
.suggestion-chips.is-avoid .suggestion-chip.is-selected { background: var(--unsafe); color: #fff; border-color: var(--unsafe); }
.suggestion-chip::before { content: "＋"; margin-right: 0.3rem; font-weight: 700; }
.suggestion-chip.is-selected::before { content: "✓"; }

/* "More menus near here" — secondary discovery, streamed in after the menu paints */
.nearby-menus { margin-top: 2rem; }
.nearby-heading { font-size: 1.05rem; margin: 0 0 0.5rem; }
.nearby-list { list-style: none; padding: 0; margin: 0; }
.nearby-list li a {
    display: flex; justify-content: space-between; gap: 0.75rem; align-items: baseline;
    padding: 0.7rem 0.9rem; margin: 0.4rem 0; border: 1px solid var(--line);
    border-radius: 0.6rem; text-decoration: none; color: inherit;
}
.nearby-list li a:hover { border-color: var(--accent); }
.nearby-name { font-weight: 600; }
.nearby-rest { color: var(--muted); font-size: 0.85rem; flex: 1; }
.nearby-dist { white-space: nowrap; color: var(--accent-fg); font-variant-numeric: tabular-nums; }

#blazor-error-ui {
    display: none;
    position: fixed;
    bottom: 0; left: 0; right: 0;
    background: #fee2e2;
    padding: 0.75rem 1.25rem;
}

/* Order list (cart) */
.add-to-list {
    margin-top: 0.5rem;
    border: 1px solid var(--accent);
    background: #eff6ff;
    color: var(--accent-fg);
    font-weight: 600;
    font-size: 0.8rem;
    padding: 0.3rem 0.7rem;
    border-radius: 999px;
    cursor: pointer;
}
.add-to-list:hover { background: var(--accent-fg); color: #fff; }

.cart-fab {
    position: fixed;
    right: 1rem;
    bottom: 1rem;
    z-index: 20;
    background: var(--safe);
    color: #fff;
    border: none;
    font-weight: 700;
    min-height: 44px; /* the shared action-button height every header action + FAB matches */
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0.45rem 1.1rem;
    border-radius: 999px;
    box-shadow: 0 4px 12px rgba(0,0,0,0.2);
    cursor: pointer;
}

/* The order list is a full-width drawer over a dimming overlay (Kaaptive T1.1) — not the old bottom-right popup.
   It sits below any top nav (--patron-topbar-h, 0 today) and the head with the close button is pinned so it stays
   visible while the body scrolls. This is the pattern for every contextual popup in the app. */
.cart-drawer-scrim { position: fixed; inset: 0; background: rgba(0, 0, 0, 0.5); z-index: 45; }
.cart-drawer {
    position: fixed; left: 0; right: 0; bottom: 0; top: var(--patron-topbar-h, 0px); z-index: 46;
    width: 100%; background: var(--card);
    display: flex; flex-direction: column;
    box-shadow: 0 -4px 24px rgba(0, 0, 0, 0.2);
}
.cart-drawer-head {
    flex: none; display: flex; justify-content: space-between; align-items: center;
    padding: 0.85rem 1rem; border-bottom: 1px solid var(--line); background: var(--card);
}
.cart-drawer-head strong { font-size: 1.05rem; }
.cart-drawer-body { flex: 1; overflow-y: auto; padding: 0.85rem 1rem 4rem; max-width: 720px; width: 100%; margin: 0 auto; }
.cart-close { min-height: 44px; border: 1px solid var(--accent); background: none; color: var(--accent-fg); border-radius: 999px; padding: 0.3rem 0.95rem; font-weight: 600; cursor: pointer; }

/* Per-line note label + the per-line "Known Allergens" box (the as-of-add captured context carried to the
   kitchen). Alert-yellow, mirroring the operator order queue's warning callout for the same line. */
.cart-note-label { display: block; margin-top: 0.5rem; font-size: 0.82rem; font-weight: 600; color: var(--muted); }
.cart-note-label input { display: block; width: 100%; margin-top: 0.25rem; font-weight: 400; }
.cart-known-allergens {
    margin: 0.4rem 0 0; padding: 0.4rem 0.6rem; border-radius: 0.4rem; font-size: 0.8rem; line-height: 1.35;
    background: #fdf6e3; border: 1px solid #e6c200; border-left: 4px solid #e6c200; color: #6b5300;
}
.cart-known-allergens strong { color: #6b5300; }
.cart-empty, .cart-note-hint { color: var(--muted); font-size: 0.85rem; }
.cart-lines { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.6rem; }
.cart-line { border-bottom: 1px solid var(--line); padding-bottom: 0.5rem; }
.cart-line-head { display: flex; align-items: center; gap: 0.5rem; justify-content: space-between; }
.cart-line-name { font-weight: 600; flex: 1; }
.cart-qty { display: inline-flex; align-items: center; gap: 0.4rem; }
.cart-qty button { width: 1.6rem; height: 1.6rem; border: 1px solid var(--line); background: var(--bg); border-radius: 0.3rem; cursor: pointer; }
.cart-remove { border: none; background: none; color: var(--unsafe); font-size: 0.8rem; cursor: pointer; }
.cart-note { width: 100%; margin-top: 0.4rem; padding: 0.35rem 0.5rem; border: 1px solid var(--line); border-radius: 0.4rem; font-size: 0.85rem; }

/* Modifications + substitutions on a line. */
.cart-mods { list-style: none; margin: 0.4rem 0 0; padding: 0; display: flex; flex-direction: column; gap: 0.3rem; }
.cart-mod { display: flex; align-items: center; gap: 0.4rem; font-size: 0.82rem; }
.cart-mod-kind { font-weight: 600; color: var(--accent-fg); min-width: 5rem; }
.cart-mod-text { flex: 1; color: var(--muted); }
.cart-mod-remove { border: none; background: none; color: var(--unsafe); cursor: pointer; font-size: 1rem; line-height: 1; }
.cart-mod-add { display: flex; gap: 0.35rem; margin-top: 0.4rem; }
.cart-mod-add select { border: 1px solid var(--line); border-radius: 0.4rem; padding: 0.3rem; font-size: 0.82rem; background: var(--bg); }
.cart-mod-input { flex: 1; border: 1px solid var(--line); border-radius: 0.4rem; padding: 0.3rem 0.5rem; font-size: 0.82rem; }
.cart-mod-add-btn { border: 1px solid var(--line); background: var(--bg); border-radius: 0.4rem; padding: 0.3rem 0.6rem; cursor: pointer; font-size: 0.82rem; }

/* Fulfillment choice + send + confirmation. */
.cart-fulfillment { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; margin: 0.8rem 0 0.5rem; font-size: 0.9rem; }
.cart-fulfillment select { border: 1px solid var(--line); border-radius: 0.4rem; padding: 0.35rem 0.5rem; background: var(--bg); }
.cart-send { width: 100%; border: none; background: var(--accent-fg); color: #fff; border-radius: 0.5rem; padding: 0.6rem; font-weight: 600; cursor: pointer; }
.cart-send:disabled { opacity: 0.6; cursor: default; }
.cart-error { color: var(--unsafe); font-size: 0.85rem; margin: 0.4rem 0; }
/* Mandatory guest contact block (name + email + phone). Mobile-first: full-width inputs with 44px touch targets and
   a per-field error the guest sees inline after a blocked submit. */
.cart-contact { display: flex; flex-direction: column; gap: 0.15rem; margin: 0.6rem 0 0.2rem; }
.cart-contact input { width: 100%; box-sizing: border-box; min-height: 44px; margin-top: 0.25rem; padding: 0.5rem 0.7rem;
    border: 1px solid var(--line); border-radius: 0.4rem; font-size: 1rem; font-weight: 400; }
.cart-contact input:focus { outline: 2px solid var(--accent); outline-offset: 1px; border-color: var(--accent); }
.cart-field-error { color: var(--unsafe); font-size: 0.8rem; margin: 0.15rem 0 0.35rem; }
/* Paired with the send button when an allergen filter is active — the handoff reminder (never a blocking gate). */
.cart-allergy-reminder { margin: 0.4rem 0; padding: 0.45rem 0.6rem; background: #fff7ed; border: 1px solid #fed7aa; border-radius: 0.4rem; font-size: 0.82rem; font-weight: 600; color: #7c2d12; }
.cart-confirmed { display: flex; flex-direction: column; gap: 0.5rem; font-size: 0.9rem; }
.cart-ref { font-weight: 700; font-family: ui-monospace, monospace; }
.cart-price-note { color: var(--unsafe); font-size: 0.85rem; }
/* Employee handoff ("or show this code…") + the in-panel order QR — mobile-first, centered in the drawer. */
.cart-handoff { display: flex; flex-direction: column; gap: 0.4rem; margin-top: 0.6rem; text-align: center; }
.cart-handoff-title { margin: 0; font-size: 0.9rem; font-weight: 600; color: var(--muted); }
.cart-handoff-reveal { border: 1px solid var(--accent); background: var(--bg); color: var(--accent-fg); border-radius: 0.5rem; padding: 0.55rem; font-weight: 600; cursor: pointer; }
.cart-handoff-reveal:disabled { opacity: 0.6; cursor: default; }
/* GO.4 dine-in reservation linkage — mobile-first: a single full-width column, 44px tap targets, no h-overflow. */
.cart-dinein { display: flex; flex-direction: column; gap: 0.5rem; margin: 0.6rem 0; padding: 0.7rem; border: 1px solid var(--line); border-radius: 0.6rem; background: var(--bg); }
.cart-dinein-title { margin: 0; font-size: 0.9rem; font-weight: 600; color: var(--muted); }
.cart-dinein-options { display: flex; flex-direction: column; gap: 0.5rem; }
.cart-dinein-opt { display: flex; align-items: flex-start; gap: 0.5rem; min-height: 44px; font-size: 0.88rem; line-height: 1.25; cursor: pointer; }
.cart-dinein-opt input { margin-top: 0.15rem; width: 1.1rem; height: 1.1rem; flex: 0 0 auto; }
.cart-dinein-attach, .cart-dinein-create { display: flex; flex-direction: column; gap: 0.5rem; }
.cart-dinein-match { display: flex; flex-wrap: wrap; gap: 0.25rem 0.6rem; padding: 0.55rem; border: 1px solid var(--line); border-radius: 0.5rem; background: #fff; font-size: 0.86rem; }
.cart-dinein-match-ref { font-weight: 600; color: var(--accent-fg); }
.cart-dinein-find { min-height: 44px; border: 1px solid var(--accent); background: var(--bg); color: var(--accent-fg); border-radius: 0.5rem; padding: 0.55rem; font-weight: 600; cursor: pointer; }
.cart-dinein-find:disabled, .cart-dinein-confirm:disabled, .cart-dinein-book:disabled { opacity: 0.6; cursor: default; }
.cart-dinein-hint, .cart-dinein-nomatch { margin: 0; font-size: 0.82rem; color: var(--muted); }
.cart-qr { display: flex; flex-direction: column; align-items: center; gap: 0.4rem; margin: 0.4rem 0; padding: 0.75rem; background: #fff; border: 1px solid var(--line); border-radius: 0.6rem; text-align: center; }
.cart-qr-title { margin: 0; font-size: 0.95rem; }
.cart-qr-img { width: 180px; max-width: 100%; height: auto; }
.cart-qr-hint { margin: 0; color: var(--muted); font-size: 0.82rem; }

/* Order status page + track link. */
.cart-track { display: inline-block; text-align: center; border: 1px solid var(--accent); color: var(--accent-fg); border-radius: 0.5rem; padding: 0.5rem; font-weight: 600; text-decoration: none; }
.order-status { max-width: 560px; margin: 0 auto; padding: 1rem 1rem 4rem; }
.order-status-back { color: var(--accent-fg); text-decoration: none; font-size: 0.9rem; }
.order-status-head { display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; margin: 1rem 0 0.25rem; }
.order-status-ref { font-family: ui-monospace, monospace; font-weight: 700; font-size: 1.1rem; }
.order-status-badge { font-size: 0.8rem; font-weight: 700; padding: 0.2rem 0.6rem; border-radius: 999px; white-space: nowrap; }
.order-status-badge.is-requested { background: #eff6ff; color: #1d4ed8; }
.order-status-badge.is-accepted { background: #dcfce7; color: var(--safe); }
/* Prep track (F-169): downstream of accepted, so it warms toward "ready" rather than repeating the green. */
.order-status-badge.is-in-kitchen { background: #ffedd5; color: #c2410c; }
.order-status-badge.is-ready { background: #dcfce7; color: var(--safe); }
.order-status-badge.is-rejected { background: #fee2e2; color: var(--unsafe); }
.order-status-badge.is-needs-edit { background: #fef3c7; color: var(--removable); }
.order-status-line { color: var(--muted); margin: 0.25rem 0 1rem; }
/* Auto-fit so the meta (Fulfillment / Total / Placed date-time) reflows to 1–2 columns on a narrow phone
   instead of squeezing a full timestamp into a ~110px third column. */
.order-status-meta { display: grid; grid-template-columns: repeat(auto-fit, minmax(8.5rem, 1fr)); gap: 0.75rem; margin: 0 0 1.25rem; }
.order-status-meta dt { font-size: 0.75rem; color: var(--muted); text-transform: uppercase; letter-spacing: 0.03em; }
.order-status-meta dd { margin: 0.15rem 0 0; font-weight: 600; }
.order-status-history-title { font-size: 1rem; margin: 0 0 0.5rem; }
.order-status-timeline { list-style: none; margin: 0 0 1.25rem; padding: 0; display: flex; flex-direction: column; gap: 0.4rem; }
.order-status-timeline li { display: flex; justify-content: space-between; align-items: center; gap: 0.5rem; padding: 0.5rem 0.75rem; border-left: 3px solid var(--line); background: var(--card); border-radius: 0.4rem; }
.order-status-timeline li.is-accepted { border-left-color: var(--safe); }
.order-status-timeline li.is-rejected { border-left-color: var(--unsafe); }
.order-status-timeline li.is-needs-edit { border-left-color: var(--removable); }
.order-status-step-time { color: var(--muted); font-size: 0.8rem; }
.order-status-refresh { border: 1px solid var(--line); background: var(--card); border-radius: 0.5rem; padding: 0.5rem 1rem; cursor: pointer; }
.order-status-missing h1 { font-size: 1.4rem; }

/* Pay with a That Menu App gift card (apply stored value to this check).
   The two apply buttons below carried a second, distinct contrast defect from the one F-136 named:
   they inherited --ink onto the accent fill, which measured 3.41:1 — and unlike the white-label
   buttons, moving the fill to --accent-fg alone would have driven that DOWN to 2.50:1. They take the
   white label the rest of the sheet's primary actions use, which is 5.87:1 on the ramp token. */
.order-status-giftcard { border: 1px solid var(--line); background: var(--card); border-radius: 0.6rem; padding: 0.9rem 1rem; margin: 0 0 1.25rem; }
.order-status-giftcard-title { font-size: 1rem; margin: 0 0 0.25rem; }
.order-status-giftcard-hint { color: var(--muted); font-size: 0.85rem; margin: 0 0 0.6rem; }
.order-status-giftcard-row { display: flex; gap: 0.5rem; flex-wrap: wrap; }
.order-status-giftcard-input { flex: 1 1 10rem; min-width: 0; border: 1px solid var(--line); border-radius: 0.5rem; padding: 0.5rem 0.7rem; font: inherit; text-transform: uppercase; }
.order-status-giftcard-apply { border: 1px solid var(--line); background: var(--accent-fg); color: #fff; border-radius: 0.5rem; padding: 0.5rem 1.1rem; cursor: pointer; }
.order-status-giftcard-apply:disabled { opacity: 0.55; cursor: default; }
.order-status-giftcard-result { font-size: 0.88rem; margin: 0.6rem 0 0; }
.order-status-giftcard-result.is-ok { color: var(--safe); }
.order-status-giftcard-result.is-error { color: var(--unsafe); }

/* Loyalty apply: the guest re-enters the email captured on the order (SEC2.4) before points are spent. Mobile-first:
   the field and action stack full-width on a phone (flex-wrap) and sit inline once there's room. */
.order-status-loyalty-row { display: flex; gap: 0.5rem; flex-wrap: wrap; margin: 0.5rem 0 0; }
.order-status-loyalty-email { flex: 1 1 12rem; min-width: 0; border: 1px solid var(--line); border-radius: 0.5rem; padding: 0.5rem 0.7rem; font: inherit; }
.order-status-loyalty-apply, .order-status-loyalty-check { border: 1px solid var(--line); background: var(--accent-fg); color: #fff; border-radius: 0.5rem; padding: 0.5rem 1.1rem; cursor: pointer; }
.order-status-loyalty-apply:disabled, .order-status-loyalty-check:disabled { opacity: 0.55; cursor: default; }

/* Tip, scheduled time, totals, order note. */
.cart-when { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; margin: 0 0 0.5rem; font-size: 0.9rem; }
.cart-when select, .cart-when-time { border: 1px solid var(--line); border-radius: 0.4rem; padding: 0.35rem 0.5rem; background: var(--bg); }
/* The tip area is opt-in: "Add Tip" reveals the presets + a custom dollar entry. */
.cart-add-tip { min-height: 44px; margin: 0.5rem 0; padding: 0.5rem 1rem; border: 1px dashed var(--line); border-radius: 0.5rem; background: var(--card); color: var(--accent-fg); font-weight: 600; cursor: pointer; }
.cart-tip { margin: 0.5rem 0; font-size: 0.9rem; }
.cart-tip-options { display: flex; gap: 0.4rem; margin-top: 0.35rem; flex-wrap: wrap; }
.cart-tip-btn { min-height: 44px; border: 1px solid var(--line); background: var(--card); border-radius: 999px; padding: 0.3rem 0.9rem; cursor: pointer; font-size: 0.85rem; }
.cart-tip-btn.is-active { border-color: var(--accent-fg); background: var(--accent-fg); color: #fff; }
.cart-tip-custom-row { display: flex; align-items: center; gap: 0.35rem; margin-top: 0.4rem; }
.cart-tip-custom-input { flex: 1; min-height: 44px; border: 1px solid var(--line); border-radius: 0.4rem; padding: 0.4rem 0.6rem; font-size: 0.9rem; }
.cart-totals { margin: 0.5rem 0; font-size: 0.9rem; border-top: 1px solid var(--line); padding-top: 0.5rem; }
.cart-totals .d-flex { display: flex; justify-content: space-between; }
.cart-totals-total { margin-top: 0.25rem; }
.cart-order-note { width: 100%; margin: 0.4rem 0; padding: 0.4rem 0.6rem; border: 1px solid var(--line); border-radius: 0.4rem; font-size: 0.85rem; }

/* Item customize modal (pick priced modifier/substitution options). */
.customize-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.5); display: flex; align-items: flex-end; justify-content: center; z-index: 50; }
.customize-modal { background: var(--card); width: 100%; max-width: 560px; max-height: 85vh; overflow-y: auto; border-radius: 0.75rem 0.75rem 0 0; padding: 1rem 1.25rem 1.5rem; }
.customize-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.75rem; }
.customize-group { border: 1px solid var(--line); border-radius: 0.5rem; padding: 0.5rem 0.75rem; margin: 0 0 0.75rem; }
.customize-group legend { font-weight: 600; padding: 0 0.35rem; }
.customize-option { display: flex; align-items: center; gap: 0.5rem; padding: 0.3rem 0; }
.customize-option > span { flex: 1; }
.customize-price { color: var(--muted); font-variant-numeric: tabular-nums; }
@media (min-width: 600px) { .customize-overlay { align-items: center; } .customize-modal { border-radius: 0.75rem; } }

/* Item detail dialog (name/photo click-through): full description + suggested pairings, over the list so closing
   returns the guest to their scroll position. Mobile-first: a bottom sheet on phones, a centred card from 600px up. */
.menu-detail-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.5); display: flex; align-items: flex-end; justify-content: center; z-index: 50; }
.menu-detail-modal { background: var(--card); width: 100%; max-width: 560px; max-height: 85vh; overflow-y: auto; border-radius: 0.75rem 0.75rem 0 0; padding: 1rem 1.25rem 1.5rem; }
.menu-detail-head { display: flex; justify-content: space-between; align-items: center; gap: 0.75rem; margin-bottom: 0.5rem; }
.menu-detail-name { font-size: 1.15rem; overflow-wrap: anywhere; }
.menu-detail-close { min-height: 44px; border: 1px solid var(--accent); background: none; color: var(--accent-fg); border-radius: 999px; padding: 0.3rem 0.95rem; font-weight: 600; cursor: pointer; flex: none; }
.menu-detail-price { margin: 0.35rem 0 0; font-variant-numeric: tabular-nums; font-weight: 600; }
.menu-detail-desc { margin: 0.5rem 0 0; color: var(--ink); }
.menu-detail-pairs { margin-top: 1rem; border-top: 1px solid var(--line); padding-top: 0.75rem; }
.menu-detail-pairs-head { margin: 0 0 0.25rem; font-size: 0.95rem; }
@media (min-width: 600px) { .menu-detail-overlay { align-items: center; } .menu-detail-modal { border-radius: 0.75rem; } }

/* "Like or dislike this dish" trigger, at the bottom of the item detail. */
.menu-detail-dislike {
    min-height: 44px; margin-top: 1rem; width: 100%; border: 1px solid var(--line); background: var(--card);
    color: var(--ink); border-radius: 0.5rem; font-weight: 600; font-size: 0.9rem; cursor: pointer;
}
.menu-detail-dislike:hover { background: #f3f4f6; }

/* UXD.3: the dish actions row on the detail — favourite (shared .fav-toggle vocabulary), share, and the add
   action (shared .add-to-list vocabulary, pushed to the right). 44px targets throughout. */
.menu-detail-actions { display: flex; align-items: center; flex-wrap: wrap; gap: 0.5rem; margin-top: 0.75rem; }
.menu-detail-share {
    min-height: 44px; display: inline-flex; align-items: center; gap: 0.35rem; border: 1px solid var(--line);
    background: var(--card); color: var(--ink); border-radius: 999px; padding: 0.3rem 0.95rem;
    font-weight: 600; font-size: 0.85rem; cursor: pointer;
}
.menu-detail-share-copied { font-size: 0.8rem; color: var(--muted); }
.menu-detail-add { flex: 1; min-width: 8rem; margin-left: auto; }

/* UXD.3: tappable "pairs well with" — a visible dish pairing is a pill button opening that dish's detail; a
   notes-only pairing stays plain muted text on the same row rhythm. */
.menu-detail-pair-list { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 0.5rem; }
.menu-detail-pair { display: inline-flex; align-items: center; }
.menu-detail-pair-open {
    min-height: 44px; border: 1px solid var(--accent); background: none; color: var(--accent-fg);
    border-radius: 999px; padding: 0.3rem 0.95rem; font-weight: 600; font-size: 0.85rem; cursor: pointer;
}
.menu-detail-pair-open:hover { background: #eff6ff; }
.menu-detail-pair-note { color: var(--muted); font-size: 0.9rem; padding: 0.3rem 0.2rem; }

/* "What do you like or dislike about this dish?" (PD.6 + UXD.3) — a right-aligned slide-in drawer over the item
   detail, same slide-from-the-right vocabulary as the search & filter drawer (one system), mobile-first
   (full-width down to 375px). */
.dislike-drawer-scrim { position: fixed; inset: 0; background: rgba(0, 0, 0, 0.5); z-index: 55; }
.dislike-drawer {
    position: fixed; top: 0; right: 0; height: 100%; width: min(90vw, 360px); z-index: 56;
    background: var(--card); box-shadow: -2px 0 18px rgba(0, 0, 0, 0.18);
    display: flex; flex-direction: column;
    transform: translateX(100%); transition: transform 0.2s ease; visibility: hidden;
}
.dislike-drawer.is-open { transform: translateX(0); visibility: visible; }
.dislike-drawer-head {
    display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; flex: none;
    padding: 0.85rem 1rem; border-bottom: 1px solid var(--line);
}
.dislike-drawer-close {
    min-height: 44px; border: 1px solid var(--accent); background: none; color: var(--accent-fg);
    border-radius: 999px; padding: 0.3rem 0.95rem; font-weight: 600; cursor: pointer; flex: none;
}
.dislike-drawer-body { overflow-y: auto; flex: 1; padding: 0.5rem 1rem 1.5rem; }
.dislike-drawer-empty { color: var(--muted); }

/* UXD.3 + T1.11: one row per attribute, grouped by canon category. Non-allergen rows carry a LIKE and a DISLIKE
   pill; allergen rows carry only the route into Avoid Allergens — 44px touch targets at 375px throughout. */
.pref-group { margin-top: 0.85rem; }
.pref-group-heading {
    margin: 0; font-size: 0.75rem; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase;
    color: var(--muted);
}
.pref-group-note { margin: 0.3rem 0 0; font-size: 0.78rem; line-height: 1.35; color: var(--muted); }
.pref-rows { list-style: none; margin: 0.5rem 0 0; padding: 0; }
.pref-row { display: flex; align-items: center; gap: 0.5rem; padding: 0.15rem 0; }
.pref-row-name { flex: 1; min-width: 0; font-size: 0.9rem; overflow-wrap: anywhere; }
.pref-row-unverified {
    display: inline-block; margin-left: 0.35rem; border: 1px solid var(--line); border-radius: 999px;
    padding: 0 0.4rem; font-size: 0.68rem; font-weight: 600; text-transform: uppercase; color: var(--muted);
    white-space: nowrap;
}
.pref-row-like, .pref-row-dislike, .pref-row-avoid {
    min-height: 44px; flex: none; border: 1px solid var(--line); background: var(--card); color: var(--ink);
    border-radius: 999px; padding: 0.3rem 0.8rem; font-weight: 600; font-size: 0.85rem; cursor: pointer;
}
.pref-row-like.is-on { border-color: var(--accent-fg); background: var(--accent-fg); color: #fff; }
.pref-row-dislike.is-on { border-color: #b91c1c; background: #b91c1c; color: #fff; }
/* The allergen row's only affordance — deliberately the safety colour, never the dislike pill's. */
.pref-row-avoid { border-color: #b91c1c; color: #b91c1c; }
.dislike-drawer-allergy-note { margin: 0.85rem 0 0; font-size: 0.85rem; color: var(--muted); }
.dislike-drawer-allergy-link {
    min-height: 44px; border: none; background: none; color: var(--accent-fg); font-weight: 600;
    text-decoration: underline; cursor: pointer; padding: 0;
}
.dislike-drawer-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 1rem; }
.dislike-drawer-confirm {
    min-height: 44px; flex: 1; border: none; background: var(--accent-fg); color: #fff; border-radius: 999px;
    font-weight: 700; font-size: 0.9rem; cursor: pointer;
}
/* V68.4: when a mood is in play the drawer offers a scope choice — the mood-worded option takes its own full-width
   row (its label is the longest) so at 375px the three actions stack cleanly instead of crowding one line. */
.dislike-drawer-confirm-scoped { flex-basis: 100%; }
.dislike-drawer-confirm:disabled { background: var(--line); color: var(--muted); cursor: not-allowed; }
.dislike-drawer-cancel {
    min-height: 44px; flex: 1; border: 1px solid var(--line); background: var(--card); color: var(--ink);
    border-radius: 999px; font-weight: 600; font-size: 0.9rem; cursor: pointer;
}
@media (prefers-reduced-motion: reduce) { .dislike-drawer { transition: none; } }

/* Confirms what a dislike pick added, once the item detail has closed (mirrors the drawer's own share-copied note). */
.dislike-toast {
    display: flex; align-items: center; gap: 0.5rem; margin: 0 0 1rem; padding: 0.5rem 0.75rem;
    background: #eff6ff; border: 1px solid #bfdbfe; border-radius: 0.4rem; font-size: 0.85rem; color: #1e40af;
}
.dislike-toast-dismiss { min-height: 44px; border: none; background: none; color: inherit; font-weight: 600; cursor: pointer; }

/* Reservation request form + status. */
.reserve { max-width: 560px; margin: 0 auto; padding: 0.5rem 0 2rem; }
.reserve-back { display: inline-block; margin-bottom: 0.75rem; color: var(--accent-fg); text-decoration: none; font-size: 0.9rem; }
.reserve-head { margin-bottom: 1.25rem; }
.reserve-head h1 { margin: 0 0 0.25rem; }
.reserve-venue { margin: 0 0 0.4rem; font-weight: 600; }
.reserve-tagline { color: var(--muted); margin: 0; }
.reserve-form { display: flex; flex-direction: column; gap: 1rem; }
.reserve-field { display: flex; flex-direction: column; gap: 0.35rem; font-weight: 600; }
.reserve-field > span { font-size: 0.9rem; }
.reserve-optional { color: var(--muted); font-weight: 400; }
.reserve-field input, .reserve-field select { width: 100%; padding: 0.6rem 0.7rem; border: 1px solid var(--line);
    border-radius: 0.5rem; font-size: 1rem; font-weight: 400; background: var(--card); color: var(--ink); }
.reserve-field input:focus, .reserve-field select:focus { outline: 2px solid var(--accent); outline-offset: 1px; border-color: var(--accent); }
.reserve-error { color: var(--unsafe); background: #fee2e2; border-radius: 0.5rem; padding: 0.5rem 0.7rem; margin: 0; }
.reserve-submit { display: inline-block; text-align: center; width: 100%; border: none; background: var(--accent-fg);
    color: #fff; border-radius: 0.5rem; padding: 0.7rem; font-weight: 600; font-size: 1rem; cursor: pointer; text-decoration: none; }
.reserve-submit:disabled { opacity: 0.55; cursor: default; }
.reserve-submit-ghost { background: var(--card); color: var(--accent-fg); border: 1px solid var(--line); }
.reserve-hint { color: var(--muted); font-size: 0.85rem; margin: 0.25rem 0 0; }
.reserve-attach { display: flex; align-items: flex-start; gap: 0.6rem; padding: 0.75rem 0.85rem; border: 1px solid var(--accent);
    background: #eff6ff; border-radius: 0.6rem; font-weight: 400; cursor: pointer; }
.reserve-attach input { margin-top: 0.2rem; width: 1.1rem; height: 1.1rem; accent-color: var(--accent); }
.reserve-attach-hint { display: block; color: var(--muted); font-size: 0.85rem; margin-top: 0.15rem; }

.reserve-confirmed { text-align: center; padding: 1rem 0; }
.reserve-confirmed-icon { width: 3rem; height: 3rem; line-height: 3rem; margin: 0 auto 0.75rem; border-radius: 50%;
    background: #dcfce7; color: var(--safe); font-size: 1.5rem; font-weight: 700; }
.reserve-confirmed h1 { margin: 0 0 0.4rem; }
.reserve-summary { display: grid; gap: 0.5rem; margin: 1rem 0 1.25rem; text-align: left; }
.reserve-summary > div { display: flex; justify-content: space-between; gap: 1rem; border-bottom: 1px solid var(--line); padding-bottom: 0.5rem; }
.reserve-summary dt { color: var(--muted); margin: 0; }
.reserve-summary dd { margin: 0; font-weight: 600; }
.reserve-ref { font-family: ui-monospace, monospace; font-weight: 700; }

.reserve-status-head { display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; margin-bottom: 0.5rem; }
.reserve-status-line { color: var(--muted); margin: 0 0 0.5rem; }
.reserve-badge { font-size: 0.8rem; font-weight: 700; padding: 0.2rem 0.6rem; border-radius: 999px; white-space: nowrap; }
.reserve-badge.is-requested { background: #eff6ff; color: #1d4ed8; }
.reserve-badge.is-confirmed { background: #dcfce7; color: var(--safe); }
.reserve-badge.is-seated { background: #e0e7ff; color: #4338ca; }
.reserve-badge.is-completed { background: #f3f4f6; color: var(--muted); }
.reserve-badge.is-cancelled { background: #fee2e2; color: var(--unsafe); }
.reserve-missing { text-align: center; padding: 1.5rem 0; }

/* "Your items nearby" — the item-first results (dishes on your menu, by nearby restaurant). Phone-first single column. */
.nearby { max-width: 640px; margin: 0 auto; }
.nearby-back { display: inline-flex; align-items: center; min-height: 44px; color: var(--accent-fg); text-decoration: none; font-size: 0.9rem; }
.nearby-title { font-size: 1.5rem; margin: 0.25rem 0 0.75rem; }
.nearby-title em { font-style: italic; font-weight: 800; color: var(--accent); }
.nearby-chips { margin: 0 0 1rem; }
.nearby-count { color: var(--muted); margin: 0 0 1rem; font-size: 0.9rem; }
.nearby-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.6rem; }
.nearby-card { height: 5rem; border-radius: 0.6rem; }
.nearby-rest { margin: 0 0 1.25rem; }
.nearby-rest-name { font-size: 1.05rem; margin: 0 0 0.5rem; display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.5rem; }
.nearby-rest-where { color: var(--muted); font-size: 0.85rem; font-weight: 400; }
.nearby-rest-distance { color: var(--accent-fg); font-size: 0.85rem; font-weight: 600; font-variant-numeric: tabular-nums; }
.nearby-rest-directions { display: inline-block; margin: 0 0 0.6rem; min-height: 44px; line-height: 1.6rem; font-size: 0.85rem; font-weight: 600; color: var(--accent-fg); text-decoration: none; }
.nearby-rest-directions::before { content: "\2192\00a0"; }

/* Two-tier honesty banner atop each restaurant's dish group (S4.2 / KV.3): a verified member menu reads
   quietly; a scraped, unverified listing is a RED alert banner pinned above its dishes — a guest with an
   allergy must see the "not verified" warning before any dish under it. */
.nearby-rest-tier { display: block; margin: 0 0 0.6rem; font-size: 0.85rem; }
.nearby-rest-tier.is-verified { color: var(--safe); font-weight: 600; }
.nearby-rest-tier.is-unverified { padding: 0.5rem 0.75rem; background: #fef2f2; border: 1px solid var(--unsafe); border-left-width: 4px; border-radius: 0.5rem; color: var(--unsafe); font-weight: 700; }
/* Verified-only: an unverified restaurant is a calm location card (no menu shown), never a red allergy alert. */
.nearby-rest-tier.is-offplatform { color: var(--muted); font-weight: 600; }
.nearby-rest-invite { display: inline-block; margin: 0 0 0.6rem; min-height: 44px; line-height: 1.6rem; font-size: 0.85rem; font-weight: 600; color: var(--accent-fg); text-decoration: none; }
.nearby-rest-invite::before { content: "\2b\00a0"; }
.nearby-count-more { display: block; margin-top: 0.35rem; color: var(--muted); }

/* Session-only sort toggle (mobile-first): a full-width segmented control shown once location is shared. */
.nearby-sort { display: flex; gap: 0.4rem; margin: 0 0 1rem; }
.nearby-sort-option { flex: 1; min-height: 44px; padding: 0.5rem 0.75rem; border: 1px solid var(--line); border-radius: 0.6rem; background: #fff; color: var(--muted); font-weight: 600; cursor: pointer; }
.nearby-sort-option.is-active { border-color: var(--accent); color: var(--accent-fg); background: #eff6ff; }
.nearby-dishes { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.5rem; }
.nearby-dish { background: var(--card); border: 1px solid var(--line); border-left: 4px solid var(--accent); border-radius: 0.5rem; padding: 0.7rem 0.9rem; }
.nearby-dish-head { display: flex; justify-content: space-between; align-items: baseline; gap: 0.75rem; }
.nearby-dish-name { font-weight: 600; min-width: 0; overflow-wrap: anywhere; }
.nearby-dish-price { flex: none; font-variant-numeric: tabular-nums; font-weight: 600; }
.nearby-dish-desc { margin: 0.3rem 0 0; color: var(--muted); font-size: 0.9rem; }
.nearby-dish-why { display: inline-block; margin-top: 0.35rem; font-size: 0.78rem; font-weight: 600; color: var(--accent-fg); background: #eff6ff; border: 1px solid #bfdbfe; border-radius: 999px; padding: 0.1rem 0.55rem; }

/* UXA safety surfaces on the nearby dish card: the "must be modified*" pill (shared .verdict-badge visuals),
   its "*must request no <x>" footnote (the same wrapping chip language as the menu card — clean at 375px),
   and the per-restaurant "N dishes hidden for your allergens" honesty line. */
.nearby-dish .verdict-badge { display: inline-block; margin-top: 0.35rem; }
.nearby-dish-mustrequest { margin: 0.3rem 0 0; display: flex; flex-wrap: wrap; align-items: center; gap: 0.3rem; }
.nearby-hidden-safety { margin: 0.5rem 0 0; font-size: 0.85rem; color: var(--muted); }

/* UXD.2 dish-first cards: the dish leads; the restaurant is the card's SECONDARY line, and the demoted
   per-restaurant attribution (tier + locality + directions) reads as one light foot under the group. */
.nearby-dish-at { margin: 0.35rem 0 0; display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.5rem; font-size: 0.85rem; }
.nearby-dish-at-name { color: var(--muted); font-weight: 600; }
.nearby-dish-at-distance { color: var(--accent-fg); font-weight: 600; font-variant-numeric: tabular-nums; }
.nearby-rest-foot { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.5rem 0.9rem; margin: 0.35rem 0 0; }
.nearby-rest-foot .nearby-rest-tier, .nearby-rest-foot .nearby-rest-directions { margin: 0; }
.nearby-rest-foot .nearby-rest-tier { font-weight: 500; }

/* UXD.2 mood-from-search return note: the honest "Hid N items with <term>" figure plus the loop-closing
   affordances (save-as-mood / promote-to-always-on). A dismissible aside, never a wall. */
.nearby-loop { position: relative; margin: 0 0 1rem; padding: 0.85rem 2.4rem 0.85rem 1rem; border: 1px solid var(--line); border-radius: 0.7rem; background: #f8fafc; }
.nearby-loop-dismiss { position: absolute; top: 0.2rem; right: 0.2rem; min-width: 44px; min-height: 44px; border: 0; background: none; color: var(--muted); font-size: 1.3rem; line-height: 1; cursor: pointer; }
.nearby-loop-hid { margin: 0; font-weight: 600; color: var(--ink); }
.nearby-loop-promote { display: inline-block; margin-top: 0.6rem; min-height: 44px; padding: 0.5rem 1.1rem; border: 0; border-radius: 0.6rem; background: var(--accent-fg); color: #fff; font-weight: 700; cursor: pointer; }
.nearby-loop-promoted { margin: 0.5rem 0 0; font-size: 0.9rem; color: var(--safe); font-weight: 600; }
.nearby-loop .ym-save-mood { margin: 0.75rem 0 0; padding: 0; border: 0; background: none; max-width: none; }
.nearby-loop .ym-save-mood-dismiss { display: none; } /* the outer note owns dismissal — one × */

/* UXD.2 "Back to results" chrome on a menu reached from /nearby — the loop's explicit way back. */
.menu-back-results { display: inline-block; margin: 0 0 0.5rem; min-height: 44px; line-height: 1.6rem; font-size: 0.9rem; font-weight: 600; color: var(--accent-fg); text-decoration: none; }

/* The dish head is a full-width toggle (inline detail below); styled as content, not button chrome. */
.nearby-dish-toggle { display: flex; width: 100%; justify-content: space-between; align-items: baseline; gap: 0.75rem; min-height: 44px; padding: 0; border: 0; background: none; font: inherit; color: inherit; text-align: left; cursor: pointer; }
.nearby-dish-detail { margin-top: 0.5rem; padding-top: 0.5rem; border-top: 1px dashed var(--line); }
.nearby-dish-where { margin: 0 0 0.4rem; font-size: 0.85rem; color: var(--muted); }

/* Location anchoring: one calm opt-in affordance; denial degrades to an honest hint. */
.nearby-use-location { display: block; width: 100%; min-height: 44px; margin: 0 0 1rem; padding: 0.6rem 1rem; border: 1px solid var(--line); border-radius: 0.6rem; background: #fff; color: var(--accent-fg); font-weight: 600; cursor: pointer; }
/* The area-first gate (owner ruling 2026-07-31): one calm card — location in a tap, or a typed city/ZIP. */
.nearby-area-prompt { padding: 1.5rem 1rem; border: 1px solid var(--line); border-radius: 0.8rem; background: #fff; }
.area-prompt-title { margin: 0 0 0.35rem; font-size: 1.15rem; }
.area-prompt-hint { margin: 0 0 1rem; font-size: 0.9rem; color: var(--muted); }
.area-prompt-geo-denied { margin: 0 0 1rem; font-size: 0.85rem; color: var(--muted); }
.area-prompt-label { display: block; margin: 0 0 0.35rem; font-size: 0.85rem; color: var(--muted); }
.area-prompt-row { display: flex; gap: 0.5rem; }
.area-prompt-input { flex: 1 1 auto; min-height: 44px; padding: 0.5rem 0.75rem; border: 1px solid var(--line); border-radius: 0.6rem; font-size: 1rem; }
.area-prompt-submit { flex: 0 0 auto; min-height: 44px; }
.area-prompt-error { margin: 0.75rem 0 0; font-size: 0.85rem; color: var(--danger, #b3261e); }
/* Results always carry an anchor now — the quiet line names it, with an inline change affordance. */
.nearby-area-line { margin: 0 0 1rem; font-size: 0.85rem; color: var(--muted); }
/* The off-platform card's source link-out — a quiet external affordance beside the invite. */
.nearby-rest-source { display: inline-block; margin: 0.35rem 0.75rem 0.35rem 0; font-size: 0.85rem; color: var(--accent-fg); text-decoration: underline; }
/* The counted demand affordance: the ask count line + the one-tap ask button. */
.nearby-rest-asks { margin: 0.35rem 0 0.35rem; font-size: 0.85rem; color: var(--muted); }
.nearby-rest-ask { display: inline-block; min-height: 40px; margin: 0.25rem 0.75rem 0.25rem 0; padding: 0.4rem 0.9rem; border: 1px solid var(--line); border-radius: 0.6rem; background: #fff; color: var(--accent-fg); font-weight: 600; cursor: pointer; }
.nearby-rest-ask:disabled { color: var(--muted); cursor: default; }
/* Coming soon: the area has no subscriber restaurants at all — a calm hero, never an error. */
.nearby-coming-soon { margin: 0 0 1.25rem; padding: 1.5rem 1rem; border: 1px solid var(--line); border-radius: 0.8rem; background: #fff; text-align: center; }
.coming-soon-title { margin: 0 0 0.5rem; font-size: 1.25rem; }
.coming-soon-copy { margin: 0 0 0.5rem; font-size: 0.9rem; color: var(--muted); }
.coming-soon-hint { margin: 0; font-size: 0.85rem; color: var(--muted); }
.nearby-area-change { margin-left: 0.5rem; min-height: 32px; padding: 0.15rem 0.6rem; border: 1px solid var(--line); border-radius: 0.5rem; background: #fff; color: var(--accent-fg); font-size: 0.8rem; font-weight: 600; cursor: pointer; }
.nearby-geo-hint { margin: 0 0 1rem; font-size: 0.85rem; color: var(--muted); }
.nearby-empty { text-align: center; padding: 2rem 1rem; color: var(--muted); }
.nearby-empty-hint { font-size: 0.9rem; }
.nearby-empty .home-cta { margin-top: 1rem; }
.nearby-more { display: block; margin: 1.25rem auto 0; border: 0; cursor: pointer; }
.nearby-more[disabled] { opacity: 0.6; cursor: default; }

/* "Clear all search & filters" — a quiet, full-width reset in the drawer (confirm-gated, resets every filter +
   the saved profile but never the legal consents). Muted so it never competes with the primary controls; the
   44px floor keeps it tappable one-handed. */
.filter-clear-all-row { margin: var(--filter-section-gap) 0 0; }
.filter-clear-all {
    width: 100%; min-height: 44px; border: 1px solid var(--line); background: none;
    color: var(--muted); border-radius: 0.5rem; font-weight: 600; font-size: 0.9rem; cursor: pointer;
}
.filter-clear-all:hover { background: #f9fafb; color: var(--ink); }

/* Unobtrusive attribution footer at the bottom of every public menu + the /nearby list. Small, muted, centered;
   the brand word in the brand blue. Emitted in the prerender too (PatronAppShell) so there's no hydrate pop-in. */
.powered-by {
    margin: 2rem 0 0; padding: 1rem 0 0; border-top: 1px solid var(--line);
    text-align: center; font-size: 0.75rem; color: var(--muted);
}
.powered-by-brand { color: var(--accent-fg); font-weight: 600; }

/* The builder's ratified 3-layer zones (UX-P1c): the moods layer's list, starter templates, and create row.
   Zones reuse the ym-box frame; the templates are tappable 44px chips that pre-fill the create input. */
.ym-moodzone-sub { margin: 0 0 0.85rem; color: var(--muted, #64748b); font-size: 0.9rem; }
.ym-moodzone-list { list-style: none; margin: 0 0 0.85rem; padding: 0; display: flex; flex-wrap: wrap; gap: 0.5rem; }
.ym-moodzone-mood { min-height: 44px; display: inline-flex; align-items: center; padding: 0.4rem 0.9rem; border: 1px solid var(--line); border-radius: 999px; background: #fff; font-weight: 600; }
.ym-mood-templates { display: flex; flex-wrap: wrap; gap: 0.5rem; margin: 0 0 0.6rem; }
.ym-mood-template { min-height: 44px; padding: 0.4rem 0.9rem; border: 1px dashed var(--line); border-radius: 999px; background: #fff; color: var(--accent-fg); font-weight: 600; cursor: pointer; }
.ym-mood-template:hover, .ym-mood-template:focus { border-color: var(--accent); }
.ym-mood-createrow { display: flex; gap: 0.5rem; margin: 0 0 0.9rem; }
/* min-width:0 defeats the flex item's auto minimum — without it the placeholder's min-content width pushes the
   Create button past the refine drawer's right edge at 375px (measured: 12.8px of horizontal scroll). */
.ym-mood-name { flex: 1; min-width: 0; min-height: 44px; padding: 0.45rem 0.7rem; border: 1px solid var(--line); border-radius: 0.6rem; font-size: 1rem; }
.ym-mood-create { min-height: 44px; padding: 0.45rem 1rem; border: 0; border-radius: 0.6rem; background: var(--accent-fg); color: #fff; font-weight: 700; cursor: pointer; }
.ym-mood-create[disabled] { opacity: 0.7; cursor: default; }
.ym-mood-created { margin: 0 0 0.6rem; color: #166534; font-size: 0.9rem; }
.ym-mood-error { margin: 0 0 0.6rem; color: #b91c1c; font-size: 0.85rem; }
.ym-zone-moods .ym-signin { display: inline-block; min-height: 44px; padding: 0.6rem 0.15rem 0.9rem; }

/* The refine drawer's top "save this search as a mood" toggle. Same ym-box language as the zones below it, so the
   drawer reads as one stack; the name field only exists once the toggle is on, and 44px targets keep it one-handed. */
.ym-save-search-mood-check { font-weight: 600; }
.ym-save-search-mood-namerow { margin: 0.75rem 0 0; }
.ym-save-search-mood-name { width: 100%; min-height: 44px; padding: 0.45rem 0.7rem; border: 1px solid var(--line); border-radius: 0.6rem; font-size: 1rem; }
.ym-save-search-mood-anon { margin: 0.6rem 0 0.2rem; color: var(--muted, #64748b); font-size: 0.9rem; }
.ym-save-search-mood-signin { display: inline-block; min-height: 44px; padding: 0.6rem 0.15rem; }
.ym-save-search-mood-saved { margin: 0.6rem 0 0; color: #166534; font-size: 0.9rem; }
.ym-save-search-mood-error { margin: 0.6rem 0 0; color: #b91c1c; font-size: 0.85rem; }

/* UXD.4 live mood zone: the switcher reuses the mood-pill look as tappable buttons (active = filled), and the
   in-place editor's save row keeps the 44px one-handed targets. */
.ym-moodzone-switch { display: flex; flex-wrap: wrap; gap: 0.5rem; margin: 0 0 0.85rem; }
button.ym-moodzone-mood { cursor: pointer; }
.ym-moodzone-mood.is-active { border-color: var(--accent-fg); background: var(--accent-fg); color: #fff; }
.ym-mood-editor { margin: 0 0 0.9rem; }
.ym-mood-saverow { display: flex; gap: 0.5rem; margin: 0 0 0.6rem; }
.ym-mood-saveback, .ym-mood-saveas { min-height: 44px; padding: 0.45rem 1rem; border: 0; border-radius: 0.6rem; background: var(--accent-fg); color: #fff; font-weight: 700; cursor: pointer; }
.ym-mood-saveas { background: #fff; color: var(--accent-fg); border: 1px solid var(--accent); }
.ym-mood-saveback[disabled], .ym-mood-saveas[disabled] { opacity: 0.7; cursor: default; }
.ym-mood-saveas-name { flex: 1; min-height: 44px; padding: 0.45rem 0.7rem; border: 1px solid var(--line); border-radius: 0.6rem; font-size: 1rem; }
.ym-mood-saved { margin: 0 0 0.6rem; color: #166534; font-size: 0.9rem; }

/* UXD.4 as-you-type assist: a compact suggestion row directly under the term input — one tap takes a term. */
.ym-typeahead { display: flex; flex-wrap: wrap; gap: 0.5rem; margin: 0.4rem 0 0.6rem; }
.ym-typeahead-option { min-height: 44px; padding: 0 0.9rem; border: 1px solid var(--line); border-radius: 999px; background: #fff; color: var(--accent-fg); font-size: 0.92rem; font-weight: 600; cursor: pointer; }
.ym-typeahead-option:hover, .ym-typeahead-option:focus { border-color: var(--accent); }

/* The first-run walk-through chrome: a quiet progress line and the per-step actions (Continue leads; Skip and
   Skip-all are low-emphasis text buttons — skipping is always allowed, never a wall). */
.ym-wt-progress { margin: 0 0 1rem; color: var(--muted, #64748b); font-size: 0.9rem; font-weight: 600; }
.ym-wt-actions { display: flex; flex-direction: column; gap: 0.6rem; }
.ym-wt-next { min-height: 44px; }
.ym-wt-skip, .ym-wt-skipall { min-height: 44px; border: 0; background: none; color: var(--muted, #64748b); font-size: 0.95rem; font-weight: 600; cursor: pointer; text-decoration: underline; }
.ym-wt-skip:hover, .ym-wt-skip:focus, .ym-wt-skipall:hover, .ym-wt-skipall:focus { color: var(--accent-fg); }

/* UXD.5 dashboard sections: the explicit Saved list and the automatic Visited list, adjacent and distinct.
   Rows reuse the home-recent link visuals; the keep/unkeep affordances sit beside the link at the 44px floor. */
.home-saved, .home-visited { max-width: 32rem; margin: 2rem auto; }
.home-saved h2, .home-visited h2 { font-size: 1.1rem; margin: 0 0 0.6rem; }
.home-saved-row, .home-visited-row { display: flex; align-items: stretch; gap: 0.5rem; }
.home-saved-row .home-recent-link, .home-visited-row .home-recent-link { flex: 1; min-width: 0; }
.home-visited-save, .home-saved-remove { flex: none; min-height: 44px; padding: 0 0.9rem; border: 1px solid var(--line); border-radius: 0.5rem; background: #fff; color: var(--accent-fg); font-weight: 600; cursor: pointer; }
.home-visited-save:hover, .home-saved-remove:hover { border-color: var(--accent); }
.home-visited-done { flex: none; align-self: center; color: var(--safe); font-weight: 700; font-size: 0.85rem; padding: 0 0.4rem; }
.home-list-empty { color: var(--muted); }

/* The Saved view's favourite-dish rollup: dishes grouped under their restaurant, deep-linking into the dish. */
.home-saved-dishgroup { margin: 1rem 0 0; }
.home-saved-dishgroup-title { font-size: 0.95rem; margin: 0 0 0.4rem; color: var(--muted); }
.home-saved-dishes { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.4rem; }
.home-saved-dish { display: flex; align-items: center; min-height: 44px; padding: 0 0.8rem; border: 1px solid var(--line); border-radius: 0.5rem; text-decoration: none; color: inherit; font-weight: 600; }
.home-saved-dish:hover { border-color: var(--accent); }

/* UXD.5 light routes share one phone-first column. */
.patron-listpage, .patron-prefspage { max-width: 32rem; margin: 0 auto; }
.patron-listpage-sub { color: var(--muted); margin: 0.5rem 0 1rem; }
.patron-listpage-cross { display: inline-flex; align-items: center; min-height: 44px; margin-top: 0.75rem; color: var(--accent-fg); text-decoration: none; font-weight: 600; }
.patron-listpage-cross:hover { text-decoration: underline; }
.patron-listpage .home-saved, .patron-listpage .home-visited, .patron-listpage .home-recent { margin: 1rem auto 0; }
.prefs-saved { background: #dcfce7; color: var(--safe); border-radius: 0.5rem; padding: 0.6rem 0.9rem; font-weight: 600; }
/* The avatar picker (USERfb.2026072313.2). A wrapping grid of 44px-tall targets so the whole set fits a 375px phone
   without a horizontal scroller, and each choice reads as a toggle (the chosen one carries the accent). */
.patron-avatar-picker { margin: 0 0 1rem; padding: 0.75rem 0.9rem 0.9rem; border: 1px solid var(--line); border-radius: 0.6rem; background: var(--card); }
.patron-avatar-picker legend { padding: 0 0.3rem; font-weight: 700; }
.patron-avatar-hint { margin: 0 0 0.6rem; color: var(--muted); font-size: 0.9rem; }
.patron-avatar-choices { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.patron-avatar-choice { display: inline-flex; align-items: center; gap: 0.35rem; min-height: 44px; padding: 0 0.6rem; border: 1px solid var(--line); border-radius: 999px; background: transparent; color: inherit; font: inherit; cursor: pointer; }
.patron-avatar-choice:hover { border-color: var(--accent); }
.patron-avatar-choice.is-chosen { border-color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); font-weight: 700; }
.patron-avatar-glyph { font-size: 1.15rem; line-height: 1; }
.patron-avatar-clear { display: inline-flex; align-items: center; min-height: 44px; margin-top: 0.6rem; padding: 0; border: 0; background: none; color: var(--accent-fg); font: inherit; font-weight: 600; cursor: pointer; }
.patron-avatar-clear[disabled] { color: var(--muted); cursor: default; }
.moods-page .ym-zone-moods { margin-top: 0.5rem; }
.moods-see-results { display: inline-flex; margin-top: 0.9rem; }

/* Orders entry: the reference lookup above this device's recents. */
.orders-lookup { display: flex; gap: 0.5rem; margin: 0.75rem 0 1rem; }
.orders-lookup-input { flex: 1; min-width: 0; min-height: 44px; padding: 0 0.75rem; border: 1px solid var(--line); border-radius: 0.5rem; font-size: 1rem; }
.orders-lookup-go { flex: none; min-height: 44px; padding: 0 1rem; border: 0; border-radius: 0.5rem; background: var(--accent-fg); color: #fff; font-weight: 700; cursor: pointer; }

/* The menu page's save/bookmark toggle, beside Share in the header actions. */
.menu-save { display: inline-flex; align-items: center; min-height: 44px; padding: 0 0.9rem; border: 1px solid var(--line); border-radius: 999px; background: #fff; color: var(--ink); font-weight: 600; cursor: pointer; }
.menu-save:hover { border-color: var(--accent); }
.menu-save.is-saved { border-color: var(--safe); color: var(--safe); }
