/* ============================================================================
   Storefront — on top of Bootstrap + shared/theme.css.

   The look is "precise retail": a cool grey canvas, white cards separated by
   hairlines rather than shadows, one grotesque carrying display and UI, and a
   mono face carrying every figure and micro-label. The tenant's brand colour
   is the only hue, so it always reads as the brand.

   Two devices tie the system together and both are built from tokens, so they
   survive every skin and every brand colour:

   1. The MONOGRAM. An item with no photo is not a hole in the grid — it gets
      a generated tile: its initials set huge in the display face over a fine
      brand-tinted hatch. The hero repeats the same treatment at page scale
      with the shop's own initial, so a text-only catalog looks authored
      rather than unfinished.
   2. The INDEX. Categories are numbered in mono (01 / 02 / 03) in the rail and
      again on the section heads. A catalog genuinely is an ordered list, so
      the numbering carries real structure rather than decorating it.
   ============================================================================ */

/* ---------------------------------------------------------------------------
   Scrollbars — the last piece of native chrome on the page, so it gets skinned
   like everything else.

   The contract is six tokens, resolved on whatever element is scrolling. The
   defaults derive from the neutral palette, so a skin that only re-points
   --surface-2/--line-strong (every dark theme does) gets a matching scrollbar
   for free; a skin with an opinion overrides the tokens directly.

   Cascade: these defaults -> .mode-* (store type) -> .theme-* (skin file, which
   loads last). The classes live on BOTH <html> and <body>: the document
   scrollbar is painted by the root element, which inherits nothing from body.

   Only fine pointers get the treatment. Defining ::-webkit-scrollbar opts the
   element out of overlay scrollbars, which on touch would turn an invisible
   bar into a permanent one.
   --------------------------------------------------------------------------- */
:root {
  --scrollbar-size: 12px;                    /* thickness of the track */
  --scrollbar-gutter: 3px;                   /* transparent inset around thumb */
  --scrollbar-radius: var(--r-pill);
  --scrollbar-track: var(--surface-2);
  --scrollbar-thumb: var(--line-strong);
  --scrollbar-thumb-hover: color-mix(in srgb, var(--primary) 60%, var(--line-strong));
  --scrollbar-std-width: auto;               /* auto | thin | none (Firefox path) */
}

/* Store type, for the skins that don't state a preference (classic serves both).
   A menu is one long read, so it gets a bar you can grab; a catalog is browsed
   in a grid, so the bar stays out of the way. */
.mode-restaurant { --scrollbar-size: 13px; }
.mode-products   { --scrollbar-size: 10px; --scrollbar-gutter: 2px; }

@media (pointer: fine) {
  /* Colour-only path for engines without the WebKit pseudo-elements (Firefox).
     It is gated because Chromium and Safari support BOTH, and there the
     standard properties win outright — setting scrollbar-color would cost us
     the size, radius and inset below, and hand back the stepper arrows. */
  @supports not selector(::-webkit-scrollbar) {
    html, .modal-body, .offcanvas-body, .scroll-skin {
      scrollbar-width: var(--scrollbar-std-width);
      scrollbar-color: var(--scrollbar-thumb) var(--scrollbar-track);
    }
  }

  html::-webkit-scrollbar,
  .modal-body::-webkit-scrollbar,
  .offcanvas-body::-webkit-scrollbar,
  .scroll-skin::-webkit-scrollbar {
    width: var(--scrollbar-size);
    height: var(--scrollbar-size);
  }
  /* Customising the scrollbar drops WebKit back to its legacy widget, which
     brings stepper arrows with it. Nothing else on the page has them. */
  html::-webkit-scrollbar-button,
  .modal-body::-webkit-scrollbar-button,
  .offcanvas-body::-webkit-scrollbar-button,
  .scroll-skin::-webkit-scrollbar-button {
    display: none;
    width: 0;
    height: 0;
  }
  html::-webkit-scrollbar-track,
  .modal-body::-webkit-scrollbar-track,
  .offcanvas-body::-webkit-scrollbar-track,
  .scroll-skin::-webkit-scrollbar-track,
  html::-webkit-scrollbar-corner,
  .modal-body::-webkit-scrollbar-corner,
  .offcanvas-body::-webkit-scrollbar-corner,
  .scroll-skin::-webkit-scrollbar-corner {
    background: var(--scrollbar-track);
  }
  /* The inset is a transparent border with the paint clipped to the content
     box — that is what lets the thumb sit inside the track at any thickness. */
  html::-webkit-scrollbar-thumb,
  .modal-body::-webkit-scrollbar-thumb,
  .offcanvas-body::-webkit-scrollbar-thumb,
  .scroll-skin::-webkit-scrollbar-thumb {
    background: var(--scrollbar-thumb);
    background-clip: content-box;
    border: var(--scrollbar-gutter) solid transparent;
    border-radius: var(--scrollbar-radius);
  }
  html::-webkit-scrollbar-thumb:hover,
  .modal-body::-webkit-scrollbar-thumb:hover,
  .offcanvas-body::-webkit-scrollbar-thumb:hover,
  .scroll-skin::-webkit-scrollbar-thumb:hover {
    background: var(--scrollbar-thumb-hover);
    background-clip: content-box;
  }
}

/* Skip-to-content link: off-screen until focused. */
.skip-link {
  position: absolute; left: 1rem; top: -3rem; z-index: 2000;
  background: var(--primary); color: var(--brand-contrast);
  padding: 0.55rem 1rem; border-radius: var(--r-sm);
  font-family: var(--font-mono); font-size: 0.78rem;
  text-transform: uppercase; letter-spacing: var(--track-label);
  text-decoration: none;
  transition: top var(--transition);
}
.skip-link:focus { top: 0.5rem; color: var(--brand-contrast); box-shadow: var(--shadow); }

/* ---------------------------------------------------------------------------
   Header — a slim hairline bar. No shadow: the rule does the separating.
   --------------------------------------------------------------------------- */
.site-header { z-index: 1030; }

.navbar {
  --bs-navbar-padding-y: 0.55rem;
  background: color-mix(in srgb, var(--surface) 88%, transparent) !important;
  backdrop-filter: saturate(1.5) blur(14px);
  border-bottom: var(--hair) solid var(--line) !important;
}
.navbar-brand {
  font-family: var(--font-display);
  font-size: 1.12rem; font-weight: 700;
  letter-spacing: var(--track-display);
  color: var(--ink);
}
.navbar-brand:hover { color: var(--ink); }
.navbar-brand .logo { height: 30px; width: auto; }

.navbar .nav-link {
  font-size: 0.92rem; font-weight: 600; color: var(--ink-2);
  border-radius: var(--r-sm); padding: 0.35rem 0.7rem;
  transition: color var(--transition), background var(--transition);
}
.navbar .nav-link:hover { color: var(--ink); background: var(--surface-2); }

/* Utility links read as the quiet, functional layer they are. */
.navbar .btn-link {
  font-family: var(--font-mono);
  font-size: 0.74rem; font-weight: 500;
  text-transform: uppercase; letter-spacing: var(--track-label);
  color: var(--ink-2); padding-inline: 0.55rem;
}
.navbar .btn-link:hover { color: var(--ink); }

/* Auth-dependent header items. The signed-out set is the default, so the
   header is correct with JS off and correct for the anonymous visitor the
   cached HTML was rendered for; `is-authed` (set in <head> from the stored
   token) swaps the pair before the first paint rather than after a round
   trip, which is what used to flash. */
.js-auth-in { display: none; }
html.is-authed .js-auth-in { display: block; }
html.is-authed .js-auth-out { display: none; }

/* ---------------------------------------------------------------------------
   Password strength meter. Four segments that fill as the estimate rises —
   feedback on how strong the password is, never a gate on its shape.
   --------------------------------------------------------------------------- */
.pw-meter { margin-top: 0.5rem; }
.pw-meter__track { display: flex; gap: 0.25rem; }
.pw-meter__track span {
  flex: 1; height: 0.25rem; border-radius: 999px;
  background: var(--line);
  transition: background var(--transition);
}
.pw-meter__text {
  margin: 0.35rem 0 0; font-size: 0.78rem; color: var(--ink-2);
  min-height: 1.1em;   /* reserve the line so the form doesn't jump */
}
/* One hue per level, dimmest to brightest. The "too short" level deliberately
   fills nothing: there is no partial credit below the minimum. */
.pw-meter[data-level="1"] .pw-meter__track span:nth-child(-n+1),
.pw-meter[data-level="2"] .pw-meter__track span:nth-child(-n+2),
.pw-meter[data-level="3"] .pw-meter__track span:nth-child(-n+3),
.pw-meter[data-level="4"] .pw-meter__track span { background: var(--pw-fill); }
.pw-meter[data-level="0"] { --pw-fill: var(--line); }
.pw-meter[data-level="1"] { --pw-fill: #c0392b; }
.pw-meter[data-level="2"] { --pw-fill: #d68910; }
.pw-meter[data-level="3"] { --pw-fill: #4b8b3b; }
.pw-meter[data-level="4"] { --pw-fill: #2e7d32; }
.pw-meter[data-level="0"] .pw-meter__text { color: var(--ink-2); }

/* Profile dropdown: fit the menu to its items (Bootstrap defaults to a 10rem
   minimum, which left a wide empty gutter next to two short labels). */
#account-menu .dropdown-menu {
  min-width: max-content;
  border-color: var(--line);
  border-radius: var(--r);
  box-shadow: var(--shadow);
  padding: 0.3rem;
}
#account-menu .dropdown-item { padding: 0.4rem 0.9rem; border-radius: var(--r-xs); font-size: 0.9rem; }

/* The cart is the one solid control in the header — it is the page's job. */
#cart-button {
  position: relative;
  --bs-btn-bg: var(--ink);
  --bs-btn-border-color: var(--ink);
  --bs-btn-color: var(--surface);
  --bs-btn-hover-bg: var(--primary);
  --bs-btn-hover-border-color: var(--primary);
  --bs-btn-hover-color: var(--brand-contrast);
  --bs-btn-active-bg: var(--brand-strong);
  --bs-btn-active-border-color: var(--brand-strong);
  --bs-btn-active-color: var(--brand-contrast);
  --bs-btn-border-radius: var(--r-pill);
  --bs-btn-padding-x: 0.95rem;
  font-size: 0.82rem; letter-spacing: 0.02em;
}
#cart-button .bi-bag { display: inline-block; }
/* Icon and count only on a phone, beside the menu button: the word would
   crowd a long business name off the bar. */
@media (max-width: 575.98px) { #cart-button .cart-button__text { display: none; } }
#cart-button.has-items .bi-bag { animation: cart-wiggle 5s ease-in-out infinite; }
@keyframes cart-wiggle {
  0%, 88%, 100% { transform: rotate(0) scale(1); }
  91% { transform: rotate(-11deg) scale(1.1); }
  94% { transform: rotate(9deg) scale(1.1); }
  97% { transform: rotate(-5deg) scale(1.05); }
}
#cart-count {
  top: 0.2rem;
  font-family: var(--font-mono); font-size: 0.62rem;
  background: var(--primary) !important; color: var(--brand-contrast) !important;
  border: 2px solid var(--surface);
  padding: 0.1rem 0.35rem;
}
#cart-count:empty, #cart-count[data-empty="true"] { display: none; }

/* ---------------------------------------------------------------------------
   Announcement bar
   --------------------------------------------------------------------------- */
.announce-bar {
  display: flex; align-items: center; justify-content: center;
  padding: 0.45rem 1rem;
  background: var(--ink); color: var(--surface);
  font-family: var(--font-mono); font-size: 0.74rem;
  text-transform: uppercase; letter-spacing: var(--track-label);
  text-align: center;
}
.announce-bar__text { margin: 0; }
.announce-bar__link {
  color: var(--brand-contrast); font-weight: 500;
  text-decoration: underline; text-underline-offset: 3px;
}

/* ---------------------------------------------------------------------------
   Hero — "the counter". A status line, the shop's name at full size, and the
   shop's own initial ghosted into the panel with the same hatch the monogram
   tiles use. No stock gradient blobs: the identity is typographic.
   --------------------------------------------------------------------------- */
.hero {
  position: relative;
  overflow: hidden;
  border-radius: var(--r-xl);
  border: var(--hair) solid var(--line);
  background: var(--surface);
  padding: clamp(1.5rem, 3.4vw, 2.75rem);
}
/* The shop monogram. Sits in the panel's right third, clipped by the corner,
   and is filled with the very hatch the item tiles use — the letter is drawn
   in stripes rather than in flat colour, so hero and grid read as one device
   at two scales. */
.hero__mark {
  position: absolute; right: clamp(0.5rem, 2.5vw, 3rem); top: 50%;
  translate: 0 -50%;
  font-family: var(--font-display); font-weight: 800;
  font-size: clamp(7rem, 17vw, 13rem); line-height: 1;
  letter-spacing: -0.06em;
  background-image: repeating-linear-gradient(45deg,
    color-mix(in srgb, var(--primary) 26%, transparent) 0 2px,
    transparent 2px 10px);
  -webkit-background-clip: text; background-clip: text;
  color: transparent;
  pointer-events: none; user-select: none;
  z-index: 0;
}
.hero__inner { position: relative; z-index: 1; max-width: 40rem; }

/* Live status: a dot, the word, the hours. Real information, set as data. */
.eyebrow {
  display: inline-flex; align-items: center; gap: 0.5rem;
  font-family: var(--font-mono);
  font-size: 0.72rem; font-weight: 500;
  letter-spacing: var(--track-label); text-transform: uppercase;
  color: var(--ink-2);
  margin-bottom: 1.1rem;
}
.eyebrow::before {
  content: ""; width: 0.45rem; height: 0.45rem; border-radius: 50%;
  background: var(--success); flex: none;
  box-shadow: 0 0 0 0 color-mix(in srgb, var(--success) 55%, transparent);
  animation: status-pulse 2.8s ease-out infinite;
}
/* Closed is a state, not a skin choice, so it has to outrank the skins: five
   of them restyle `.eyebrow::before` from a `body.theme-x` prefix and load
   after this file, which used to leave a live brand dot pulsing beside a
   notice saying ordering is paused. The class is repeated to buy the
   specificity that beats them. */
.eyebrow.is-closed.is-closed { color: var(--ink-3); }
.eyebrow.is-closed.is-closed::before {
  background: var(--ink-3);
  box-shadow: none;
  animation: none;
}
@keyframes status-pulse {
  0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--success) 55%, transparent); }
  70%, 100% { box-shadow: 0 0 0 0.4rem transparent; }
}
.eyebrow__sep { color: var(--line-strong); }

.hero h1 {
  font-family: var(--font-display);
  font-size: clamp(2.1rem, 6vw, 4rem);
  line-height: 0.95;
  letter-spacing: var(--track-display);
  margin-bottom: 0.75rem;
  text-wrap: balance;
}
.hero__tagline {
  font-size: clamp(1.02rem, 1.7vw, 1.22rem);
  color: var(--ink-2); max-width: 32rem; margin-bottom: 1.5rem;
  line-height: 1.5;
}
.hero__actions { display: flex; flex-wrap: wrap; gap: 0.6rem; }

/* The three reassurance lines, set as a hairline-separated spec row rather
   than another set of pills. */
.hero__badges {
  display: flex; flex-wrap: wrap; gap: 0.5rem 1.6rem;
  list-style: none; padding: 1.25rem 0 0; margin: 1.75rem 0 0;
  border-top: var(--hair) solid var(--line);
  position: relative; z-index: 1;
}
.hero__badges li {
  display: flex; align-items: center; gap: 0.45rem;
  font-family: var(--font-mono); font-size: 0.72rem;
  text-transform: uppercase; letter-spacing: var(--track-label);
  color: var(--ink-3);
}
.hero__badges li::before {
  content: ""; width: 0.3rem; height: 0.3rem; flex: none;
  background: var(--primary); rotate: 45deg;
}

/* ---------------------------------------------------------------------------
   Catalog ticker — the board above the counter. Real items and real prices,
   pulled from the rendered catalog by menu.js, scrolling at reading pace.
   Each entry opens its item, so it is navigation and not ornament.
   --------------------------------------------------------------------------- */
.ticker {
  position: relative;
  margin: 0.9rem 0 1.75rem;
  border-block: var(--hair) solid var(--line);
  background: var(--brand-wash);
  overflow: hidden;
  --ticker-fade: 4rem;
  mask-image: linear-gradient(90deg, transparent, #000 var(--ticker-fade),
              #000 calc(100% - var(--ticker-fade)), transparent);
}
.ticker:empty { display: none; }
.ticker__track {
  display: flex; width: max-content;
  animation: ticker-run 48s linear infinite;
}
.ticker:hover .ticker__track,
.ticker:focus-within .ticker__track { animation-play-state: paused; }
@keyframes ticker-run {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }   /* the track holds two identical runs */
}
.ticker__item {
  display: inline-flex; align-items: center; gap: 0.5rem;
  padding: 0.6rem 0; margin-right: 1.5rem;
  border: 0; background: none;
  font-family: var(--font-mono); font-size: 0.76rem;
  text-transform: uppercase; letter-spacing: var(--track-label);
  color: var(--ink-2); white-space: nowrap; cursor: pointer;
  transition: color var(--transition);
}
.ticker__item:hover { color: var(--brand-ink); }
.ticker__item::after {
  content: ""; width: 0.25rem; height: 0.25rem; rotate: 45deg;
  background: var(--line-strong); margin-left: 1.15rem;
}
.ticker__price { color: var(--ink); font-weight: 500; }
@media (prefers-reduced-motion: reduce) {
  .ticker { mask-image: linear-gradient(90deg, #000 calc(100% - var(--ticker-fade)), transparent); }
  .ticker__track { animation: none; }
}

/* ---------------------------------------------------------------------------
   Category index rail — numbered, sticky, with a brand underline that slides.
   --------------------------------------------------------------------------- */
.category-nav {
  position: sticky; top: var(--header-h, 4.35rem); z-index: 1020;
  display: flex; gap: 0.15rem; overflow-x: auto;
  padding: 0.1rem 0 0;
  background: color-mix(in srgb, var(--paper) 90%, transparent);
  backdrop-filter: saturate(1.4) blur(12px);
  border-bottom: var(--hair) solid var(--line);
  scrollbar-width: none;
}
.category-nav::-webkit-scrollbar { display: none; }
.category-nav:empty { display: none; }
.category-nav__link {
  flex: 0 0 auto; white-space: nowrap; text-decoration: none;
  position: relative; z-index: 1;
  display: inline-flex; align-items: baseline; gap: 0.45rem;
  padding: 0.7rem 0.9rem 0.75rem;
  font-weight: 600; font-size: 0.92rem; color: var(--ink-3);
  transition: color var(--transition);
}
.category-nav__num {
  font-family: var(--font-mono); font-size: 0.68rem; font-weight: 400;
  color: var(--line-strong);
  transition: color var(--transition);
}
.category-nav__link:hover { color: var(--ink); }
.category-nav__link:hover .category-nav__num { color: var(--ink-3); }
.category-nav__link.is-active { color: var(--ink); }
.category-nav__link.is-active .category-nav__num { color: var(--primary); }
/* No-JS fallback underline; .has-ink swaps it for the sliding bar. */
.category-nav__link.is-active { box-shadow: inset 0 -2px 0 var(--primary); }
.category-nav__ink {
  position: absolute; bottom: 0; left: 0; width: 0; height: 2px;
  background: var(--primary);
  pointer-events: none;
  transition: left var(--transition-slow), width var(--transition-slow);
}
.category-nav.has-ink .category-nav__link.is-active { box-shadow: none; }

/* Anchor jumps from the rail glide instead of teleporting. */
@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}

/* ---------------------------------------------------------------------------
   Search — a hairline field, not a pill. Sits under the rail.
   --------------------------------------------------------------------------- */
/* Ratings and reviews (reviews.js). Stars inherit the brand colour so every
   theme gets them for free. */
.stars { display: inline-flex; gap: 0.12rem; color: var(--primary); font-size: 1rem; }
.stars--sm { font-size: 0.8rem; }
.rating-badge {
  display: inline-flex; align-items: center; gap: 0.25rem;
  font-family: var(--font-mono); font-size: 0.78rem; color: var(--ink-2);
}
.rating-badge .bi { color: var(--primary); }
.modal-rating:empty { display: none; }
.product-page__rating a { color: var(--ink-2); }
.item-reviews { margin-top: 1.5rem; padding-top: 1.25rem; border-top: var(--hair) solid var(--line); }
.item-reviews[hidden] { display: none; }
.reviews__heading { font-size: 1.15rem; margin-bottom: 0.9rem; }
.reviews-summary { display: flex; flex-wrap: wrap; gap: 1rem 2rem; align-items: center; margin-bottom: 1.25rem; }
.reviews-summary__score { display: grid; justify-items: start; gap: 0.2rem; }
.reviews-summary__average { font-size: 2.2rem; font-weight: 700; line-height: 1; color: var(--ink); }
.reviews-summary__count { font-size: 0.85rem; color: var(--ink-2); }
.reviews-summary__bars { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.25rem; flex: 1 1 14rem; max-width: 22rem; }
.reviews-summary__bars li { display: grid; grid-template-columns: 4.5rem 1fr 2rem; align-items: center; gap: 0.5rem; font-size: 0.8rem; color: var(--ink-2); }
.reviews-summary__track { height: 0.45rem; border-radius: var(--r-pill); background: var(--surface-2); overflow: hidden; }
.reviews-summary__fill { display: block; height: 100%; background: var(--primary); }
.reviews-summary__n { text-align: right; font-family: var(--font-mono); }
.reviews__list { list-style: none; margin: 0 0 1rem; padding: 0; display: grid; gap: 1.1rem; }
.review__head { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; }
.review__title { color: var(--ink); }
.review__meta { margin: 0.2rem 0 0.35rem; font-size: 0.8rem; color: var(--ink-3); }
.review__body { margin: 0; white-space: pre-line; overflow-wrap: anywhere; }
.review__reply {
  margin-top: 0.6rem; padding: 0.6rem 0.85rem; border-left: 3px solid var(--primary);
  background: var(--surface-2); border-radius: 0 var(--r-sm) var(--r-sm) 0; font-size: 0.9rem;
}

/* The account page's star picker: radios in reverse order, laid out
   right-to-left, so "this star and every one before it" is a sibling rule. */
.review-form { margin-top: 0.6rem; }
.review-form__stars { border: 0; padding: 0; margin: 0; }
.star-picker { display: inline-flex; flex-direction: row-reverse; gap: 0.15rem; }
.star-picker__input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.star-picker__star { cursor: pointer; font-size: 1.6rem; color: var(--line-strong); padding: 0 0.1rem; min-width: 1.75rem; }
.star-picker__star:hover, .star-picker__star:hover ~ .star-picker__star,
.star-picker__input:checked ~ .star-picker__star { color: var(--primary); }
.star-picker__input:focus-visible + .star-picker__star { outline: 2px solid var(--primary); outline-offset: 2px; border-radius: var(--r-xs); }

/* A variant that has sold out stays listed, visibly unavailable. */
.form-check--sold-out .form-check-label { color: var(--ink-3); }

/* "Email me when it's back" (stock-alert.js). */
.stock-alert { padding: 0.85rem 1rem; border: var(--hair) dashed var(--line-strong); border-radius: var(--r-sm); background: var(--surface-2); }
.stock-alert__heading { margin: 0 0 0.5rem; font-weight: 600; color: var(--ink); }
#modal-stock-alert[hidden], #product-stock-alert[hidden] { display: none; }

/* Pre-orders: the card badge, the picker's note, and the line under a cart
   or order item. */
.preorder-badge {
  font-family: var(--font-mono); font-size: 0.7rem; text-transform: uppercase;
  letter-spacing: var(--track-label); padding: 0.15rem 0.45rem;
  border-radius: var(--r-pill); border: var(--hair) solid var(--primary); color: var(--brand-ink);
}
.preorder-note {
  margin: 0 0 0.75rem; padding: 0.6rem 0.8rem; border-radius: var(--r-sm);
  background: color-mix(in srgb, var(--primary) 8%, var(--surface)); font-size: 0.9rem;
}
.preorder-note[hidden] { display: none; }

/* Sale prices: the price charged, the regular one struck through beside it,
   and a chip that says so (services/sale_prices.py). */
/* Out-ranks `.menu-card .price` and `.ticker__price`, which set the ink
   colour further down this file. */
.price.price--sale, .menu-card .price.price--sale, .ticker__price.price--sale {
  color: var(--brand-ink); font-weight: 600;
}
.price-was {
  font-family: var(--font-mono); font-size: 0.8em; color: var(--ink-3);
  font-variant-numeric: tabular-nums; margin: 0 0.2rem 0 0.35rem;
}
.sale-badge {
  font-family: var(--font-mono); font-size: 0.62rem; font-weight: 600;
  text-transform: uppercase; letter-spacing: var(--track-label);
  padding: 0.18rem 0.45rem; border-radius: var(--r-xs); white-space: nowrap;
  background: color-mix(in srgb, var(--primary) 14%, var(--surface)); color: var(--brand-ink);
  border: var(--hair) solid var(--primary);
}
.sale-note {
  margin: 0 0 0.75rem; padding: 0.6rem 0.8rem; border-radius: var(--r-sm);
  background: color-mix(in srgb, var(--primary) 8%, var(--surface)); font-size: 0.9rem;
}
.sale-note[hidden] { display: none; }
.line-preorder { color: var(--brand-ink); font-size: 0.8rem; }

/* Wishlist heart and the account page's saved items (wishlist.js). */
.wishlist-toggle { display: inline-flex; align-items: center; gap: 0.35rem; color: var(--ink-2); text-decoration: none; min-height: 1.5rem; }
.wishlist-toggle[hidden] { display: none; }
.wishlist-toggle.is-saved, .wishlist-toggle .bi-heart-fill { color: var(--primary); }
.wishlist-row { display: flex; justify-content: space-between; align-items: center; gap: 0.75rem; padding: 0.55rem 0; border-bottom: var(--hair) solid var(--line); }
.wishlist-row__link { display: flex; flex-direction: column; text-decoration: none; color: var(--ink); min-width: 0; }

/* Automatic offers above the menu (promotions.js). */
.offer-strip {
  margin: 1.5rem 0 0; padding: 0.9rem 1.1rem;
  border: var(--hair) solid color-mix(in srgb, var(--primary) 35%, var(--line));
  border-radius: var(--r);
  background: color-mix(in srgb, var(--primary) 7%, var(--surface));
}
.offer-strip__list { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.35rem; }
.offer-strip__list li { display: flex; align-items: baseline; gap: 0.55rem; font-weight: 600; color: var(--ink); }
.offer-strip__list .bi { color: var(--primary); }
.offer-strip__note { margin: 0.35rem 0 0; font-size: 0.85rem; color: var(--ink-2); }
.menu-search { position: relative; margin: 1.5rem 0 2rem; }
.menu-search .bi {
  position: absolute; left: 0; top: 50%; translate: 0 -50%;
  color: var(--ink-3); pointer-events: none; font-size: 0.95rem;
}
.menu-search .form-control {
  border: 0; border-bottom: var(--hair) solid var(--line-strong);
  border-radius: 0; background: transparent;
  padding: 0.65rem 0 0.65rem 1.75rem;
  font-size: 1rem;
}
.menu-search .form-control:focus {
  box-shadow: none; border-bottom-color: var(--primary);
  background: transparent;
}
.menu-no-results { padding: 1.5rem 0; color: var(--ink-2); }
/* Nothing orderable at all — the same treatment as an empty search, with more
   room, since it is the only thing standing where the whole catalog goes. */
.menu-empty { padding: 3rem 0; color: var(--ink-2); }

/* ---------------------------------------------------------------------------
   Loading skeleton — mirrors the real grid so the page does not jump.
   --------------------------------------------------------------------------- */
.menu-skeleton { display: grid; gap: 1.5rem; }
.skeleton-grid {
  display: grid; gap: 0.9rem;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 20rem), 1fr));
}
.skeleton-head { height: 1.6rem; width: 11rem; border-radius: var(--r-xs); }
.skeleton-card {
  display: flex; min-height: 8.5rem;
  border: var(--hair) solid var(--line); border-radius: var(--r-lg);
  background: var(--surface); overflow: hidden;
}
.skeleton-card__img { flex: 0 0 8.5rem; }
.skeleton-card__body { flex: 1; padding: 1.1rem 1.2rem; display: grid; gap: 0.6rem; align-content: start; }
.skeleton-line { height: 0.8rem; border-radius: var(--r-xs); }
/* Mixed from --ink rather than painted in --surface-2, so the bar contrasts
   with whatever it sits on: --ink is dark on a light skin and light on a dark
   one, and the old surface-on-surface fill was invisible on the dark themes. */
.skeleton,
#account-section.loading-profile .js-skel-profile,
#account-section.loading-rewards .js-skel-rewards {
  background: linear-gradient(100deg,
              color-mix(in srgb, var(--ink) 9%, transparent) 30%,
              color-mix(in srgb, var(--ink) 20%, transparent) 50%,
              color-mix(in srgb, var(--ink) 9%, transparent) 70%);
  background-size: 220% 100%;
  animation: skeleton-sweep 1.5s linear infinite;
}
@keyframes skeleton-sweep { to { background-position: -220% 0; } }

/* The account dashboard is revealed from the stored token before /auth/me
   answers (the same optimistic paint as the header), so a field with no value
   yet has to read as loading. A shimmer says "coming"; an empty line says
   "we have no name for you", which isn't true. */
#account-section.loading-profile .js-skel-profile,
#account-section.loading-rewards .js-skel-rewards {
  color: transparent;
  display: inline-block;
  min-width: 7rem;
  /* These fields are empty until the data lands, and an empty inline-block is
     zero-high — without a min-height the bar exists but paints nothing. */
  min-height: 1.05em;
  border-radius: var(--r-xs);
}
@media (prefers-reduced-motion: reduce) {
  .skeleton,
  #account-section.loading-profile .js-skel-profile,
  #account-section.loading-rewards .js-skel-rewards { animation: none; }
}

/* ---------------------------------------------------------------------------
   Category sections — the heading is a rule row: index, name, hairline, count.
   --------------------------------------------------------------------------- */
.menu-category { scroll-margin-top: calc(var(--header-h, 4.35rem) + 3.4rem); }
.menu-category > h2 {
  display: flex; align-items: baseline; gap: 0.85rem;
  font-family: var(--font-display);
  font-size: clamp(1.35rem, 3vw, 1.85rem);
  letter-spacing: var(--track-display);
  margin-bottom: 1.1rem;
}
.menu-category__index {
  font-family: var(--font-mono); font-size: 0.78rem; font-weight: 400;
  letter-spacing: 0; color: var(--primary);
  align-self: center;
}
.menu-category__rule { flex: 1 1 auto; height: var(--hair); background: var(--line); }
.menu-category__count {
  font-family: var(--font-mono); font-size: 0.7rem; font-weight: 500;
  text-transform: uppercase; letter-spacing: var(--track-label);
  color: var(--ink-3); white-space: nowrap;
}
/* Daypart chip on a category heading (e.g. "7:00 AM–11:00 AM"). */
.menu-category__hours {
  font-family: var(--font-mono); font-size: 0.68rem;
  letter-spacing: 0.04em; white-space: nowrap;
  color: var(--brand-ink); background: var(--brand-tint);
  border-radius: var(--r-xs); padding: 0.18rem 0.45rem;
}
.menu-category__hours.is-off {
  color: var(--ink-3); background: var(--surface-2);
  text-decoration: line-through;
}

/* ---------------------------------------------------------------------------
   Item card
   ---------------------------------------------------------------------------
   One architecture, two orientations. Restaurant rows put the copy first and
   the picture at the end of the row; product grids stack the picture on top
   (column-reverse, since the media is appended after the body). The add cue
   always straddles the seam between the two, so it reads as the hinge of the
   card whichever way the card is turned.
   --------------------------------------------------------------------------- */
.menu-card {
  position: relative;
  display: flex; height: 100%;
  background: var(--surface);
  border: var(--hair) solid var(--line);
  border-radius: var(--r-lg);
  overflow: visible;
  transition: border-color var(--transition), box-shadow var(--transition),
              transform var(--transition);
}
.menu-card:hover {
  border-color: var(--line-strong);
  box-shadow: var(--shadow-sm);
}
.menu-card:focus-within { border-color: var(--primary); box-shadow: var(--ring); }

.menu-card__body {
  flex: 1 1 auto; min-width: 0;
  display: flex; flex-direction: column;
  padding: 1.05rem 1.15rem;
}
.menu-card__title {
  font-size: 1rem; font-weight: 650;
  letter-spacing: var(--track-tight);
  line-height: 1.25;
  margin: 0 0 0.35rem;
}
/* The card-opening control is a real button, reset to look like the title. */
.menu-card__open {
  border: 0; background: none; padding: 0; margin: 0;
  font: inherit; letter-spacing: inherit; color: var(--ink);
  text-align: left; cursor: pointer;
}
/* The ring goes on the button, not on the card. .menu-card:focus-within above
   would be the tidier place for it, but every theme sets border/box-shadow on
   `body.theme-x .menu-card` — one specificity step higher — so the card's
   focus ring never paints and keyboard visitors get nothing. No theme targets
   this selector, so here it survives. */
.menu-card__open:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 3px;
  border-radius: var(--r-xs);
  box-shadow: none;
}
.menu-card:hover .menu-card__title { color: var(--brand-ink); }

.menu-card__desc {
  font-size: 0.875rem; line-height: 1.45; color: var(--ink-2);
  margin: 0 0 0.9rem;
  display: -webkit-box; -webkit-box-orient: vertical;
  -webkit-line-clamp: 2; line-clamp: 2; overflow: hidden;
}
.menu-card__desc:empty { display: none; }

.menu-card__foot {
  display: flex; flex-wrap: wrap; align-items: center; gap: 0.4rem;
  margin-top: auto;
}
.menu-card .price {
  font-family: var(--font-mono); font-size: 0.95rem; font-weight: 500;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
  margin-right: 0.2rem;
}

/* Micro-chips: same mono voice as every other label on the page. */
.popular-badge, .diet-chip, .sold-out-badge {
  font-family: var(--font-mono); font-size: 0.62rem; font-weight: 500;
  text-transform: uppercase; letter-spacing: var(--track-label);
  padding: 0.18rem 0.45rem; border-radius: var(--r-xs);
  white-space: nowrap;
}
.popular-badge { background: var(--primary); color: var(--brand-contrast); }
.diet-chip { background: var(--surface-2); color: var(--ink-3); }
/* Sold out stays on the page, readable but plainly not for sale right now. */
.sold-out-badge { background: var(--ink); color: var(--surface); }
.menu-card--sold-out .price { text-decoration: line-through; opacity: 0.6; }
.menu-card--sold-out .menu-card__media { opacity: 0.55; }
.menu-card--sold-out .menu-card__add { display: none; }
.modal-diet { display: flex; flex-wrap: wrap; gap: 0.35rem; margin-bottom: 1rem; }
.modal-diet:empty { display: none; }

/* ---- Media slot -------------------------------------------------------- */
/* The slot itself is unclipped so the add cue can hang over its edge; the
   frame inside does the clipping for the image. */
.menu-card__media {
  position: relative;
  flex: 0 0 var(--media-w, 9rem);
  align-self: stretch;
  container-type: inline-size;
}
/* Inset absolutely rather than by padding + a stretched height: the slot's
   own height comes from a flex stretch (rows) or an aspect-ratio (grids), and
   neither gives a child a height percentage can resolve against without the
   frame spilling past the card's bottom edge. Layouts retune --frame-inset. */
.menu-card__frame {
  position: absolute; inset: var(--frame-inset, 0.5rem);
  border-radius: calc(var(--r-lg) - 0.5rem);
  overflow: hidden;
  background: var(--surface-2);
}
.menu-card__media img {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform var(--transition-slow);
}
.menu-card:hover .menu-card__media img { transform: scale(1.045); }

/* Second picture of a gallery, cross-faded in on hover: the cheapest possible
   "there is more here". */
.menu-card__media-alt { opacity: 0; transition: opacity var(--transition-slow); }
.menu-card:hover .menu-card__media-alt,
.menu-card:focus-within .menu-card__media-alt { opacity: 1; }
.menu-card__shots {
  position: absolute; left: 0.4rem; bottom: 0.4rem; z-index: 2;
  font-family: var(--font-mono); font-size: 0.6rem;
  letter-spacing: 0.05em; text-transform: uppercase;
  background: color-mix(in srgb, var(--ink) 78%, transparent);
  color: #fff; padding: 0.1rem 0.35rem; border-radius: var(--r-xs);
  backdrop-filter: blur(4px);
}

/* ---- The monogram tile (signature) --------------------------------------
   An item with no picture still gets a designed surface: its initials over a
   fine brand hatch. Four deterministic variants (menu.js seeds data-variant
   from the item name) vary tint weight and hatch angle only — never hue — so
   the wall of tiles has rhythm while staying strictly on-brand. */
.menu-card__monogram {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  background-color: var(--brand-wash);
  background-image: repeating-linear-gradient(
    var(--hatch-angle, 45deg),
    color-mix(in srgb, var(--primary) 11%, transparent) 0 1px,
    transparent 1px var(--hatch-gap, 9px));
  overflow: hidden;
}
.menu-card__monogram span {
  font-family: var(--font-display); font-weight: 800;
  font-size: 42cqw; line-height: 1;
  letter-spacing: -0.05em;
  color: color-mix(in srgb, var(--primary) var(--mark-weight, 30%), transparent);
  user-select: none;
}
/* Diagonals only, in two directions at two spacings: the wall gets rhythm
   without any tile turning into ruled notepaper. */
.menu-card__monogram[data-variant="1"] { --hatch-angle: 135deg; --mark-weight: 38%; }
.menu-card__monogram[data-variant="2"] { --hatch-gap: 5px; --mark-weight: 24%; }
.menu-card__monogram[data-variant="3"] { --hatch-angle: 135deg; --hatch-gap: 15px; --mark-weight: 33%; }

/* "Show the whole image" (settings.image_fit = contain): the picture is fitted
   inside the frame instead of cropped, and the zoom-on-hover is dropped —
   it reads as a crop, which is exactly what this mode avoids. */
body.imgfit-contain .menu-card__frame { background: var(--surface-2); }
body.imgfit-contain .menu-card__media img { object-fit: contain; padding: 0.45rem; }
body.imgfit-contain .menu-card:hover .menu-card__media img { transform: none; }
body.imgfit-contain .modal-gallery__img { object-fit: contain; }
body.imgfit-contain .modal-gallery__stage { background: var(--surface-2); }
body.imgfit-contain .modal-gallery__thumb img { object-fit: contain; background: var(--surface-2); }

/* ---- The add cue --------------------------------------------------------
   Decorative on purpose: the whole card is the button (stretched-link), and
   what it opens is the item, not an instant add. The cue marks where the
   card is going to take you. */
.menu-card__add {
  position: absolute; z-index: 2;
  left: -0.9rem; bottom: 0.55rem;
  width: 1.9rem; height: 1.9rem;
  display: grid; place-items: center;
  border-radius: 50%;
  background: var(--surface); color: var(--ink-2);
  border: var(--hair) solid var(--line-strong);
  font-size: 1.05rem; line-height: 1;
  transition: background var(--transition), color var(--transition),
              border-color var(--transition), transform var(--transition);
}
.menu-card:hover .menu-card__add {
  background: var(--primary); color: var(--brand-contrast);
  border-color: var(--primary); transform: scale(1.08);
}

/* ---------------------------------------------------------------------------
   Products mode — picture on top, copy beneath.
   --------------------------------------------------------------------------- */
body.mode-products .menu-card { flex-direction: column-reverse; }
body.mode-products .menu-card__media {
  flex: none; width: 100%;
  aspect-ratio: var(--media-ratio, 1 / 1);
  --frame-inset: 0.5rem 0.5rem 0;
}
body.mode-products .menu-card__body { padding: 0.85rem 0.95rem 0.95rem; }
body.mode-products .menu-card__title { font-size: 0.95rem; }
body.mode-products .menu-card__desc { font-size: 0.82rem; -webkit-line-clamp: 2; line-clamp: 2; }
body.mode-products .menu-card__add { left: auto; right: 0.55rem; bottom: -0.9rem; }
body.mode-products .skeleton-grid {
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 13rem), 1fr));
}
body.mode-products .skeleton-card { flex-direction: column-reverse; min-height: 0; }
body.mode-products .skeleton-card__img { flex: none; height: 9rem; }

/* ---------------------------------------------------------------------------
   Layouts — structure only (proportions, density, picture placement). The
   allow-list of which mode may use which layout lives in services/themes.py.
   --------------------------------------------------------------------------- */

/* -- Restaurant ---------------------------------------------------------- */

/* Compact menu: a true list. No pictures, price pinned right. */
body.layout-compact_menu .menu-card { border-radius: var(--r); }
body.layout-compact_menu .menu-card__body {
  display: grid; grid-template-columns: 1fr auto;
  grid-template-areas: "title price" "desc price";
  align-items: baseline; column-gap: 1rem;
  padding: 0.8rem 1rem;
}
body.layout-compact_menu .menu-card__title { grid-area: title; margin-bottom: 0.15rem; font-size: 0.95rem; }
body.layout-compact_menu .menu-card__desc { grid-area: desc; margin: 0; -webkit-line-clamp: 1; line-clamp: 1; }
body.layout-compact_menu .menu-card__foot { grid-area: price; margin: 0; align-self: center; }
body.layout-compact_menu .menu-card__media,
body.layout-compact_menu .menu-card__add { display: none; }

/* Feature menu: large showcase cards, picture on top. */
body.layout-feature_menu .site-container { max-width: 72rem; }
body.layout-feature_menu .menu-card { flex-direction: column-reverse; }
body.layout-feature_menu .menu-card__media {
  flex: none; width: 100%; aspect-ratio: 16 / 10; --frame-inset: 0.5rem 0.5rem 0;
}
body.layout-feature_menu .menu-card__body { padding: 1.15rem 1.25rem 1.25rem; }
body.layout-feature_menu .menu-card__title { font-size: 1.2rem; }
body.layout-feature_menu .menu-card__desc { -webkit-line-clamp: 3; line-clamp: 3; }
body.layout-feature_menu .menu-card .price { font-size: 1.05rem; }
body.layout-feature_menu .menu-card__add { left: auto; right: 0.55rem; bottom: -0.9rem; }

/* Menu board: text-only columns with a dotted leader running name → price,
   the way a printed bill of fare sets it. */
body.layout-menu_board .menu-category > h2 { margin-bottom: 0.5rem; }
body.layout-menu_board .menu-card {
  border: 0; border-radius: 0; background: transparent;
}
body.layout-menu_board .menu-card:hover { box-shadow: none; background: transparent; }
body.layout-menu_board .menu-card:hover .menu-card__title { color: var(--ink); }
body.layout-menu_board .menu-card__body {
  display: grid; grid-template-columns: auto 1fr auto;
  grid-template-areas: "title leader price" "desc desc desc";
  align-items: baseline; column-gap: 0.6rem;
  padding: 0.7rem 0.25rem;
  border-bottom: var(--hair) solid var(--line);
}
body.layout-menu_board .menu-card__title { grid-area: title; font-size: 1rem; margin: 0; }
body.layout-menu_board .menu-card__body::after {
  content: ""; grid-area: leader; align-self: center;
  height: 0; border-bottom: 1px dotted var(--line-strong);
}
body.layout-menu_board .menu-card__desc {
  grid-area: desc; margin: 0.2rem 0 0; -webkit-line-clamp: 1; line-clamp: 1;
  max-width: 30rem;
}
body.layout-menu_board .menu-card__foot { grid-area: price; margin: 0; }
body.layout-menu_board .menu-card__media,
body.layout-menu_board .menu-card__add,
body.layout-menu_board .diet-chip { display: none; }
body.layout-menu_board .popular-badge {
  background: transparent; color: var(--primary); padding-inline: 0;
}

/* Image strip: wide photo rows. */
body.layout-image_strip_menu .site-container { max-width: 68rem; }
body.layout-image_strip_menu .menu-card { --media-w: 15rem; min-height: 10.5rem; }
body.layout-image_strip_menu .menu-card__body { padding: 1.35rem 1.45rem; }
body.layout-image_strip_menu .menu-card__title { font-size: 1.25rem; }
body.layout-image_strip_menu .menu-card__desc { -webkit-line-clamp: 3; line-clamp: 3; max-width: 40rem; }
body.layout-image_strip_menu .menu-card .price { font-size: 1.1rem; }

/* Spotlight: oversized hero cards, picture on top. */
body.layout-spotlight_menu .site-container { max-width: 78rem; }
body.layout-spotlight_menu .menu-card { flex-direction: column-reverse; }
body.layout-spotlight_menu .menu-card__media {
  flex: none; width: 100%; aspect-ratio: 3 / 2; --frame-inset: 0.5rem 0.5rem 0;
}
body.layout-spotlight_menu .menu-card__body { padding: 1.5rem 1.6rem 1.6rem; }
body.layout-spotlight_menu .menu-card__title { font-family: var(--font-display); font-size: clamp(1.4rem, 3vw, 2rem); letter-spacing: var(--track-display); }
body.layout-spotlight_menu .menu-card__desc { font-size: 0.98rem; -webkit-line-clamp: 3; line-clamp: 3; }
body.layout-spotlight_menu .menu-card .price { font-size: 1.3rem; }
body.layout-spotlight_menu .menu-card__add { left: auto; right: 0.55rem; bottom: -0.9rem; width: 2.3rem; height: 2.3rem; }

/* -- Product store ------------------------------------------------------- */

/* Compact shop: more products per row, no description. */
body.layout-compact_shop .menu-search { max-width: 30rem; }
body.mode-products.layout-compact_shop .menu-card { border-radius: var(--r); }
body.mode-products.layout-compact_shop .menu-card__body { padding: 0.6rem 0.7rem 0.7rem; }
body.mode-products.layout-compact_shop .menu-card__title { font-size: 0.84rem; }
body.mode-products.layout-compact_shop .menu-card__desc { display: none; }
body.mode-products.layout-compact_shop .menu-card .price { font-size: 0.85rem; }
body.mode-products.layout-compact_shop .menu-card__add { width: 1.6rem; height: 1.6rem; font-size: 0.9rem; bottom: -0.75rem; }

/* Editorial shop: larger portrait tiles. */
body.mode-products.layout-editorial_shop .site-container { max-width: 76rem; }
body.mode-products.layout-editorial_shop .menu-card { --media-ratio: 4 / 5; }
body.mode-products.layout-editorial_shop .menu-card__body { padding: 1.15rem 1.2rem 1.25rem; }
body.mode-products.layout-editorial_shop .menu-card__title { font-size: 1.05rem; }
body.mode-products.layout-editorial_shop .menu-card__desc { -webkit-line-clamp: 3; line-clamp: 3; }
body.mode-products.layout-editorial_shop .menu-card .price { font-size: 1.1rem; }

/* Catalog rows: full-detail list with the picture on the left. */
body.mode-products.layout-catalog_rows .site-container { max-width: 70rem; }
body.mode-products.layout-catalog_rows .menu-card {
  flex-direction: row-reverse; --media-w: 11rem; min-height: 9rem;
}
body.mode-products.layout-catalog_rows .menu-card__media {
  flex: 0 0 var(--media-w); width: auto; aspect-ratio: auto; --frame-inset: 0.5rem;
}
body.mode-products.layout-catalog_rows .menu-card__body { padding: 1.1rem 1.25rem; }
body.mode-products.layout-catalog_rows .menu-card__title { font-size: 1.1rem; }
body.mode-products.layout-catalog_rows .menu-card__desc { -webkit-line-clamp: 3; line-clamp: 3; }
body.mode-products.layout-catalog_rows .menu-card__add { left: auto; right: -0.9rem; bottom: 0.55rem; }

/* Masonry: a wall of mixed tile heights, cycling every three cards. */
body.mode-products.layout-masonry_shop .menu-category > ul > .col:nth-child(3n + 1) .menu-card { --media-ratio: 4 / 5; }
body.mode-products.layout-masonry_shop .menu-category > ul > .col:nth-child(3n + 2) .menu-card { --media-ratio: 1 / 1; }
body.mode-products.layout-masonry_shop .menu-category > ul > .col:nth-child(3n) .menu-card { --media-ratio: 3 / 4; }
body.mode-products.layout-masonry_shop .menu-card__desc { -webkit-line-clamp: 2; line-clamp: 2; }

/* Showcase: wide spotlight tiles, picture beside the copy. */
body.mode-products.layout-showcase_products .site-container { max-width: 82rem; }
body.mode-products.layout-showcase_products .menu-card {
  flex-direction: row-reverse; --media-w: 45%; min-height: 15rem;
}
body.mode-products.layout-showcase_products .menu-card__media {
  flex: 0 0 var(--media-w); width: auto; aspect-ratio: auto; --frame-inset: 0.5rem;
}
body.mode-products.layout-showcase_products .menu-card__body {
  padding: 1.75rem 1.9rem; justify-content: center;
}
body.mode-products.layout-showcase_products .menu-card__title {
  font-family: var(--font-display); font-size: clamp(1.35rem, 2.6vw, 1.9rem);
  letter-spacing: var(--track-display);
}
body.mode-products.layout-showcase_products .menu-card__desc { font-size: 0.98rem; -webkit-line-clamp: 4; line-clamp: 4; }
body.mode-products.layout-showcase_products .menu-card .price { font-size: 1.3rem; }
body.mode-products.layout-showcase_products .menu-card__add { left: auto; right: -0.9rem; bottom: 0.55rem; }

/* Side-by-side rows have nowhere to go on a phone: stack them. */
@media (max-width: 36rem) {
  body.mode-products.layout-catalog_rows .menu-card,
  body.mode-products.layout-showcase_products .menu-card {
    flex-direction: column-reverse;
  }
  body.mode-products.layout-catalog_rows .menu-card__media,
  body.mode-products.layout-showcase_products .menu-card__media {
    flex: none; width: 100%; aspect-ratio: 4 / 3; --frame-inset: 0.5rem 0.5rem 0;
  }
  body.mode-products.layout-catalog_rows .menu-card__add,
  body.mode-products.layout-showcase_products .menu-card__add {
    right: 0.55rem; bottom: -0.9rem;
  }
  body.layout-image_strip_menu .menu-card { --media-w: 8rem; min-height: 0; }
  body.layout-image_strip_menu .menu-card__body { padding: 1rem 1.1rem; }
  body.layout-image_strip_menu .menu-card__title { font-size: 1.05rem; }
}

/* ---------------------------------------------------------------------------
   Notices — closure banners, sold-out warnings, checkout confirmations.
   Bootstrap's own alert palette is compiled from its blues and yellows and
   ignores the tokens, so it has to be re-pointed here or a notice arrives in
   a colour scheme the rest of the page never uses.
   --------------------------------------------------------------------------- */
.site-main .alert {
  border: var(--hair) solid transparent;
  border-radius: var(--r-sm);
  padding: 0.85rem 1.1rem;
  font-size: 0.92rem;
  box-shadow: none;
}
.site-main .alert-warning {
  background: var(--warning-bg); border-color: color-mix(in srgb, var(--warning) 30%, transparent);
  color: color-mix(in srgb, var(--warning) 75%, var(--ink));
}
.site-main .alert-success {
  background: var(--success-bg); border-color: color-mix(in srgb, var(--success) 30%, transparent);
  color: color-mix(in srgb, var(--success) 75%, var(--ink));
}
.site-main .alert-danger {
  background: var(--danger-bg); border-color: color-mix(in srgb, var(--danger) 30%, transparent);
  color: color-mix(in srgb, var(--danger) 75%, var(--ink));
}
.site-main .alert-info {
  background: var(--info-bg); border-color: color-mix(in srgb, var(--info) 30%, transparent);
  color: color-mix(in srgb, var(--info) 75%, var(--ink));
}

/* ---------------------------------------------------------------------------
   Item modal
   --------------------------------------------------------------------------- */
#item-modal .modal-header { border-bottom: var(--hair) solid var(--line); padding: 1.15rem 1.35rem; }
#item-modal .modal-title {
  font-family: var(--font-display); font-size: 1.4rem;
  letter-spacing: var(--track-display);
}
#item-modal .modal-body { padding: 1.35rem; }
#item-modal .modal-footer { background: var(--surface-2); border-top: var(--hair) solid var(--line); }
#modal-description { color: var(--ink-2); line-height: 1.55; }
#modal-description:empty { display: none; }
#modal-groups fieldset {
  border: var(--hair) solid var(--line); border-radius: var(--r);
  padding: 0.95rem 1.05rem; margin-bottom: 0.85rem;
}
#modal-groups legend {
  float: none; width: auto; padding: 0 0.4rem; margin-left: -0.4rem;
  font-size: 0.92rem; font-weight: 650;
}
#modal-groups .form-check { padding-block: 0.2rem; }
#modal-price { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }

/* ---- Item modal gallery ------------------------------------------------ */
.modal-gallery { margin-bottom: 1.15rem; }
.modal-gallery__stage {
  position: relative; aspect-ratio: 4 / 3;
  border-radius: var(--r); overflow: hidden; background: var(--surface-2);
}
.modal-gallery__img { width: 100%; height: 100%; object-fit: cover; display: block; }
.modal-gallery__nav {
  position: absolute; top: 50%; translate: 0 -50%;
  width: 2.1rem; height: 2.1rem; display: grid; place-items: center;
  border: var(--hair) solid var(--line); border-radius: 50%;
  background: color-mix(in srgb, var(--surface) 88%, transparent);
  backdrop-filter: blur(6px);
  color: var(--ink); font-size: 1.2rem; line-height: 1; cursor: pointer;
  transition: background var(--transition), transform var(--transition);
}
.modal-gallery__nav:hover { background: var(--surface); transform: translateY(-50%) scale(1.06); }
.modal-gallery__nav--prev { left: 0.6rem; }
.modal-gallery__nav--next { right: 0.6rem; }
.modal-gallery__count {
  position: absolute; right: 0.6rem; bottom: 0.6rem;
  font-family: var(--font-mono); font-size: 0.68rem;
  background: color-mix(in srgb, var(--ink) 78%, transparent);
  color: #fff; padding: 0.15rem 0.45rem; border-radius: var(--r-xs);
  backdrop-filter: blur(4px);
}
/* One picture needs no controls — just the picture. */
.modal-gallery.is-single .modal-gallery__nav,
.modal-gallery.is-single .modal-gallery__count,
.modal-gallery.is-single .modal-gallery__thumbs { display: none; }
.modal-gallery__thumbs { display: flex; gap: 0.4rem; margin-top: 0.5rem; overflow-x: auto; scrollbar-width: none; }
.modal-gallery__thumbs::-webkit-scrollbar { display: none; }
.modal-gallery__thumb {
  flex: 0 0 3.4rem; padding: 0; cursor: pointer;
  border: 2px solid transparent; border-radius: var(--r-xs);
  overflow: hidden; background: none; opacity: 0.55;
  transition: opacity var(--transition), border-color var(--transition);
}
.modal-gallery__thumb img { width: 100%; aspect-ratio: 1; object-fit: cover; display: block; }
.modal-gallery__thumb:hover { opacity: 1; }
.modal-gallery__thumb.is-active { border-color: var(--primary); opacity: 1; }

/* ---------------------------------------------------------------------------
   Quantity stepper — cart drawer + checkout summary lines
   --------------------------------------------------------------------------- */
.qty-stepper {
  display: inline-flex; align-items: center;
  border: var(--hair) solid var(--line-strong); border-radius: var(--r-sm);
  background: var(--surface);
  overflow: hidden;
}
.qty-stepper button {
  border: 0; background: transparent;
  width: 1.8rem; height: 1.8rem;
  display: grid; place-items: center;
  font-size: 1rem; line-height: 1; color: var(--ink-2);
  cursor: pointer;
  transition: background var(--transition), color var(--transition);
}
.qty-stepper button:hover:not(:disabled) { background: var(--surface-2); color: var(--ink); }
.qty-stepper button:disabled { opacity: 0.3; cursor: default; }
.qty-stepper button:focus-visible { outline: none; box-shadow: var(--ring); }
.qty-stepper .qty {
  min-width: 1.6rem; text-align: center;
  font-family: var(--font-mono); font-size: 0.82rem; font-weight: 500;
  font-variant-numeric: tabular-nums;
}

/* ---------------------------------------------------------------------------
   Cart drawer (offcanvas)
   --------------------------------------------------------------------------- */
#cart-drawer { --bs-offcanvas-width: 27rem; }
#cart-drawer .offcanvas-header { padding: 1.15rem 1.35rem; }
#cart-drawer .offcanvas-title {
  font-family: var(--font-mono); font-size: 0.78rem;
  text-transform: uppercase; letter-spacing: var(--track-label);
  color: var(--ink-2);
}
#cart-drawer .offcanvas-body { padding: 0 1.35rem 1.35rem; }
.group-cart-panel { padding-block: 1rem; border-color: var(--line) !important; }
.group-cart-panel + #cart-lines { padding-top: 0.25rem; }
.group-line-owner {
  color: var(--primary);
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
#cart-lines li { border-bottom: var(--hair) solid var(--line) !important; padding-block: 0.9rem; }
#cart-lines li:last-child { border-bottom: 0 !important; }
#cart-empty { font-family: var(--font-mono); font-size: 0.78rem; text-transform: uppercase; letter-spacing: var(--track-label); }
.cart-foot { border-top: var(--hair) solid var(--line); }
.cart-foot .btn { border-radius: var(--r); }
#cart-subtotal { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }

/* ---------------------------------------------------------------------------
   Checkout
   --------------------------------------------------------------------------- */
.checkout-summary { position: sticky; top: calc(var(--header-h, 4.35rem) + 1rem); }
#checkout-form fieldset .btn-group { width: 100%; }
#checkout-form fieldset .btn-group .btn { flex: 1; }
.totals { display: grid; grid-template-columns: 1fr auto; gap: 0.4rem 1rem; }
.totals dt { font-weight: 400; color: var(--ink-2); font-size: 0.9rem; }
.totals dd {
  margin: 0; text-align: right;
  font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-size: 0.9rem;
}
.totals dt:last-of-type, .totals dd:last-of-type {
  font-weight: 600; font-size: 1.15rem; color: var(--ink);
  border-top: var(--hair) solid var(--line); padding-top: 0.6rem; margin-top: 0.3rem;
}
/* Fees the customer chooses. A bag charge only works as a deterrent if
   declining it is as easy as accepting it, so the control is a plain row with
   the price stated on the label rather than something to hunt for. */
.fee-options { display: grid; gap: 0.5rem; }
.fee-option {
  display: flex; align-items: flex-start; gap: 0.6rem;
  padding: 0.7rem 0.85rem; border: var(--hair) solid var(--line);
  border-radius: var(--radius, 0.5rem); cursor: pointer;
}
.fee-option--stepper {
  justify-content: space-between; align-items: center; cursor: default;
}
.fee-option input[type="checkbox"] { margin-top: 0.15rem; flex: none; }
/* The stepper must never be squeezed by the label beside it. `.qty-stepper`
   sets `overflow: hidden`, which zeroes a flex item's automatic minimum size —
   so without these two the row shrinks the control to a sliver and clips its
   own buttons, leaving a couple of unclickable pixels where "+" should be. */
.fee-option .qty-stepper { flex: none; }
.fee-option__text { display: block; min-width: 0; }
.fee-option__label { font-weight: 600; font-size: 0.95rem; }
.fee-option__note {
  margin: 0.2rem 0 0; font-size: 0.8rem; line-height: 1.4; color: var(--ink-2);
}
/* A fee's disclosure sits with the charge itself — a mandatory fee has to be
   explained where it is added, not in a footnote nobody scrolls to. */
.totals__note {
  display: block; margin-top: 0.15rem; max-width: 34ch;
  font-size: 0.75rem; line-height: 1.35; color: var(--ink-3, var(--ink-2));
}
#checkout-lines li {
  display: flex; justify-content: space-between; gap: 0.75rem;
  padding: 0.6rem 0; border-bottom: var(--hair) solid var(--line);
}
#checkout-lines .line-meta { display: block; font-size: 0.82rem; }
.checkout-line__right { display: flex; align-items: center; gap: 0.75rem; white-space: nowrap; font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
.checkout-line__remove { color: var(--ink-3); font-size: 1rem; line-height: 1; transition: color var(--transition); }
.checkout-line__remove:hover { color: var(--danger); }
.checkout-line__remove:focus-visible { outline: none; box-shadow: var(--ring); border-radius: var(--r-xs); }
#payment-section { border-color: var(--brand-line); }
.pay-divider {
  display: flex; align-items: center; gap: 0.75rem;
  margin: 1rem 0 0; color: var(--ink-3);
  font-family: var(--font-mono); font-size: 0.7rem;
  text-transform: uppercase; letter-spacing: var(--track-label);
}
.pay-divider::before, .pay-divider::after {
  content: ""; flex: 1; border-top: var(--hair) solid var(--line);
}

/* Tip selector */
.tip-options { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.tip-btn {
  flex: 1 1 auto; min-width: 4.5rem;
  padding: 0.55rem 0.75rem; border-radius: var(--r-sm);
  border: var(--hair) solid var(--line-strong); background: var(--surface);
  color: var(--ink); font-family: var(--font-mono); font-size: 0.85rem; font-weight: 500;
  cursor: pointer;
  transition: background var(--transition), border-color var(--transition), color var(--transition);
}
.tip-btn:hover { border-color: var(--ink); }
.tip-btn.active { background: var(--primary); border-color: var(--primary); color: var(--brand-contrast); }
.tip-btn:focus-visible { outline: none; box-shadow: var(--ring); }

/* Carrier rate picker (checkout, shipping orders) */
.rate-options { display: flex; flex-direction: column; gap: 0.5rem; }
.rate-option {
  display: flex; align-items: center; gap: 0.6rem;
  padding: 0.6rem 0.8rem; border-radius: var(--r-sm);
  border: var(--hair) solid var(--line-strong); background: var(--surface);
  cursor: pointer;
  transition: background var(--transition), border-color var(--transition);
}
.rate-option:hover { border-color: var(--ink); }
.rate-option:has(input:checked) { border-color: var(--primary); background: var(--brand-wash); }
.rate-option input[type="radio"] { margin: 0; flex: none; }
.rate-option__carrier { flex: 1 1 auto; font-weight: 600; font-size: 0.9rem; }
.rate-option__price { font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-weight: 500; }

/* Checkout upsells + promo */
.upsell-items { display: flex; flex-direction: column; gap: 0.5rem; }
.upsell-item { display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; }
.upsell-item__name { font-weight: 600; font-size: 0.9rem; }
.prep-note { color: var(--ink-2); font-size: 0.88rem; }

/* Courier attribution, under the order summary. Built entirely from tokens —
   no literal colours — so it re-skins with the store and survives the dark
   themes, which re-point --surface-2/--ink rather than adding a dark rule.
   The mark is painted in --ink on --surface, which inverts with the skin and
   so stays a high-contrast chip either way. */
.courier-banner {
  display: flex; align-items: flex-start; gap: 0.7rem;
  padding: 0.8rem 0.9rem;
  border: var(--hair) solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface-2);
}
.courier-banner[hidden] { display: none; }
.courier-banner__mark {
  flex: none;
  display: grid; place-items: center;
  width: 2.25rem; height: 2.25rem;
  border-radius: var(--r-xs);
  background: var(--ink); color: var(--surface);
}
.courier-banner__mark svg { width: 1.3rem; height: 1.3rem; }
.courier-banner__text { display: block; min-width: 0; }
.courier-banner__title {
  display: block;
  font-family: var(--font-mono);
  font-size: 0.68rem; font-weight: 600;
  letter-spacing: var(--track-label); text-transform: uppercase;
  color: var(--ink);
}
.courier-banner__body {
  display: block; margin-top: 0.2rem;
  font-size: 0.82rem; line-height: 1.45; color: var(--ink-2);
  text-wrap: pretty;
}

/* ---------------------------------------------------------------------------
   Order tracking — live operational timeline + full order record
   --------------------------------------------------------------------------- */
.track-shell { max-width: 76rem; }
.track-lookup { max-width: 62rem; margin: 0 auto; border-color: var(--line); }
.track-lookup .card-body { padding: clamp(1.25rem, 3vw, 2rem); }
.track-lookup h1 { margin: 0.15rem 0 0.45rem; font-size: clamp(1.75rem, 4vw, 2.6rem); }
.track-eyebrow {
  margin: 0; color: var(--ink-3); font-family: var(--font-mono);
  font-size: 0.68rem; font-weight: 600; text-transform: uppercase;
  letter-spacing: var(--track-label);
}
.track-lookup__form {
  display: grid; grid-template-columns: minmax(9rem, 0.65fr) minmax(14rem, 1.35fr) auto;
  gap: 0.85rem; align-items: end;
}
.track-lookup__form .btn { min-height: 2.75rem; padding-inline: 1.3rem; }

.track-result { margin-top: 1.5rem; scroll-margin-top: 6rem; }
.track-result__header {
  display: flex; justify-content: space-between; align-items: flex-start;
  gap: 1rem; padding: 1.2rem 0;
}
.track-result__header h2 {
  margin: 0.1rem 0; font-family: var(--font-display);
  font-size: clamp(1.7rem, 4vw, 2.5rem); letter-spacing: var(--track-display);
}
.track-status { padding: 0.45rem 0.85rem; font-size: 0.74rem; }
.track-status[data-status="ready"],
.track-status[data-status="completed"] { background: var(--success-bg); color: var(--success); }
.track-status[data-status="in_progress"],
.track-status[data-status="out_for_delivery"],
.track-status[data-status="shipped"] { background: var(--info-bg); color: var(--info); }
.track-status[data-status="pending_payment"] { background: var(--warning-bg); color: color-mix(in srgb, var(--warning) 75%, #000); }
.track-status[data-status="canceled"],
.track-status[data-status="expired"] { background: var(--surface-3); color: var(--ink-2); }
.track-status[data-status="refunded"] { background: var(--warning-bg); color: var(--warning); }
.track-live-note { margin: 0.25rem 0 0; color: var(--ink-3); font-size: 0.78rem; }

.track-overview {
  display: grid; grid-template-columns: minmax(0, 1.55fr) minmax(18rem, 0.75fr);
  gap: 1rem;
}
.track-panel {
  background: var(--surface); border: var(--hair) solid var(--line);
  border-radius: var(--r-lg); box-shadow: var(--shadow-xs);
  padding: clamp(1.1rem, 2.5vw, 1.5rem);
}
.track-panel__head {
  display: flex; justify-content: space-between; align-items: flex-start;
  gap: 1rem; margin-bottom: 1.25rem;
}
.track-panel h3 {
  margin: 0.18rem 0 0; font-family: var(--font-display);
  font-size: 1.25rem; letter-spacing: var(--track-display);
}
.track-live-dot {
  display: inline-flex; align-items: center; gap: 0.4rem;
  color: var(--success); font-family: var(--font-mono); font-size: 0.68rem;
  font-weight: 600; text-transform: uppercase; letter-spacing: var(--track-label);
}
.track-live-dot::before {
  content: ""; width: 0.5rem; height: 0.5rem; border-radius: 50%;
  background: currentColor; box-shadow: 0 0 0 0.22rem var(--success-bg);
}

.track-progress {
  display: grid; grid-template-columns: repeat(5, 1fr);
  list-style: none; margin: 2.1rem 0 0; padding: 0;
}
.track-progress__step {
  position: relative; min-width: 0; text-align: center;
  color: var(--ink-3);
}
.track-progress__step::before {
  content: ""; position: absolute; top: 1rem; left: 0; right: 0;
  height: 0.2rem; background: var(--surface-3); z-index: 0;
}
.track-progress__step:first-child::before { left: 50%; }
.track-progress__step:last-child::before { right: 50%; }
.track-progress__step.is-complete::before,
.track-progress__step.is-current::before { background: var(--primary); }
.track-progress__marker {
  position: relative; z-index: 1; display: grid; place-items: center;
  width: 2.1rem; height: 2.1rem; margin: 0 auto 0.7rem;
  border: 0.18rem solid var(--surface-3); border-radius: 50%;
  background: var(--surface); color: var(--ink-3);
  font-family: var(--font-mono); font-size: 0.72rem; font-weight: 700;
}
.track-progress__step.is-complete .track-progress__marker,
.track-progress__step.is-current .track-progress__marker {
  border-color: var(--primary); background: var(--primary);
  color: var(--brand-contrast);
}
.track-progress__step.is-current .track-progress__marker {
  box-shadow: 0 0 0 0.28rem var(--brand-wash);
}
.track-progress__step.is-stopped .track-progress__marker {
  border-color: var(--ink-3); background: var(--ink-3); box-shadow: none;
}
.track-progress__copy { display: flex; flex-direction: column; gap: 0.2rem; padding: 0 0.3rem; }
.track-progress__copy strong { color: inherit; font-size: 0.78rem; line-height: 1.25; }
.track-progress__copy small {
  color: var(--ink-3); font-family: var(--font-mono);
  font-size: 0.62rem; line-height: 1.3;
}
.track-progress__step.is-complete,
.track-progress__step.is-current { color: var(--ink); }

.track-timing { border-top: 0.3rem solid var(--line-strong); }
.track-timing.is-good { border-top-color: var(--success); }
.track-timing.is-late { border-top-color: var(--danger); }
.track-timing__state {
  margin: 0.3rem 0 0; font-family: var(--font-display);
  font-size: 1.35rem; font-weight: 700; line-height: 1.2;
}
.track-timing.is-good .track-timing__state { color: var(--success); }
.track-timing.is-late .track-timing__state { color: var(--danger); }
.track-timing__countdown {
  min-height: 1.5em; margin: 0.3rem 0 1.2rem;
  color: var(--ink-2); font-weight: 600;
}
.track-timebar { margin: 1.2rem 0; }
.track-timebar__rail {
  height: 0.55rem; overflow: hidden; border-radius: var(--r-pill);
  background: var(--surface-3);
}
.track-timebar__fill {
  display: block; width: 0; height: 100%; border-radius: inherit;
  background: var(--primary); transition: width 0.4s ease;
}
.track-timing.is-good .track-timebar__fill { background: var(--success); }
.track-timing.is-late .track-timebar__fill { background: var(--danger); }
.track-timebar__labels {
  display: flex; justify-content: space-between; gap: 1rem; margin-top: 0.45rem;
}
.track-timebar__labels span { display: flex; flex-direction: column; }
.track-timebar__labels strong {
  font-family: var(--font-mono); font-size: 0.62rem;
  text-transform: uppercase; letter-spacing: var(--track-label);
}
.track-timebar__labels small { color: var(--ink-3); font-size: 0.68rem; }

.track-facts, .track-info-list, .track-totals { margin: 0; }
.track-facts > div, .track-info-list > div {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: 1rem; padding: 0.62rem 0; border-bottom: var(--hair) solid var(--line);
}
.track-facts > div:last-child, .track-info-list > div:last-child { border-bottom: 0; }
.track-facts dt, .track-info-list dt {
  color: var(--ink-3); font-family: var(--font-mono); font-size: 0.64rem;
  font-weight: 600; text-transform: uppercase; letter-spacing: var(--track-label);
}
.track-facts dd, .track-info-list dd {
  margin: 0; max-width: 66%; color: var(--ink); text-align: right;
  font-size: 0.85rem; font-weight: 600;
}

.track-details-grid {
  display: grid; grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
  gap: 1rem; margin-top: 1rem;
}
.track-carrier {
  margin-top: 1rem; padding: 1rem; border-radius: var(--r);
  background: var(--info-bg); color: var(--ink);
}
.track-carrier > strong {
  display: block; margin-bottom: 0.25rem; font-family: var(--font-mono);
  font-size: 0.65rem; text-transform: uppercase; letter-spacing: var(--track-label);
}
.track-carrier p { margin: 0 0 0.7rem; overflow-wrap: anywhere; }
.track-items { border-top: var(--hair) solid var(--line); }
.track-item {
  display: flex; justify-content: space-between; gap: 1rem;
  padding: 0.85rem 0; border-bottom: var(--hair) solid var(--line);
}
.track-item__copy { display: flex; flex-direction: column; gap: 0.15rem; }
.track-item__copy small { color: var(--ink-3); font-size: 0.76rem; }
.track-item__copy .track-item__prep { color: var(--brand-ink); }
.track-item__price {
  flex: none; font-family: var(--font-mono); font-size: 0.82rem;
  font-variant-numeric: tabular-nums;
}
.track-totals {
  display: grid; grid-template-columns: 1fr auto; gap: 0.45rem 1rem;
  padding-top: 1rem;
}
.track-totals dt { color: var(--ink-2); font-weight: 500; }
.track-totals dd { margin: 0; text-align: right; font-variant-numeric: tabular-nums; }
.track-totals__total {
  margin-top: 0.35rem; padding-top: 0.7rem;
  border-top: var(--hair) solid var(--line-strong);
  color: var(--ink) !important; font-size: 1.05rem; font-weight: 700 !important;
}
.track-totals__refund { color: var(--danger) !important; }
.track-actions {
  display: flex; justify-content: flex-end; align-items: center;
  gap: 1rem; min-height: 3rem; margin-top: 1rem;
}

@media (max-width: 62rem) {
  .track-overview, .track-details-grid { grid-template-columns: 1fr; }
}
@media (max-width: 42rem) {
  .track-lookup__form { grid-template-columns: 1fr; }
  .track-result__header { align-items: center; }
  .track-progress {
    grid-template-columns: 1fr; gap: 0; margin-top: 0.5rem;
  }
  .track-progress__step {
    display: grid; grid-template-columns: 2.1rem 1fr;
    gap: 0.75rem; min-height: 4rem; text-align: left;
  }
  .track-progress__step::before {
    top: 0; bottom: 0; left: 0.95rem !important; right: auto !important;
    width: 0.2rem; height: auto;
  }
  .track-progress__step:first-child::before { top: 1rem; }
  .track-progress__step:last-child::before { bottom: calc(100% - 1rem); }
  .track-progress__marker { margin: 0; }
  .track-progress__copy { padding: 0.15rem 0 0; }
  .track-facts > div, .track-info-list > div { align-items: flex-start; }
  .track-actions { align-items: stretch; flex-direction: column; }
  .track-actions .btn { width: 100%; }
}

/* ---------------------------------------------------------------------------
   Account — categorized settings, one panel visible at a time.

   Desktop: a vertical rail (hairline right edge, brand bar marks the active
   item) sits beside the panel column. Below the lg breakpoint the same list
   turns into the horizontal scrolling rail already used for menu categories,
   sticky under the header, so the pattern reads as familiar rather than a
   second nav idiom.
   --------------------------------------------------------------------------- */
.account-layout { display: flex; flex-direction: column; gap: 1.25rem; }
.account-nav {
  display: flex; gap: 0.35rem; overflow-x: auto;
  position: sticky; top: var(--header-h, 4.35rem); z-index: 5;
  background: color-mix(in srgb, var(--paper) 92%, transparent);
  backdrop-filter: saturate(1.4) blur(12px);
  border-bottom: var(--hair) solid var(--line);
  padding: 0.1rem 0 0; margin: 0 -0.1rem;
  scrollbar-width: none;
}
.account-nav::-webkit-scrollbar { display: none; }
.account-nav__link {
  appearance: none; background: none; border: 0;
  flex: 0 0 auto; white-space: nowrap;
  padding: 0.7rem 0.9rem 0.75rem;
  font-weight: 600; font-size: 0.92rem; color: var(--ink-3);
  box-shadow: inset 0 -2px 0 transparent;
  transition: color var(--transition), box-shadow var(--transition);
}
.account-nav__link:hover { color: var(--ink); }
.account-nav__link.is-active { color: var(--ink); box-shadow: inset 0 -2px 0 var(--primary); }
.account-panels { min-width: 0; }
.account-panel { max-width: 46rem; }

@media (min-width: 992px) {
  .account-layout { flex-direction: row; align-items: flex-start; gap: 2.5rem; }
  .account-nav {
    flex: 0 0 12rem; flex-direction: column; gap: 0;
    position: sticky; top: calc(var(--header-h, 4.35rem) + 1.25rem);
    background: none; backdrop-filter: none;
    border-bottom: 0; border-inline-end: var(--hair) solid var(--line);
    padding: 0 1.25rem 0 0; margin: 0;
  }
  .account-nav__link {
    text-align: left; padding: 0.6rem 0;
    box-shadow: none; border-inline-end: 2px solid transparent;
    margin-inline-end: -1px;
  }
  .account-nav__link.is-active {
    box-shadow: none; border-inline-end-color: var(--primary);
  }
  .account-panels { flex: 1 1 auto; }
}

#rewards-summary { font-family: var(--font-mono); font-weight: 500; }
.rewards-card .rewards-balance { display: flex; align-items: baseline; gap: 0.5rem; flex-wrap: wrap; }
.gift-cards-list { display: grid; gap: 0.75rem; }
.gift-card-item { border: 1px solid var(--bs-border-color, #ddd); border-radius: 0.75rem; padding: 0.85rem 1rem; }
.gift-card-item__head { display: flex; justify-content: space-between; align-items: baseline; gap: 0.75rem; flex-wrap: wrap; }
.gift-card-item__balance { font-weight: 700; }
.gift-card-item__message { font-style: italic; }
.gift-card-item__history li { color: var(--bs-secondary-color, #6c757d); }
.gift-card-saved { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 0.5rem; }
.rewards-balance__num {
  font-family: var(--font-display); font-size: 2.6rem; line-height: 1;
  color: var(--ink); letter-spacing: var(--track-display);
  font-variant-numeric: tabular-nums;
}
.rewards-balance__label {
  font-family: var(--font-mono); font-size: 0.72rem; font-weight: 500;
  text-transform: uppercase; letter-spacing: var(--track-label); color: var(--ink-3);
}
.rewards-note {
  color: var(--ink-2); background: var(--surface-2);
  border-radius: var(--r-sm); padding: 0.6rem 0.8rem; font-size: 0.88rem;
}

.tier-status__name { font-weight: 700; color: var(--ink); }
.tier-status__bar { height: 0.4rem; border-radius: var(--r-pill); background: var(--surface-2); }
.tier-status__bar .progress-bar { background: var(--primary); }
#tier-current-perk { color: var(--ink-2); }

.tier-ladder__row {
  display: grid; grid-template-columns: 1fr auto; gap: 0.1rem 0.75rem;
  align-items: baseline; padding: 0.55rem 0.7rem; border-radius: var(--r-sm);
}
.tier-ladder__row + .tier-ladder__row { margin-top: 0.2rem; }
.tier-ladder__row.is-current { background: var(--brand-wash); box-shadow: inset 2px 0 0 var(--primary); }
.tier-ladder__name { font-weight: 600; color: var(--ink); }
.tier-ladder__row:not(.is-reached) .tier-ladder__name { color: var(--ink-3); }
.tier-ladder__req { font-family: var(--font-mono); font-size: 0.72rem; grid-column: 1; color: var(--ink-3); }
.tier-ladder__perk { grid-column: 2; grid-row: 1 / span 2; align-self: center; font-weight: 600; font-size: 0.85rem; color: var(--brand-ink); white-space: nowrap; }
.tier-ladder__row:not(.is-reached) .tier-ladder__perk { color: var(--ink-3); }
.tier-ladder__badge { font-size: 0.62rem; vertical-align: middle; }

.rewards-history { max-height: 16rem; overflow-y: auto; }

/* Personal info list */
.info-list .info-row {
  display: flex; justify-content: space-between; align-items: baseline; gap: 1rem;
  padding: 0.7rem 0; border-bottom: var(--hair) solid var(--line);
}
.info-list .info-row:last-child { border-bottom: 0; }
.info-list dt {
  font-family: var(--font-mono); font-size: 0.7rem; font-weight: 500;
  text-transform: uppercase; letter-spacing: var(--track-label);
  color: var(--ink-3); margin: 0; flex: 0 0 auto;
}
.info-list dd { text-align: right; color: var(--ink); word-break: break-word; margin: 0; }
.inline-edit { background: var(--surface-2); border: var(--hair) solid var(--line); border-radius: var(--r); padding: 1rem; }

/* Two-factor enrollment. The QR is inline SVG sized by its own viewBox, so it
   is capped here rather than left to fill the card; the white plate is not
   decoration — a dark theme would otherwise put black modules on a dark
   background and no camera would read it. */
.mfa-qr svg { display: block; width: 100%; max-width: 12rem; height: auto;
              background: #fff; padding: 0.5rem; border-radius: var(--r); }
/* Bootstrap paints <code> pink, which on this card reads as an error rather
   than the value you are meant to copy into your authenticator. */
#mfa-secret { font-size: 1.05rem; letter-spacing: 0.08em; word-break: break-all;
              color: var(--ink); }
/* Recovery codes are transcribed by hand off a screen or a printout, so they
   get a monospace face and room to breathe. */
.mfa-codes { display: grid; grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
             gap: 0.35rem 1rem; margin: 0 0 0.75rem; }
.mfa-codes li { font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
                font-size: 1rem; letter-spacing: 0.04em; }
.receipt__tools { margin-top: 1.25rem; text-align: center; }
.receipt__tools-status { margin-top: 0.6rem; }

@media print {
  /* Printing an open receipt prints the receipt, not the account behind it. */
  body:has(#receipt-modal.show) > *:not(#receipt-modal) { display: none !important; }
  #receipt-modal.show { position: static; overflow: visible; }
  #receipt-modal .modal-dialog { max-width: none; margin: 0; transform: none; }
  #receipt-modal .receipt__chrome, #receipt-modal .receipt__tools { display: none; }
  /* Printing the codes panel should print the codes, not the whole account. */
  body:has(#mfa-codes-panel:not([hidden])) > *:not(:has(#mfa-codes-panel)) { display: none; }
  #mfa-codes-copy, #mfa-codes-download, #mfa-codes-print,
  #mfa-codes-ack, #mfa-codes-done { display: none; }
}

/* Order cards sit inside the Orders panel — keep them light, not layered. */
.order-card {
  border: var(--hair) solid var(--line);
  border-radius: var(--r);
  background: var(--surface-2);
  padding: 1rem 1.15rem;
  box-shadow: none;
  margin-bottom: 0.8rem;
}
.order-card:last-child { margin-bottom: 0 !important; }
.order-card .status-badge { float: right; }
.order-receipt-toggle {
  font-family: var(--font-mono); font-size: 0.72rem;
  text-transform: uppercase; letter-spacing: var(--track-label);
  text-decoration: none;
}
.order-receipt-toggle:hover { text-decoration: underline; }

/* ---------------------------------------------------------------------------
   Receipt modal — a printed register receipt: narrow tape, centered header,
   dashed rules, tabular money.
   --------------------------------------------------------------------------- */
/* Bootstrap only auto-centers .modal-dialog horizontally at >=576px; below
   that it uses a small fixed margin instead, so a plain max-width here (with
   no matching margin) left the dialog flush against the left edge on small
   windows. Centering explicitly, unconditionally, keeps the narrow
   receipt-tape width at every size. */
.receipt-dialog { max-width: 24rem; margin-left: auto; margin-right: auto; }
.receipt { border-radius: var(--r); }
.receipt__chrome { border-bottom: 0; padding-bottom: 0; }
.receipt__body {
  font-family: var(--font-mono);
  font-size: 0.8rem; line-height: 1.6; color: var(--ink);
  padding: 0 1.5rem 1.5rem;
}
.receipt__header { text-align: center; margin-bottom: 0.25rem; }
.receipt__logo { max-height: 2.5rem; margin-bottom: 0.5rem; }
.receipt__business { font-family: var(--font-display); font-size: 1.1rem; font-weight: 700; letter-spacing: var(--track-display); }
.receipt__tagline, .receipt__contact { color: var(--ink-2); font-size: 0.75rem; }
.receipt__divider { border-top: 1px dashed var(--line-strong); margin: 0.75rem 0; }
.receipt__meta { color: var(--ink-2); }
.receipt__row { display: flex; justify-content: space-between; gap: 0.75rem; }
.receipt__row + .receipt__row { margin-top: 0.3rem; }
.receipt__row span:last-child { font-variant-numeric: tabular-nums; white-space: nowrap; }
.receipt__mods { color: var(--ink-3); font-size: 0.72rem; padding-left: 1rem; margin-top: -0.1rem; }
.receipt__grand-total { font-weight: 500; font-size: 0.95rem; }
.receipt__refunded { color: var(--danger); margin-top: 0.3rem; }
.receipt__thanks { text-align: center; color: var(--ink-2); }

/* ---------------------------------------------------------------------------
   Cookie consent banner — floats above the fixed footer bar.
   --------------------------------------------------------------------------- */
/* Over the pinned bars (1030), under Bootstrap's drawer and modal backdrops
   (1040+): at 3500 it sat on top of the item dialog's "Add to cart". */
.cookie-banner {
  position: fixed; left: 1rem; right: 1rem; z-index: 1035;
  bottom: calc(var(--footer-h, 0px) + 1rem);
  max-width: 42rem; margin: 0 auto;
  display: flex; align-items: center; gap: 1rem; flex-wrap: wrap;
  background: var(--ink); color: var(--surface);
  border-radius: var(--r); box-shadow: var(--shadow-lg);
  padding: 0.9rem 1.15rem;
}
.cookie-banner__text { margin: 0; font-size: 0.84rem; color: color-mix(in srgb, var(--surface) 80%, transparent); flex: 1 1 16rem; }
.cookie-banner__text a { color: var(--surface); text-decoration: underline; }

/* ---------------------------------------------------------------------------
   Footer
   --------------------------------------------------------------------------- */
.site-footer { background: var(--surface) !important; border-top: var(--hair) solid var(--line) !important; }
.site-footer .display-serif { letter-spacing: var(--track-display); }
.footer-head {
  font-family: var(--font-mono); font-size: 0.7rem;
  text-transform: uppercase; letter-spacing: var(--track-label);
  font-weight: 500; color: var(--ink-3); margin-bottom: 0.7rem;
}
.site-footer .subscribe .form-control { border-radius: var(--r-sm) 0 0 var(--r-sm); }
/* min-height: a 24px tap target (WCAG 2.2 2.5.8); these measured 17-18px. */
.footer-map {
  color: var(--ink-2); text-decoration: none; font-size: 0.92rem; overflow-wrap: anywhere;
  display: inline-flex; align-items: center; gap: 0.35rem; min-height: 1.5rem;
}
.footer-map:hover { color: var(--brand-ink); text-decoration: underline; }
.footer-map .bi { color: var(--primary); }

/* The links + company name, in a slim bar under the footer. Pinned to the
   viewport only on wide screens: on a phone it cost 85px of every screen for
   Terms and Privacy, which is where the cart bar belongs instead. */
.footer-bar {
  background: var(--surface);
  border-top: var(--hair) solid var(--line);
}
@media (min-width: 992px) {
  .footer-bar {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 1030;
    background: color-mix(in srgb, var(--surface) 92%, transparent);
    backdrop-filter: saturate(1.4) blur(12px);
  }
}

/* Phones and tablets: a "View cart" bar once there is something in it. */
.cart-bar {
  position: fixed; left: 0.75rem; right: 0.75rem; bottom: 0.75rem; z-index: 1030;
  display: flex; align-items: center; gap: 0.75rem;
  min-height: 3.25rem; padding: 0.6rem 1.1rem;
  border: 0; border-radius: var(--r-pill);
  background: var(--ink); color: var(--surface);
  font-weight: 600; text-align: left;
  box-shadow: 0 10px 30px color-mix(in srgb, var(--ink) 28%, transparent);
}
.cart-bar[hidden] { display: none; }
.cart-bar:hover, .cart-bar:focus-visible { background: var(--primary); color: var(--brand-contrast); }
.cart-bar__count {
  min-width: 1.75rem; height: 1.75rem; padding: 0 0.4rem;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--r-pill);
  background: var(--primary); color: var(--brand-contrast);
  font-family: var(--font-mono); font-size: 0.85rem;
}
.cart-bar__label { flex: 1; }
.cart-bar__total { font-family: var(--font-mono); }
@media (min-width: 992px) { .cart-bar { display: none !important; } }
.footer-bar__inner {
  display: flex; flex-wrap: wrap; align-items: center; gap: 0.4rem 1.25rem;
  padding-top: 0.65rem; padding-bottom: 0.65rem;
}
/* site.js sets --footer-h to whatever is pinned to the bottom (the links bar
   on desktop, the cart bar on phones) so content always clears it. */
body { padding-bottom: var(--footer-h, 0px); }
/* Sparse utility screens (sign in / reset) hide the footer + bar and center. */
body.hide-footer .site-footer, body.hide-footer .footer-bar { display: none !important; }
body.hide-footer { padding-bottom: 0 !important; }
body.hide-footer .site-main { display: flex; align-items: center; justify-content: center; }
body.hide-footer .site-main > .container { width: 100%; }
.footer-nav { display: flex; flex-wrap: wrap; align-items: center; gap: 0.4rem 1.25rem; }
.footer-nav__link {
  display: inline-flex; align-items: center; min-height: 1.5rem;
  font-family: var(--font-mono); font-size: 0.7rem;
  text-transform: uppercase; letter-spacing: var(--track-label);
  color: var(--ink-3); text-decoration: none;
  transition: color var(--transition);
}
.footer-nav__link:hover { color: var(--ink); }
.footer-copy {
  margin-left: auto;
  font-family: var(--font-mono); font-size: 0.7rem;
  text-transform: uppercase; letter-spacing: var(--track-label);
  color: var(--ink-3);
}

/* ---------------------------------------------------------------------------
   Content article
   --------------------------------------------------------------------------- */
.article h1 { font-family: var(--font-display); letter-spacing: var(--track-display); }
.article__body { line-height: 1.7; color: var(--ink); }
.article__body h2, .article__body h3 { font-family: var(--font-display); margin-top: 1.9rem; letter-spacing: var(--track-display); }
.article__body a { color: var(--brand-ink); }

/* ---------------------------------------------------------------------------
   Error page — the status number is decorative; the headline carries meaning.
   --------------------------------------------------------------------------- */
.error-page { max-width: 34rem; margin: 0 auto; text-align: center; padding: 3rem 0 4rem; }
.error-page__code {
  font-family: var(--font-mono);
  font-size: 0.78rem; letter-spacing: var(--track-label); text-transform: uppercase;
  color: var(--ink-3); margin: 0 0 1.25rem;
}
.error-page__title { font-family: var(--font-display); font-size: clamp(1.6rem, 4vw, 2.4rem); letter-spacing: var(--track-display); margin: 0 0 0.7rem; }
.error-page__message { color: var(--ink-2); font-size: 1.02rem; margin: 0 0 1.9rem; }
.error-page__actions { display: flex; flex-wrap: wrap; gap: 0.6rem; justify-content: center; }
.error-page__help { color: var(--ink-3); font-size: 0.88rem; margin: 1.9rem 0 0; }

/* ---- Language switcher -------------------------------------------------
   Sits with the other nav actions. Rendered only when the store offers more
   than one language, so a single-language shop is visually unchanged. */
.lang-switch .dropdown-menu { min-width: max-content; border-color: var(--line); border-radius: var(--r); padding: 0.3rem; box-shadow: var(--shadow); }
.lang-switch .dropdown-item { border-radius: var(--r-xs); font-size: 0.9rem; }
.lang-switch .dropdown-item.active { background: var(--surface-2); color: var(--ink); font-weight: 600; }
.lang-switch .bi-translate { margin-inline-end: 0.25rem; }

/* ---------------------------------------------------------------------------
   Small screens
   --------------------------------------------------------------------------- */
@media (max-width: 575.98px) {
  /* No fixed rail offset here: the base rule tracks the measured header
     height (--header-h), which already shrinks with the mobile navbar. */
  #cart-drawer { --bs-offcanvas-width: 100%; }
  .hero { padding: 1.5rem 1.25rem; }
  .hero__mark { font-size: 13rem; right: -2rem; opacity: 0.7; }
  .hero__actions .btn { flex: 1 1 auto; }
  .menu-card { --media-w: 7rem; }
  .footer-copy { margin-left: 0; width: 100%; }
}

/* ---------------------------------------------------------------------------
   Support — the help desk.

   Two layouts in one page. The ask view is a wide form beside a narrow rail of
   the visitor's own conversations; the thread view replaces both with a single
   column of messages, because reading a conversation is a one-track job and
   anything beside it competes with it.

   Messages are chat bubbles with a deliberate asymmetry: the customer's own
   words sit right and brand-tinted, the store's sit left on the plain surface.
   That is the only place the brand hue appears in the thread, so "who said
   this" is legible before a single word is read.
   --------------------------------------------------------------------------- */
.support-shell { max-width: 74rem; }
.support-eyebrow {
  margin: 0; color: var(--ink-3); font-family: var(--font-mono);
  font-size: 0.68rem; font-weight: 600; text-transform: uppercase;
  letter-spacing: var(--track-label);
}
.support-hero { margin-bottom: clamp(1.5rem, 4vw, 2.5rem); }
.support-hero__title { margin: 0.3rem 0 0.5rem; font-size: clamp(1.9rem, 5vw, 3rem); letter-spacing: var(--track-display); }
.support-hero__lede { color: var(--ink-2); font-size: 1.05rem; max-width: 44rem; margin: 0; }
.support-hero__meta { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 1.15rem; }
.support-chip {
  display: inline-flex; align-items: center; gap: 0.4rem;
  background: var(--surface); border: var(--hair) solid var(--line);
  border-radius: var(--r-pill); padding: 0.34rem 0.8rem;
  font-size: 0.82rem; color: var(--ink-2);
}
.support-chip .bi { color: var(--primary); }

.support-grid {
  display: grid; grid-template-columns: minmax(0, 1.6fr) minmax(17rem, 0.85fr);
  gap: clamp(1rem, 2.5vw, 1.75rem); align-items: start;
}
.support-card { border-color: var(--line); border-radius: var(--r-lg); box-shadow: var(--shadow-xs); }
.support-card .card-body { padding: clamp(1.15rem, 3vw, 1.9rem); }
.support-card--quiet { background: var(--surface-2); box-shadow: none; }
.support-card__title { font-family: var(--font-display); letter-spacing: var(--track-tight); margin-bottom: 0.3rem; }
.support-side { display: grid; gap: clamp(1rem, 2.5vw, 1.75rem); }

.support-form { display: grid; gap: 1rem; margin-top: 1.25rem; }
.support-form__row { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }
.support-counter {
  margin-top: 0.3rem; text-align: right;
  font-family: var(--font-mono); font-size: 0.7rem; color: var(--ink-3);
}
.support-signed-as {
  margin: 0; padding: 0.6rem 0.85rem; border-radius: var(--r-sm);
  background: var(--brand-wash); border: var(--hair) solid var(--brand-line);
  font-size: 0.86rem; color: var(--ink-2);
}
.support-privacy { margin: 0; font-size: 0.78rem; color: var(--ink-3); text-align: center; }

.support-threads { display: grid; gap: 0.5rem; margin: 1rem 0; }
.support-empty { margin: 1rem 0; color: var(--ink-3); font-size: 0.88rem; }
.support-thread-row {
  display: flex; align-items: center; gap: 0.75rem; width: 100%; text-align: left;
  background: var(--surface); border: var(--hair) solid var(--line);
  border-radius: var(--r-sm); padding: 0.7rem 0.85rem;
  transition: border-color var(--transition), background var(--transition);
}
.support-thread-row:hover { border-color: var(--brand-line); background: var(--brand-wash); }
.support-thread-row__main { display: grid; gap: 0.15rem; min-width: 0; flex: 1 1 auto; }
.support-thread-row__subject { font-weight: 600; color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.support-thread-row__meta { font-family: var(--font-mono); font-size: 0.68rem; color: var(--ink-3); }
.support-thread-row__right { display: grid; gap: 0.3rem; justify-items: end; }
.support-dot {
  font-family: var(--font-mono); font-size: 0.6rem; text-transform: uppercase;
  letter-spacing: var(--track-label); color: var(--brand-contrast);
  background: var(--primary); border-radius: var(--r-pill); padding: 0.15rem 0.5rem;
}

/* Status pills. Colour carries the same meaning here as in the console: the
   store owes a reply (brand), the customer does (neutral), or it's done. */
.support-status {
  font-family: var(--font-mono); font-size: 0.62rem; text-transform: uppercase;
  letter-spacing: var(--track-label); border-radius: var(--r-pill);
  padding: 0.2rem 0.6rem; white-space: nowrap;
  background: var(--surface-2); color: var(--ink-2);
}
.support-status--open { background: var(--brand-tint); color: var(--brand-ink); }
.support-status--awaiting_customer { background: var(--warning-bg); color: var(--warning); }
.support-status--resolved { background: var(--success-bg); color: var(--success); }
.support-status--closed { background: var(--surface-3); color: var(--ink-3); }

.support-lookup { border-top: var(--hair) solid var(--line); padding-top: 1.1rem; margin-top: 1.1rem; }
.support-lookup__intro { font-size: 0.84rem; color: var(--ink-3); margin-bottom: 0.75rem; }
.support-lookup #support-lookup-ref { font-family: var(--font-mono); text-transform: uppercase; }
.support-links { list-style: none; margin: 0.75rem 0 0; padding: 0; display: grid; gap: 0.55rem; }
.support-links a { color: var(--ink-2); text-decoration: none; display: flex; align-items: center; gap: 0.5rem; font-size: 0.9rem; }
.support-links a:hover { color: var(--brand-ink); }
.support-links .bi { color: var(--primary); }

/* ---- One conversation --------------------------------------------------- */
.support-thread { max-width: 52rem; margin: 0 auto; }
.support-thread__bar { display: flex; align-items: center; justify-content: space-between; gap: 1rem; margin-bottom: 0.75rem; }
.support-back { text-decoration: none; padding-left: 0; }
.support-ref {
  font-family: var(--font-mono); font-size: 0.72rem; letter-spacing: var(--track-label);
  text-transform: uppercase; color: var(--ink-3);
}
.support-thread__head { display: flex; justify-content: space-between; align-items: flex-start; gap: 1rem; padding-bottom: 1.1rem; border-bottom: var(--hair) solid var(--line); }
.support-thread__meta { margin: 0; font-size: 0.84rem; color: var(--ink-3); }

.support-messages { list-style: none; margin: 1.5rem 0; padding: 0; display: grid; gap: 1rem; }
.support-msg {
  max-width: 88%; justify-self: start;
  background: var(--surface-2); border-radius: var(--r) var(--r) var(--r) var(--r-xs);
  padding: 0.85rem 1.05rem;
}
.support-msg--mine {
  justify-self: end; background: var(--brand-tint);
  border-radius: var(--r) var(--r) var(--r-xs) var(--r);
}
.support-msg__head { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; margin-bottom: 0.35rem; }
.support-msg__who { font-weight: 600; font-size: 0.84rem; color: var(--ink); }
.support-msg__when { font-family: var(--font-mono); font-size: 0.65rem; color: var(--ink-3); white-space: nowrap; }
/* pre-wrap, because someone typing a support message uses line breaks to
   separate the three things they are asking about. */
.support-msg__body { white-space: pre-wrap; line-height: 1.65; color: var(--ink); overflow-wrap: anywhere; }
.support-system {
  justify-self: center; text-align: center;
  font-family: var(--font-mono); font-size: 0.66rem; text-transform: uppercase;
  letter-spacing: var(--track-label); color: var(--ink-3);
}

.support-reply { border-top: var(--hair) solid var(--line); padding-top: 1.25rem; }
.support-reply__actions { display: flex; flex-wrap: wrap; gap: 0.6rem; margin-top: 0.75rem; }

@media (max-width: 900px) {
  .support-grid { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 575.98px) {
  .support-form__row { grid-template-columns: 1fr; }
  .support-msg { max-width: 100%; }
}

/* Shown in place of the signup form when the address has ordered as a guest:
   the account is claimed from an emailed link. Reassurance, not an error. */
.claim-sent {
  margin: 0; padding: 0.9rem 1.05rem;
  background: var(--brand-wash); border: var(--hair) solid var(--brand-line);
  border-radius: var(--r-sm); color: var(--ink-2); line-height: 1.6;
}

/* Placeholder bubble held in the markup for a deep-linked conversation, so the
   card has the shape of a thread during its one fetch instead of being empty.
   Replaced wholesale by the first render. */
.support-msg--loading { width: min(88%, 26rem); }
.support-msg__line {
  display: block; height: 0.72rem; border-radius: var(--r-pill);
  background: var(--surface-3); animation: support-pulse 1.4s ease-in-out infinite;
}
.support-msg__line + .support-msg__line { margin-top: 0.5rem; }
.support-msg__line--short { width: 62%; }
@keyframes support-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.45; } }
@media (prefers-reduced-motion: reduce) {
  .support-msg__line { animation: none; }
}

/* ---------------------------------------------------------------------------
   Sales-tax exemption certificate.

   A photograph of a piece of paper, uploaded by someone standing at a counter
   with their phone. The drop zone is deliberately large and shows the picture
   back at full width the moment it is chosen — "is that readable?" is the
   only question that matters before sending, and it cannot be answered from a
   filename.
   ------------------------------------------------------------------------ */
.exemption-note {
  padding: 0.75rem 0.9rem; border-radius: var(--r-sm);
  border-left: 3px solid var(--bs-danger, #dc3545);
  background: color-mix(in srgb, var(--bs-danger, #dc3545) 8%, var(--surface));
  color: var(--ink-2);
}
.exemption-note strong { color: var(--ink); }

.exemption-onfile { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; }
/* Shown in a wide modal, at its own size, so the page can actually be read —
   and left scrollable so pinch-zoom on a phone still works. */
.certificate-view { background: var(--surface-2); }
.certificate-view__img {
  display: block; max-width: 100%; margin: 0 auto;
  border-radius: var(--r-xs);
}

.exemption-drop {
  position: relative; display: block; width: 100%; padding: 1.4rem 1rem;
  border: 2px dashed var(--line-strong, var(--line)); border-radius: var(--r-sm);
  background: var(--surface-2); text-align: center; cursor: pointer;
  transition: border-color 0.15s ease, background 0.15s ease;
}
.exemption-drop:hover,
.exemption-drop:focus-within,
.exemption-drop.is-over { border-color: var(--primary); background: var(--surface); }
.exemption-drop__body { display: flex; flex-direction: column; align-items: center; gap: 0.5rem; }
/* A span wearing .btn (see the comment in account.html). It must not swallow
   the click — the surrounding label is what opens the file dialog. */
.exemption-drop__btn { pointer-events: none; }
.exemption-drop__hint { font-size: 0.82rem; color: var(--ink-3); }
/* Once a file is chosen the picture *is* the control, so the prompt gets out
   of its way rather than sitting above it. */
.exemption-drop:has(.exemption-drop__preview:not([hidden])) .exemption-drop__body { display: none; }
.exemption-drop__preview {
  display: block; width: 100%; max-height: 20rem; object-fit: contain;
  border-radius: var(--r-xs);
}

/* Mandatory order fees, stated next to the prices they add to
   (templates/site/_fee_disclosure.html). Plain and legible on purpose: the
   law's word is "conspicuous", so this is not styled as fine print. */
.fee-disclosure {
  margin: 0 0 1.25rem;
  padding: 0.85rem 1rem;
  border: var(--hair) solid var(--line-strong);
  border-radius: var(--r-sm);
  background: var(--surface-2);
  color: var(--ink);
  font-size: 0.95rem;
}
.fee-disclosure__heading { font-size: 1rem; font-weight: 700; margin: 0 0 0.25rem; }
.fee-disclosure__intro { margin: 0 0 0.4rem; color: var(--ink-2); }
.fee-disclosure__list { margin: 0; padding-left: 1.1rem; }
.fee-disclosure__list li + li { margin-top: 0.25rem; }
.fee-disclosure__why { display: block; color: var(--ink-2); }

/* ---- Dine-in table strip (site.js renderTableStrip) --------------------- */
.table-strip {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: center;
  gap: 0.25rem 0.75rem; padding: 0.5rem 1rem;
  background: var(--primary); color: var(--brand-contrast);
  font-weight: 600; text-align: center;
}
.table-strip__leave {
  color: inherit; text-decoration: underline; padding: 0; font-weight: 500;
}
.table-strip__leave:hover, .table-strip__leave:focus-visible { color: inherit; opacity: 0.85; }
/* Laid out here rather than with Bootstrap's .d-flex, whose !important
   display would override [hidden] and show the card to every customer. */
.dine-in-card:not([hidden]) {
  display: flex; flex-wrap: wrap; align-items: center;
  justify-content: space-between; gap: 0.5rem;
}

/* Memberships */
.members-badge { font-size: .75rem; font-weight: 600; padding: .1rem .5rem;
  border-radius: 999px; background: var(--bs-primary-bg-subtle, #eef);
  color: var(--bs-primary-text-emphasis, #224); }
.membership-terms ul { padding-left: 1.1rem; margin-bottom: .5rem; }
/* Scrolled to on Join / back; clear the sticky header so the back link shows. */
.membership-plans, .membership-checkout { scroll-margin-top: 6rem; }
/* A signed-in visitor may already be a member, whose cards membership.js
   turns into "your plan" / "upgrade". Keep them unpainted until that's
   known, so Join buttons never flash up first for a member. */
html.is-authed .membership-plans:not(.is-checked) { visibility: hidden; }
.membership-join.is-current { border-left: 3px solid var(--bs-primary, #0d6efd); padding-left: .75rem; }
/* Two prices on one plan (monthly and yearly) are two choices: space them. */
.membership-join + .membership-join { margin-top: 1.25rem; padding-top: 1.25rem;
  border-top: 1px solid var(--bs-border-color, #dee2e6); }
.membership-your-plan { font-size: .7rem; font-weight: 600; letter-spacing: .02em; vertical-align: middle; }
.membership-checkout-frame { position: relative; }
.membership-checkout-frame:has(> .membership-checkout-loading:not([hidden])) { min-height: 20rem; }
.membership-checkout-loading { position: absolute; inset: 0; z-index: 1; display: flex; flex-direction: column; gap: .9rem;
  background: var(--bs-card-bg, var(--bs-body-bg, #fff)); }
.membership-checkout-loading[hidden] { display: none; }
.membership-checkout-loading__text { color: var(--bs-secondary-color, #6c757d); }
.membership-checkout-loading__bar { height: 2.75rem; border-radius: .5rem; }
.membership-checkout-loading__bar--short { width: 40%; }
.membership-save-offer { background: var(--bs-light, #f8f9fa); padding: .5rem .75rem;
  border-radius: .375rem; }
.member-teaser a { font-weight: 600; }
.membership-perk-list li { padding: .15rem 0; }

/* The Membership tab's card and invoices (account-membership-billing.js). */
.membership-card-list { display: grid; gap: .5rem; }
.membership-card-option { display: flex; align-items: center; gap: .6rem; padding: .6rem .8rem;
  border: 1px solid var(--bs-border-color, #dee2e6); border-radius: .5rem; cursor: pointer; margin: 0; }
.membership-card-option .form-check-input { margin: 0; flex: none; }
.membership-card-option:has(input:checked) { border-color: var(--bs-primary, #0d6efd); }
.membership-card-option .badge { margin-left: auto; }
.membership-card-due { color: var(--bs-danger, #dc3545); }
.membership-past__row { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem .75rem;
  padding: .6rem 0; border-top: 1px solid var(--bs-border-color, #dee2e6); }
.membership-past__row:first-child { border-top: 0; padding-top: 0; }
.membership-past__row .badge { margin-left: auto; }
.membership-invoices__row { padding: .6rem 0; border-top: 1px solid var(--bs-border-color, #dee2e6); }
.membership-invoices__row:first-child { border-top: 0; padding-top: 0; }
.membership-invoices__line { display: flex; flex-wrap: wrap; justify-content: space-between; gap: .5rem; align-items: center; }
.membership-invoice { margin-top: .75rem; padding: .75rem .9rem; border-radius: .5rem;
  background: var(--bs-tertiary-bg, #f8f9fa); }
.membership-invoice p { margin: 0 0 .35rem; }
.membership-invoice__lines, .membership-invoice__totals { width: 100%; border-collapse: collapse; font-size: .9rem; }
.membership-invoice__lines td { padding: .4rem 0; border-top: 1px solid var(--bs-border-color, #dee2e6); vertical-align: top; }
.membership-invoice__lines td:last-child, .membership-invoice__totals td { text-align: right; white-space: nowrap; padding-left: 1rem; }
.membership-invoice__period { font-size: .8rem; color: var(--bs-secondary-color, #6c757d); }
.membership-invoice__totals { width: min(16rem, 100%); margin: .5rem 0 0 auto; }
.membership-invoice__totals th { font-weight: 400; padding: .2rem 0; }
.membership-invoice__totals .is-total th, .membership-invoice__totals .is-total td { font-weight: 700; }
/* Printing one invoice: only the print-only sheet shows, black on white. */
.invoice-print { display: none; }
@media print {
  body.is-printing-invoice > *:not(.invoice-print) { display: none !important; }
  body.is-printing-invoice { background: #fff; }
  body.is-printing-invoice .invoice-print { display: block; color: #000; font: 11pt/1.45 system-ui, sans-serif; padding: .5in; }
  .invoice-print * { color: #000; background: none; }
  .invoice-print__head { display: flex; justify-content: space-between; align-items: baseline;
    border-bottom: 2px solid #000; padding-bottom: .5rem; margin-bottom: .75rem; font-size: 16pt; }
  .invoice-print p { margin: 0 0 .4rem; }
  .invoice-print table { width: 100%; border-collapse: collapse; }
  .invoice-print td, .invoice-print th { padding: .4rem .3rem; border-bottom: 1px solid #999; text-align: left; vertical-align: top; }
  .invoice-print td:last-child, .invoice-print .membership-invoice__totals td { text-align: right; white-space: nowrap; }
  .invoice-print .membership-invoice__totals { width: 16rem; margin: 1rem 0 0 auto; }
  .invoice-print .membership-invoice__period { font-size: 9pt; color: #444; }
}

/* The member pass QR (account-membership.js): black on white in every theme, for the scanner. */
.member-pass__qr { width: min(15rem, 70vw); aspect-ratio: 1; background: #fff; padding: .5rem; border-radius: .5rem; }
.member-pass__qr svg { width: 100%; height: 100%; display: block; }

/* A member's last quote, dimmed while the new one loads (checkout.js). */
#totals.is-updating { opacity: .55; transition: opacity .15s ease; }

/* ---------------------------------------------------------------------------
   Gift cards (/gift-cards): the form on the left, the card as it will read on
   the right. The preview is the one place the brand colour fills a surface —
   it is the thing being bought, so it should look like something to give.
   --------------------------------------------------------------------------- */
.gift-shop { max-width: 70rem; }
.gift-shop__hero { margin-bottom: clamp(1.5rem, 4vw, 2.5rem); max-width: 44rem; }
.gift-shop__title { margin: 0.3rem 0 0.5rem; font-size: clamp(1.9rem, 5vw, 3rem); letter-spacing: var(--track-display); }
.gift-shop__lede { color: var(--ink-2); font-size: 1.05rem; margin: 0; }
.gift-shop__grid {
  display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
  gap: clamp(1.25rem, 3vw, 2.5rem); align-items: start;
}
.gift-shop__card { border-color: var(--line); border-radius: var(--r-lg); box-shadow: var(--shadow-xs); }
.gift-shop__card .card-body { padding: clamp(1.15rem, 3vw, 1.9rem); }
.gift-shop__section { margin-bottom: 1.75rem; }
.gift-shop__section-title { font-family: var(--font-display); letter-spacing: var(--track-tight); margin-bottom: 0.85rem; }
.gift-shop__row { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }

.gift-amounts { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.gift-amount {
  min-width: 4.75rem; padding: 0.6rem 1rem; text-align: center; cursor: pointer;
  border: var(--hair) solid var(--line); border-radius: var(--r-pill);
  background: var(--surface); font-weight: 600; font-variant-numeric: tabular-nums;
  transition: border-color var(--transition), background var(--transition), color var(--transition);
}
.gift-amount:hover { border-color: var(--brand-line); background: var(--brand-wash); }
.btn-check:checked + .gift-amount {
  background: var(--primary); border-color: var(--primary); color: var(--brand-contrast);
}
.btn-check:focus-visible + .gift-amount { box-shadow: 0 0 0 0.25rem var(--brand-wash); }
.gift-custom { margin-top: 0.9rem; max-width: 16rem; }
.gift-who { margin-bottom: 1.1rem; }

.gift-shop__aside { position: sticky; top: 6rem; display: grid; gap: 1.1rem; }
.gift-preview {
  aspect-ratio: 1.586; border-radius: var(--r-xl); padding: clamp(1.1rem, 3vw, 1.5rem);
  display: flex; flex-direction: column; justify-content: space-between;
  color: var(--brand-contrast);
  background:
    radial-gradient(120% 90% at 100% 0%, color-mix(in srgb, var(--brand-contrast) 18%, transparent), transparent 60%),
    linear-gradient(135deg, var(--primary), var(--brand-stronger));
  box-shadow: var(--shadow-lg);
}
.gift-preview__top { display: flex; justify-content: space-between; align-items: center; font-size: 1.35rem; }
.gift-preview__brand { font-family: var(--font-display); font-weight: 700; font-size: 1.05rem; letter-spacing: var(--track-tight); }
.gift-preview__amount {
  font-family: var(--font-display); font-weight: 800; line-height: 1;
  font-size: clamp(2.6rem, 7vw, 3.6rem); letter-spacing: var(--track-display);
  font-variant-numeric: tabular-nums;
}
.gift-preview__bottom { display: flex; justify-content: space-between; align-items: end; gap: 0.75rem; }
.gift-preview__to { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.gift-preview__code { font-family: var(--font-mono); font-size: 0.72rem; opacity: 0.75; white-space: nowrap; }
.gift-preview-note {
  margin: 0; padding: 0.9rem 1.1rem; border-radius: 0 var(--r-sm) var(--r-sm) 0;
  background: var(--surface-2); border-left: 3px solid var(--primary);
  color: var(--ink-2); white-space: pre-line; overflow-wrap: anywhere;
}
.gift-preview-note__from { font-size: 0.88rem; color: var(--ink-3); }
.gift-perks { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.55rem; font-size: 0.92rem; color: var(--ink-2); }
.gift-perks .bi { color: var(--primary); margin-right: 0.4rem; }

.gift-done .card-body { padding-block: clamp(2rem, 6vw, 3.5rem); }
.gift-done__icon {
  width: 4rem; height: 4rem; margin: 0 auto 1rem; border-radius: 50%;
  display: grid; place-items: center; font-size: 1.8rem;
  background: var(--brand-wash); color: var(--brand-ink);
}
#gift-done-body { max-width: 30rem; margin-inline: auto; overflow-wrap: anywhere; }

@media (max-width: 767.98px) {
  .gift-shop__grid { grid-template-columns: minmax(0, 1fr); }
  /* The card first on a phone: it is what the page is about. */
  .gift-shop__aside { position: static; order: -1; }
  .gift-preview { max-width: 22rem; }
  .gift-shop__row { grid-template-columns: minmax(0, 1fr); }
}
