:root {
  --fg: #1a1a1a;
  --muted: #6b6b6b;
  --accent: #c2410c;
  --bg: #fafaf7;
  --card: #ffffff;
  --line: #e5e5e0;
}

* { box-sizing: border-box; }

body {
  font: 16px/1.4 system-ui, -apple-system, "Segoe UI", sans-serif;
  background: var(--bg);
  color: var(--fg);
  margin: 0;
  padding: 0 1rem 4rem;
  max-width: 720px;
  margin-inline: auto;
}

.brand { padding: 1.5rem 0 1rem; border-bottom: 1px solid var(--line); text-align: center; }
.brand h1 { margin: 0; font-size: 1.6rem; }
.brand .brand-logo {
  display: block;
  margin: 0 auto;
  max-height: 96px;
  max-width: 60vw;
  height: auto;
  width: auto;
}
.brand .brand-tagline {
  margin: .35rem 0 0;
  font-style: italic;
  color: var(--muted);
}
.brand .loc { color: var(--muted); margin: .25rem 0 0; }

/* Body-level background image (tenant default). The brand header gets a
   translucent scrim so the title/logo stay readable over busy photos. */
body.has-menu-bg .brand {
  background: color-mix(in srgb, var(--bg) 78%, transparent);
  backdrop-filter: blur(2px);
  border-radius: 12px;
  padding-inline: 1rem;
}

.category { margin-top: 1.5rem; padding: 1rem 0; }
/* Per-category background lands directly on the section element via an
   injected <style> block (CategoryBgStyle). The article rows below get
   their own scrim so prices and names stay readable. */
.category h2 { font-size: 1.1rem; margin: 0 0 .5rem; color: var(--accent); }
.category ul { list-style: none; padding: 0; margin: 0; }
body.has-menu-bg .category .article,
.category.has-bg .article {
  background: color-mix(in srgb, var(--card) 82%, transparent);
  border-radius: 8px;
  padding-inline: .75rem;
}

.article {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  padding: .75rem 0;
  border-bottom: 1px solid var(--line);
}
.article .info { display: flex; flex-direction: column; }
.article .name { font-weight: 600; }
.article .desc { color: var(--muted); font-size: .9rem; margin-top: .15rem; }
.article .price { font-variant-numeric: tabular-nums; white-space: nowrap; }

/* ---------- Discover: the brandless landing ----------

   Everything below borrows the guest menu's type scale and chip shapes
   (defined further down in this file, on :root, so they resolve here too).
   Two pages that both list places to eat shouldn't be two visual systems. */

.discover-hero { padding: 2rem 0 1.25rem; }
.discover-hero h1 {
  margin: 0;
  font-family: var(--menu-display);
  font-size: clamp(1.75rem, 6.5vw, 2.25rem);
  font-weight: 640;
  line-height: 1.05;
  letter-spacing: -.028em;
}
.discover-hero p {
  margin: .5rem 0 0;
  max-width: 34rem;
  color: var(--muted);
  font-size: var(--t-md);
  line-height: 1.5;
}

/* The order-type tabs. Scrollable rather than wrapped: three chips fit on
   any phone, and a row that reflows to two lines moves the search box down
   the page on exactly the narrow screens that can least afford it. */
.discover-tabs {
  display: flex;
  gap: .35rem;
  margin: 1.25rem 0 .75rem;
  overflow-x: auto;
  scrollbar-width: none;
}
.discover-tabs::-webkit-scrollbar { display: none; }
.discover-tab {
  flex: 0 0 auto;
  padding: .45rem .9rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--card);
  color: var(--muted);
  font-size: var(--t-md);
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
}
.discover-tab:hover { border-color: var(--menu-edge); color: var(--fg); }
.discover-tab.is-active {
  border-color: transparent;
  background: var(--accent);
  color: var(--card);
}

.discover-controls {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: .5rem;
  margin: 0 0 1rem;
}
.discover-search {
  width: 100%;
  padding: .75rem 1rem;
  border: 1px solid var(--line);
  border-radius: 12px;
  font-size: 1rem;
  background: var(--card);
  color: var(--fg);
}
.discover-search:focus { outline: none; border-color: var(--accent); }
.loc-btn {
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  padding: .75rem 1rem;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--card);
  color: var(--fg);
  font-size: var(--t-md);
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
}
.loc-btn:hover { border-color: var(--accent); color: var(--accent); }
.loc-btn.busy { opacity: .55; cursor: progress; }
.loc-btn.busy::after {
  content: "…";
  display: inline-block;
  width: 1ch;
}

/* Distance sorting reorders the whole list silently. This says it is on and
   is the way back off it. */
.discover-geo-note {
  display: flex;
  align-items: center;
  gap: .6rem;
  margin: 0 0 1rem;
}
.geo-chip {
  padding: .2rem .6rem;
  border: 1px solid var(--menu-edge);
  border-radius: 999px;
  background: var(--menu-wash);
  color: color-mix(in srgb, var(--accent) 82%, var(--fg));
  font-size: var(--t-xs);
  font-weight: 600;
}
.geo-clear {
  color: var(--muted);
  font-size: var(--t-md);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.geo-clear:hover { color: var(--fg); }

.discover-list {
  list-style: none;
  padding: 0;
  margin: 0;
}
.discover-list .empty {
  padding: 2.5rem 0;
  text-align: center;
  color: var(--muted);
  font-size: var(--t-md);
}

/* One row per place: picture, name, where it is, and how you can order from
   it. The card is the link — the title carries a stretched ::after so the
   whole row is one target — and the pickup/delivery chips are separate
   anchors lifted above it, which is also why they can't be nested inside it. */
.discover-card {
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: .9rem;
  padding: .9rem 0;
  border-bottom: 1px solid var(--line);
}
.discover-card-media {
  flex: 0 0 88px;
  width: 88px;
  height: 88px;
  display: grid;
  place-items: center;
  overflow: hidden;
  border-radius: 14px;
  background: var(--menu-wash);
}
.discover-card-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.discover-card-initial {
  font-family: var(--menu-display);
  font-size: 1.75rem;
  font-weight: 640;
  color: color-mix(in srgb, var(--accent) 70%, var(--fg));
}
.discover-card-body { flex: 1 1 auto; min-width: 0; }
.discover-card .title-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: .75rem;
}
.discover-card-title {
  color: inherit;
  text-decoration: none;
  font-size: var(--t-base);
  font-weight: 600;
}
.discover-card-title::after {
  content: "";
  position: absolute;
  inset: 0;
}
.discover-card:hover .discover-card-title { color: var(--accent); }
.discover-card .loc {
  display: block;
  margin-top: .1rem;
  color: var(--muted);
  font-size: var(--t-md);
}
.discover-card-tagline {
  margin: .3rem 0 0;
  color: var(--menu-ink-3);
  font-size: var(--t-md);
  line-height: 1.45;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.discover-card-actions {
  position: relative;
  z-index: 1;
  display: flex;
  flex-wrap: wrap;
  gap: .4rem;
  margin-top: .55rem;
}

.dist-pill {
  flex: 0 0 auto;
  padding: .15rem .55rem;
  border-radius: 999px;
  background: color-mix(in srgb, var(--fg) 6%, var(--card));
  color: var(--muted);
  font-size: var(--t-xs);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* Shared by the discover cards and the menu masthead: one pill shape for
   "this is a way to order from here". */
.mode-chip,
.mode-switch-opt {
  padding: .25rem .65rem;
  border: 1px solid var(--menu-edge);
  border-radius: 999px;
  background: var(--menu-wash);
  color: color-mix(in srgb, var(--accent) 82%, var(--fg));
  font-size: var(--t-xs);
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
}
.mode-chip:hover {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--card);
}

/* The masthead switcher. The active mode is filled, the alternative is an
   outline you can tap, and once there is a cart it goes flat and unclickable
   rather than disappearing — a control that vanishes on the first tap of "+"
   reads as a bug. */
.mode-switch { display: inline-flex; gap: .3rem; }
.mode-switch-opt.is-active {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--card);
}
a.mode-switch-opt:hover {
  border-color: var(--accent);
  color: var(--accent);
}
.mode-switch-opt.is-locked {
  border-color: var(--line);
  background: transparent;
  color: var(--muted);
  cursor: not-allowed;
}

@media (max-width: 480px) {
  .discover-controls { grid-template-columns: 1fr; }
  .loc-btn { justify-content: center; }
  .discover-card-media { flex-basis: 68px; width: 68px; height: 68px; border-radius: 12px; }
  .discover-card-initial { font-size: 1.4rem; }
}

/* ---------- Auth / Admin ---------- */
.auth-page { padding: 3rem 0; text-align: center; }
.auth-page h1 { font-size: 1.4rem; margin: 0; }
.auth-page p  { color: var(--muted); margin: .5rem 0 1.5rem; }

.provider-list {
  display: flex;
  flex-direction: column;
  gap: .75rem;
  max-width: 360px;
  margin: 0 auto;
}
.provider-btn {
  display: flex;
  align-items: center;
  gap: .75rem;
  padding: .9rem 1rem;
  border: 1px solid var(--line);
  border-radius: 10px;
  color: var(--fg);
  background: #fff;
  text-decoration: none;
  font-weight: 600;
  transition: border-color .15s ease, transform .05s ease;
}
.provider-btn:hover  { border-color: var(--accent); }
.provider-btn:active { transform: translateY(1px); }
.provider-mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem; height: 1.75rem;
  border-radius: 50%;
  background: #f1f1ec;
  font-weight: 700;
}
.provider-btn.google .provider-mark   { background: #4285F4; color: #fff; }
.provider-btn.apple .provider-mark    { background: #000;     color: #fff; font-size: 1.1rem; }
.provider-btn.facebook .provider-mark { background: #1877F2; color: #fff; }

.auth-divider {
  display: flex;
  align-items: center;
  gap: .75rem;
  max-width: 360px;
  margin: 1.25rem auto;
  color: var(--muted);
  font-size: .8rem;
}
.auth-divider::before,
.auth-divider::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--line);
}

.email-login {
  display: flex;
  flex-direction: column;
  gap: .5rem;
  max-width: 360px;
  margin: 0 auto;
  text-align: left;
}
.email-login label { font-size: .8rem; color: var(--muted); }
.email-login input {
  padding: .75rem .8rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: #fff;
  font: inherit;
}
.email-login input:focus { outline: none; border-color: var(--accent); }
.email-login .btn { width: 100%; }
.email-login .muted.small {
  margin: .25rem 0 0;
  text-align: center;
  word-break: normal;
}

/* The admin shell itself (top bar, sidebar, content column) lives in the
   "Admin chrome" block at the bottom of this file. What's left here is the
   in-page furniture every admin section shares. */
.admin-section { margin-top: 1rem; }
.section-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  margin-bottom: 1rem;
}
.section-head h2 { margin: 0; font-size: 1.2rem; }

.tenant-form { display: flex; flex-direction: column; gap: .75rem; }
.tenant-form label { display: flex; flex-direction: column; gap: .25rem; }
.tenant-form label > span { font-size: .85rem; color: var(--muted); }
.tenant-form input:not([type="checkbox"]),
.tenant-form select {
  padding: .55rem .75rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: #fff;
  font-size: 1rem;
}
.tenant-form select { min-width: 0; }
.tenant-form input:not([type="checkbox"]):focus,
.tenant-form select:focus { outline: none; border-color: var(--accent); }
.tenant-form input:disabled { background: #f5f5f1; color: var(--muted); }
.tenant-form small { color: var(--muted); font-size: .8rem; }
.two-col {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: .75rem;
}
.agent-block {
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 1rem;
  display: flex;
  flex-direction: column;
  gap: .75rem;
}
.agent-block legend { padding: 0 .5rem; color: var(--muted); }

/* Location picker — geocode button, OpenStreetMap map, coordinate inputs.
   Leaflet ships its own stylesheet (leaflet.min.css); this is the frame
   around the map plus the pin, which is a divIcon rather than Leaflet's
   default marker image so the vendored CSS needs no images/ directory. */
.geo-picker {
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 1rem;
  display: flex;
  flex-direction: column;
  gap: .75rem;
}
.geo-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .75rem;
  flex-wrap: wrap;
}
.geo-title { font-size: .85rem; color: var(--muted); }
.geo-actions { display: flex; gap: .5rem; flex-wrap: wrap; }
.geo-map {
  height: 280px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: #eceee9;
  /* Own stacking context: Leaflet's panes and controls sit at z-index
     400+ and would otherwise punch through sticky admin chrome. */
  position: relative;
  z-index: 0;
}
.geo-coords { display: grid; grid-template-columns: 1fr 1fr; gap: .75rem; }
.geo-picker .geocode-status:empty { display: none; }
.geo-picker .status-line { padding: 0; }
/* Coordinates are 6-decimal values; stepping them by 1 is never the
   intent, so the spinners just take up room. */
.geo-coords input::-webkit-outer-spin-button,
.geo-coords input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.geo-coords input { -moz-appearance: textfield; appearance: textfield; }
.geo-pin span {
  display: block;
  width: 20px;
  height: 20px;
  border-radius: 50% 50% 50% 0;
  transform: rotate(-45deg);
  background: var(--accent);
  border: 2px solid #fff;
  box-shadow: 0 2px 6px rgba(0, 0, 0, .35);
}
.leaflet-container { font: inherit; }
@media (max-width: 560px) {
  .geo-map { height: 220px; }
  .geo-coords { grid-template-columns: 1fr; }
}

/* Theme picker — radio cards with swatches. */
.theme-picker {
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 1rem;
}
.theme-picker legend { padding: 0 .5rem; color: var(--muted); }
.theme-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: .75rem;
  margin-top: .25rem;
}
.theme-option { cursor: pointer; }
.theme-option input { position: absolute; opacity: 0; pointer-events: none; }
.theme-card {
  display: flex;
  flex-direction: column;
  gap: .35rem;
  padding: .75rem;
  border: 2px solid var(--line);
  border-radius: 10px;
  background: #fff;
  transition: border-color .12s ease, transform .05s ease;
}
.theme-option input:checked + .theme-card {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(194,65,12,.12);
}
.theme-option input:focus-visible + .theme-card {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.theme-option:hover .theme-card { transform: translateY(-1px); }
.theme-swatches { display: flex; gap: .25rem; }
.theme-swatch {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  display: inline-block;
}
.theme-card strong { font-size: .9rem; }
.theme-card small { color: var(--muted); font-size: .8rem; line-height: 1.3; }

/* Live preview inside the admin theme picker. Uses its own scoped vars
   (--preview-*) so swapping doesn't leak to the rest of the admin page. */
.theme-preview {
  margin-top: 1rem;
  padding: 1rem;
  background: var(--preview-bg, var(--bg));
  border: 1px solid var(--line);
  border-radius: 10px;
  transition: background-color .15s ease;
}
.theme-preview h4 {
  margin: 0 0 .6rem;
  font-size: .75rem;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: .08em;
}
.preview-page {
  display: flex;
  flex-direction: column;
  gap: .5rem;
}
.preview-brand {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: .65rem .85rem;
  background: var(--preview-card, var(--card));
  border-radius: 8px;
  transition: background-color .15s ease;
}
.preview-brand strong { font-size: .95rem; }
.preview-table {
  font-size: .7rem;
  padding: .15rem .55rem;
  border-radius: 999px;
  background: var(--preview-accent, var(--accent));
  color: #fff;
  transition: background-color .15s ease;
}
.preview-article {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: .6rem .85rem;
  background: var(--preview-card, var(--card));
  border-radius: 8px;
  transition: background-color .15s ease;
}
.preview-article > div:first-child { display: flex; flex-direction: column; }
.preview-article strong { font-size: .9rem; }
.preview-article small { color: var(--muted); font-size: .75rem; }
.preview-article-right {
  display: flex;
  align-items: center;
  gap: .65rem;
  font-variant-numeric: tabular-nums;
}
.preview-add {
  width: 1.6rem; height: 1.6rem;
  border-radius: 50%;
  border: 1px solid var(--preview-accent, var(--accent));
  background: transparent;
  color: var(--preview-accent, var(--accent));
  font-size: 1rem;
  line-height: 1;
  cursor: default;
  transition: border-color .15s ease, color .15s ease;
}
.preview-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .75rem;
  padding: .65rem .9rem;
  background: var(--preview-accent, var(--accent));
  color: #fff;
  border-radius: 8px;
  font-size: .85rem;
  transition: background-color .15s ease;
}
.muted-on-accent { opacity: .85; }

.agent-test { min-height: 1.25rem; }
.agent-test-line { margin: 0; font-size: .9rem; }
.agent-test-line.ok  { color: #166534; }
.agent-test-line.bad { color: #911; }
.form-actions { display: flex; gap: .75rem; margin-top: .5rem; }
.btn.small { padding: .4rem .75rem; font-size: .85rem; }
@media (max-width: 480px) { .two-col { grid-template-columns: 1fr; } }

.empty-state { padding: 3rem 0; text-align: center; color: var(--muted); }
.empty { color: var(--muted); padding: 1rem 0; }

.brand .table {
  display: inline-block;
  margin-top: .35rem;
  padding: .15rem .55rem;
  background: var(--accent);
  color: #fff;
  border-radius: 999px;
  font-size: .8rem;
}

/* ============================================================
   GUEST MENU
   ------------------------------------------------------------
   The palette here is not ours: --accent, --bg and --card come from the
   tenant's theme, so everything below is written as a *structure* that has
   to hold up under any three colours a place picks. What we control is the
   type, the rhythm, and the one element the page is remembered by — the
   index in .menu-index, which names every section, counts it, marks where
   you are, and on a wide screen moves into the left margin so a desktop
   viewport stops being 700px of empty paper.
   ============================================================ */

:root {
  --menu-col: 44rem;
  --menu-index-col: 12.5rem;
  --menu-gutter: 3rem;
  --menu-wash: color-mix(in srgb, var(--accent) 7%, var(--card));
  --menu-edge: color-mix(in srgb, var(--accent) 22%, transparent);
  --menu-ink-3: color-mix(in srgb, var(--fg) 52%, var(--bg));
  --menu-shade: 0 14px 34px -18px color-mix(in srgb, var(--fg) 45%, transparent);

  /* The display face is a seasoning, not the meal. It sets the place's name
     and the section headings and nothing else — an earlier pass put it on
     dish names, prices, buttons and the footer address at weight 650-750,
     and the page came out shouting every word at once. Everything a guest
     actually reads is the system UI face at ordinary weights.

     No web font: this page is opened on restaurant wifi from a QR code and
     has to paint on the first frame. `ui-rounded` only resolves in Safari;
     Chrome falls through it, so a real family has to follow it or headings
     land on the default serif. */
  --menu-display: ui-rounded, "SF Pro Rounded", "Avenir Next",
                  "Segoe UI Variable Display", "Segoe UI", system-ui, sans-serif;

  /* One scale, 13/15/16/17px on a 16px root, so nothing is sized by feel. */
  --t-xs: .6875rem;   /* 11px — currency code, counts, eyebrows      */
  --t-sm: .75rem;     /* 12px — ingredients, fine print              */
  --t-md: .8125rem;   /* 13px — descriptions, meta, controls, index  */
  --t-base: .9375rem; /* 15px — dish names, prices                   */
  --t-lg: 1.0625rem;  /* 17px — section headings                     */
}

/* The whole guest menu is one column on a phone and a two-column reading
   spread once there is room for the index to stand beside the menu rather
   than on top of it. */
body:has(.menu-brand) {
  max-width: none;
  padding-inline: 0;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
body:has(.menu-brand) > .brand,
body:has(.menu-brand) > .menu,
body:has(.menu-brand) > .menu-index,
body:has(.menu-brand) > .menu-footer {
  width: min(100% - 2rem, var(--menu-col));
  margin-inline: auto;
}

/* ---------- masthead ---------- */

.menu-brand {
  position: relative;
  margin: 0 auto;
  padding: 1rem 0 .9rem;
  background: transparent;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  text-align: left;
}
.menu-brand-utilities {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: .5rem;
  min-height: 1.75rem;
  margin-bottom: .9rem;
}
.menu-brand-title { min-width: 0; }
/* The name, not a billboard. It was clamp(2.5rem, 11vw, 3.6rem) at weight
   750 — roughly a quarter of a phone screen spent before the first dish, in
   Avenir's Heavy cut. Two thirds the size at 640 reads as confident rather
   than loud, and the menu starts above the fold. */
.menu-brand h1 {
  margin: 0;
  font-family: var(--menu-display);
  font-size: clamp(1.75rem, 6.5vw, 2.25rem);
  font-weight: 640;
  line-height: 1.05;
  letter-spacing: -.028em;
}
.menu-brand .brand-logo {
  margin: 0;
  max-height: 72px;
}
.menu-brand .brand-tagline {
  max-width: 34rem;
  margin: .4rem 0 0;
  color: var(--muted);
  font-size: var(--t-md);
  font-style: normal;
  line-height: 1.5;
}

/* One meta line: where you are, what table, what it's like outside. These
   were three separate blocks pinned to three different edges. */
.menu-brand-meta {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: .4rem .7rem;
  margin-top: .6rem;
  font-size: var(--t-md);
  color: var(--muted);
}
.menu-brand-meta:empty { display: none; }
.menu-brand-place { color: var(--menu-ink-3); }

/* The table badge answers "will this order reach me?" — worth stating,
   not worth being the brightest thing on the page. An outlined chip with a
   live dot says it without shouting in solid accent. */
.here-badge {
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  padding: .15rem .5rem .15rem .45rem;
  border: 1px solid var(--menu-edge);
  border-radius: 999px;
  background: var(--menu-wash);
  color: color-mix(in srgb, var(--accent) 82%, var(--fg));
  font-size: var(--t-xs);
  font-weight: 600;
  letter-spacing: 0;
  white-space: nowrap;
}
.here-badge::before {
  content: "";
  width: .35rem;
  height: .35rem;
  border-radius: 50%;
  background: var(--accent);
}
.welcome-weather {
  display: inline-flex;
  align-items: center;
  gap: .3rem;
  padding: 0;
  background: transparent;
  border: 0;
  font-size: var(--t-md);
  color: var(--muted);
}
.welcome-weather .w-icon { font-family: sans-serif; font-size: .875rem; line-height: 1; }
.welcome-weather .w-temp {
  font-weight: 550;
  color: var(--menu-ink-3);
  font-variant-numeric: tabular-nums;
}
.welcome-weather .w-label { color: var(--muted); }

.welcome-quote {
  margin: 1.15rem 0 0;
  padding: 1rem 0 0;
  border-top: 1px solid var(--line);
  text-align: left;
}
.welcome-quote p {
  margin: 0;
  font-style: italic;
  color: var(--fg);
  line-height: 1.45;
}
.welcome-quote cite {
  display: block;
  margin-top: .35rem;
  color: var(--muted);
  font-size: .85rem;
  font-style: normal;
}

/* ---------- the index (signature) ---------- */

.menu-index {
  position: sticky;
  z-index: 7;
  top: 0;
  padding: 0;
}
/* The tint and blur live on a pseudo-element bled to the viewport edges, so
   rows slide under a full-width strip instead of out from behind a floating
   one — and so the parent keeps a plain background for the desktop rail. */
.menu-index::before {
  content: "";
  position: absolute;
  z-index: -1;
  inset: 0 calc(50% - 50vw);
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  border-bottom: 1px solid var(--line);
}
.menu-index-title { display: none; }
.menu-index-track {
  display: flex;
  gap: 1.35rem;
  overflow-x: auto;
  scrollbar-width: none;
  scroll-behavior: smooth;
  overscroll-behavior-x: contain;
}
.menu-index-track::-webkit-scrollbar { display: none; }

/* Underlined tabs rather than filled pills. A pill's own padding pushed its
   label a dozen pixels right of the column edge, so the one element whose
   job is to organise the page was the only thing not lined up with it. A
   tab's text sits exactly on the rail, and the marker is a rule under it. */
.menu-index a {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  padding: .55rem 0 .5rem;
  border: 0;
  border-bottom: 2px solid transparent;
  color: var(--muted);
  font-size: var(--t-md);
  font-weight: 550;
  text-decoration: none;
  white-space: nowrap;
  transition: color .18s ease, border-color .18s ease;
}
.menu-index-count {
  color: color-mix(in srgb, var(--fg) 32%, var(--bg));
  font-size: var(--t-xs);
  font-weight: 550;
  font-variant-numeric: tabular-nums;
  transition: color .18s ease;
}
.menu-index a:hover { color: var(--fg); }
.menu-index a:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 3px;
}
/* .is-current is set by menu-index.js from an IntersectionObserver. Without
   the script the index is still a working list of anchor links. */
.menu-index a.is-current {
  border-bottom-color: var(--accent);
  color: var(--fg);
}
.menu-index a.is-current .menu-index-count { color: var(--accent); }

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

.menu { padding-top: .25rem; }
.menu > .category {
  margin: 0;
  padding: 1.15rem 0 .35rem;
  scroll-margin-top: 3.25rem;
}
.menu > .category + .category { border-top: 1px solid var(--line); }
.menu > .category h2 {
  display: flex;
  align-items: center;
  gap: .75rem;
  margin: 0 0 .2rem;
  color: var(--fg);
  font-family: var(--menu-display);
  font-size: var(--t-lg);
  font-weight: 620;
  letter-spacing: -.02em;
  line-height: 1.2;
}
.menu > .category h2::after {
  content: "";
  flex: 1 1 auto;
  height: 1px;
  background: var(--line);
}
.menu .category ul { list-style: none; padding: 0; margin: 0; }

/* A row is a grid, not a flex line, because the four things in it want two
   different widths. The dish name shares the top line with the price so the
   two read together; everything underneath — description, ingredients,
   rating — spans the full width instead of being squeezed into whatever the
   price column leaves over. On a phone that is the difference between a
   readable sentence and four words per line.

       [photo]  Ćevapi 10 kom              620 RSD  [+]
       [photo]  Hand-rolled every morning, grilled over
                beech charcoal.
*/
.menu .article {
  position: relative;
  display: grid;
  grid-template-columns: 1fr auto;
  grid-template-rows: auto auto;
  align-items: start;
  gap: .1rem 1rem;
  padding: .7rem .5rem;
  margin-inline: -.5rem;
  border: 0;
  border-radius: 12px;
  transition: background-color .16s ease;
}
/* Drawn inset rather than as a shadow on the article's own box: the row is
   deliberately half a rem wider than the column so its hover state has
   somewhere to go, and a divider following that box sat 8px outside the
   rail everything else lines up on. */
.menu .article + .article::before {
  content: "";
  position: absolute;
  top: 0;
  left: .5rem;
  right: .5rem;
  height: 1px;
  background: var(--line);
}
.menu .article > .name { grid-area: 1 / 1; align-self: center; }
.menu .article > .info { grid-area: 2 / 1 / 3 / 3; }
.menu .article > .article-actions { grid-area: 1 / 2; }
.menu .article > .info:empty { display: none; }

.menu-photos .article { grid-template-columns: 4.25rem 1fr auto; }
.menu-photos .article > picture,
.menu-photos .article > .article-img { grid-area: 1 / 1 / 3 / 2; }
.menu-photos .article > .name { grid-area: 1 / 2; }
.menu-photos .article > .info { grid-area: 2 / 2 / 3 / 4; }
.menu-photos .article > .article-actions { grid-area: 1 / 3; }
/* A menu that mixes photographed and unphotographed items keeps the text
   aligned: the ones without a photo skip the gutter instead of leaving a
   hole in it. */
.menu-photos .article:not(:has(> picture, > .article-img)) > .name { grid-area: 1 / 1 / 2 / 3; }
.menu-photos .article:not(:has(> picture, > .article-img)) > .info { grid-area: 2 / 1 / 3 / 4; }

.menu .article > picture {
  display: block;
  width: 4.25rem;
  height: 4.25rem;
}
.menu .article-img {
  display: block;
  width: 4.25rem;
  height: 4.25rem;
  border-radius: 12px;
  object-fit: cover;
  background: color-mix(in srgb, var(--fg) 5%, var(--card));
}
.menu .article > picture .article-img { width: 100%; height: 100%; }

.menu .article .info {
  display: flex;
  flex-direction: column;
  gap: .18rem;
  min-width: 0;
}
/* Body face, not the display face. Twenty dish names set in a geometric
   heavy is a wall; the display face earns its keep on the two or three
   headings that structure the page. */
.menu .article .name {
  font-size: var(--t-base);
  font-weight: 550;
  line-height: 1.3;
  letter-spacing: -.005em;
  color: var(--fg);
  text-decoration: none;
}
/* The row is the link. The stretched pseudo-element makes the whole card
   tappable — a thumb aiming at a name on a phone should not have to hit
   the word itself — while leaving the add/customize control clickable on
   its own. */
.menu .article .name-link::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
}
.menu .article:hover { background: color-mix(in srgb, var(--fg) 3.5%, transparent); }
.menu .article:has(.name-link:focus-visible) {
  background: color-mix(in srgb, var(--fg) 3.5%, transparent);
  outline: 2px solid var(--accent);
  outline-offset: 0;
}
.menu .article .name-link:focus-visible { outline: none; }

/* Two lines of description is a menu; five lines is an essay that pushes
   the next dish off the screen. */
.menu .article .desc {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  color: var(--muted);
  font-size: var(--t-md);
  line-height: 1.45;
}
.menu .article .desc p { margin: 0; }
.menu .article .ingredients {
  color: var(--menu-ink-3);
  font-size: var(--t-sm);
  font-style: normal;
  line-height: 1.4;
}
.menu .article .review-summary.inline {
  display: flex;
  align-items: center;
  gap: .3rem;
  margin-top: .05rem;
  font-size: var(--t-sm);
}
.menu .article .review-summary .stars { font-size: var(--t-xs); letter-spacing: -.02em; }
.menu .article .review-avg { font-weight: 600; color: var(--menu-ink-3); }
.menu .article .review-count { color: var(--muted); }

/* ---------- price + action column ---------- */

/* Price and control sit side by side, not stacked: half the rows on a real
   menu are a name and nothing else, and stacking made those two lines tall
   for no reason. Side by side, a one-line dish stays a one-line row. */
.menu .article-actions {
  position: relative;
  z-index: 1;
  flex: 0 0 auto;
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: .6rem;
}
.menu .article .price,
.combo-foot .price {
  display: flex;
  align-items: baseline;
  gap: .25rem;
  white-space: nowrap;
}
.price-amount {
  color: var(--fg);
  font-size: var(--t-base);
  font-weight: 600;
  letter-spacing: -.01em;
  font-variant-numeric: tabular-nums;
}
.price-cur {
  color: var(--muted);
  font-size: var(--t-xs);
  font-weight: 500;
  letter-spacing: .01em;
}
/* A discounted price is three things — the badge, the old number, the new
   one — so it gets a two-column grid rather than a wrapping flex row, where
   the badge stretched into a solid bar across the whole column. */
.menu .article .price.discounted {
  display: grid;
  grid-template-columns: auto auto;
  justify-content: end;
  align-items: baseline;
  gap: .15rem .35rem;
}
.menu .article .price.discounted .price-was {
  grid-column: 1;
  color: var(--muted);
  font-size: var(--t-md);
  font-weight: 400;
  font-variant-numeric: tabular-nums;
  text-decoration-thickness: 1px;
}
.menu .article .price.discounted .price-now {
  grid-column: 2;
  display: flex;
  align-items: baseline;
  gap: .28rem;
}
.menu .article .price.discounted .price-now .price-amount { color: var(--accent); }
.deal-badge {
  grid-column: 1 / 3;
  justify-self: end;
  width: max-content;
  padding: .1rem .4rem;
  border-radius: 5px;
  background: var(--accent);
  color: #fff;
  font-family: inherit;
  font-size: .625rem;
  font-weight: 650;
  letter-spacing: .04em;
  text-transform: uppercase;
}

/* One control, one silhouette, one meaning — so the right edge of the menu
   reads as a column, and so "add this" looks the same whether or not the
   kitchen needs a question answered first. */
.menu .add-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 1.875rem;
  min-width: 1.875rem;
  width: auto;
  padding: 0 .4rem;
  border: 1px solid color-mix(in srgb, var(--accent) 30%, transparent);
  border-radius: 999px;
  background: transparent;
  color: var(--accent);
  font-size: 1.05rem;
  font-weight: 500;
  line-height: 1;
  text-decoration: none;
  cursor: pointer;
  transition: background-color .15s ease, border-color .15s ease,
              color .15s ease, transform .12s ease;
}
.menu .add-btn:hover {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}
.menu .add-btn:active { transform: translateY(1px); }
.menu .add-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* ---------- combos ---------- */

.combos-section .combos-row {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: min(17rem, 78%);
  gap: .85rem;
  margin: 0;
  padding: .25rem .5rem .75rem;
  margin-inline: -.5rem;
  list-style: none;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
}
.combos-section .combos-row::-webkit-scrollbar { display: none; }

.combo-card {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--card);
  scroll-snap-align: start;
}
/* Unconstrained, a combo photo rendered at its natural size and swallowed
   the entire first screen of the menu. The ratio belongs on the img, not on
   the <picture>: a percentage height inside an aspect-ratio box is not a
   definite height, so the image fell back to its intrinsic size anyway. */
.combo-image {
  display: block;
  overflow: hidden;
  background: color-mix(in srgb, var(--fg) 6%, var(--card));
}
.combo-image img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 10;
  object-fit: cover;
}
.combo-body {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  gap: .2rem;
  padding: .8rem .9rem .9rem;
}
.combo-name {
  font-size: var(--t-base);
  font-weight: 600;
  letter-spacing: -.005em;
}
.combo-items { color: var(--menu-ink-3); font-size: var(--t-sm); }
.combo-desc {
  margin: .15rem 0 0;
  color: var(--muted);
  font-size: var(--t-md);
  line-height: 1.4;
}
.combo-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .75rem;
  margin-top: auto;
  padding-top: .7rem;
}
.combo-foot .add-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.875rem;
  height: 1.875rem;
  border: 1px solid var(--menu-edge);
  border-radius: 999px;
  background: var(--menu-wash);
  color: var(--accent);
  font-size: 1.05rem;
  line-height: 1;
  cursor: pointer;
  transition: background-color .15s ease, border-color .15s ease, color .15s ease;
}
.combo-foot .add-btn:hover {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}

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

.menu-footer {
  margin: 1.75rem auto 0;
  padding: 1.15rem 0 max(1.5rem, env(safe-area-inset-bottom));
  border-top: 1px solid var(--line);
}
.menu-footer-label {
  margin: 0;
  color: var(--muted);
  font-size: var(--t-xs);
  font-weight: 600;
  letter-spacing: .09em;
  text-transform: uppercase;
}
.menu-footer-address {
  margin: .25rem 0 0;
  font-size: var(--t-base);
  font-weight: 550;
}
.menu-footer-map {
  display: inline-block;
  margin-top: .3rem;
  color: var(--accent);
  font-size: var(--t-md);
  font-weight: 550;
  text-decoration: none;
  border-bottom: 1px solid var(--menu-edge);
}
.menu-footer-map:hover { border-color: var(--accent); }
.menu-footer-fine {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  margin: 1.15rem 0 0;
  color: var(--muted);
  font-size: var(--t-sm);
}
.menu-footer-mark {
  font-family: var(--menu-display);
  font-weight: 620;
  letter-spacing: -.02em;
  color: color-mix(in srgb, var(--fg) 32%, var(--bg));
}
/* Below the fixed cart bar there has to be somewhere for the page to end. */
body:has(.cart-bar.has-items) .menu-footer { padding-bottom: 5.5rem; }

/* ---------- explore promo ---------- */

.explore-link { margin: .5rem 0 0; }
.explore-link a {
  color: var(--accent);
  text-decoration: none;
  font-size: .9rem;
  font-weight: 600;
}
.explore-link a:hover { text-decoration: underline; }

/* A compact, dismissible city-guide promo. It enters from below like a
   small ad, then stays clear of the sticky cart summary if one appears. */
.explore-promo {
  position: fixed;
  z-index: 8;
  left: 50%;
  bottom: max(1rem, env(safe-area-inset-bottom));
  display: flex;
  align-items: center;
  width: max-content;
  max-width: calc(100vw - 2rem);
  padding: .25rem .3rem .25rem .75rem;
  border: 1px solid var(--menu-edge);
  border-radius: 999px;
  background: color-mix(in srgb, var(--card) 94%, var(--accent));
  box-shadow: var(--menu-shade), 0 2px 6px rgba(26, 26, 26, .08);
  animation: explore-promo-in .48s .25s cubic-bezier(.2, .9, .25, 1.15) both;
}
body:has(.cart-bar.has-items) .explore-promo { bottom: calc(5.25rem + env(safe-area-inset-bottom)); }
.explore-promo a {
  overflow: hidden;
  padding: .35rem .2rem;
  color: var(--accent);
  text-decoration: none;
  font-size: var(--t-md);
  font-weight: 550;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.explore-promo a:hover { text-decoration: underline; }
.explore-promo-close {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 1.75rem;
  height: 1.75rem;
  margin-left: .35rem;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--muted);
  font: inherit;
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
}
.explore-promo-close:hover {
  background: color-mix(in srgb, var(--fg) 7%, transparent);
  color: var(--fg);
}
.explore-promo a:focus-visible,
.explore-promo-close:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
@keyframes explore-promo-in {
  from { opacity: 0; transform: translate(-50%, 1.5rem) scale(.96); }
  to { opacity: 1; transform: translate(-50%, 0) scale(1); }
}

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

/* The language picker is emitted by the layout, outside the header, so on
   the menu page it has to be positioned onto the header's utility row
   rather than flowing into it. Top and height come from the same numbers
   the row uses — .menu-brand's padding-top and the row's min-height — or
   the two utilities sit ten pixels out of line with each other.

   This lives inside the menu block, not with the other picker rules further
   down, because the wide-screen override below has to come after it: both
   selectors have the same specificity, and a media query adds none. */
body:has(.menu-brand) { position: relative; }
body:has(.menu-brand) > .language-picker {
  position: absolute;
  top: 1rem;
  left: 1rem;
  height: 1.75rem;
  margin: 0;
}

/* ---------- wide screens: the index moves into the margin ---------- */

/* Past this width the page stops being a phone column stranded in the middle
   of a monitor and becomes a spread: masthead and footer full width, the
   dishes on a reading measure, and the index standing in the left margin
   where it can stay visible for the whole scroll. */
@media (min-width: 62rem) {
  body:has(.menu-index) {
    display: grid;
    grid-template-columns:
      minmax(1.5rem, 1fr)
      var(--menu-index-col)
      var(--menu-gutter)
      minmax(0, var(--menu-col))
      minmax(1.5rem, 1fr);
    align-content: start;
  }
  /* Everything the guest reads shares one left edge — masthead, dish names,
     footer — and the index is the only thing that lives in the margin. The
     margin column is part of the centred grid, so the spread balances even
     though the reading column alone sits right of centre. */
  body:has(.menu-index) > .brand,
  body:has(.menu-index) > .menu,
  body:has(.menu-index) > .menu-footer {
    grid-column: 4;
    width: auto;
    margin-inline: 0;
  }
  body:has(.menu-index) > .brand { grid-row: 1; }
  /* The two utilities belong to the same bar. The picker lives outside the
     header in the DOM (every page gets one from the layout), so on desktop
     it joins the header's grid cell and takes the left end of the row that
     the sign-in link already ends. */
  body:has(.menu-index) > .language-picker {
    z-index: 10;
    grid-row: 1;
    grid-column: 4;
    top: 1rem;
    left: 0;
    margin: 0;
  }
  body:has(.menu-index) > .menu-index { grid-row: 2; grid-column: 2; }
  body:has(.menu-index) > .menu { grid-row: 2; }
  body:has(.menu-index) > .menu-footer { grid-row: 3; }

  .menu-index {
    position: sticky;
    top: 2.5rem;
    align-self: start;
    width: auto;
    margin: 0;
    justify-self: stretch;
    padding: 1.5rem 0 0;
    background: none;
  }
  .menu-index::before { display: none; }
  .menu-index-title {
    display: block;
    margin: 0 0 .6rem .875rem;
    color: var(--muted);
    font-size: var(--t-xs);
    font-weight: 600;
    letter-spacing: .09em;
    text-transform: uppercase;
  }
  .menu-index-track {
    flex-direction: column;
    gap: 0;
    overflow: visible;
    border-left: 1px solid var(--line);
  }
  /* Same idea turned ninety degrees: the marker is a rule on the reading
     side of the rail, and every label starts on one vertical line. */
  .menu-index a {
    justify-content: space-between;
    width: 100%;
    padding: .3rem 0 .3rem .75rem;
    margin-left: -1px;
    border-bottom: 0;
    border-left: 2px solid transparent;
    font-size: var(--t-md);
  }
  .menu-index a.is-current { border-left-color: var(--accent); }
  .menu-index-label {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .menu-brand { padding-bottom: 1.25rem; }
  .menu-brand h1 { font-size: 2.5rem; }
  .menu { padding-top: 0; }
  .menu > .category:first-child { padding-top: 0; }
  .menu > .category { scroll-margin-top: 2.5rem; }
  .combos-section .combos-row { grid-auto-columns: 17rem; }
}

/* ---------- narrow phones ---------- */

@media (max-width: 26rem) {
  .menu-brand-meta { gap: .4rem .6rem; }
  .welcome-weather .w-label { display: none; }
  .menu .article { gap: .3rem .7rem; }
  .menu-photos .article { grid-template-columns: 3.5rem 1fr auto; }
  .menu .article > picture,
  .menu .article > .article-img { width: 3.5rem; height: 3.5rem; }
  .menu-footer-fine { flex-direction: column; gap: .5rem; }
}

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

/* Deliberately almost none. The only movement on this page is the index
   marker following the scroll and the row/button states under a finger —
   both feedback, not decoration. A staggered entrance was tried here and
   removed: it delayed the one thing a hungry person opened the page for. */
@media (prefers-reduced-motion: reduce) {
  .explore-promo { animation: none; transform: translateX(-50%); }
  .menu-index-track { scroll-behavior: auto; }
}

/* /{brand}/explore page. */
.explore-main { padding-bottom: 3rem; }
.city-card {
  margin-top: 1rem;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 14px;
  overflow: hidden;
}
.city-hero {
  display: block;
  width: 100%;
  max-height: 240px;
  object-fit: cover;
  background: #f1f1ec;
}
.city-body { padding: 1rem 1.1rem 1.25rem; }
.city-body h2 { margin: 0 0 .25rem; font-size: 1.3rem; }
.city-desc { margin: 0 0 .75rem; color: var(--muted); font-size: .9rem; }
.city-extract { margin: 0; line-height: 1.55; color: var(--fg); }
.city-links {
  display: flex;
  gap: .5rem;
  flex-wrap: wrap;
  margin-top: 1rem;
}
.city-links .btn { padding: .55rem 1rem; font-size: .9rem; }

/* Curated attractions (guest-facing on /{brand}/explore). */
.attractions-public { margin-top: 1.5rem; }
.attractions-public h2 { margin: 0 0 .5rem; font-size: 1.1rem; }
.attractions-public ul { list-style: none; padding: 0; margin: 0; }
.attraction-card {
  padding: .85rem 1rem;
  margin-bottom: .5rem;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 10px;
}
.attraction-card strong { display: block; font-size: 1rem; }
.attraction-card p { margin: .25rem 0 .35rem; color: var(--fg); line-height: 1.45; }
.attraction-link {
  font-size: .85rem;
  color: var(--accent);
  text-decoration: none;
}
.attraction-link:hover { text-decoration: underline; }

/* Admin form attractions section. */
.attractions-admin {
  margin-top: 1.5rem;
  padding-top: 1.25rem;
  border-top: 1px dashed var(--line);
  display: flex;
  flex-direction: column;
  gap: .75rem;
}
.attractions-admin h3 { margin: 0; font-size: 1rem; }
.attractions-admin .hint { margin: 0; color: var(--muted); font-size: .85rem; }
.attractions-admin .empty { color: var(--muted); padding: .5rem 0; }
.attraction-list { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: .5rem; }
.attraction-row {
  display: flex;
  align-items: flex-start;
  gap: .75rem;
  padding: .65rem .85rem;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 8px;
}
.attraction-row.editing { background: #fafaf7; border-style: dashed; }
.attraction-body { flex: 1; display: flex; flex-direction: column; gap: .15rem; }
.attraction-body p { margin: 0; }
.muted { color: var(--muted); font-size: .85rem; }
/* `.muted.small` is the meta line under a title on every admin row, so it
   is mostly prose. It used to carry `word-break: break-all` for the one
   case that needed it — a pasted attraction URL — which broke ordinary
   sentences mid-word ("fulfil when i / t's done"). Only the URL breaks now. */
.muted.small { font-size: .8rem; }
.attraction-body .muted.small,
.reveal-pair .muted.small { overflow-wrap: anywhere; }

.reorder {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .15rem;
  cursor: grab;
  padding-top: .15rem;
}
.reorder:active { cursor: grabbing; }
.drag-grip {
  color: var(--muted);
  font-size: 1rem;
  line-height: 1;
  user-select: none;
  letter-spacing: -2px;
}
.reorder-btn {
  width: 1.5rem; height: 1.5rem; padding: 0;
  border: 1px solid var(--line);
  background: #fff;
  border-radius: 4px;
  color: var(--muted);
  cursor: pointer;
  line-height: 1;
  font-size: .9rem;
}
.reorder-btn:hover { color: var(--accent); border-color: var(--accent); }

.drag-ghost {
  opacity: .35;
  background: var(--accent) !important;
  color: #fff;
}

.row-actions { display: flex; gap: .35rem; }
.row-btn {
  width: 1.75rem; height: 1.75rem; padding: 0;
  border: 1px solid var(--line);
  background: #fff;
  border-radius: 6px;
  color: var(--muted);
  cursor: pointer;
  line-height: 1;
  font-size: 1rem;
}
.row-btn:hover { color: var(--accent); border-color: var(--accent); }
.row-btn.danger:hover { color: #911; border-color: #911; }

.attraction-edit {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: .5rem;
}
.attraction-edit label { display: flex; flex-direction: column; gap: .25rem; }
.attraction-edit label > span { font-size: .8rem; color: var(--muted); }
.attraction-edit input,
.attraction-edit textarea {
  padding: .45rem .6rem;
  border: 1px solid var(--line);
  border-radius: 6px;
  font: inherit;
}
.attraction-edit textarea { resize: vertical; }
.attraction-edit input:focus,
.attraction-edit textarea:focus { outline: none; border-color: var(--accent); }
.attraction-form {
  display: flex;
  flex-direction: column;
  gap: .5rem;
  padding: .85rem 1rem;
  background: #fafaf7;
  border: 1px dashed var(--line);
  border-radius: 10px;
}
.attraction-form textarea {
  padding: .55rem .75rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  font: inherit;
  resize: vertical;
}
.attraction-form textarea:focus { outline: none; border-color: var(--accent); }

.article-actions {
  display: flex;
  align-items: center;
  gap: .75rem;
}

.add-btn {
  width: 2rem;
  height: 2rem;
  border-radius: 50%;
  border: 1px solid var(--accent);
  background: #fff;
  color: var(--accent);
  font-size: 1.25rem;
  line-height: 1;
  cursor: pointer;
}
.add-btn:active { background: var(--accent); color: #fff; }

/* .add-btn is also an <a> on rows whose product has modifiers — same control,
   it just navigates to the options page instead of posting to the cart. */
.add-btn { text-decoration: none; }

/* Sticky bottom cart bar on the menu page. */
.cart-bar {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  max-width: 720px;
  margin-inline: auto;
  padding: 0 1rem 1rem;
  pointer-events: none;
}
.cart-bar.empty { display: none; }
.cart-bar.has-items { display: block; }
.cart-bar-link {
  pointer-events: auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: .9rem 1.1rem;
  background: var(--accent);
  color: #fff;
  text-decoration: none;
  border-radius: 12px;
  box-shadow: 0 6px 20px rgba(0,0,0,.18);
  font-weight: 600;
}
.cart-bar-link .count { opacity: .9; font-weight: 500; }
.cart-bar.error {
  pointer-events: auto;
  padding: .75rem 1rem;
  border-radius: 8px;
  background: #fee;
  color: #911;
}

/* Full cart page. */
.cart-main { padding-bottom: 4rem; }
.cart-view .empty { text-align: center; }
.cart-items {
  list-style: none;
  padding: 0;
  margin: 1rem 0;
}
.cart-item {
  display: grid;
  grid-template-columns: 1fr auto auto auto;
  align-items: center;
  gap: .75rem;
  padding: .75rem 0;
  border-bottom: 1px solid var(--line);
}
.cart-item .info { display: flex; flex-direction: column; }
.cart-item .name { font-weight: 600; }
.cart-item .unit { color: var(--muted); font-size: .85rem; }
.cart-item .subtotal { font-variant-numeric: tabular-nums; }
.qty-input {
  width: 3.5rem;
  padding: .35rem .5rem;
  border: 1px solid var(--line);
  border-radius: 6px;
  text-align: center;
}
.remove-btn {
  border: none;
  background: transparent;
  font-size: 1.2rem;
  color: var(--muted);
  cursor: pointer;
}
.remove-btn:hover { color: #911; }

.cart-total {
  display: flex;
  justify-content: space-between;
  padding: 1rem 0;
  border-top: 2px solid var(--line);
  font-size: 1.1rem;
}

.cart-actions { display: flex; gap: .75rem; margin-top: 1rem; flex-wrap: wrap; }
.btn {
  padding: .75rem 1.25rem;
  border-radius: 8px;
  border: 1px solid transparent;
  font-size: 1rem;
  cursor: pointer;
}
.btn.primary { background: var(--accent); color: #fff; }
.btn.ghost   { background: transparent; color: var(--muted); border-color: var(--line); }
.btn-link { color: var(--accent); }

.status-line { padding: .5rem 0; color: var(--muted); }
.status-line.ok  { color: #166534; }
.status-line.bad { color: #911; }
.status-line small { display: block; color: var(--muted); font-size: .85rem; }

.checkout-panel {
  flex: 1 1 100%;
  display: flex;
  flex-direction: column;
  gap: .75rem;
  padding: 1rem;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 12px;
}
.pin-label { display: flex; flex-direction: column; gap: .5rem; }
.pin-label > span { color: var(--muted); font-size: .9rem; }
.pin-input {
  font-size: 1.6rem;
  letter-spacing: .5em;
  text-align: center;
  padding: .65rem .75rem;
  border: 2px solid var(--line);
  border-radius: 10px;
  background: #fafaf7;
}
.pin-input:focus { outline: none; border-color: var(--accent); background: #fff; }
.pin-error { color: #911; margin: 0; font-size: .9rem; }

/* ---------- Super-admin ---------- */
.admin-platform-link {
  padding: .25rem .65rem;
  border-radius: 999px;
  background: #1a1a1a;
  color: #fff;
  font-size: .75rem;
  letter-spacing: .03em;
  text-decoration: none;
  font-weight: 600;
}
.admin-platform-link:hover { background: var(--accent); }

.super-nav {
  display: flex;
  gap: 1rem;
  align-items: center;
  font-size: .9rem;
}
.super-nav a {
  color: var(--muted);
  text-decoration: none;
  padding: .25rem 0;
  border-bottom: 2px solid transparent;
}
.super-nav a.active {
  color: var(--fg);
  border-bottom-color: var(--accent);
}
.super-nav a:hover { color: var(--fg); }

.super-table {
  width: 100%;
  border-collapse: collapse;
  margin-top: .5rem;
  font-size: .9rem;
}
.super-table th,
.super-table td {
  text-align: left;
  padding: .65rem .5rem;
  border-bottom: 1px solid var(--line);
}
.super-table th {
  color: var(--muted);
  font-weight: 600;
  font-size: .8rem;
  text-transform: uppercase;
  letter-spacing: .04em;
}
.super-table tr:last-child td { border-bottom: none; }
.super-table code {
  font-family: ui-monospace, monospace;
  font-size: .85rem;
  color: var(--muted);
}
.super-table time { color: var(--muted); font-variant-numeric: tabular-nums; }
.super-row-actions { display: flex; gap: .35rem; flex-wrap: wrap; justify-content: flex-end; }
.super-row-actions .btn { padding: .35rem .65rem; font-size: .8rem; }

.btn.danger { color: #911; border-color: rgba(145,17,17,.3); }
.btn.danger:hover { color: #fff; background: #911; border-color: #911; }

.badge {
  display: inline-block;
  margin-left: .35rem;
  padding: .05rem .45rem;
  border-radius: 999px;
  font-size: .65rem;
  letter-spacing: .04em;
  text-transform: uppercase;
}
.badge.super { background: #1a1a1a; color: #fff; }

/* Members section (admin tenant form). */
.members-admin {
  margin-top: 1.5rem;
  padding-top: 1.25rem;
  border-top: 1px dashed var(--line);
  display: flex;
  flex-direction: column;
  gap: .75rem;
}
.members-admin h3 { margin: 0; font-size: 1rem; }
.members-admin .hint { margin: 0; color: var(--muted); font-size: .85rem; }
.members-admin .empty { color: var(--muted); padding: .5rem 0; }
.member-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: .35rem;
}
.member-row {
  display: flex;
  align-items: center;
  gap: .75rem;
  padding: .55rem .85rem;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 8px;
}
.member-info {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: .15rem;
  min-width: 0;
}
.member-info strong { font-size: .95rem; }
.member-form {
  display: flex;
  flex-direction: column;
  gap: .5rem;
  padding: .85rem 1rem;
  background: #fafaf7;
  border: 1px dashed var(--line);
  border-radius: 10px;
}
.member-form label { display: flex; flex-direction: column; gap: .25rem; }
.member-form label > span { font-size: .85rem; color: var(--muted); }
.member-form input {
  padding: .55rem .75rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  font: inherit;
}
.member-form input:focus,
.member-form select:focus { outline: none; border-color: var(--accent); }
.member-form select {
  padding: .55rem .75rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: #fff;
  font: inherit;
}

.sub-head {
  margin: 0;
  font-size: .8rem;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: .06em;
}

.invitation-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: .35rem;
}
.invitation-row { background: #fafaf7; }

.role-badge {
  display: inline-block;
  padding: .1rem .55rem;
  border-radius: 999px;
  font-size: .7rem;
  letter-spacing: .04em;
  text-transform: uppercase;
  border: 1px solid var(--line);
  color: var(--muted);
  background: #fff;
  white-space: nowrap;
}
.role-badge.role-owner {
  background: var(--accent);
  color: #fff;
  border-color: var(--accent);
}
.role-badge.role-manager {
  background: #f1f1ec;
  color: var(--fg);
}

.badge.pending {
  background: #f1f1ec;
  color: var(--muted);
  border: 1px dashed var(--line);
}

.provider-pill {
  display: inline-block;
  margin-right: .25rem;
  margin-bottom: .15rem;
  padding: .1rem .55rem;
  font-size: .7rem;
  letter-spacing: .03em;
  border-radius: 999px;
  background: #f1f1ec;
  color: var(--fg);
  border: 1px solid var(--line);
  white-space: nowrap;
}
.provider-pill.google   { background: #4285F4; color: #fff; border-color: #4285F4; }
.provider-pill.apple    { background: #000;    color: #fff; border-color: #000; }
.provider-pill.facebook { background: #1877F2; color: #fff; border-color: #1877F2; }

/* "Your usuals" recommendation strip on the menu page. */
.favorites { margin: 1rem 0 1.5rem; }
.favorites-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: .75rem;
  margin: 0 0 .5rem;
}
.favorites-head h2 {
  margin: 0;
  font-size: .85rem;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--muted);
}
.clear-history-btn {
  background: transparent;
  border: none;
  padding: 0;
  color: var(--muted);
  font-size: .75rem;
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
}
.clear-history-btn:hover { color: var(--accent); }
.favorites.cleared p { margin: .25rem 0; }

/* AI theme palette generator (admin form). */
.generate-theme {
  margin-top: 1rem;
  padding: .85rem 1rem;
  background: #fafaf7;
  border: 1px dashed var(--line);
  border-radius: 10px;
}
.generate-theme summary {
  cursor: pointer;
  font-size: .85rem;
  color: var(--muted);
  list-style: none;
}
.generate-theme summary::before {
  content: "✨ ";
  margin-right: .2rem;
}
.generate-theme[open] summary { color: var(--fg); margin-bottom: .5rem; }
.generate-form {
  display: flex;
  flex-direction: column;
  gap: .5rem;
}
.generate-form label { display: flex; flex-direction: column; gap: .25rem; }
.generate-form label > span { font-size: .8rem; color: var(--muted); }
.generate-form textarea {
  padding: .55rem .75rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: #fff;
  font: inherit;
  resize: vertical;
}
.generate-form textarea:focus { outline: none; border-color: var(--accent); }
.generate-form .form-actions {
  display: flex;
  align-items: center;
  gap: .75rem;
}
/* htmx adds the .htmx-request class to the form (or button) while a
   request is in flight; we surface that as a Working… label. */
.generate-form [data-htmx-indicator] { display: none; }
.generate-form.htmx-request [data-htmx-indicator],
.generate-form button.htmx-request + [data-htmx-indicator] { display: inline; }

/* Admin Stripe block — mirrors .agent-block visually. */
.payments-block {
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 1rem;
  display: flex;
  flex-direction: column;
  gap: .5rem;
}
.payments-block legend { padding: 0 .5rem; color: var(--muted); }

/* Guest-side paid pill. */
.status-line.payment-paid {
  display: inline-block;
  padding: .35rem .75rem;
  border-radius: 8px;
  background: rgba(22, 101, 52, .08);
  border: 1px solid rgba(22, 101, 52, .2);
}

/* Invitation email delivery pill. Sits below the email + provider line. */
.email-status {
  display: inline-block;
  margin-top: .15rem;
  padding: .05rem .5rem;
  border-radius: 999px;
  font-size: .7rem;
  letter-spacing: .03em;
  text-transform: uppercase;
  border: 1px solid var(--line);
  cursor: help;
}
.email-status.ok    { background: rgba(22, 101, 52, .08); color: #166534; border-color: rgba(22, 101, 52, .2); }
.email-status.bad   { background: rgba(145, 17, 17, .08); color: #911; border-color: rgba(145, 17, 17, .2); }
.email-status.muted { background: #f1f1ec; color: var(--muted); }

/* Language stays a native select for platform-quality input, but its closed
   state is presented as a compact globe + locale utility instead of a wide,
   visually detached dropdown. */
.language-picker {
  position: relative;
  width: 3.35rem;
  height: 2rem;
  margin: .5rem 0 0 auto;
  z-index: 10;
}
.language-picker-face {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .3rem;
  width: 100%;
  height: 100%;
  border: 1px solid var(--line);
  border-radius: 7px;
  background: color-mix(in srgb, var(--card) 88%, transparent);
  color: var(--muted);
  font-size: .6875rem;
  font-weight: 600;
  letter-spacing: .05em;
  text-transform: uppercase;
}
.language-picker-face svg { flex: 0 0 auto; }
.language-picker select {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  cursor: pointer;
}
.language-picker:hover .language-picker-face {
  border-color: color-mix(in srgb, var(--accent) 38%, var(--line));
  color: var(--fg);
}
.language-picker:has(select:focus-visible) .language-picker-face {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
.favorites-row {
  list-style: none;
  margin: 0;
  padding: 0 0 .4rem;
  display: flex;
  gap: .6rem;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: thin;
  -webkit-overflow-scrolling: touch;
}
.favorite-card {
  flex: 0 0 auto;
  scroll-snap-align: start;
  display: flex;
  align-items: center;
  gap: .6rem;
  padding: .55rem .75rem;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 10px;
  min-width: 180px;
}
.favorite-info { display: flex; flex-direction: column; min-width: 0; }
.favorite-info strong {
  font-size: .9rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 12rem;
}
.favorite-info .muted.small { font-size: .75rem; }

/* Brandless marketing landing at `/`. Dual-audience but tilted toward
   restaurant owners — the geo-discover used to live here and is now one
   click away via .landing-discover-line. */
.landing-page { padding: 2rem 0 3rem; }
.landing-hero { text-align: center; padding: 1rem 0 2rem; }
.landing-hero h1 {
  font-size: 2rem;
  line-height: 1.15;
  margin: 0 0 .75rem;
}
.landing-hero .lead {
  margin: 0 auto 1.5rem;
  max-width: 32rem;
  color: var(--muted);
  font-size: 1.05rem;
}
.landing-cta {
  display: inline-flex;
  flex-wrap: wrap;
  gap: .75rem;
  justify-content: center;
  margin-bottom: 1rem;
}
.landing-cta .btn { padding: .75rem 1.25rem; font-size: 1rem; }
.landing-discover-line { margin-top: 1.25rem; font-size: .95rem; }
.landing-discover-line a { color: var(--accent); }

.landing-features {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1rem;
  margin: 2rem 0;
}
.landing-features .feature {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 1rem;
}
.landing-features .feature strong { display: block; margin-bottom: .35rem; }
.landing-features .feature p { margin: 0; color: var(--muted); font-size: .9rem; }
.landing-foot { text-align: center; padding-top: 1rem; }

@media (max-width: 640px) {
  .landing-hero h1 { font-size: 1.5rem; }
  .landing-features { grid-template-columns: 1fr; }
}

/* Welcome banner on the first-tenant create form (?welcome=1). Slimmer
   than .welcome-card since it sits inside an admin section. */
.welcome-banner {
  margin: 0 0 1.25rem;
  padding: 1rem 1.1rem;
  background: linear-gradient(135deg, #fff 0%, #fff8f0 100%);
  border: 1px solid var(--line);
  border-radius: 12px;
}
.welcome-banner h2 { margin: 0 0 .35rem; font-size: 1.1rem; }
.welcome-banner p  { margin: 0; color: var(--muted); }

/* REST API credentials block on the tenant edit page. */
.api-credentials-admin { margin-top: 1.5rem; }
.api-credentials-admin h3 { margin: 0 0 .25rem; }
.api-credentials-admin .hint { color: var(--muted); font-size: .9rem; margin: 0 0 .75rem; }
.api-credentials-admin code {
  background: #f5f5f0;
  padding: .05rem .35rem;
  border-radius: 4px;
  font-size: .85rem;
}
.api-credential-list { list-style: none; padding: 0; margin: 0 0 1rem; }
.api-credential-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .5rem;
  padding: .55rem 0;
  border-bottom: 1px solid var(--line);
}
.api-credential-info { display: flex; flex-direction: column; min-width: 0; }
.api-credential-info strong { font-size: .95rem; }
.api-credential-form { display: flex; flex-direction: column; gap: .5rem; }
.reveal-block {
  margin: 0 0 1rem;
  padding: .75rem 1rem;
  background: #fff8f0;
  border: 1px solid var(--line);
  border-radius: 10px;
}
.reveal-pair { display: grid; grid-template-columns: 6rem 1fr; gap: .25rem .75rem; margin: .5rem 0 0; }
.reveal-pair dt { color: var(--muted); font-size: .85rem; }
.reveal-pair dd { margin: 0; word-break: break-all; }
.reveal-pair .secret { background: #fff3e0; }
.status-line.warn { color: #a86a18; }

/* Custom domains (admin → Domain). Reuses the credentials panel's shape:
   a list of rows, each able to expand into the DNS records still needed. */
.domains-admin { display: flex; flex-direction: column; gap: 1rem; }
.domain-list { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: .75rem; }
.domain-row {
  padding: .75rem 1rem;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: #fff;
}
/* A domain that was working and has stopped is the one state worth a colour:
   it still serves, so nothing else on the page would show it is wrong. */
.domain-row.domain-failing { border-color: #e6c07a; background: #fffdf6; }
.domain-row.domain-pending { background: #fafaf7; }
.domain-head { display: flex; align-items: center; flex-wrap: wrap; gap: .5rem; }
.domain-host { font-weight: 600; word-break: break-all; }
.domain-actions { display: flex; gap: .35rem; margin-left: auto; flex-wrap: wrap; }
.domain-error { margin: .5rem 0 0; }
.domain-records { margin-top: .75rem; padding-top: .75rem; border-top: 1px dashed var(--line); }
.domain-records .hint { margin: 0 0 .5rem; color: var(--muted); font-size: .9rem; }
.domain-form { display: flex; flex-direction: column; gap: .5rem; }
.dns-table { width: 100%; border-collapse: collapse; font-size: .85rem; }
.dns-table th {
  text-align: left;
  color: var(--muted);
  font-weight: 500;
  font-size: .75rem;
  text-transform: uppercase;
  letter-spacing: .04em;
  padding: .25rem .5rem .25rem 0;
}
.dns-table td { padding: .35rem .5rem .35rem 0; vertical-align: top; border-top: 1px solid var(--line); }
.dns-table code { background: #f5f5f0; padding: .05rem .35rem; border-radius: 4px; word-break: break-all; }
.dns-table small { display: block; margin-top: .25rem; font-size: .8rem; }

.badge.ok    { background: #dcfce7; color: #166534; }
.badge.warn  { background: #fef3c7; color: #92400e; }
.badge.muted { background: #f0f0ea; color: var(--muted); }

/* ============================================================
   Admin polish — card-based lists, sticky actions. Scoped via
   :has(.admin-shell) so guest pages keep the narrow reading column.
   ============================================================ */

/* Admin section is the main content card on every admin page. */
body:has(.admin-shell) .admin-section {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 14px;
  padding: 1.25rem 1.5rem 1.75rem;
  box-shadow: 0 1px 2px rgba(0, 0, 0, .03);
}

body:has(.admin-shell) .section-head {
  margin-bottom: 1.25rem;
  padding-bottom: .75rem;
  border-bottom: 1px solid var(--line);
}
body:has(.admin-shell) .section-head h2 {
  font-size: 1.35rem;
  font-weight: 700;
}
body:has(.admin-shell) .section-head-actions {
  display: flex;
  gap: .5rem;
  align-items: center;
  flex-wrap: wrap;
}

/* ---------- Menu admin overview (categories + products) ---------- */

.menu-admin-grid {
  display: grid;
  grid-template-columns: minmax(260px, 320px) 1fr;
  gap: 1.5rem;
  align-items: start;
}
.menu-admin-col h3 {
  margin: 0 0 .75rem;
  font-size: .95rem;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--muted);
}
@media (max-width: 820px) {
  .menu-admin-grid { grid-template-columns: 1fr; }
}

/* Category list — compact rows with subtle hover. Auto-saves on blur via
   hx-trigger="change" so there's no visible Save button cluttering the
   row; the screen-reader-only submit keeps Enter-to-save working. */
.category-list {
  list-style: none;
  padding: 0;
  margin: 0 0 .75rem;
  display: flex;
  flex-direction: column;
  gap: .35rem;
}
.cat-row {
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: .35rem;
  align-items: center;
  padding: .35rem .5rem;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 8px;
  transition: border-color .15s ease, box-shadow .15s ease;
}
.cat-row:hover {
  border-color: #cfcfc6;
  box-shadow: 0 1px 2px rgba(0, 0, 0, .04);
}
.cat-row .drag-grip {
  color: #c0c0b8;
  cursor: grab;
  letter-spacing: -2px;
  user-select: none;
  font-size: .95rem;
  padding: 0 .15rem;
}
.cat-row .drag-grip:active { cursor: grabbing; }

/* The form is just a transparent wrapper for HTMX/Enter handling — let
   the input fill the row's middle column. */
.cat-edit {
  display: flex;
  align-items: center;
  min-width: 0;
}
.cat-edit input {
  width: 100%;
  padding: .4rem .55rem;
  border: 1px solid transparent;
  background: transparent;
  border-radius: 6px;
  font-size: .95rem;
  color: var(--fg);
}
.cat-edit input:hover { background: #fafaf7; }
.cat-edit input:focus {
  outline: none;
  border-color: var(--accent);
  background: #fff;
}

.cat-delete {
  width: 26px;
  height: 26px;
  padding: 0;
  font-size: 1.1rem;
  line-height: 1;
  border-radius: 50%;
  opacity: 0;
  transition: opacity .15s ease, color .15s ease, border-color .15s ease;
}
.cat-row:hover .cat-delete,
.cat-row:focus-within .cat-delete {
  opacity: 1;
}

/* Screen-reader-only utility — keeps the submit button accessible while
   hiding it visually. Used by the category auto-save form. */
.sr-only {
  position: absolute !important;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.cat-create {
  display: flex;
  gap: .35rem;
  padding: .25rem 0;
}
.cat-create input {
  flex: 1;
  padding: .55rem .75rem;
  border: 1px dashed var(--line);
  border-radius: 8px;
  background: #fff;
  font-size: .95rem;
}
.cat-create input:focus { outline: none; border-color: var(--accent); border-style: solid; }

/* Product search input — client-side filter; live-hides .product-row whose
   data-name doesn't match. Sits above the grouped product lists. */
.product-search {
  margin: 0 0 .75rem;
}
.product-search-input {
  width: 100%;
  padding: .55rem .75rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: #fff;
  font-size: .95rem;
}
.product-search-input:focus {
  outline: none;
  border-color: var(--accent);
}
.product-search-empty {
  margin: .5rem 0;
}

/* Product groups — one section per category, each with its own sortable
   list inside. The header counts products in the group for quick glance. */
.product-group {
  margin: 0 0 1.25rem;
}
.product-group-title {
  margin: 0 0 .4rem;
  font-size: .85rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--muted);
  display: flex;
  align-items: baseline;
  gap: .4rem;
}

/* Product list — card rows with thumbnail. */
.product-list {
  list-style: none;
  padding: 0;
  margin: 0 0 1rem;
  display: flex;
  flex-direction: column;
  gap: .5rem;
}
.product-row {
  display: grid;
  grid-template-columns: auto 56px 1fr auto;
  gap: .85rem;
  align-items: center;
  padding: .65rem .85rem;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 10px;
  transition: border-color .15s ease, box-shadow .15s ease, transform .05s ease;
}
.product-row:hover {
  border-color: #cfcfc6;
  box-shadow: 0 2px 6px rgba(0, 0, 0, .05);
}
.product-row.hidden {
  opacity: .55;
  background: #fafaf7;
}
.product-row .drag-grip {
  color: #c0c0b8;
  cursor: grab;
  letter-spacing: -2px;
  user-select: none;
  font-size: 1rem;
}
.product-row .drag-grip:active { cursor: grabbing; }
.product-thumb {
  width: 56px;
  height: 56px;
  border-radius: 8px;
  background: #f1f1ec;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.product-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.thumb-placeholder {
  color: var(--muted);
  font-weight: 700;
  font-size: 1.4rem;
}
.product-main {
  display: flex;
  flex-direction: column;
  gap: .15rem;
  min-width: 0;
}
.product-title-row {
  display: flex;
  align-items: center;
  gap: .4rem;
  flex-wrap: wrap;
}
.product-title-row strong { font-size: 1rem; }
.product-actions {
  display: flex;
  gap: .3rem;
  flex-wrap: wrap;
  justify-content: flex-end;
}
@media (max-width: 640px) {
  .product-row {
    grid-template-columns: 48px 1fr;
    grid-template-rows: auto auto;
  }
  .product-row .drag-grip { display: none; }
  .product-actions { grid-column: 1 / -1; justify-content: flex-start; }
}

.product-create {
  display: grid;
  grid-template-columns: 1fr auto auto auto;
  gap: .5rem;
  padding: .75rem;
  background: #fafaf7;
  border: 1px dashed var(--line);
  border-radius: 10px;
}
.product-create input,
.product-create select {
  padding: .55rem .65rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: #fff;
  font-size: .9rem;
}
.product-create input:focus,
.product-create select:focus { outline: none; border-color: var(--accent); }
@media (max-width: 640px) {
  .product-create { grid-template-columns: 1fr 1fr; }
  .product-create button { grid-column: 1 / -1; }
}

/* Badges on product rows. */
.badge.pos       { background: #1a73e8; color: #fff; }
.badge.mods      { background: rgba(194, 65, 12, .12); color: var(--accent); border: 1px solid rgba(194, 65, 12, .25); }
.badge.hidden    { background: #f1f1ec; color: var(--muted); border: 1px solid var(--line); }
.badge {
  display: inline-flex;
  align-items: center;
  padding: .1rem .5rem;
  border-radius: 999px;
  font-size: .7rem;
  font-weight: 600;
  letter-spacing: .03em;
  text-transform: uppercase;
}

/* ---------- Product edit page ---------- */

.product-edit-page .section-head {
  align-items: flex-start;
}
.product-edit-page .section-head h2 {
  font-size: 1.4rem;
  margin-bottom: .15rem;
}

.product-edit-grid {
  display: grid;
  grid-template-columns: minmax(220px, 280px) 1fr;
  gap: 1.5rem;
  align-items: start;
}
@media (max-width: 820px) {
  .product-edit-grid { grid-template-columns: 1fr; }
}

.product-edit-aside { position: sticky; top: 1rem; }

.product-image-block {
  display: flex;
  flex-direction: column;
  gap: .75rem;
}
.product-image-preview {
  width: 100%;
  aspect-ratio: 1 / 1;
  border-radius: 12px;
  overflow: hidden;
  background: #f1f1ec;
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
}
.product-image-preview img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.image-placeholder {
  color: var(--muted);
  font-size: .9rem;
}
.product-image-preview form {
  position: absolute;
  bottom: .5rem;
  right: .5rem;
}
.product-image-upload {
  display: flex;
  flex-direction: column;
  gap: .5rem;
  padding: .75rem;
  background: #fafaf7;
  border: 1px dashed var(--line);
  border-radius: 10px;
}
.product-image-upload label > span {
  font-size: .85rem;
  font-weight: 600;
  display: block;
  margin-bottom: .35rem;
}
.product-image-upload input[type="file"] {
  display: block;
  font-size: .85rem;
}

.product-edit-form.card {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  padding: 1.25rem;
  background: #fafaf7;
  border: 1px solid var(--line);
  border-radius: 12px;
}
.product-edit-form label {
  display: flex;
  flex-direction: column;
  gap: .3rem;
}
.product-edit-form label > span {
  font-size: .85rem;
  font-weight: 600;
  color: var(--fg);
}
.product-edit-form input[type="text"],
.product-edit-form input[type="url"],
.product-edit-form input[type="number"],
.product-edit-form select,
.product-edit-form textarea {
  padding: .6rem .75rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: #fff;
  font-size: 1rem;
  font-family: inherit;
}
.product-edit-form input:focus,
.product-edit-form select:focus,
.product-edit-form textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(194, 65, 12, .12);
}
.product-edit-form input:disabled {
  background: #f1f1ec;
  color: var(--muted);
}
.product-edit-form small {
  color: var(--muted);
  font-size: .8rem;
}
/* Layout comes from the shared .checkbox-label rule; this only adds the
   breathing room the taller product fields around it need. */
.product-edit-form .checkbox-label { padding: .5rem 0; }
.product-edit-form .checkbox-label > span { font-weight: 500; color: var(--fg); }

.sticky-save {
  position: sticky;
  bottom: 0;
  margin: .5rem -1.25rem -1.25rem;
  padding: .9rem 1.25rem;
  background: rgba(250, 250, 247, .92);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  border-top: 1px solid var(--line);
  border-radius: 0 0 12px 12px;
  display: flex;
  gap: .75rem;
  z-index: 5;
}

/* ---------- Rich text (markdown rendered) on guest pages ---------- */

.rich-text { line-height: 1.5; }
.rich-text p { margin: .25rem 0; }
.rich-text p:first-child { margin-top: 0; }
.rich-text p:last-child { margin-bottom: 0; }
.rich-text strong { font-weight: 600; }
.rich-text em { font-style: italic; }
.rich-text ul,
.rich-text ol { padding-left: 1.1rem; margin: .35rem 0; }
.rich-text li { margin: .1rem 0; }
.rich-text a { color: var(--accent); text-decoration: underline; }
.rich-text code {
  background: #f1f1ec;
  padding: 0 .25rem;
  border-radius: 3px;
  font-size: .9em;
}
.rich-text blockquote {
  margin: .35rem 0;
  padding-left: .65rem;
  border-left: 3px solid var(--line);
  color: var(--muted);
}

/* Article description on the menu list — keep it compact. */
.article .desc.rich-text {
  color: var(--muted);
  font-size: .9rem;
  margin-top: .15rem;
}
.article .ingredients {
  display: block;
  color: var(--muted);
  font-size: .8rem;
  margin-top: .2rem;
  font-style: italic;
}

/* ---------- EasyMDE styling — match the rest of the admin ---------- */

.EasyMDEContainer .CodeMirror {
  border: 1px solid var(--line);
  border-radius: 0 0 8px 8px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .95rem;
  background: #fff;
  color: var(--fg);
}
.EasyMDEContainer .editor-toolbar {
  border: 1px solid var(--line);
  border-bottom: none;
  border-radius: 8px 8px 0 0;
  background: #fafaf7;
  padding: .35rem .25rem;
  opacity: 1;
}
.EasyMDEContainer .editor-toolbar button {
  color: var(--fg);
  border: 1px solid transparent;
  border-radius: 6px;
  width: 28px;
  height: 28px;
  margin: 0 1px;
}
.EasyMDEContainer .editor-toolbar button:hover,
.EasyMDEContainer .editor-toolbar button.active {
  background: rgba(194, 65, 12, .1);
  border-color: rgba(194, 65, 12, .25);
}
.EasyMDEContainer .editor-toolbar i.separator {
  border-left: 1px solid var(--line);
  margin: 0 .15rem;
}
.EasyMDEContainer .editor-preview,
.EasyMDEContainer .editor-preview-side {
  background: #fff;
  font-family: inherit;
  font-size: 1rem;
  line-height: 1.5;
  border-color: var(--line);
}
.EasyMDEContainer .CodeMirror-focused {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(194, 65, 12, .12);
}

/* Replace EasyMDE's expected Font Awesome glyphs with unicode characters
   so we don't have to ship the FA dep. Each `i.fa-*` is a 14px square; we
   render the symbol via CSS content with a fallback monospace font for
   alignment. The button keeps the FA class for EasyMDE's own state
   tracking (active/inactive) — only the visual is swapped. */
.EasyMDEContainer .editor-toolbar i.fa,
.EasyMDEContainer .editor-toolbar i[class*=" fa-"],
.EasyMDEContainer .editor-toolbar i[class^="fa-"] {
  font-style: normal;
  font-family: ui-sans-serif, system-ui, sans-serif;
  font-weight: 700;
  font-size: 14px;
  line-height: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 14px;
  height: 14px;
}
.EasyMDEContainer .editor-toolbar i.fa-bold::before          { content: "B"; }
.EasyMDEContainer .editor-toolbar i.fa-italic::before        { content: "I"; font-style: italic; }
.EasyMDEContainer .editor-toolbar i.fa-strikethrough::before { content: "S"; text-decoration: line-through; }
.EasyMDEContainer .editor-toolbar i.fa-header::before,
.EasyMDEContainer .editor-toolbar i.fa-heading::before       { content: "H"; }
.EasyMDEContainer .editor-toolbar i.fa-code::before          { content: "<>"; font-size: 11px; letter-spacing: -1px; }
.EasyMDEContainer .editor-toolbar i.fa-quote-left::before    { content: "\201C"; font-size: 18px; line-height: .8; }
.EasyMDEContainer .editor-toolbar i.fa-list-ul::before       { content: "\2022\2022"; letter-spacing: 2px; }
.EasyMDEContainer .editor-toolbar i.fa-list-ol::before       { content: "1."; font-size: 11px; }
.EasyMDEContainer .editor-toolbar i.fa-link::before          { content: "\1F517"; font-size: 13px; }
.EasyMDEContainer .editor-toolbar i.fa-image::before         { content: "\25A3"; font-size: 14px; }
.EasyMDEContainer .editor-toolbar i.fa-table::before         { content: "\25A6"; font-size: 14px; }
.EasyMDEContainer .editor-toolbar i.fa-minus::before         { content: "\2014"; }
.EasyMDEContainer .editor-toolbar i.fa-eye::before           { content: "\25C9"; font-size: 12px; }
.EasyMDEContainer .editor-toolbar i.fa-columns::before       { content: "\25A5"; }
.EasyMDEContainer .editor-toolbar i.fa-arrows-alt::before    { content: "\2922"; font-size: 16px; }
.EasyMDEContainer .editor-toolbar i.fa-question-circle::before { content: "?"; }
.EasyMDEContainer .editor-toolbar i.fa-eraser::before        { content: "\232B"; }
.EasyMDEContainer .editor-toolbar i.fa-undo::before          { content: "\21B6"; font-size: 16px; }
.EasyMDEContainer .editor-toolbar i.fa-redo::before,
.EasyMDEContainer .editor-toolbar i.fa-repeat::before        { content: "\21B7"; font-size: 16px; }

/* ---------- Product gallery (admin edit page) ---------- */

.product-gallery-block {
  display: flex;
  flex-direction: column;
  gap: .85rem;
}
.gallery-title {
  margin: 0;
  font-size: .8rem;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--muted);
  font-weight: 700;
}
.gallery-empty {
  padding: 1.5rem 1rem;
  border-radius: 12px;
  text-align: center;
  background: #f1f1ec;
}
.gallery-grid {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
  gap: .5rem;
}
.gallery-item {
  position: relative;
  aspect-ratio: 1 / 1;
  background: #f1f1ec;
  border-radius: 10px;
  overflow: hidden;
  border: 2px solid transparent;
  cursor: grab;
  transition: border-color .15s ease, box-shadow .15s ease;
}
.gallery-item:hover {
  box-shadow: 0 2px 8px rgba(0, 0, 0, .1);
}
.gallery-item:active { cursor: grabbing; }
.gallery-item.is-primary {
  border-color: var(--accent);
}
.gallery-item img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  user-select: none;
}
.primary-badge {
  position: absolute;
  top: .3rem;
  left: .3rem;
  background: var(--accent);
  color: #fff;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: .85rem;
  pointer-events: none;
}
.gallery-item-actions {
  position: absolute;
  top: .3rem;
  right: .3rem;
  display: flex;
  gap: .25rem;
  opacity: 0;
  transition: opacity .15s ease;
}
.gallery-item:hover .gallery-item-actions,
.gallery-item:focus-within .gallery-item-actions {
  opacity: 1;
}
.gi-btn {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: none;
  background: rgba(255, 255, 255, .92);
  color: var(--fg);
  font-size: .85rem;
  font-weight: 700;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 1px 3px rgba(0, 0, 0, .15);
  padding: 0;
  line-height: 1;
}
.gi-btn:hover { background: #fff; color: var(--accent); }
.gi-btn.danger:hover { color: #911; }

/* "Paste a URL" disclosure. */
.paste-url { margin: 0; }
.paste-url summary {
  cursor: pointer;
  color: var(--muted);
  font-size: .85rem;
  padding: .25rem 0;
  list-style: none;
}
.paste-url summary::before {
  content: "▸ ";
  margin-right: .15rem;
  transition: transform .15s ease;
  display: inline-block;
}
.paste-url[open] summary::before {
  content: "▾ ";
}
.paste-url-form {
  display: flex;
  gap: .35rem;
  margin-top: .5rem;
}
.paste-url-form input {
  flex: 1;
  padding: .5rem .65rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: #fff;
  font-size: .9rem;
}
.paste-url-form input:focus { outline: none; border-color: var(--accent); }

/* ---------- Guest gallery (customize page) ---------- */

.guest-gallery {
  margin: .75rem 0 1rem;
}
.guest-gallery.single {
  border-radius: 12px;
  overflow: hidden;
  max-height: 340px;
  background: #f1f1ec;
}
.guest-gallery.single img {
  width: 100%;
  height: 100%;
  max-height: 340px;
  object-fit: cover;
  display: block;
}
.guest-gallery-strip {
  list-style: none;
  padding: 0 .25rem .5rem;
  margin: 0;
  display: flex;
  gap: .5rem;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
}
.guest-gallery-strip::-webkit-scrollbar { height: 6px; }
.guest-gallery-strip::-webkit-scrollbar-thumb {
  background: rgba(0, 0, 0, .12);
  border-radius: 3px;
}
.guest-gallery-item {
  flex: 0 0 auto;
  width: 240px;
  height: 180px;
  border-radius: 10px;
  overflow: hidden;
  scroll-snap-align: start;
  background: #f1f1ec;
}
.guest-gallery-item.is-hero {
  width: 320px;
  height: 240px;
}
.guest-gallery-item img,
.guest-gallery-item picture {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
@media (max-width: 480px) {
  .guest-gallery-item { width: 200px; height: 150px; }
  .guest-gallery-item.is-hero { width: 280px; height: 210px; }
}

/* ---------- Cart page (guest) ---------- */

/* The cart had a grid for its line items and nothing for anything below
   them. The checkout form in particular had no rules at all, so its labels
   and inputs fell back to inline flow: "Name [input] Phone [input] Delivery
   address" on one line with the textarea orphaned underneath. */

.cart-main { display: flex; flex-direction: column; gap: 1.25rem; }

/* Links on the guest cart route through the brand accent like every other
   link a guest sees; the default blue read as a browser artefact. */
.cart-main a,
.cart-view a,
.brand .loc a { color: var(--accent); text-decoration: none; }
.cart-main a:hover,
.cart-view a:hover,
.brand .loc a:hover { text-decoration: underline; }

/* Which order this is — table 5, pickup, delivery. Read once, at the top. */
.fulfillment-badge {
  display: inline-block;
  margin: .35rem 0 0;
  padding: .15rem .65rem;
  border-radius: 999px;
  background: #f1f1ec;
  color: var(--fg);
  font-size: .8rem;
}

.cart-items { margin: 0; }
.cart-item { padding: .85rem 0; }
.cart-item .subtotal { font-weight: 600; }

/* The chosen options, indented under the item they belong to. */
.cart-item-modifiers {
  list-style: none;
  margin: .3rem 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: .1rem;
}
.cart-item-modifiers li {
  display: flex;
  gap: .35rem;
  color: var(--muted);
  font-size: .85rem;
}
.cart-item-modifiers li::before { content: "·"; }
.mod-delta { font-variant-numeric: tabular-nums; }

.cart-line {
  display: flex;
  justify-content: space-between;
  padding: .25rem 0;
  color: var(--muted);
  font-size: .9rem;
}
.cart-line span:last-child { font-variant-numeric: tabular-nums; }
.cart-line.discount { color: #166534; }
.cart-total { align-items: baseline; font-variant-numeric: tabular-nums; }

/* Checkout: name, phone, and an address for delivery. */
.contact-fields { display: flex; flex-direction: column; gap: .75rem; }
.contact-fields label { display: flex; flex-direction: column; gap: .25rem; }
.contact-fields label > span {
  color: var(--muted);
  font-size: .85rem;
  font-weight: 500;
}
.contact-fields input:not([type="radio"]):not([type="checkbox"]),
.contact-fields textarea,
.contact-fields select {
  width: 100%;
  padding: .65rem .75rem;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--bg);
  font: inherit;
}
.contact-fields textarea { min-height: 4.5rem; resize: vertical; }

/* Pickup vs delivery, chosen here rather than on the way in. */
.fulfillment-picker {
  display: flex;
  gap: .5rem;
  flex-wrap: wrap;
  margin: 0;
  padding: 0;
  border: 0;
}
.fulfillment-picker legend {
  padding: 0;
  margin-bottom: .35rem;
  color: var(--muted);
  font-size: .85rem;
  font-weight: 500;
}
.fulfillment-option {
  flex: 1 1 8rem;
  flex-direction: row !important;
  align-items: center;
  gap: .55rem;
  padding: .65rem .8rem;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--bg);
  cursor: pointer;
}
.fulfillment-option input { flex: none; width: auto; accent-color: var(--accent); margin: 0; }
.fulfillment-option > span { flex: 1 1 auto; }
.fulfillment-picker:has(input:checked) .fulfillment-option:has(input:checked) {
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 7%, var(--card));
}

/* The address field stays in the DOM so selecting delivery reveals it with
   no round trip. The server-rendered class covers the single-mode case,
   where there are no radios for :has() to read; the :has() rules win over it
   whenever a picker is actually on screen. */
.delivery-address-field { display: none; }
.checkout-panel.is-delivery .delivery-address-field { display: flex; }
.checkout-panel:has(input[name="fulfillment"][value="delivery"]:checked) .delivery-address-field { display: flex; }
.checkout-panel:has(input[name="fulfillment"][value="pickup"]:checked) .delivery-address-field { display: none; }
.contact-fields input:focus,
.contact-fields textarea:focus,
.contact-fields select:focus { outline: none; border-color: var(--accent); }
.contact-fields p { margin: 0; }

.checkout-panel .btn.primary { width: 100%; font-weight: 600; }
.checkout-panel > .muted { margin: 0; text-align: center; }
.cart-actions { align-items: flex-start; }

/* Service channel — only rendered for a guest who is actually at the place. */
.service-panel:empty { display: none; }
.service-panel:not(:empty) {
  padding: 1rem 1.1rem;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--card);
}
.service-heading { margin: 0 0 .6rem; font-size: 1rem; }
.service-actions { display: flex; gap: .5rem; flex-wrap: wrap; }
.service-actions form { display: contents; }
.service-btn { padding: .55rem .9rem; font-size: .9rem; border-radius: 999px; }
.service-flash { margin: 0 0 .6rem; }
.service-message {
  display: flex;
  gap: .5rem;
  margin-top: .75rem;
}
.service-message input {
  flex: 1 1 auto;
  min-width: 0;
  padding: .55rem .75rem;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--bg);
  font: inherit;
}
.service-message input:focus { outline: none; border-color: var(--accent); }
.service-message .btn { padding: .55rem .9rem; font-size: .9rem; white-space: nowrap; }

@media (max-width: 480px) {
  .service-actions .service-btn { flex: 1 1 auto; }
}

/* ---------- Customize page (guest) ---------- */

/* This page had no styles of its own. What it looked like was browser
   defaults plus whatever the admin modifier editor's `.modifier-options`
   rules happened to do to it — a collision, not a decision. The guest
   classes are scoped (`.customize-*`) now, so this block is the whole
   design and the editor can change without reaching the guest. */

.back-link {
  display: inline-block;
  margin-bottom: .35rem;
  color: var(--accent);
  text-decoration: none;
  font-size: .9rem;
}
.back-link:hover { text-decoration: underline; }

.customize { display: flex; flex-direction: column; gap: 1.25rem; margin-top: 1.25rem; }
.customize-form { display: flex; flex-direction: column; gap: .85rem; }

.modifier-fieldset {
  margin: 0;
  padding: .9rem 1rem 1rem;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--card);
}
.modifier-fieldset legend {
  display: flex;
  align-items: center;
  gap: .5rem;
  flex-wrap: wrap;
  padding: 0 .35rem;
  margin-left: -.35rem;
}
.modifier-fieldset .group-title { font-weight: 600; }
.modifier-fieldset .group-rule { color: var(--muted); font-size: .8rem; }
.required-pill {
  padding: .1rem .5rem;
  border-radius: 999px;
  background: rgba(194, 65, 12, .12);
  border: 1px solid rgba(194, 65, 12, .25);
  color: var(--accent);
  font-size: .7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .04em;
}

.customize-options {
  list-style: none;
  margin: .6rem 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: .4rem;
}
/* The label is the target, not the 16px radio inside it. A guest picking a
   size is holding a phone in one hand. */
.option-label {
  display: flex;
  align-items: center;
  gap: .7rem;
  padding: .7rem .8rem;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--bg);
  cursor: pointer;
  transition: border-color .12s ease, background-color .12s ease;
}
.option-label:hover { border-color: #cfcdc4; }
.option-label input {
  flex: none;
  width: 1.15rem;
  height: 1.15rem;
  margin: 0;
  accent-color: var(--accent);
}
/* :has is what makes the selected row read as selected without any JS. */
.customize-option:has(input:checked) .option-label {
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 7%, var(--card));
}
.option-label:has(input:focus-visible) { outline: 2px solid var(--accent); outline-offset: 2px; }
.customize-option-name { flex: 1 1 auto; min-width: 0; }
.customize-option-delta {
  flex: none;
  color: var(--muted);
  font-size: .9rem;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.customize-option:has(input:checked) .customize-option-delta { color: var(--accent); }

/* Quantity left, price + CTA right. Sticky because a product with three
   modifier groups is taller than a phone screen, and the button a guest
   came here to press shouldn't be the part that scrolls away. */
.customize-bar {
  position: sticky;
  bottom: 0;
  z-index: 2;
  display: flex;
  align-items: center;
  gap: .75rem 1rem;
  flex-wrap: wrap;
  padding: .75rem 0 .5rem;
  background: linear-gradient(to top, var(--bg) 72%, transparent);
}
.qty-row { display: flex; align-items: center; gap: .6rem; }
.qty-label { color: var(--muted); font-size: .9rem; }
.qty-stepper {
  display: inline-flex;
  align-items: stretch;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--card);
  overflow: hidden;
}
.qty-stepper:focus-within { border-color: var(--accent); }
.qty-step {
  width: 2.4rem;
  border: 0;
  background: transparent;
  color: var(--fg);
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
}
.qty-step:hover { background: #f1f1ec; color: var(--accent); }
.qty-stepper input {
  width: 3rem;
  padding: .55rem 0;
  border: 0;
  border-inline: 1px solid var(--line);
  background: transparent;
  font: inherit;
  font-variant-numeric: tabular-nums;
  text-align: center;
  /* The native spinners are a duplicate of the two buttons either side of
     them, at a fifth of the size. */
  -moz-appearance: textfield;
  appearance: textfield;
}
.qty-stepper input::-webkit-outer-spin-button,
.qty-stepper input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.qty-stepper input:focus { outline: none; }

.customize-actions { display: flex; align-items: center; gap: .85rem; margin-left: auto; }
.customize-base { display: flex; flex-direction: column; line-height: 1.25; }
.customize-base-label { color: var(--muted); font-size: .75rem; }
.customize-base .price-now { font-weight: 600; font-variant-numeric: tabular-nums; }
.customize-base .price-was { color: var(--muted); font-size: .8rem; }
.customize-actions .btn.primary { padding: .7rem 1.25rem; border-radius: 10px; font-weight: 600; }

/* Menu-only code, or no table scanned: the page ends at the price. */
.customize-price-only {
  margin: 0;
  font-size: 1.15rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.customize-price-only .price-was {
  margin-right: .4rem;
  color: var(--muted);
  font-size: .9rem;
  font-weight: 400;
}

.cross-sell-suggestions h3 { margin: 0 0 .5rem; font-size: 1rem; }
.suggestion-row {
  list-style: none;
  margin: 0;
  padding: 0 0 .35rem;
  display: flex;
  gap: .5rem;
  overflow-x: auto;
}
.suggestion-card { flex: 0 0 auto; }
.suggestion-card a {
  display: flex;
  flex-direction: column;
  gap: .15rem;
  width: 9.5rem;
  padding: .65rem .75rem;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--card);
  color: inherit;
  text-decoration: none;
}
.suggestion-card a:hover { border-color: var(--accent); }

@media (max-width: 480px) {
  .customize-actions { width: 100%; margin-left: 0; justify-content: space-between; }
}

/* ---------- Reviews ---------- */

.stars {
  display: inline-flex;
  gap: .05rem;
  color: #d4a017;
  font-size: 1rem;
  line-height: 1;
  letter-spacing: -1px;
}
.stars .star { color: #d4a017; }
.stars .star:not(.filled) { color: #d4d4cf; }

.review-summary {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  margin: .35rem 0;
  font-size: .9rem;
}
.review-summary .review-avg {
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.review-summary.inline {
  display: flex;
  font-size: .8rem;
  margin: .15rem 0 0;
}
.review-summary.inline .stars { font-size: .85rem; }

.name-link {
  color: inherit;
  text-decoration: none;
}
.name-link:hover { color: var(--accent); }

.reviews {
  margin-top: 2rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--line);
}
.reviews h3 {
  margin: 0 0 .75rem;
  font-size: 1.1rem;
}

.review-list {
  list-style: none;
  padding: 0;
  margin: 1rem 0 0;
  display: flex;
  flex-direction: column;
  gap: .75rem;
}
.review-card {
  padding: .85rem 1rem;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 10px;
}
.review-head {
  display: flex;
  align-items: center;
  gap: .55rem;
  flex-wrap: wrap;
}
.review-name { font-weight: 600; font-size: .9rem; }
.review-date { font-variant-numeric: tabular-nums; }
.review-body {
  margin: .35rem 0 0;
  line-height: 1.45;
  white-space: pre-wrap;
}

/* Star rating picker — radios reversed in DOM so CSS sibling combinators
   light up the chosen star + every star to its left. */
.review-form {
  display: flex;
  flex-direction: column;
  gap: .75rem;
  padding: 1rem;
  background: #fafaf7;
  border: 1px solid var(--line);
  border-radius: 10px;
  margin-bottom: 1rem;
}
.review-form > legend,
.review-form > label > span {
  font-weight: 600;
  font-size: .9rem;
}
.rating-picker {
  border: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: row-reverse;
  justify-content: flex-end;
  gap: .2rem;
}
.rating-picker legend {
  width: 100%;
  margin-bottom: .35rem;
  font-weight: 600;
  font-size: .9rem;
}
.rating-picker input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}
.rating-picker label {
  font-size: 1.8rem;
  line-height: 1;
  color: #d4d4cf;
  cursor: pointer;
  transition: color .1s ease, transform .05s ease;
}
.rating-picker label:hover,
.rating-picker label:hover ~ label,
.rating-picker input:checked ~ label {
  color: #d4a017;
}
.rating-picker label:hover { transform: scale(1.1); }

.review-form textarea,
.review-form input[type="text"] {
  padding: .55rem .75rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: #fff;
  font-size: .95rem;
  font-family: inherit;
  resize: vertical;
}
.review-form textarea:focus,
.review-form input[type="text"]:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(194, 65, 12, .12);
}
.review-form button { align-self: flex-start; }

/* Selects — WebKit paints native chrome (grey gradient + system arrow) over
   the border/background each form rule above already sets, so a select read
   as a different control than the text input beside it. Reset `appearance`
   and draw our own chevron instead.

   This block sits last on purpose: the component rules use the `background`
   shorthand, which would wipe the chevron out if they came after, and their
   shorthand `padding` would eat the room the chevron needs on the right. */
.tenant-form select,
.member-form select,
.product-create select,
.product-edit-form select,
.language-picker select {
  appearance: none;
  -webkit-appearance: none;
  font-family: inherit;
  color: var(--fg);
  background-color: #fff;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8' fill='none' stroke='%236b6b6b' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M1 1.5 6 6.5 11 1.5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right .7rem center;
  background-size: .7rem;
  padding-right: 2rem;
  cursor: pointer;
}
/* The language picker is the one deliberately small, muted select. */
.language-picker select {
  color: var(--muted);
  padding-right: 1.3rem;
  background-position: right .4rem center;
  background-size: .5rem;
}

/* Checkbox rows — box and text on one line, the text reading as a statement
   rather than as the muted caption the other fields put above their input.
   Sits last for the same reason as the select block: the per-form `label`
   rules above stack children in a column, which would drop the text below
   the box. Centred so the row lines up with the field beside it in a
   .two-col pair, where the neighbour is taller (caption + input + hint). */
label.checkbox-label {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: .5rem;
}
label.checkbox-label > span {
  font-size: .95rem;
  color: var(--fg);
}
.checkbox-label input[type="checkbox"] {
  flex: none;
  width: 1.05rem;
  height: 1.05rem;
  margin: 0;
  accent-color: var(--accent);
  cursor: pointer;
}

/* ============================================================
   Admin chrome — top bar, place switcher, sidebar, page furniture.

   The admin used to be a single centred column with a thin header and no
   navigation: each section was reachable only from a row of buttons on the
   settings page, so moving between two sections meant passing through a
   third. This block is the persistent frame that replaced it.

   Everything is scoped under .admin-shell (or body:has(.admin-shell)) so
   the guest menu, which shares this stylesheet, is untouched.
   ============================================================ */

.admin-shell {
  --topbar-h: 3.5rem;
  --nav-w: 15rem;
  --admin-canvas: #f7f6f1;
  --admin-rail: #fbfaf7;
  --admin-nav-fg: #4a463e;
  --admin-nav-muted: #9a978d;
  --admin-tint: color-mix(in srgb, var(--accent) 9%, #fff);
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

body:has(.admin-shell) {
  max-width: none;
  margin: 0;
  padding: 0;
  background: #f7f6f1;
}

/* The admin has its own account chrome and doesn't use the guest picker. */
body:has(.admin-shell) .language-picker { display: none; }

/* ---------- Top bar ---------- */

.admin-topbar {
  position: sticky;
  top: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  gap: .75rem;
  height: var(--topbar-h);
  padding: 0 1rem;
  background: #fff;
  border-bottom: 1px solid var(--line);
}
.admin-logo {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  font-weight: 700;
  color: var(--fg);
  text-decoration: none;
  white-space: nowrap;
}
.admin-logo-mark {
  display: grid;
  place-items: center;
  width: 1.6rem;
  height: 1.6rem;
  border-radius: 7px;
  background: var(--accent);
  color: #fff;
  font-size: .95rem;
  line-height: 1;
}
.admin-topbar-right {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: .75rem;
}
.topbar-link {
  color: var(--muted);
  text-decoration: none;
  font-size: .875rem;
  white-space: nowrap;
}
.topbar-link:hover { color: var(--accent); }

/* ---------- Pop-out menus (place switcher, account) ---------- */

.admin-pop { position: relative; }
.admin-pop > summary {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  padding: .35rem .6rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: #fff;
  font-size: .9rem;
  font-weight: 600;
  color: var(--fg);
  cursor: pointer;
  list-style: none;
  max-width: 15rem;
}
.admin-pop > summary::-webkit-details-marker { display: none; }
.admin-pop > summary:hover { border-color: color-mix(in srgb, var(--accent) 45%, var(--line)); }
.admin-pop[open] > summary {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(194, 65, 12, .12);
}
.switch-label {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.pop-caret { color: var(--muted); font-size: .7rem; }
.admin-pop-panel {
  position: absolute;
  top: calc(100% + .4rem);
  left: 0;
  min-width: 15rem;
  max-height: 70vh;
  overflow-y: auto;
  padding: .35rem;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 11px;
  box-shadow: 0 12px 32px rgba(0, 0, 0, .12);
  z-index: 70;
}
.admin-pop-panel.align-right { left: auto; right: 0; }
.admin-pop-title {
  margin: .3rem .55rem .35rem;
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--admin-nav-muted, #9a978d);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.admin-pop-list { list-style: none; margin: 0; padding: 0; }
.admin-pop-item {
  display: flex;
  flex-direction: column;
  gap: .1rem;
  width: 100%;
  padding: .45rem .55rem;
  border: 0;
  border-radius: 7px;
  background: none;
  font: inherit;
  font-size: .9rem;
  text-align: left;
  color: var(--fg);
  text-decoration: none;
  cursor: pointer;
}
.admin-pop-item:hover { background: #f2f1eb; }
.admin-pop-item.is-current { background: var(--admin-tint, #fdf2ec); color: var(--accent); font-weight: 600; }
.pop-item-meta { font-size: .75rem; color: var(--muted); font-family: ui-monospace, monospace; }
.admin-pop-item.is-current .pop-item-meta { color: inherit; opacity: .75; }
.admin-pop-foot {
  margin-top: .3rem;
  padding-top: .3rem;
  border-top: 1px solid var(--line);
}
.avatar {
  display: grid;
  place-items: center;
  width: 1.75rem;
  height: 1.75rem;
  border-radius: 50%;
  background: var(--accent);
  color: #fff;
  font-size: .8rem;
  font-weight: 700;
}
.admin-account > summary { padding: .25rem .45rem; }

/* ---------- Sidebar ---------- */

.admin-body {
  flex: 1;
  display: grid;
  grid-template-columns: var(--nav-w) minmax(0, 1fr);
  align-items: start;
}
.admin-nav {
  position: sticky;
  top: var(--topbar-h);
  max-height: calc(100vh - var(--topbar-h));
  overflow-y: auto;
  padding: 1rem .6rem 2rem;
  background: var(--admin-rail, #fbfaf7);
  border-right: 1px solid var(--line);
}
.admin-nav-group + .admin-nav-group { margin-top: 1.1rem; }
.admin-nav-title {
  margin: 0 0 .3rem .6rem;
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--admin-nav-muted, #9a978d);
}
.admin-nav-item {
  display: flex;
  align-items: center;
  gap: .55rem;
  padding: .45rem .6rem;
  border-radius: 8px;
  color: var(--admin-nav-fg, #4a463e);
  font-size: .9rem;
  font-weight: 500;
  text-decoration: none;
}
.admin-nav-item + .admin-nav-item { margin-top: .1rem; }
.admin-nav-item:hover { background: #f0efe8; color: var(--fg); }
.admin-nav-item.is-active {
  background: var(--admin-tint, #fdf2ec);
  color: var(--accent);
  font-weight: 650;
}
.admin-nav-item .nav-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nav-icon { width: 1.05rem; height: 1.05rem; flex: none; opacity: .8; }
.admin-nav-item.is-active .nav-icon { opacity: 1; }
.nav-badge {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.25rem;
  height: 1.25rem;
  padding: 0 .35rem;
  border-radius: 999px;
  background: var(--accent);
  color: #fff;
  font-size: .7rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* ---------- Content column ---------- */

.admin-main {
  min-width: 0;
  padding: 1.5rem 1.5rem 4rem;
}
.admin-main > * {
  max-width: 68rem;
  margin-inline: auto;
}
.section-head-text { min-width: 0; }
.section-sub {
  margin: .3rem 0 0;
  max-width: 60ch;
  color: var(--muted);
  font-size: .875rem;
  font-weight: 400;
  line-height: 1.45;
}

@media (max-width: 900px) {
  /* The sidebar becomes a scrollable strip under the top bar: same order,
     same active state, no off-canvas drawer to discover. */
  .admin-body { grid-template-columns: minmax(0, 1fr); }
  .admin-nav {
    position: sticky;
    top: var(--topbar-h);
    z-index: 50;
    display: flex;
    gap: .3rem;
    max-height: none;
    overflow-x: auto;
    overflow-y: hidden;
    padding: .5rem .75rem;
    border-right: 0;
    border-bottom: 1px solid var(--line);
    scrollbar-width: thin;
  }
  .admin-nav-group { display: contents; }
  .admin-nav-title { display: none; }
  .admin-nav-item { white-space: nowrap; flex: none; }
  .admin-nav-item + .admin-nav-item { margin-top: 0; }
  .admin-main { padding: 1rem .75rem 3rem; }
  body:has(.admin-shell) .admin-section { padding: 1rem; border-radius: 12px; }
  .admin-logo-word { display: none; }
}

/* ---------- Places list (account level) ---------- */

.place-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
  gap: .75rem;
}
.place-card {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: #fff;
  overflow: hidden;
}
.place-card:hover { border-color: color-mix(in srgb, var(--accent) 40%, var(--line)); }
.place-open {
  display: flex;
  flex-direction: column;
  gap: .15rem;
  padding: .9rem 1rem;
  color: inherit;
  text-decoration: none;
}
.place-name { font-size: 1rem; }
.place-loc { color: var(--muted); font-size: .85rem; }
.place-slug { color: var(--muted); font-size: .78rem; font-family: ui-monospace, monospace; }
.place-actions {
  display: flex;
  gap: .35rem;
  padding: .55rem .75rem;
  border-top: 1px solid var(--line);
  background: #fbfaf7;
}
.place-actions .btn { padding: .3rem .6rem; font-size: .8rem; }

.empty-state {
  padding: 2.5rem 1rem;
  text-align: center;
  border: 1px dashed var(--line);
  border-radius: 12px;
}
.empty-state h3 { margin: 0 0 .35rem; font-size: 1.05rem; }
.empty-state p { margin: 0 auto 1rem; max-width: 42ch; color: var(--muted); }

/* ---------- Place overview ---------- */

.overview-url {
  display: flex;
  align-items: center;
  gap: .6rem;
  flex-wrap: wrap;
  padding: .6rem .8rem;
  margin-bottom: 0;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: #fbfaf7;
}
.overview-url-label {
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--muted);
}
.overview-url code {
  font-family: ui-monospace, monospace;
  font-size: .875rem;
  word-break: break-all;
}

.stat-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: .75rem;
}
.stat-tile {
  display: flex;
  flex-direction: column;
  gap: .1rem;
  padding: .9rem 1rem;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: #fff;
  color: inherit;
  text-decoration: none;
}
.stat-tile:hover { border-color: color-mix(in srgb, var(--accent) 40%, var(--line)); }
.stat-tile.is-alert {
  border-color: color-mix(in srgb, var(--accent) 45%, var(--line));
  background: var(--admin-tint, #fdf2ec);
}
.stat-n { font-size: 1.75rem; font-weight: 700; line-height: 1.1; font-variant-numeric: tabular-nums; }
.stat-tile.is-alert .stat-n { color: var(--accent); }
.stat-label { font-size: .875rem; font-weight: 600; }
.stat-hint { font-size: .78rem; color: var(--muted); line-height: 1.35; }

.quick-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
  gap: .75rem;
}
.quick-card {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: .15rem .6rem;
  align-items: center;
  padding: .85rem 1rem;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: #fff;
  color: inherit;
  text-decoration: none;
}
.quick-card:hover { border-color: color-mix(in srgb, var(--accent) 40%, var(--line)); }
.quick-card .nav-icon { grid-row: span 2; width: 1.25rem; height: 1.25rem; color: var(--accent); }
.quick-title { font-weight: 600; font-size: .92rem; }
.quick-hint { font-size: .78rem; color: var(--muted); line-height: 1.35; }

/* Setup checklist — the onboarding path, Shopify-style: visible progress,
   every row a link straight to the screen that finishes it. */
.setup-card {
  margin-top: 1.5rem;
  padding: 1rem 1.15rem 1.15rem;
  border: 1px solid color-mix(in srgb, var(--accent) 30%, var(--line));
  border-radius: 12px;
  background: var(--admin-tint, #fdf2ec);
}
.setup-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: .75rem;
  flex-wrap: wrap;
}
.setup-head h3 { margin: 0; font-size: 1rem; }
.setup-progress { font-size: .8rem; color: var(--muted); font-variant-numeric: tabular-nums; }
.setup-list { list-style: none; margin: .75rem 0 0; padding: 0; display: flex; flex-direction: column; gap: .1rem; }
.setup-step {
  display: flex;
  align-items: flex-start;
  gap: .6rem;
  padding: .4rem 0;
}
.setup-check {
  display: grid;
  place-items: center;
  flex: none;
  width: 1.15rem;
  height: 1.15rem;
  margin-top: .1rem;
  border: 1.5px solid color-mix(in srgb, var(--accent) 35%, var(--line));
  border-radius: 50%;
  background: #fff;
  font-size: .7rem;
  line-height: 1;
  color: #fff;
}
.setup-step.is-done .setup-check { background: #166534; border-color: #166534; }
.setup-text { display: flex; flex-direction: column; gap: .05rem; min-width: 0; }
.setup-text a { color: var(--fg); font-weight: 600; font-size: .9rem; }
.setup-step.is-done .setup-text a { color: var(--muted); font-weight: 500; text-decoration-line: line-through; }
.setup-text small { color: var(--muted); font-size: .78rem; }
.setup-optional {
  align-self: flex-start;
  margin-top: .15rem;
  padding: 0 .35rem;
  border-radius: 999px;
  background: rgba(0, 0, 0, .06);
  color: var(--muted);
  font-size: .65rem;
  letter-spacing: .04em;
  text-transform: uppercase;
}

/* ---------- Settings screen ---------- */

/* Jump-to rail. The settings form is long by nature (it is the whole
   configuration of a place); the rail gives it the landmarks a flat scroll
   never had. */
.settings-jump {
  position: sticky;
  top: calc(var(--topbar-h) + .5rem);
  z-index: 20;
  display: flex;
  gap: .3rem;
  overflow-x: auto;
  margin-bottom: 1.25rem;
  padding: .35rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: color-mix(in srgb, #fff 88%, transparent);
  backdrop-filter: blur(6px);
  scrollbar-width: none;
}
.settings-jump::-webkit-scrollbar { display: none; }
.settings-jump a {
  padding: .3rem .7rem;
  border-radius: 999px;
  color: var(--muted);
  font-size: .82rem;
  font-weight: 500;
  text-decoration: none;
  white-space: nowrap;
}
.settings-jump a:hover { background: #f2f1eb; color: var(--fg); }

/* One card look for every settings group, including the fieldsets that
   already had their own border (theme, branding, POS, payments, webhook). */
.settings-card,
.settings-form .theme-picker,
.settings-form .branding-panel,
.settings-form .webhook-block {
  display: flex;
  flex-direction: column;
  gap: .75rem;
  padding: 1.1rem 1.25rem 1.25rem;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: #fff;
  scroll-margin-top: calc(var(--topbar-h) + 3.5rem);
}
.settings-card > legend,
.settings-form .theme-picker > legend,
.settings-form .branding-panel > legend,
.settings-form .webhook-block > legend {
  padding: 0;
  font-size: .95rem;
  font-weight: 700;
  color: var(--fg);
}
.card-hint {
  margin: -.25rem 0 0;
  max-width: 62ch;
  color: var(--muted);
  font-size: .82rem;
  line-height: 1.45;
}
.card-actions { display: flex; align-items: center; gap: .75rem; flex-wrap: wrap; }
.settings-form { gap: 1rem; }

/* Save bar — the form is tall enough that the buttons need to follow you
   down it. */
.settings-form .save-bar {
  position: sticky;
  bottom: 0;
  z-index: 30;
  display: flex;
  align-items: center;
  gap: .75rem;
  flex-wrap: wrap;
  margin: .25rem -1.5rem -1.75rem;
  padding: .85rem 1.5rem;
  border-top: 1px solid var(--line);
  background: color-mix(in srgb, #fff 92%, transparent);
  backdrop-filter: blur(6px);
}
.save-hint { color: var(--muted); font-size: .8rem; }

.welcome-banner {
  padding: 1rem 1.25rem;
  margin-bottom: 1.25rem;
  border: 1px solid color-mix(in srgb, var(--accent) 30%, var(--line));
  border-radius: 12px;
  background: var(--admin-tint, #fdf2ec);
}
.welcome-banner h2 { margin: 0 0 .25rem; font-size: 1.1rem; }
.welcome-banner p { margin: 0; color: var(--muted); max-width: 62ch; }

/* ---------- Developers page ---------- */

.info-card {
  margin-top: 1.5rem;
  padding: 1rem 1.25rem 1.25rem;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: #fbfaf7;
}
.info-card h3 { margin: 0 0 .35rem; font-size: .95rem; }
.kv-list { display: grid; grid-template-columns: auto 1fr; gap: .35rem .9rem; margin: .75rem 0 0; }
.kv-list dt { color: var(--muted); font-size: .82rem; }
.kv-list dd { margin: 0; }
.kv-list code { font-family: ui-monospace, monospace; font-size: .82rem; word-break: break-all; }

@media (max-width: 560px) {
  .kv-list { grid-template-columns: 1fr; gap: .1rem; }
  .kv-list dd { margin-bottom: .5rem; }
  .settings-form .save-bar { margin-inline: -1rem; padding-inline: 1rem; }
}

/* ---------- Admin chrome, follow-ups ---------- */

/* The location card already draws a box; the picker inside it shouldn't
   draw a second one. */
.settings-card > .geo-picker {
  border: 0;
  border-radius: 0;
  padding: 0;
}

/* Two sticky rails one under the other is one too many on a phone, where
   the sidebar has already become a sticky strip. */
@media (max-width: 900px) {
  .settings-jump { position: static; }
}

/* Reduced motion / older engines: backdrop-filter is decoration, the solid
   fallback underneath is what has to stay readable. */
@supports not (backdrop-filter: blur(6px)) {
  .settings-jump,
  .settings-form .save-bar { background: #fff; }
}

/* ============================================================
   Admin panel — in-panel content system.

   The shell gave every screen the same frame. This gives the inside of
   the frame the same vocabulary. Before it the panels drifted badly: the
   menu admin had hand-tuned rows, while promotions, combos, events,
   surveys, analytics and the staff console had good semantic class names
   that no rule ever matched — so they rendered as bulleted lists of bare
   controls next to a carefully styled sidebar.

   Four primitives cover every screen:

     .admin-section h3     a label for a block inside a panel
     .card                 a bordered block — the create and edit forms
     *-list / *-row        one record: media, title + meta, actions
     .badge                status, sitting inline with the title

   Field styling is a :where() baseline (zero specificity) so the older
   hand-tuned forms — product edit, theme picker, geo picker — keep
   winning wherever they deliberately differ.
   ============================================================ */

/* ---------- Buttons: shared behaviour for <a> and <button> ---------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .35rem;
  font-family: inherit;
  line-height: 1.25;
  white-space: nowrap;
  /* Half these are <a> — without this they arrive underlined, which is
     what made "Edit" and "Delete" read as links wearing button costumes. */
  text-decoration: none;
  transition: background-color .12s ease, border-color .12s ease, color .12s ease;
}
.btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.btn[disabled], .btn[aria-disabled="true"] { opacity: .5; cursor: not-allowed; }
.btn.ghost { background: #fff; color: #4a463e; }
.btn.ghost:hover { background: #f6f5f0; border-color: #cfcdc4; color: var(--fg); }
.btn.primary:hover { background: color-mix(in srgb, var(--accent) 88%, #000); }
/* Destructive stays quiet until you reach for it. A row with a
   permanently red button reads as an error state. */
.btn.ghost.danger { color: #8a4a3a; border-color: var(--line); background: #fff; }
.btn.ghost.danger:hover { color: #fff; background: #911; border-color: #911; }

/* ---------- Block labels inside a panel ---------- */

body:has(.admin-shell) .admin-section > h3,
body:has(.admin-shell) .analytics-top > h3,
body:has(.admin-shell) .api-credentials-admin > h3,
body:has(.admin-shell) .members-admin > h3,
body:has(.admin-shell) .attractions-admin > h3,
body:has(.admin-shell) .combo-items-block > h3,
body:has(.admin-shell) .survey-questions > h3 {
  margin: 1.75rem 0 .5rem;
  font-size: .78rem;
  font-weight: 700;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--muted);
}
/* Only the label that opens a panel loses its top margin — using
   :first-of-type collapsed "Existing promotions" against the create card
   above it, because the card's own heading is an h4. */
body:has(.admin-shell) .admin-section > .section-head + h3 { margin-top: 0; }
/* The one-line description that follows a block label. */
body:has(.admin-shell) .admin-section > h3 + p.muted.small,
body:has(.admin-shell) .admin-section > .hint,
body:has(.admin-shell) .api-credentials-admin > .hint,
body:has(.admin-shell) .members-admin > .hint,
body:has(.admin-shell) .attractions-admin > .hint {
  margin: -.25rem 0 .75rem;
  max-width: 70ch;
  color: var(--muted);
  font-size: .82rem;
  line-height: 1.5;
}

/* These three panels used to hang off the bottom of the settings form and
   still carried the dashed rule that separated them from it. Each is its
   own page now, so the rule is a line under nothing. */
body:has(.admin-shell) .members-admin,
body:has(.admin-shell) .api-credentials-admin,
body:has(.admin-shell) .attractions-admin {
  margin-top: 0;
  padding-top: 0;
  border-top: 0;
}

/* ---------- Fields: baseline every admin form inherits ---------- */

:where(body:has(.admin-shell) .admin-section) :where(label) {
  display: flex;
  flex-direction: column;
  gap: .25rem;
  font-size: .82rem;
  color: var(--muted);
}
:where(body:has(.admin-shell) .admin-section) :where(
  input:not([type="checkbox"]):not([type="radio"]):not([type="file"]):not([type="color"]),
  select,
  textarea
) {
  width: 100%;
  padding: .5rem .7rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: #fff;
  font: inherit;
  font-size: .95rem;
  color: var(--fg);
}
:where(body:has(.admin-shell) .admin-section) :where(input, select, textarea):focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(194, 65, 12, .12);
}
:where(body:has(.admin-shell) .admin-section) :where(textarea) {
  min-height: 5rem;
  resize: vertical;
  line-height: 1.45;
}
:where(body:has(.admin-shell) .admin-section) :where(label > span) {
  font-size: .82rem;
  color: var(--muted);
}
:where(body:has(.admin-shell) .admin-section) :where(small) {
  color: var(--muted);
  font-size: .78rem;
  line-height: 1.45;
}

/* ---------- Card: the create / edit block ---------- */

body:has(.admin-shell) .admin-section .card {
  display: flex;
  flex-direction: column;
  gap: .75rem;
  padding: 1rem 1.15rem 1.15rem;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: #fff;
}
body:has(.admin-shell) .admin-section .card > h4 {
  margin: 0;
  font-size: .95rem;
  font-weight: 700;
}
body:has(.admin-shell) .admin-section .card .form-actions {
  align-items: center;
  margin-top: .25rem;
  flex-wrap: wrap;
}
body:has(.admin-shell) .admin-section .form-actions .muted { font-size: .8rem; }

/* ---------- Record rows: one shape for every list ---------- */

.promo-list, .event-list, .survey-list, .combo-list,
.service-list, .order-list, .table-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: .5rem;
}
.promo-row, .event-row, .survey-row, .combo-row,
.service-card, .order-card, .table-row {
  display: flex;
  align-items: center;
  gap: .75rem 1rem;
  flex-wrap: wrap;
  padding: .7rem .9rem;
  border: 1px solid var(--line);
  border-left: 3px solid var(--line);
  border-radius: 10px;
  background: #fff;
  transition: border-color .12s ease, box-shadow .12s ease;
}
.promo-row:hover, .event-row:hover, .survey-row:hover, .combo-row:hover, .table-row:hover {
  box-shadow: 0 1px 2px rgba(0, 0, 0, .04);
  border-color: #cfcdc4;
}
/* The left edge carries state, so a list of twenty scans at a glance. */
.promo-row.live, .event-row.live, .combo-row.live, .survey-row.active { border-left-color: #2f7d4f; }
.promo-row.draft, .event-row.draft, .combo-row.draft, .survey-row.draft { border-left-color: var(--line); }
.event-row.past { border-left-color: var(--line); opacity: .65; }

.promo-main, .event-main, .survey-row-main, .combo-row-main,
.service-card-main, .order-card-main, .table-row-main {
  flex: 1 1 18rem;
  display: flex;
  flex-direction: column;
  gap: .15rem;
  min-width: 0;
}
.promo-title-row, .event-title-row, .survey-title-row, .combo-title-row,
.service-card-head, .order-card-head, .table-title-row {
  display: flex;
  align-items: center;
  gap: .5rem;
  flex-wrap: wrap;
}
.promo-title-row > strong, .event-title-row > strong, .survey-title-row > strong,
.combo-title-row > strong, .service-card-head > strong, .order-card-head > strong {
  font-size: .95rem;
}
.promo-actions, .event-actions, .survey-row-actions, .combo-row-actions,
.service-card-actions, .order-card-actions, .table-row-actions {
  display: flex;
  align-items: center;
  gap: .35rem;
  flex-wrap: wrap;
  margin-left: auto;
}
.promo-actions form, .event-actions form, .survey-row-actions form,
.combo-row-actions form, .publish-toggle { display: contents; }

/* Thumbnail column on event rows. */
.event-thumb {
  flex: none;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: 8px;
  overflow: hidden;
  background: #f2f1eb;
  display: grid;
  place-items: center;
}
.event-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.event-thumb .thumb-placeholder { color: var(--muted); font-weight: 700; font-size: 1rem; }

/* ---------- Badges ---------- */

/* The base class only ever defined variants, so a bare <span class="badge">
   rendered as small caps floating in the row. */
.badge {
  background: #f1f1ec;
  color: #57534a;
  border: 1px solid var(--line);
}
.badge.ack     { background: #eaf3ee; color: #2f7d4f; border-color: #cfe3d7; }
.badge.new     { background: rgba(194, 65, 12, .12); color: var(--accent); border-color: rgba(194, 65, 12, .25); }
.badge.past    { background: #f1f1ec; color: var(--muted); }
/* A marketplace order that broke one of our modifier-group selection rules.
   Amber, not red: the order is valid and already paid — someone just has to
   fill in a choice the marketplace never asked the guest to make.

   The base .badge is built for one-word statuses (NEW, ACCEPTED), so it
   uppercases and letter-spaces its content. This one carries a sentence —
   "Size: pick at least 1, got 0" — which in caps reads as shouting and scans
   worse than the order line it sits next to. Keep the pill, drop the caps. */
.badge.rule-gap {
  background: #fdf4e3;
  color: #8a5a12;
  border-color: #efdcb4;
  font-weight: 500;
  font-size: .75rem;
  text-transform: none;
  letter-spacing: normal;
}
.email-status  { align-self: flex-start; }

/* ---------- Staff console ---------- */

.service-console > h3 { margin-top: 2rem; }
.service-console > h3:first-of-type { margin-top: 0; }
.service-empty {
  padding: 1.25rem;
  border: 1px dashed var(--line);
  border-radius: 10px;
  text-align: center;
}
/* Kind and urgency read off the left edge — the one thing a phone propped
   on the pass has to communicate across the kitchen. */
.service-card.kind-call { border-left-color: var(--accent); }
.service-card.kind-bill { border-left-color: #1a73e8; }
.service-card.kind-message { border-left-color: #8a8a80; }
.order-card.kind-delivery { border-left-color: var(--accent); }
.order-card.kind-pickup { border-left-color: #1a73e8; }
.order-card.kind-room_service { border-left-color: #7a4fbf; }
.service-card, .order-card { align-items: flex-start; }
.service-kind, .order-dest { font-size: .95rem; }
.service-table {
  padding: .1rem .5rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  font-size: .75rem;
  color: var(--muted);
}
.service-body { margin: .25rem 0 0; line-height: 1.45; }
.order-total { margin-left: auto; font-weight: 700; font-variant-numeric: tabular-nums; }
.order-items {
  list-style: none;
  margin: .4rem 0 .25rem;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: .1rem;
  font-size: .9rem;
}
.order-items .q { display: inline-block; min-width: 2rem; color: var(--muted); font-variant-numeric: tabular-nums; }
/* The chosen options. Dimmer than the product name, but not .muted — on the
   pass "Pizza, Velika" is one instruction to read, not an aside about one.

   The gap is a margin, not a space in the markup: templ emits these spans
   adjacent with no whitespace between them, which is also why .badge carries
   its own margin-left rather than trusting the template. */
.order-items .mods { margin-left: .35rem; color: #57534a; }
.order-items .mods::before { content: "· "; color: var(--muted); }
.order-contact { margin: .2rem 0 0; }

/* ---------- Analytics ---------- */

.analytics-funnel {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
  gap: .75rem;
}
.funnel-stat {
  display: flex;
  flex-direction: column;
  gap: .1rem;
  padding: .9rem 1rem;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: #fff;
}
.funnel-n { font-size: 1.75rem; font-weight: 700; line-height: 1.1; font-variant-numeric: tabular-nums; }
.funnel-label { font-size: .8rem; }
.analytics-conversion {
  margin: .75rem 0 0;
  padding: .6rem .9rem;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: #fbfaf7;
}
.analytics-tops {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr));
  gap: 1.5rem;
}
.analytics-list {
  list-style: none;
  margin: 0;
  padding: 0;
  counter-reset: rank;
  display: flex;
  flex-direction: column;
}
.analytics-row {
  counter-increment: rank;
  display: grid;
  grid-template-columns: 1.25rem 1fr auto;
  align-items: center;
  gap: .6rem;
  padding: .5rem 0;
  border-bottom: 1px solid var(--line);
  font-size: .92rem;
}
.analytics-row:last-child { border-bottom: 0; }
.analytics-row::before {
  content: counter(rank);
  color: var(--muted);
  font-size: .78rem;
  font-variant-numeric: tabular-nums;
}
.an-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.an-count { color: var(--muted); font-variant-numeric: tabular-nums; font-size: .85rem; }

/* ---------- Survey builder + results ---------- */

.survey-question-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: .35rem;
}
.survey-question-row {
  display: flex;
  align-items: center;
  gap: .75rem;
  padding: .55rem .8rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: #fff;
}
.survey-question-row > :first-child { flex: 1; min-width: 0; }
.result-question { gap: .5rem; }
.result-option-list, .result-text-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: .3rem;
}
.result-option-list li {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: .6rem;
  padding: .35rem 0;
  border-bottom: 1px solid var(--line);
  font-size: .92rem;
}
.result-option-list li:last-child { border-bottom: 0; }
.ro-count { color: var(--muted); font-variant-numeric: tabular-nums; }
.result-text-list li {
  padding: .5rem .75rem;
  border-left: 2px solid var(--line);
  background: #fbfaf7;
  border-radius: 0 8px 8px 0;
  font-size: .92rem;
  line-height: 1.45;
}

/* ---------- Combos: the item picker on the edit page ---------- */

.combo-item-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: .35rem;
}
.combo-item-row {
  display: flex;
  align-items: center;
  gap: .75rem;
  padding: .5rem .8rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: #fff;
}
.combo-item-row > :first-child { flex: 1; }
.combo-qty { color: var(--muted); font-variant-numeric: tabular-nums; }
.combo-item-add { display: flex; gap: .5rem; align-items: flex-end; flex-wrap: wrap; }
.combo-item-add label { flex: 1 1 12rem; }

/* ---------- Menu admin: the category row regained a wrapper ---------- */

/* .cat-row was a 3-column grid back when grip / name / delete were its
   direct children. They live in .cat-row-main now, so the grid was laying
   out one child and the row grew to fit a stack. */
.cat-row {
  display: flex;
  flex-direction: column;
  /* The grid rule above also set align-items:center, which in a column
     flex centres the children instead of the (former) grid cells. */
  align-items: stretch;
  gap: .15rem;
  padding: .3rem .5rem .35rem;
}
.cat-row-main {
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: .35rem;
  align-items: center;
}
.cat-bg-details > summary {
  padding: .1rem 0 .1rem 1.6rem;
  color: var(--muted);
  font-size: .75rem;
  cursor: pointer;
  list-style: none;
}
.cat-bg-details > summary::-webkit-details-marker { display: none; }
.cat-bg-details > summary::before { content: "▸ "; }
.cat-bg-details[open] > summary::before { content: "▾ "; }
.cat-bg-details > summary:hover { color: var(--accent); }

/* ---------- Developers: label the credential field like every other ---------- */

/* Field, then button underneath — the same shape as every other "add"
   form in the admin. Side by side, the button baselined against the
   label's hint text rather than its input. */
.api-credential-form {
  align-items: flex-start;
  padding-top: .75rem;
  border-top: 1px solid var(--line);
}
.api-credential-form label { align-self: stretch; }

/* ---------- Sidebar: run the rail the full height of the page ---------- */

/* max-height left the column as tall as its content, so the divider
   stopped mid-page and the rail looked like it had come loose. */
.admin-nav { height: calc(100vh - var(--topbar-h)); }
@media (max-width: 900px) { .admin-nav { height: auto; } }

/* ---------- Admin panel: last-mile corrections ---------- */

/* These panels mark their busy text with a data attribute rather than
   htmx's own `.htmx-indicator` class, and nothing ever hid it — so
   "Working…" and "Working… (5–15s)" sat permanently beside buttons that
   weren't doing anything. */
[data-htmx-indicator] { display: none; }
.htmx-request [data-htmx-indicator],
.htmx-request[data-htmx-indicator] { display: inline; }

/* A button inside a column-flex label or card is a control, not a field:
   it should size to its text instead of stretching the full width the way
   the input above it does. */
body:has(.admin-shell) .admin-section label > button,
body:has(.admin-shell) .admin-section label > .btn,
body:has(.admin-shell) .admin-section .card > button,
body:has(.admin-shell) .admin-section .card > .btn,
body:has(.admin-shell) .admin-section .settings-card > button,
body:has(.admin-shell) .admin-section .settings-card > .btn {
  align-self: flex-start;
}

/* Save confirmation reads as a result, not as a stray green sentence. */
body:has(.admin-shell) .admin-section > .status-line.ok,
body:has(.admin-shell) .admin-section > .status-line.bad {
  margin: 0 0 1rem;
  padding: .55rem .85rem;
  border: 1px solid;
  border-radius: 10px;
  font-size: .9rem;
}
body:has(.admin-shell) .admin-section > .status-line.ok {
  border-color: #cfe3d7;
  background: #f2f8f4;
}
body:has(.admin-shell) .admin-section > .status-line.bad {
  border-color: #e6c9c4;
  background: #fdf4f2;
}

/* ---------- Edit pages: the blocks the product page had and the rest didn't ---------- */

/* The event editor was written to mirror the product editor — aside on the
   left, form on the right — but only the product grid ever got a rule, so
   the photo block stacked above a full-width form. */
.event-edit-grid {
  display: grid;
  grid-template-columns: minmax(220px, 280px) 1fr;
  gap: 1.5rem;
  align-items: start;
}
@media (max-width: 820px) {
  .event-edit-grid { grid-template-columns: 1fr; }
}
.event-edit-aside { position: sticky; top: calc(var(--topbar-h) + 1rem); }
.event-image-block { display: flex; flex-direction: column; gap: .75rem; }
.event-image-preview {
  width: 100%;
  aspect-ratio: 4 / 3;
  border-radius: 12px;
  overflow: hidden;
  background: #f1f1ec;
  display: grid;
  place-items: center;
}
.event-image-preview img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* Upload boxes read as one affordance rather than three loose controls. */
.image-upload, .event-image-upload {
  display: flex;
  flex-direction: column;
  gap: .5rem;
  padding: .85rem;
  border: 1px dashed var(--line);
  border-radius: 12px;
  background: #fbfaf7;
}
.image-title {
  margin: 0;
  font-size: .8rem;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--muted);
}
.image-upload input[type="file"],
.event-image-upload input[type="file"] { font-size: .82rem; }

/* Cross-sell picker on the product page: same row shape as everywhere else. */
.cross-sell-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: .35rem;
}
.cross-sell-row {
  display: flex;
  align-items: center;
  gap: .75rem;
  padding: .45rem .75rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: #fff;
}
.cross-sell-row > :first-child { flex: 1; min-width: 0; }
.cross-sell-add, .survey-question-add {
  display: flex;
  align-items: flex-end;
  gap: .5rem;
  flex-wrap: wrap;
}
.cross-sell-add select, .cross-sell-add label { flex: 1 1 14rem; }
.survey-question-add { flex-direction: column; align-items: stretch; }

.modifier-editor { display: flex; flex-direction: column; gap: 1rem; }
.markdown-editor { display: flex; flex-direction: column; gap: .25rem; }

/* ---------- Modifier editor ---------- */

.modifier-groups {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: .75rem;
}
.modifier-group {
  display: flex;
  flex-direction: column;
  gap: .5rem;
  padding: .85rem 1rem 1rem;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: #fff;
}
.group-head,
.modifier-options > li,
.modifier-option-create,
.modifier-group-create {
  display: flex;
  align-items: center;
  gap: .5rem;
  flex-wrap: wrap;
}
.group-name, .option-name { flex: 1 1 10rem; width: auto; }
.option-delta, .modifier-option-create input[type="number"] { flex: 0 0 6rem; width: 6rem; }
.bound { flex: 0 0 auto; flex-direction: row; align-items: center; gap: .35rem; }
.bound input { width: 4.5rem; }
.modifier-options {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: .35rem;
}
.modifier-options > li {
  padding: .4rem .6rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: #fbfaf7;
}
.modifier-options > li > form {
  display: contents;
}
.modifier-option-create input[type="text"],
.modifier-group-create input[type="text"] { flex: 1 1 10rem; width: auto; }
.modifier-option-create, .modifier-group-create {
  padding-top: .6rem;
  border-top: 1px dashed var(--line);
}
.modifier-group-create { padding: .85rem 1rem; border: 1px dashed var(--line); border-radius: 12px; }

/* Checklist rows are targets, not prose — the browser's link underline made
   the two outstanding steps look like an error message. */
.setup-text a { text-decoration: none; }
.setup-text a:hover { text-decoration: underline; }

/* The tenant form element is intentionally empty — its fields join it by
   `form="tenant-form"` so the Theme and Branding panels can keep their own
   HTMX sub-forms without HTML's no-nested-forms rule closing the outer one
   early. Nothing to lay out, so take it out of the flex flow. */
.settings-form > form#tenant-form { display: none; }

/* ---------------------------------------------------------------------------
   Buyer sign-in and account pages.

   The sign-in methods reuse .auth-page / .provider-list / .email-login from
   the merchant login screen — the two pages differ in chrome and copy, not in
   the shape of a "pick how you want to sign in" form, and keeping one set of
   rules means a provider button can't look right on one and wrong on the
   other.
--------------------------------------------------------------------------- */

.phone-login,
.phone-code { display: flex; flex-direction: column; gap: .5rem; margin: 0 auto; max-width: 22rem; text-align: left; }
.phone-login label,
.phone-code label { font-size: .8rem; color: var(--muted); }
.phone-login input,
.phone-code input {
  padding: .65rem .8rem;
  border: 1px solid var(--line);
  border-radius: 10px;
  font: inherit;
  background: var(--card);
}
.phone-login input:focus,
.phone-code input:focus { outline: none; border-color: var(--accent); }
.phone-login .btn,
.phone-code .btn { width: 100%; }
/* The code is the only thing on the page worth looking at — space the digits
   so a six-character string reads as six characters. */
.phone-code input { font-size: 1.4rem; letter-spacing: .35em; text-align: center; }

.order-verification {
  display: flex;
  flex-direction: column;
  gap: .75rem;
  padding: 1rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  text-align: center;
}
.order-verification h3,
.order-verification p { margin: 0; }
.order-verification > form:not(.phone-code) .btn { width: 100%; }

/* Sign-in / account affordance in the brand header. Quiet by design: it sits
   next to the tagline and must not compete with the menu itself. */
.buyer-nav { margin: .35rem 0 0; font-size: .85rem; }
.buyer-nav a { color: var(--muted); }
.buyer-nav a:hover { color: var(--accent); }
.menu-brand .buyer-nav { margin: 0 0 0 auto; }
.menu-brand .buyer-nav a {
  display: inline-flex;
  align-items: center;
  min-height: 1.75rem;
  padding: .15rem 0;
  border: 0;
  border-bottom: 1px solid var(--line);
  border-radius: 0;
  background: transparent;
  color: var(--fg);
  font-size: var(--t-md);
  font-weight: 550;
  text-decoration: none;
}
.menu-brand .buyer-nav a:hover {
  border-color: var(--accent);
  color: var(--accent);
}
.menu-brand a:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.buyer-account { padding-bottom: 2rem; }
.buyer-account h2 { font-size: 1.05rem; margin: 1.75rem 0 .6rem; }
.buyer-account h3 { font-size: .9rem; margin: 0 0 .5rem; }
.buyer-profile {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1rem 0;
  border-bottom: 1px solid var(--line);
}
.buyer-identity { margin: 0; font-weight: 500; }

.address-list,
.order-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .6rem; }

.address-row,
.order-row {
  padding: .8rem 1rem;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--card);
}
.address-row {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
}
/* The default address is the one that prefills checkout, so it earns a tint
   rather than only a badge — the row people scan for is the row they need. */
.address-row.is-default { border-color: var(--accent); background: #fffaf7; }
.address-body { min-width: 0; }
.address-body p { margin: .2rem 0 0; }
.address-actions { display: flex; flex-direction: column; gap: .35rem; flex: 0 0 auto; }

.address-form {
  display: flex;
  flex-direction: column;
  gap: .6rem;
  margin-top: 1rem;
  padding: 1rem;
  border: 1px dashed var(--line);
  border-radius: 12px;
}
.address-form label { display: flex; flex-direction: column; gap: .25rem; }
.address-form label > span { font-size: .8rem; color: var(--muted); }
.address-form input,
.address-form textarea {
  padding: .55rem .7rem;
  border: 1px solid var(--line);
  border-radius: 10px;
  font: inherit;
  background: var(--card);
}
.address-form textarea { min-height: 3.5rem; resize: vertical; }
.address-form input:focus,
.address-form textarea:focus { outline: none; border-color: var(--accent); }

.order-head { display: flex; align-items: baseline; gap: .6rem; flex-wrap: wrap; }
.order-items { list-style: none; margin: .4rem 0 .6rem; padding: 0; }

/* The saved-address picker sits above the contact inputs it fills. Full width
   so it lines up with them rather than reading as a stray control. */
.saved-address-picker {
  width: 100%;
  padding: .55rem .7rem;
  border: 1px solid var(--line);
  border-radius: 10px;
  font: inherit;
  background: var(--card);
}


/* ---------- Tables & QR codes (admin) ---------- */

.tables-admin { display: flex; flex-direction: column; gap: 1rem; }
.table-form { display: flex; flex-direction: column; gap: .75rem; }

/* The left edge already carries state on every other row list; here it
   carries the one thing this screen is about. */
.table-row.menu-only { border-left-color: #9a8fb8; }
.table-row:not(.menu-only) { border-left-color: #2f7d4f; }

/* The code itself, at the size you can tell two of them apart at. */
.table-qr-thumb {
  flex: none;
  width: 3.75rem;
  height: 3.75rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: #fff;
  padding: 2px;
}
.table-url {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .75rem;
  overflow-wrap: anywhere;
}
.table-mode-form { display: flex; align-items: center; gap: .35rem; }
.table-mode-select {
  padding: .35rem .5rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--card);
  font: inherit;
  font-size: .85rem;
}
.table-mode-select:focus { outline: none; border-color: var(--accent); }

/* ---------- Table QR print sheet ---------- */

.qr-sheet { padding: 1.5rem 0 3rem; }
.qr-sheet-head { display: flex; flex-direction: column; align-items: flex-start; gap: .35rem; margin-bottom: 1.5rem; }
.qr-sheet-head h1 { margin: 0; font-size: 1.4rem; }
.qr-sheet-head p { margin: 0; }
.qr-sheet-head .btn { margin-top: .5rem; }
.qr-cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
  gap: 1rem;
}
.qr-card {
  margin: 0;
  padding: 1rem;
  border: 1px dashed var(--line);
  border-radius: 12px;
  background: #fff;
  text-align: center;
  /* Never split a code across a page break — half a QR is not a QR. */
  break-inside: avoid;
}
.qr-card img { display: block; width: 100%; height: auto; max-width: 15rem; margin: 0 auto; }
.qr-card figcaption { display: flex; flex-direction: column; gap: .15rem; margin-top: .5rem; }
.qr-card strong { font-size: 1.35rem; }
.qr-card-brand { color: var(--muted); font-size: .85rem; }
.qr-card-hint { font-size: .8rem; }

@media print {
  /* The sheet is the page when it's on paper: no language switcher, no
     "Print" button, and none of the 720px body column the screen wants. */
  .no-print, .language-picker { display: none !important; }
  body { max-width: none; padding: 0; background: #fff; }
  .qr-sheet { padding: 0; }
  .qr-card { border-style: solid; border-color: #ddd; }
}
