/* The ordering surface: shell chrome, the dish panel, cart lines, the loyalty band.
   Extracted from templates/restaurant/ordering.blade.php and its partials on 2026-09-22; it was inlined into every
   ordering page, and those pages are never cached. Linked with a content
   hash (App\Support\StaticAsset), so the browser keeps it for a week and
   fetches it again only when a deploy changes it. Nothing here may depend on
   the page: a value that differs per request stays inline in the template. */

/* Ordering chrome. Deliberately NOT built on the theme preset tokens:
   this surface must read the same on every preset, so a merchant
   switching to the dark preset cannot turn their ordering page
   unreadable. The only thing the site controls here is --c-primary,
   which paints the actions. Values are measured from the reference
   ordering page (see the spec's Evidence section). */
.ord-body{
  /* Restated from the merchant dashboard (resources/views/layouts/
     shell.blade.php) so the customer ordering pages and the dashboard read
     as one product. The dashboard's --text-muted #94a3b8 is deliberately
     NOT adopted: it measures 2.56:1 on white and fails the 4.5:1 floor.
     It works there because it carries icons and decorative labels, not
     body text. Two text greys only on this surface. */
  --ord-canvas:#eef4fb; --ord-card:#ffffff; --ord-ink:#0f172a;
  --ord-ink-muted:#64748b; --ord-rule:#e2e8f0; --ord-alert:#ef4444;
  /* Two rule weights, on purpose. --ord-rule stays on decorative
     separators; --ord-rule-strong is for INTERACTIVE boundaries. On a text
     input whose fill is the same white as the card behind it, the border is
     the only thing identifying the component, and #e2e8f0 measures 1.23:1
     against white. Darkening --ord-rule globally instead would turn the
     menu's separators and the opening-hours list into a table grid. */
  /* #64748b, not #94a3b8: WCAG 1.4.11 wants 3:1 for a non-text boundary and
     #94a3b8 measures 2.56:1 on white. #64748b measures 4.76:1. */
  --ord-rule-strong:#64748b;
  --ord-radius:16px; --ord-btn-radius:10px; --ord-header-h:64px;
  --ord-shadow:0 1px 3px rgba(0,0,0,.06), 0 1px 2px rgba(0,0,0,.04);
  margin:0; background:var(--ord-canvas); color:var(--ord-ink);
  font-family:var(--font-body); line-height:1.5;
}
/* _head.blade.php sets h1,h2,h3{font-family:var(--font-heading);
   text-transform:var(--heading-case);letter-spacing:var(--heading-tracking)}
   globally, for the marketing pages that legitimately want the merchant's
   heading font. This surface is declared preset-independent (Inter
   throughout), so headings inside it - the category titles, the item
   panel's own name and group titles - must not inherit that theme font.
   Falls back to the same --font-body already used above, not a hardcoded
   family, so this stays one rule with the rest of .ord-body. */
.ord-body h1, .ord-body h2, .ord-body h3{
  font-family:var(--font-body); text-transform:none; letter-spacing:normal;
}
/* .skip-link's box model is shared in _head.blade.php; its colours and
   radius must not follow the merchant's theme preset here (that is the
   whole point of this surface), so this restates them with the ordering
   token set instead of the --ink/--canvas/--radius _head.blade.php uses
   for the marketing pages (see layout.blade.php's own .skip-link rule).
   .skip-link renders as the very first element in <body> below, so it
   is on this surface exactly as much as any other ordering chrome. */
.skip-link{background:var(--ord-ink);color:var(--ord-canvas);border-radius:var(--ord-btn-radius)}
/* The UA's own [hidden]{display:none} loses to any author display rule, and
   this surface sets several. Progressive enhancement here is done by
   TOGGLING THE ATTRIBUTE with x-bind:hidden, never with x-show - an author
   !important would beat the inline display x-show writes (see the comments
   at _item_panel.blade.php:83-84 and menu.blade.php:214-220, which record
   that exact collision on this bundled Alpine build). */
[hidden]{display:none!important}
.ord-header{
  position:sticky; top:0; z-index:40; height:var(--ord-header-h);
  display:flex; align-items:center; justify-content:space-between; gap:1rem;
  background:var(--ord-card); border-bottom:1px solid var(--ord-rule);
}
/* Full-bleed app bar: brand at the left edge, actions at the right, on
   every page that extends this shell and at every width. The 70rem cap
   that used to be here only ever bound above 1120px, so nothing below
   that moves; above it, a capped header would sit inside a 120rem menu,
   and the alternative - capping per page - makes the brand mark jump
   position between the menu and the cart page. Deliberately visible on
   the cart, checkout and order-status pages (whose content keeps its own
   44rem .ord-narrow measure) and on the info page, which has no measure
   of its own.

   (Deliberately not spelling those two page paths out as a leading-slash
   route string here: CartTest::test_the_cart_stops_offering_checkout_once
   _any_line_has_gone asserts the cart page's body does not contain the
   relative checkout route path, and assertDontSee is a plain substring
   search over the whole response - it cannot tell a CSS comment from a
   real link.)

   The gutters are the children's, unchanged: .ord-brand's
   padding-left:1.25rem and .ord-nav's padding-right:.75rem (1rem / .35rem
   below 641px). They are NOT retuned to make the glyph ink symmetric with
   the brand ink: .ord-badge is pinned right:0 against the nav button's box
   edge, so tightening that padding would push the cart badge to 9px from
   the glass.

   Nothing here touches the block axis, which is the point: --ord-header-h
   stays 64px and the four offsets measured off it do not move -
   .ord-cat and .ord-item scroll-margin-top:5.5rem, .ord-rail's sticky
   top:5.5rem, and `const header = 88` in menu.blade.php's observer. */
.ord-header-inner{width:100%;height:100%;display:flex;align-items:center;justify-content:space-between;gap:1rem}
.ord-brand{display:flex;align-items:center;gap:.625rem;padding:0 1.25rem;height:100%;text-decoration:none;color:var(--ord-ink);min-width:0}
/* The merchant's own logo, which every marketing layout already renders
   and this header never did - so a customer walked out of a branded
   storefront into the word SUBZY set in bold.

   object-fit:contain plus a max-width, which is poco's and trades' shape,
   NOT restaurant/layout.blade.php's .nav-logo, which constrains height
   alone. MediaStorage caps uploads on WIDTH only (scaleDown(width:1600)),
   so the aspect ratio of what a merchant uploads is genuinely arbitrary
   and a 1600x200 file would otherwise render 320px wide here.

   flex:none matters too: without it the name squeezes a wide logo instead
   of ellipsing itself. */
.ord-brand-logo{height:2.5rem;width:auto;max-width:8.5rem;object-fit:contain;flex:none;display:block}
/* The fallback identity when a merchant has uploaded nothing: their
   initial on the accent, rather than nothing at all. mb_substr and
   Str::upper in the markup, never substr/strtoupper - byte-slicing a
   Cyrillic name renders a replacement box. */
.ord-brand-mark{flex:none;display:grid;place-items:center;width:2.25rem;height:2.25rem;border-radius:10px;background:var(--c-primary);color:var(--c-primary-ink);font-size:1.05rem;font-weight:700;line-height:1}
/* text-transform:uppercase deliberately dropped. It overrode the
   merchant's own capitalisation ("Staklo Debi" became "STAKLO DEBI"), and
   the phone rule below already records that uppercase Cyrillic pays for
   letter-spacing twice. */
.ord-brand-name{font-size:1.0625rem;font-weight:700;letter-spacing:-.01em;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ord-nav{display:flex;align-items:center;gap:.25rem;padding-right:.75rem;height:100%}
.ord-locale{display:flex;align-items:center;gap:.25rem;padding-right:.75rem}
/* The dashboard's badge treatment: tinted ground, darker text of the same
   hue, no border. --ord-ink-muted (#64748b) on this ground measures
   4.35:1 and fails the 4.5:1 floor, so this uses the dashboard's own
   slate-600 (#475569) instead, which measures 6.92:1. */
.ord-locale a{padding:.3rem .6rem;border-radius:999px;font-size:.75rem;font-weight:700;text-decoration:none;color:#475569;background:#f1f5f9}
.ord-locale a:hover{color:var(--ord-ink)}
.ord-locale a.is-active{background:var(--c-primary);color:var(--c-primary-ink)}
/* Round 44px buttons with a gap, not 64px squares divided by hairlines.
   The squares were the merchant dashboard's toolbar idiom, restated here
   when this surface was built to read "as one product" with it - which is
   the one part of that decision aimed at the wrong audience. A customer
   choosing dinner is not watching an order queue for six hours. */
.ord-nav-btn{
  position:relative; display:inline-flex; align-items:center; justify-content:center;
  width:2.75rem; height:2.75rem; border:0; border-radius:999px;
  background:transparent; color:var(--ord-ink); cursor:pointer; text-decoration:none;
  transition:background .15s;
}
.ord-nav-btn:hover{background:#f1f5f9}
.ord-nav-btn.is-active{background:#f1f5f9}
.ord-nav-btn:focus-visible{outline:2px solid var(--ord-ink);outline-offset:-2px}
/* The four cart regions - the badge, the flash pair, the pane and the
   checkout bar - are each wrapped in a stable id so one response can swap
   all four at once. display:contents keeps those wrappers out of layout
   entirely: the header button centres its glyph with flex, and the pane is
   a flex column whose lines scroll inside a max-height. A wrapper that
   generated a box would become a flex item in both places and the pane
   would stop scrolling its lines - which no other test in the suite could
   see, so CartRegionsTest pins this declaration by name. */
.ord-cart-region{display:contents}
.ord-badge{
  position:absolute; top:.1rem; right:0; min-width:1.15rem; height:1.15rem;
  padding:0 .25rem; border-radius:999px; background:var(--c-primary); color:var(--c-primary-ink);
  font-size:.7rem; font-weight:700; display:inline-flex; align-items:center; justify-content:center;
}
/* The dashboard's alert treatment rather than a full-bleed red slab:
   tinted ground, darker text of the same hue, an accent rule down the
   side. Measured 5.91:1, which clears the floor. */
.ord-flag{background:#fef2f2;color:#b91c1c;font-weight:600;font-size:.9rem;padding:.85rem 1.25rem;text-align:center;border-bottom:1px solid #fecaca}
/* The sibling of .ord-flag for closed-for-now: outside opening hours the
   shop takes no orders, and it is the state customers meet most, so it is
   the loudest strip rather than a slate line scrolled past: white on a warm
   red, 6.6:1. It never shares a page with .ord-flag (the markup renders one
   or the other). The hours button is a white pill, a real target on the
   strip rather than underlined words inside a sentence. */
.ord-notice{display:flex;flex-wrap:wrap;align-items:center;justify-content:center;gap:.35rem .75rem;margin:0;background:#b42318;color:#fff;font-weight:700;font-size:.9rem;line-height:1.35;padding:.7rem 1.25rem;text-align:center}
.ord-notice a{display:inline-flex;align-items:center;min-height:2rem;padding:.2rem .9rem;border-radius:999px;background:#fff;color:#b42318;font-weight:800;text-decoration:none;white-space:nowrap}
.ord-notice a:hover{background:#fee4e2}
.ord-notice a:focus-visible{outline:2px solid #fff;outline-offset:2px}
/* A phone: the sentence on the left and the pill beside it, so the pinned
   strip stays two or three lines instead of growing a row for the button. */
@media (max-width:640px){
  .ord-notice{flex-wrap:nowrap;justify-content:space-between;text-align:left;font-size:.8125rem;padding:.55rem .9rem;gap:.75rem}
}
/* The opening hours, in place: a native <dialog> - focus held inside it,
   Escape and a tap on the backdrop close it - rising as a sheet on a phone
   and sitting as a card on a wider screen. Its content is the same card
   checkout draws inline while the shop is closed (_opening_hours_card). */
.ord-hours-dialog{width:min(26rem,calc(100% - 2rem));max-height:calc(100vh - 2rem);max-height:calc(100dvh - 2rem);margin:auto;padding:0;border:0;border-radius:var(--ord-radius);background:var(--ord-card);color:var(--ord-ink);box-shadow:0 24px 60px rgba(15,23,42,.28)}
.ord-hours-dialog::backdrop{background:rgba(15,23,42,.55)}
.ord-hours-dialog-inner{padding:1.5rem 1.5rem 1.25rem}
.ord-hours-dialog-close{display:flex;justify-content:flex-end;margin:1.25rem 0 0}
.ord-hours-close{display:inline-flex;align-items:center;justify-content:center;min-height:2.75rem;padding:.5rem 1.4rem;border:1.5px solid var(--ord-rule-strong);border-radius:var(--ord-btn-radius);background:transparent;color:var(--ord-ink);font:inherit;font-weight:700;cursor:pointer}
.ord-hours-close:focus-visible{outline:2px solid var(--ord-ink);outline-offset:2px}
@media (max-width:640px){
  .ord-hours-dialog{width:100%;max-width:100%;margin:auto 0 0;border-radius:16px 16px 0 0;max-height:85vh;max-height:85dvh}
}
.ord-hours-title{margin:0 0 .35rem;font-size:1.25rem;font-weight:800;color:var(--ord-ink);letter-spacing:-.01em;text-transform:none}
/* When it next opens, with a red dot: the one line a customer came for. */
.ord-hours-status{display:flex;align-items:center;gap:.5rem;margin:0 0 1rem;font-weight:700;color:var(--ord-ink)}
.ord-hours-status::before{content:"";flex:none;width:.6rem;height:.6rem;border-radius:50%;background:#b42318}
.ord-hours-list{list-style:none;margin:0;padding:0}
.ord-hours-list li{display:flex;justify-content:space-between;align-items:center;gap:1rem;padding:.55rem .75rem;border-radius:var(--ord-btn-radius);font-size:.9375rem;color:var(--ord-ink-muted);font-variant-numeric:tabular-nums}
.ord-hours-list li + li{margin-top:.1rem}
.ord-hours-list li.is-today{background:var(--ord-canvas);color:var(--ord-ink);font-weight:800}
.ord-hours-today{margin-left:.5rem;padding:.1rem .5rem;border-radius:999px;background:var(--c-primary);color:var(--c-primary-ink);font-size:.6875rem;font-weight:800;letter-spacing:.06em;text-transform:uppercase;vertical-align:middle}
.ord-hours-note{margin:1rem 0 0;font-size:.875rem;color:var(--ord-ink-muted)}
/* The header and the status strips under it, as one block. display:contents
   everywhere, so the header keeps its own sticky exactly as before; on the
   menu while a strip shows, the block itself is what sticks, so the strip
   rides under the header instead of scrolling away. The script after the
   block publishes how much taller the strip makes it (--ord-top-extra), and
   the anchor jumps take it here; the menu's sticky tracks add it too. */
.ord-top{display:contents}
.ord-top.is-pinned{display:block;position:sticky;top:0;z-index:40}
html{scroll-padding-top:var(--ord-top-extra,0px)}
/* Test mode. A third colour on purpose: .ord-flag's red says "you cannot
   order" and .ord-notice's red strip says "not now - in opening hours" - this says
   neither. It is amber because the thing it warns about is that everything
   WILL work and none of it is real. #92400e on #fffbeb measures 8.6:1.
   Sits above the two banners below it and is never suppressed by them: a
   merchant testing a paused shop needs both statements. */
.ord-testflag{background:#fffbeb;color:#92400e;font-weight:700;font-size:.9rem;padding:.85rem 1.25rem;text-align:center;border-bottom:1px solid #fde68a}
/* Fixed, not sticky: the banner above it scrolls away, and a sticky toast
   rode down with it and landed halfway down the page. Anchored to the
   BOTTOM rather than under the header, because the closed-for-now banner
   lives up there and a customer can add an item while it is showing, so a
   top anchored toast covered it. Sits above the checkout bar. */
.ord-toast{
  position:fixed; bottom:calc(6.5rem + env(safe-area-inset-bottom)); left:50%; transform:translateX(-50%); z-index:45;
  width:max-content; max-width:calc(100% - 2rem);
  background:var(--ord-ink); color:#fff; font-weight:700; font-size:.9rem;
  padding:.65rem 1.25rem; border-radius:999px; box-shadow:0 6px 20px rgba(0,0,0,.22);
}
/* Without JavaScript the fade never runs, so the toast would sit there
   forever. An animation needs no script and leaves nothing behind.
   The animation is deliberately NOT inside a prefers-reduced-motion guard,
   which is where it used to live: that made it the DISMISSAL, not just the
   fade, so a visitor with JavaScript off AND reduce-motion set had no
   dismissal path at all - a fixed pill parked over the checkout bar for the
   rest of the session. Reduce-motion collapses the duration instead, so the
   toast still goes away, just without the fade. */
.ord-toast{animation:ord-toast-out .4s ease-in 3.6s forwards}
/* The toast only tells, it takes no tap. It sits where the basket sheet's
   first line opens, and for the four seconds it shows it caught the taps
   meant for that line's stepper (measured 2026-10-12 on Pixel 7, iPhone 15
   and at 320 and 344 px, on a pickup-only site as on a delivering one). */
.ord-toast{pointer-events:none}
@media (prefers-reduced-motion:reduce){
  .ord-toast{animation-duration:0s}
}
@keyframes ord-toast-out{to{opacity:0;visibility:hidden}}
/* Visually hidden, never display:none - a display:none live region is not
   announced at all. */
.ord-live{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
.ord-shell{max-width:70rem;margin-inline:auto;padding:0 1.5rem 3rem}
.ord-card{background:var(--ord-card);padding:2rem 1.75rem 2.5rem;min-height:20rem;border:1px solid var(--ord-rule);border-radius:var(--ord-radius);box-shadow:var(--ord-shadow);margin-top:1.5rem}
/* THE primary action on this surface, defined once. It used to have three
   sizes across four screens: .ord-checkout-go at 41.6px, .ord-panel-cta at
   52px, and `class="btn btn-primary ord-cta"` on cart and checkout
   resolving through _head's .btn to 45.6px with a 2px accent border on an
   accent fill - plus .btn:focus-visible painting an accent ring on an
   accent button, which is invisible by construction. Those two pages carry
   .ord-cta alone now, so no marketing primitive reaches this surface. */
.ord-cta{display:inline-flex;align-items:center;justify-content:center;gap:7px;min-height:2.75rem;padding:10px 20px;border:0;border-radius:var(--ord-btn-radius);background:var(--c-primary);color:var(--c-primary-ink);font:inherit;font-size:.9375rem;font-weight:600;text-decoration:none;cursor:pointer;transition:background-color .15s,transform .08s}
.ord-cta:hover{background:var(--c-primary-hover)}
/* --ord-ink, not --c-primary: the accent is validated only as a six-hex
   shape, and ThemeCss clamps the ink ON the accent, never the accent's own
   luminance - so a pale merchant accent makes an accent focus ring
   invisible. .ord-checkout-go and .ord-panel-cta already did this; the rest
   of the surface now agrees with them. */
.ord-cta:focus-visible{outline:2px solid var(--ord-ink);outline-offset:2px}
.ord-cta[disabled]{opacity:.5;cursor:not-allowed}
@media (prefers-reduced-motion:no-preference){
  .ord-cta:active{transform:scale(.97)}
}
/* Sits on the page ground, where --ord-ink-muted measures 4.30:1 and
   fails the floor, so this uses --ord-ink. */
.ord-foot{margin-top:2rem;padding-top:1.5rem;border-top:1px solid var(--ord-rule)}
.ord-foot-cols{display:flex;flex-wrap:wrap;gap:1.5rem 3rem;justify-content:center;text-align:center}
/* --ord-ink, not --ord-ink-muted: this footer sits on --ord-canvas, where
   the file's own comment two rules down records that muted measures 4.30:1
   and fails the floor. */
.ord-foot-cols h2{font-size:.72rem;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--ord-ink);margin:0 0 .3rem}
.ord-foot-cols p{margin:0;font-size:.9rem;color:var(--ord-ink)}
.ord-foot-cols a{color:inherit;font-weight:600}
.ord-foot-legal{margin:1.25rem 0 0;text-align:center;font-size:.78rem}
.ord-foot-legal a{color:var(--ord-ink);text-decoration:underline;text-underline-offset:2px}
.ord-credit{padding:1.25rem;text-align:center;font-size:.78rem;color:var(--ord-ink)}
.ord-credit a{color:inherit;font-weight:600}
main:focus{outline:none}
@media (max-width:640px){
  .ord-brand{padding:0 1rem}
  /* The name wraps to two lines on phones instead of ellipsing on one.
     Measured at 360px, the tightest width worth supporting: on one line
     the name gets about 12 characters, so "Пекара Бисер" already cut and
     "Ресторан Стара Куќа" (an unremarkable name) cut badly. Two lines
     plus dropping the letter-spacing, which uppercase Cyrillic pays for
     twice, takes that to roughly 20 characters at 360 and more at 390.

     The header stays 64px: two lines at 1rem/1.15 is 37px inside it, and
     vertical centering is unaffected.

     Names past about 20 characters still ellipse at 360px. That is
     deliberate rather than solved: a three-line clamp fits one more test
     name but only by dropping the brand to .875rem across three lines,
     which reads as cramped and undercuts the header's type hierarchy for
     every merchant in order to help a rare one. Truncation here is
     visual only, since the full name stays in the DOM for screen readers
     and the brand links home. */
  .ord-brand-name{
    font-size:1rem; letter-spacing:0;
    white-space:normal; overflow-wrap:anywhere;
    display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical;
    line-height:1.15; overflow:hidden;
  }
  /* Three destinations left the restaurant name about 96px at 390px and
     66px at 360px, so a realistic name rendered as an ellipsis. Buttons
     drop to 44px, which is still the full header height and clears the
     44px tap-target guidance.

     This header used to carry locale pills on every page, and most of the
     arithmetic here was about the ~65px they cost the name. On the
     ordering surface they are gone entirely - it runs in one language now
     (App\Support\Ordering\OrderingSurface) - so the name has that room
     back. They still render for a marketing-only site borrowing this
     shell, which is why their tightened phone metrics stay below. */
  .ord-nav{gap:.1rem;padding-right:.35rem}
  .ord-locale{gap:.15rem;padding-right:.4rem}
  .ord-locale a{padding:.3rem .45rem}
  .ord-shell{padding:0 .75rem 2.5rem}
  .ord-card{padding:1.5rem 1rem 2rem;border-radius:12px;margin-top:.75rem}
}

/* ---- from restaurant/_item_panel.blade.php ---- */
  .item-panel-photo{width:100%;height:14rem;object-fit:cover;display:block}
  .item-panel-inner{padding:1.5rem;position:relative}
.item-panel-close{position:absolute;top:.75rem;right:.75rem;width:2.75rem;height:2.75rem;display:inline-flex;align-items:center;justify-content:center;border-radius:999px;background:var(--ord-card);border:1px solid var(--ord-rule);color:var(--ord-ink);text-decoration:none;cursor:pointer;font-family:inherit}
  .item-panel-close:hover{background:#F7F7F7}
  .item-panel-name{font-size:clamp(1.75rem,1.4rem + 1.6vw,2.5rem);font-weight:600;line-height:1.1;margin:0 .1rem 1rem 0;padding-right:2.5rem}
  .item-panel-desc{color:var(--ord-ink-muted);margin:0 0 1.25rem}
  /* Allergens: the sentence reads as the tail of the description (pulled up into
     its bottom margin); ordering tokens only. */
  .item-panel-allergens{margin:0 0 1.25rem;font-size:.85rem;color:var(--ord-ink-muted)}
  .item-panel-desc + .item-panel-allergens{margin-top:-.9rem}
  .ord-al-icon{width:16px;height:16px;flex:none}
  .ord-al-sr{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
  .item-panel-qty{display:flex;align-items:center;gap:.75rem;margin:0 0 1.5rem}
  .item-panel-qty-label{font-size:.85rem;font-weight:600;color:var(--ord-ink-muted)}
  /* 44px, from 37.6px. The number field between them takes the same
     min-height: a 34px box between two 44px buttons reads as a row that
     failed to render, and it is a tap target itself. */
  .item-panel-qty-btn{width:2.75rem;height:2.75rem;border:1px solid var(--ord-rule);background:var(--ord-card);color:var(--ord-ink);cursor:pointer;display:inline-flex;align-items:center;justify-content:center;font-family:inherit}
  .item-panel-qty-btn:hover{background:#F7F7F7}
  .item-panel-qty input{width:3.5rem;min-height:2.75rem;text-align:center;border:1px solid var(--ord-rule);padding:.4rem;background:var(--ord-card);color:var(--ord-ink);font:inherit;-moz-appearance:textfield}
  .item-option-group{border:0;padding:0;margin-bottom:1.25rem}
  .item-option-group.is-invalid{background:none}
  .item-option-group.is-invalid .ord-opt-row{border-color:color-mix(in srgb,#dc2626 55%,var(--ord-rule))}
  .item-option-group-title{margin:0 0 .6rem;font-size:.95rem;font-weight:700;color:var(--ord-ink)}
  .item-option-required{font-weight:400;color:var(--ord-ink-muted)}
  .ord-opt-row{display:flex;align-items:center;gap:.65rem;padding:.75rem .9rem;border:1px solid var(--ord-rule);border-radius:var(--ord-btn-radius);margin-bottom:.5rem;cursor:pointer;font-size:.9rem;background:var(--ord-card);transition:border-color .15s,background .15s}
  .ord-opt-row:hover{background:#f8fafc}
  /* Tinted ground as well as an accent border, so the chosen option reads at
     a glance rather than by a one pixel edge. */
  .ord-opt-row:has(input:checked){border-color:var(--c-primary);background:color-mix(in srgb,var(--c-primary) 8%,var(--ord-card))}
  .ord-opt-row input{flex-shrink:0;width:1.05rem;height:1.05rem}
  .ord-opt-name{flex:1;min-width:0}
  /* Badges follow the name; the margin pushes the price to the edge instead. */
  .ord-opt-row .ord-opt-name:has(+ .ord-opt-allergens){flex:0 1 auto}
  .ord-opt-allergens{display:inline-flex;flex-wrap:wrap;gap:.2rem;align-items:center;margin-right:auto;color:var(--ord-ink-muted)}
  .ord-opt-delta{flex:0 0 auto;color:var(--ord-ink-muted);font-weight:600;font-size:.85rem;white-space:nowrap}
  /* --ord-ink-muted on the plain --ord-card row clears the floor with only
     a thin margin (measured ~4.76:1), and the checked row's accent tint
     above pushes it back under 4.5:1 (measured 4.16:1 with the default
     accent). Full ink has enough margin to survive any accent's tint. */
  .ord-opt-row:has(input:checked) .ord-opt-delta{color:var(--ord-ink)}
  .item-panel-extras{border-top:1px dashed var(--ord-rule);padding-top:1rem;margin-bottom:1rem}
  .item-option-clear{background:none;border:0;padding:0;margin-left:.25rem;font:inherit;font-size:.78rem;font-weight:600;color:var(--ord-ink-muted);text-decoration:underline;cursor:pointer}
  .item-option-clear:hover{color:var(--ord-ink)}
  .item-panel-error{background:color-mix(in srgb,#dc2626 16%,var(--ord-card));border:1px solid color-mix(in srgb,#dc2626 45%,var(--ord-rule));color:var(--ord-ink);padding:.6rem .9rem;font-size:.88rem;font-weight:600;margin:0 0 1rem}
  /* Default hidden by a plain class, not x-cloak: x-cloak (or any
     pre-existing inline display:none) combined with x-show never reacts
     again on this bundled Alpine build, which is exactly why the overlay
     and the group tint use :class instead. This client-only error line
     needs the same treatment. */
  .item-panel-client-error{display:none}
  .item-panel-client-error.is-visible{display:block}
  .item-panel-footer{position:sticky;bottom:0;left:0;right:0;padding:1rem 1.5rem;background:var(--ord-card);border-top:1px solid var(--ord-rule)}
  /* Ordering tokens only: a theme preset token here would let the dark
     preset make this unreadable. --ord-ink-muted is safe on --ord-card
     (it fails on the page ground and on a light tint, not here). */
  .ord-notes{padding:0 1.5rem 1rem}
  .ord-notes-label{display:block;font-size:.875rem;font-weight:600;color:var(--ord-ink);margin-bottom:.375rem}
  /* 1rem, and never below it. iOS Safari zooms the whole page in when a
     field under 16px takes focus, and does not zoom back out when the
     keyboard closes. This is the LAST field before an irrevocable add, on
     a sheet whose footer is position:sticky (above), so the zoom left the
     add button partly behind the keyboard with no way back to it short of
     pinching. checkout.blade.php:51 pins 1rem on its own fields for the
     same reason; this was the one field on the surface still under it. */
  .ord-notes-input{width:100%;box-sizing:border-box;padding:.625rem .75rem;font:inherit;font-size:1rem;color:var(--ord-ink);background:var(--ord-card);border:1px solid var(--ord-rule);border-radius:var(--ord-btn-radius);resize:vertical}
  .ord-notes-input:focus-visible{outline:2px solid var(--ord-ink);outline-offset:1px}
  .ord-notes-input::placeholder{color:var(--ord-ink-muted)}
  .ord-notes-count{margin:.25rem 0 0;text-align:right;font-size:.75rem;color:var(--ord-ink-muted)}
  .ord-panel-cta{display:flex;align-items:stretch;width:100%;border:0;padding:0;cursor:pointer;background:var(--c-primary);color:var(--c-primary-ink);font:inherit;min-height:3.25rem;border-radius:var(--ord-btn-radius);overflow:hidden;transition:background-color .15s}
  /* Not filter:brightness(.94): see .btn-primary:hover in _head.blade.php.
     --c-primary-hover already moves the right direction for whichever ink
     is on this control. */
  .ord-panel-cta:hover{background:var(--c-primary-hover)}
  .ord-panel-cta:focus-visible{outline:2px solid var(--ord-ink);outline-offset:2px}
  .ord-panel-cta-total{flex:0 0 auto;display:flex;align-items:center;padding:0 1.1rem;font-weight:700;border-right:1px solid rgba(255,255,255,.35)}
  .ord-panel-cta-label{flex:1;display:flex;align-items:center;justify-content:center;padding:0 1rem;font-weight:700}

/* ---- from restaurant/_cart_lines.blade.php ---- */
/* The separator is a TOP border on every line after the first, not a bottom
   border with a :last-of-type reset - the reset matched nothing, because the
   total row follows the lines inside the same card, so the last line kept a
   rule that sat immediately above the total's own. */
.cart-line{display:flex;align-items:flex-start;gap:1rem;padding:1.25rem 0}
.cart-line + .cart-line{border-top:1px solid var(--ord-rule)}
/* The menu row shows a photo and the item panel shows a big one; the cart -
   where the customer confirms what they are actually buying - showed none
   at all. */
.cart-line-photo,.cart-line-photo-empty{width:3.5rem;height:3.5rem;flex:none;object-fit:cover;border-radius:10px;display:block}
.cart-line-photo-empty{background:#f1f5f9;border:1px solid var(--ord-rule)}
.cart-line-info{flex:1;min-width:0;display:flex;flex-direction:column;gap:.15rem}
.cart-line-name{font-weight:600;color:var(--ord-ink)}
.cart-line-options{color:var(--ord-ink-muted);font-size:.85rem}
/* Not muted: this is the customer's own instruction and they need to see
   it stuck. --ord-ink is safe on the card this renders in. */
.cart-line-notes{color:var(--ord-ink);font-size:.85rem;font-style:italic}
.cart-line-price{color:var(--ord-ink-muted);font-size:.875rem;font-variant-numeric:tabular-nums}
.cart-line-side{display:flex;flex-direction:column;align-items:flex-end;gap:.5rem;flex:none}
.cart-line-total{font-weight:700;color:var(--ord-ink);white-space:nowrap;font-variant-numeric:tabular-nums}

/* The stepper the item panel already ships, grown to a 44px target.
   What this replaced: a <select> of 0-20 with onchange="this.form.submit()".
   Changing a select was the whole interaction, which is a WCAG 3.2.2
   on-input change of context; in Firefox a closed select fires `change` on
   every arrow key, so a keyboard user moving 1 -> 4 submitted at 2; the
   control set border, radius, padding, background and colour but not
   `font`, and a select does not inherit it, so it rendered at the UA
   default of about 13.3px - under iOS's 16px zoom threshold; and with JS
   off the select did nothing at all while Remove submitted whatever
   quantity happened to be selected. Two plain forms have none of that. */
.cart-qty{display:flex;align-items:center;gap:.35rem}
.cart-qty form{margin:0;display:inline-flex}
.cart-qty-btn{width:2.75rem;height:2.75rem;display:inline-flex;align-items:center;justify-content:center;border:1px solid var(--ord-rule-strong);border-radius:999px;background:var(--ord-card);color:var(--ord-ink);font:inherit;cursor:pointer;transition:background-color .15s}
.cart-qty-btn:hover{background:#f1f5f9}
.cart-qty-btn:focus-visible{outline:2px solid var(--ord-ink);outline-offset:2px}
/* nowrap: "Кол. 2" is one reading, and in a narrow basket pane the space
   between the word and the number was where it broke into two lines. */
.cart-qty-value{min-width:2rem;text-align:center;font-weight:700;font-variant-numeric:tabular-nums;color:var(--ord-ink);white-space:nowrap}

@media (max-width:640px){
  /* Three 44px targets plus a total plus a thumbnail do not fit beside a
     dish name on a 390px phone - the name wrapped to three lines and the
     stepper crowded it. The stepper gets its own full-width row under the
     item instead, which is also where a thumb naturally reaches. */
  .cart-line{display:grid;grid-template-columns:auto 1fr;gap:.5rem .75rem;align-items:start}
  .cart-line-photo,.cart-line-photo-empty{width:3rem;height:3rem}
  .cart-line-side{grid-column:1 / -1;flex-direction:row;align-items:center;justify-content:space-between;width:100%}
}

/* The same reflow the phone gets, asked for by class instead of by
   viewport. The pane is 21rem - 336px - inside a viewport of at least
   1400px, so the media query above can never fire there: a viewport query
   cannot see a narrow container, and the wide layout's 3.5rem photo plus
   flex:none side column leaves about 105px for the dish name. Not a
   container query: .item-panel-overlay is a sibling of .ord-item, so
   `contain` on an ancestor would size all seventy bottom sheets.
   (0,2,0) beats the base .cart-line's (0,1,0); inside the media query the
   two carry identical declarations, which CartTest pins. */
.cart-line.is-compact{display:grid;grid-template-columns:auto 1fr;gap:.5rem .75rem;align-items:start}
.cart-line.is-compact .cart-line-photo,.cart-line.is-compact .cart-line-photo-empty{width:3rem;height:3rem}
.cart-line.is-compact .cart-line-side{grid-column:1 / -1;flex-direction:row;align-items:center;justify-content:space-between;width:100%}

/* ---- from restaurant/_order_loyalty.blade.php ---- */
.ost-loyalty{margin-top:1.25rem;background:var(--ord-card);border:1px solid var(--ord-rule);border-radius:var(--ord-radius);padding:1.25rem;box-shadow:var(--ord-shadow)}
.ost-loyalty-eyebrow{margin:0;font-size:.75rem;font-weight:700;letter-spacing:.09em;text-transform:uppercase;color:var(--ord-ink-muted)}
.ost-loyalty-name{margin:.15rem 0 0;font-size:1.15rem;font-weight:700;letter-spacing:-.01em;color:var(--ord-ink)}
.ost-loyalty-intro{margin:.4rem 0 0;font-size:.9375rem;color:var(--ord-ink-muted)}

/* The rate is the offer, so it is the one big number in the band. The
   digits take --ord-ink rather than the accent: nothing clamps a
   merchant's accent luminance, and a pale one measured 2.19:1 on this
   same page once already. */
.ost-loyalty-earn{display:flex;flex-wrap:wrap;align-items:baseline;gap:.1rem .55rem;margin:.9rem 0 0}
.ost-loyalty-earn strong{font-size:clamp(1.9rem,1.5rem + 1.4vw,2.4rem);font-weight:800;line-height:1;letter-spacing:-.02em;color:var(--ord-ink);font-variant-numeric:tabular-nums}
.ost-loyalty-earn span{font-size:.9375rem;color:var(--ord-ink-muted)}
/* The seam between what a visit earns and where the points go. */
.ost-loyalty-spend-heading{margin:1.15rem 0 0;font-size:.72rem;font-weight:700;letter-spacing:.11em;text-transform:uppercase;color:var(--ord-ink-muted)}
.ost-loyalty-note{margin:.9rem 0 0;font-size:.9375rem;color:var(--ord-ink-muted)}

/* A rail rather than a grid: a shop can run a dozen rewards and this band
   sits between the customer's status and the customer's receipt, neither
   of which may be pushed off the screen by an advertisement. It scrolls
   sideways on every width, and it is focusable, because a scroll container
   reachable only by dragging is unreachable from a keyboard. */
.ost-loyalty-rail{display:flex;gap:.9rem;list-style:none;margin:1.1rem 0 0;padding:0 0 .4rem;overflow-x:auto;scroll-snap-type:x proximity;overscroll-behavior-x:contain}
.ost-loyalty-spend-heading + .ost-loyalty-rail{margin-top:.65rem}
.ost-loyalty-rail:focus-visible{outline:2px solid var(--ord-ink);outline-offset:3px;border-radius:4px}
.ost-loyalty-reward{flex:0 0 7rem;scroll-snap-align:start;display:flex;flex-direction:column;align-items:center;text-align:center;gap:.45rem}
/* The medallion is one size whichever fills it, so a shop whose rewards
   are half photographed and half emoji does not get a ragged row. */
.ost-loyalty-photo{width:5.25rem;height:5.25rem;border-radius:50%;object-fit:cover;background:color-mix(in srgb,var(--c-primary) 12%,var(--ord-card));border:1px solid var(--ord-rule)}
.ost-loyalty-glyph{display:grid;place-items:center;font-size:2.1rem;line-height:1}
.ost-loyalty-reward-label{font-weight:600;font-size:.875rem;line-height:1.25;color:var(--ord-ink)}
.ost-loyalty-cost{display:inline-block;padding:.15rem .55rem;border-radius:999px;background:color-mix(in srgb,var(--c-primary) 18%,var(--ord-card));color:var(--ord-ink);font-size:.78rem;font-weight:700;font-variant-numeric:tabular-nums}

.ost-loyalty-tiers{list-style:none;margin:1.1rem 0 0;padding:0;display:flex;flex-direction:column;gap:.5rem}
.ost-loyalty-tier{display:flex;align-items:center;gap:.75rem;padding:.6rem .85rem;border:1px solid var(--ord-rule);border-radius:var(--ord-btn-radius);font-size:.9375rem;color:var(--ord-ink)}
.ost-loyalty-threshold{min-width:2rem;text-align:center;font-size:1.1rem;font-weight:700;font-variant-numeric:tabular-nums}
.ost-loyalty-percent{font-weight:700}

.ost-loyalty-foot{display:flex;flex-wrap:wrap;align-items:baseline;gap:.35rem .75rem;margin:1.1rem 0 0;padding-top:.85rem;border-top:1px solid var(--ord-rule);font-size:.85rem;color:var(--ord-ink-muted)}
.ost-loyalty-foot a{color:var(--ord-ink);font-weight:600;white-space:nowrap}
