/* NorthPoint Cafe — Order Ahead
   Tokens are lifted from the brand guide one-pager: Pantone 7716 teal,
   324 light teal, 714 orange, the cream, and Pantone Black C. The dark
   ground is a warm near-black derived from that black rather than a
   neutral grey, so the whole thing sits in the same temperature.

   Orange does exactly one job — the staff discount — per the brand's own
   10% usage weighting. Do not spend it on anything else: an error, a
   closed cafe or a cancelled order is weight, a border and its wording.
   cafe_order/tests_review_frontend.py fails the build if it creeps back. */

:root {
  --ink: #171412;
  --surface: #1E1A18;
  --surface-2: #211D1A;
  --raised: #262220;
  --line: #2C2724;
  --line-strong: #37312D;

  --cream: #FFF9EF;
  --body: #C9C0B7;
  --muted: #9E958C;
  /* Was #7E756D: 4.06:1 on --ink and 3.49 on --raised, under AA for the
     11px hints, the placeholders and the 9px slot label it colours. Same
     hue, the smallest lift that clears 4.5:1 on all four grounds (4.53 on
     --raised, the lightest). --ghost stays low on purpose: it only marks
     slots that cannot be chosen. */
  --faint: #918880;
  --ghost: #5C5550;
  /* The edge of an unticked checkbox or radio, which is all there is of
     the control until it is ticked. Was #4A433E: 1.62:1 on --raised, under
     WCAG 1.4.11's 3:1 for a control's boundary. Same hue and saturation,
     the smallest lift that clears 3:1 on all four grounds (3.04 on
     --raised, the lightest). */
  --edge: #766B63;

  --teal: #00968F;        /* brand */
  --teal-bright: #00B5AB; /* interactive fill, lifted for dark-mode contrast */
  --mint: #9CDBD9;        /* brand, accent text */
  --on-teal: #10201E;
  --amber: #F68D2E;       /* brand, discounts only */
  --band: #1A1715;        /* the tab bar's ground, a step under --surface */

  --sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Helvetica Neue', Arial, sans-serif;
  --serif: 'Libre Caslon Text', Georgia, 'Times New Roman', serif;

  --tap: 44px;            /* never smaller, anywhere */
  --r-sm: 12px; --r: 14px; --r-lg: 16px; --r-pill: 999px;
}

* { box-sizing: border-box; }

/* Any class that sets `display` outranks the browser's own
   [hidden]{display:none}, because a class selector beats a UA rule. That
   is how the payment-error box sat open and orange on every checkout with
   nothing wrong. Global, so it cannot bite the next component either. */
[hidden] { display: none !important; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0; background: var(--ink); color: var(--cream);
  font: 15px/1.5 var(--sans); -webkit-font-smoothing: antialiased;
}
a { color: var(--mint); text-decoration: none; }
button, input, select, textarea { font: inherit; color: inherit; }
:focus-visible { outline: 2px solid var(--teal-bright); outline-offset: 2px; border-radius: 6px; }

.shell { max-width: 460px; margin: 0 auto; min-height: 100vh;
         display: flex; flex-direction: column; padding-bottom: 96px; }

/* header */
.top { display: flex; align-items: center; gap: 12px; padding: 14px 16px; }
/* The menu's header is held at --hdr-h by .top.pinned below, not by the
   logo, so anything up to --tap is free. Past that the header grows and
   eats into the menu. The wordmark is 2.69:1, so 36px reads as ~97px wide —
   comfortable even at 320px beside "Open until 4:00 PM". */
.top .logo { height: 36px; max-height: var(--tap); width: auto; display: block; }
.back { width: var(--tap); height: var(--tap); margin-left: -10px;
        display: flex; align-items: center; justify-content: center;
        background: none; border: 0; cursor: pointer; color: var(--cream); }
.title { font: 700 20px/1.2 var(--serif); flex: 1; }

/* pickup context bar */
.context { margin: 0 16px 12px; min-height: 52px; border-radius: var(--r);
           background: var(--surface-2); border: 1px solid var(--line-strong);
           display: flex; align-items: center; gap: 10px; padding: 8px 14px; }
.context .who { flex: 1; display: flex; flex-direction: column; gap: 1px; }
.context strong { font-size: 13px; font-weight: 600; }
.context small { font-size: 11px; color: var(--muted); }

/* category chips */
.chips { display: flex; gap: 8px; padding: 0 16px 14px; overflow-x: auto;
         scrollbar-width: none; }
.chips::-webkit-scrollbar { display: none; }
.chip { min-height: var(--tap); padding: 0 16px; border-radius: var(--r-pill);
        background: var(--surface-2); border: 1px solid var(--line-strong);
        color: var(--body); font-size: 13px; font-weight: 500;
        display: inline-flex; align-items: center; white-space: nowrap; flex-shrink: 0; }
.chip[aria-current='true'] { background: var(--teal-bright); border-color: var(--teal-bright);
                             color: var(--on-teal); font-weight: 600; }

/* item rows */
.section-head { display: flex; align-items: baseline; justify-content: space-between;
                padding: 0 16px 10px; }
.section-head h2 { font: 700 19px/1.2 var(--serif); margin: 0; }
.section-head span { font-size: 12px; color: var(--muted); }

/* --- the menu's frozen header ---------------------------------------
   Everything that says WHERE you are stays put while the list moves under
   it: the wordmark and opening time, the category strip, and the name
   and count of the category you are in. A long drinks list otherwise
   scrolls the chips off the top, and switching category means scrolling
   all the way back up first -- which is the whole reason the strip is
   there.

   Three separate sticky elements rather than one wrapper, because what
   sits between them -- an open order, a closed cafe -- is news rather
   than navigation and is meant to scroll away. Those rows pass behind the
   pinned ones, which is why each pinned row carries an opaque --ink
   background instead of letting the body show through.

   The offsets are the two rows' own heights, and both are fixed rather
   than content-driven: .top is held at 72px (it was 14px + a 44px account
   control + 14px, and the offsets below still count on that),
   and .chips is a 44px chip plus its 14px bottom padding. A taller logo
   (anything past --tap) or a chip that grows has to be reflected here --
   the shortfall would show as a stripe of moving list wedged between two
   pinned rows. */
:root { --hdr-h: 72px; --chips-h: 58px; }
.top.pinned, .chips, .section-head {
  position: -webkit-sticky; position: sticky; background: var(--ink);
}
/* Only where the class is applied: the same header is on the cart,
   checkout and confirmation pages, which are short forms with nothing to
   scroll past. Under .dock (20) so the cart bar still wins. */
.top.pinned { top: 0; z-index: 12; min-height: var(--hdr-h); }
/* "Open until 4:00 PM" where the account control used to be: the menu says
   when the cafe stops taking orders, and the closed strip below says the rest. */
.open-until { margin-left: auto; font-size: 13px; color: var(--body); text-align: right; }
.chips { top: var(--hdr-h); z-index: 11; }
.section-head { top: calc(var(--hdr-h) + var(--chips-h)); z-index: 10; }

/* A phone on its side has about 375px of height. Pinning 163px of header
   to the top of that, with the cart dock taking another 76 at the bottom,
   leaves less list than header. Below this, nothing is pinned. */
@media (max-height: 520px) {
  .top.pinned, .chips, .section-head { position: static; }
}
.rows { display: flex; flex-direction: column; gap: 10px; padding: 0 16px; }
.row { display: flex; align-items: center; gap: 12px; min-height: 88px; padding: 12px;
       border-radius: var(--r-lg); background: var(--surface);
       border: 1px solid var(--line); }
.row .meta { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px;
             overflow-wrap: anywhere; }
.row .name { font: 700 16px/1.25 var(--serif); }
.row .desc { font-size: 12px; color: var(--muted); line-height: 1.35;
             display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
             overflow: hidden; }
.row .price { font-size: 13px; font-weight: 600; color: var(--mint); }
.row .add { width: 32px; height: 32px; flex-shrink: 0; border-radius: 16px;
            background: var(--raised); border: 1px solid var(--line-strong);
            display: flex; align-items: center; justify-content: center; }

/* the tile that stands in for a photo — Clover exposes none over the API */
.tile { width: 64px; height: 64px; border-radius: var(--r-sm); flex-shrink: 0;
        display: flex; align-items: center; justify-content: center;
        color: #DFF4F2; background: linear-gradient(150deg, var(--teal) 0%, #075E5C 100%); }
.tile.cold  { background: linear-gradient(150deg, #1F6F6C 0%, #0C4442 100%); }
.tile.food  { background: linear-gradient(150deg, #6B4A2A 0%, #3C2917 100%); }
.tile.snack { background: linear-gradient(150deg, #4A5A3A 0%, #2A331F 100%); }
.tile.lg { width: 100%; height: 150px; border-radius: 18px; }
.tile img { width: 100%; height: 100%; object-fit: cover; border-radius: inherit; }

/* item detail */
.detail { padding: 0 16px; display: flex; flex-direction: column; gap: 22px; }
.detail h1 { font: 700 26px/1.15 var(--serif); margin: 0 0 6px; }
.detail .lede { font-size: 13px; color: var(--muted); line-height: 1.45; margin: 0; }
.detail .from { font-size: 17px; font-weight: 700; color: var(--mint); margin-top: 6px; display: block; }
.group > .label { display: flex; align-items: baseline; gap: 8px; margin-bottom: 8px; }
.group .label b { font-size: 13px; font-weight: 700; letter-spacing: .3px; }
.group .label span { font-size: 11px; color: var(--muted); }
.opt { min-height: 52px; display: flex; align-items: center; gap: 12px;
       border-bottom: 1px solid var(--line); cursor: pointer; }
.opt:last-child { border-bottom: 0; }
.opt input { position: absolute; opacity: 0; pointer-events: none; }
.opt .box { width: 20px; height: 20px; flex-shrink: 0; border: 1.5px solid var(--edge); }
.opt .box.radio { border-radius: 10px; }
.opt .box.check { border-radius: 6px; }
.opt input:checked + .box { border-color: var(--teal-bright); background: var(--teal-bright); }
.opt input:checked + .box.radio { background: var(--ink); border-width: 5.5px; }
.opt input:checked + .box.check::after {
  content: ''; display: block; width: 6px; height: 11px; margin: 1px auto;
  border: solid var(--on-teal); border-width: 0 2.5px 2.5px 0; transform: rotate(45deg); }
/* An input hidden with opacity:0 still takes keyboard focus, and the
   global :focus-visible ring is drawn on something nobody can see. So
   every such pattern here (.opt, .pill-choice, .consent) hands the ring to
   the element drawn in the input's place. Teal, never orange. */
.opt input:focus-visible + .box { outline: 2px solid var(--teal-bright); outline-offset: 2px; }
.opt .opt-name { flex: 1; font-size: 14px; color: var(--body); }
.opt input:checked ~ .opt-name { color: var(--cream); font-weight: 500; }
.opt .opt-price { font-size: 13px; font-weight: 600; color: var(--mint); }

textarea.note { width: 100%; min-height: 76px; border-radius: var(--r);
                background: var(--surface); border: 1px solid var(--line);
                padding: 14px; color: var(--cream); resize: vertical; font-size: 13px; }
.hint { font-size: 11px; color: var(--faint); line-height: 1.4; }

/* cart */
.cart-line { border-radius: var(--r-lg); background: var(--surface);
             border: 1px solid var(--line); padding: 14px; }
.cart-line .head { display: flex; align-items: baseline; gap: 10px; }
.cart-line .head .name { flex: 1; font: 700 16px/1.25 var(--serif); }
.cart-line .mods { font-size: 12px; color: var(--muted); margin-top: 6px; line-height: 1.4; }
.cart-line .note { font-size: 12px; color: var(--mint); margin-top: 3px; }
.cart-line .actions { display: flex; align-items: center; gap: 10px; margin-top: 12px; }

.stepper { height: var(--tap); border-radius: var(--r-sm); background: var(--raised);
           display: flex; align-items: center; gap: 2px; padding: 0 4px; }
.stepper button { width: 36px; height: 36px; border: 0; background: none; cursor: pointer;
                  display: flex; align-items: center; justify-content: center; color: var(--muted); }
.stepper button:last-of-type { color: var(--cream); }
.stepper .q { font-size: 14px; font-weight: 700; min-width: 18px; text-align: center; }

.totals { display: flex; flex-direction: column; gap: 11px; padding: 4px 0; }
.totals .t { display: flex; align-items: baseline; }
.totals .t span:first-child { flex: 1; font-size: 13px; color: var(--muted); }
.totals .t span:last-child { font-size: 13px; color: var(--body); font-variant-numeric: tabular-nums; }
.totals .rule { height: 1px; background: var(--line); }
.totals .grand span:first-child { font-size: 16px; font-weight: 700; color: var(--cream); }
/* Sans, not the serif display face. The label beside it is sans, so the
   pair read as two different typefaces arguing rather than one figure. */
.totals .grand span:last-child { font-size: 22px; font-weight: 700; color: var(--cream);
                                 font-variant-numeric: tabular-nums;
                                 letter-spacing: -.01em; }
.totals .disc span { color: var(--amber) !important; }

/* buttons */
.btn { display: flex; align-items: center; justify-content: center; gap: 8px;
       min-height: 54px; border-radius: var(--r-lg); border: 0; width: 100%;
       font-size: 15px; font-weight: 700; cursor: pointer; text-align: center; }
.btn-primary { background: var(--teal-bright); color: var(--on-teal); }
.btn-ghost { background: none; border: 1px solid var(--line-strong); color: var(--body); font-weight: 600; }
.btn-dashed { background: none; border: 1px dashed var(--line-strong); color: var(--mint);
              min-height: 50px; font-size: 13px; }
.btn-icon { width: var(--tap); height: var(--tap); border-radius: var(--r-sm); border: 0;
            background: none; color: var(--faint); cursor: pointer;
            display: flex; align-items: center; justify-content: center; }

/* sticky bottom */
.dock { position: fixed; left: 0; right: 0; bottom: 0; z-index: 20;
        background: linear-gradient(180deg, rgba(23,20,18,0) 0%, var(--ink) 28%);
        padding: 18px 16px 16px; }
.dock-inner { max-width: 460px; margin: 0 auto; display: flex; gap: 12px; align-items: center; }
.cartbar { min-height: 54px; border-radius: var(--r-lg); background: var(--teal-bright);
           color: var(--on-teal); display: flex; align-items: center;
           justify-content: space-between; padding: 0 18px; width: 100%; }
.cartbar b { font-size: 15px; font-weight: 700; }
.cartbar span { font-size: 14px; font-weight: 600; }

.msgs { padding: 0 16px 12px; display: flex; flex-direction: column; gap: 8px; }
/* The neutral box is the default because only .error and .success were
   ever styled, and an info or warning message rendered as bare text. */
.msg { border-radius: var(--r-sm); padding: 11px 14px; font-size: 13px;
       background: var(--surface-2); border: 1px solid var(--line-strong); color: var(--body); }
/* Something went wrong, said without orange: cream at weight and a rule
   down the leading edge, the way the register and Manager mark theirs.
   The wording does the rest. */
.msg.error, .msg.warning { color: var(--cream); font-weight: 600;
                           border-left: 3px solid var(--body); }
.msg.success { background: rgba(0,181,171,.09); border: 1px solid rgba(0,181,171,.3); color: var(--mint); }

.empty { padding: 60px 24px; text-align: center; color: var(--muted); }
.empty h2 { font: 700 22px/1.2 var(--serif); color: var(--cream); margin: 0 0 8px; }

/* --- checkout: day tabs, ASAP card, slot grid --- */
.segmented { height: 48px; border-radius: var(--r); background: var(--surface-2);
             border: 1px solid var(--line); padding: 4px; display: flex; gap: 4px; }
.segmented .seg { flex: 1; border-radius: 11px; display: flex; align-items: center;
                  justify-content: center; font-size: 13px; font-weight: 500;
                  color: var(--muted); }
.segmented .seg.on { background: #35302C; color: var(--cream); font-weight: 700; }

.asap { width: 100%; min-height: 74px; border-radius: var(--r-lg); background: var(--surface);
        border: 1px solid var(--line); display: flex; align-items: center; gap: 14px;
        padding: 0 16px; cursor: pointer; text-align: left; }
.asap.on { border-color: var(--teal-bright); background: rgba(0,181,171,.1); }
.asap .bolt { width: 40px; height: 40px; border-radius: 20px; flex-shrink: 0;
              background: rgba(0,181,171,.14); color: var(--teal-bright);
              display: flex; align-items: center; justify-content: center; }
.asap-text { display: flex; flex-direction: column; gap: 2px; }
.asap-text strong { font-size: 14px; font-weight: 600; }
.asap-text small { font-size: 12px; color: var(--muted); }

.slotgrid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; }
.slot { min-height: 58px; border-radius: 13px; background: var(--surface);
        border: 1px solid var(--line); display: flex; flex-direction: column;
        align-items: center; justify-content: center; gap: 2px; cursor: pointer;
        color: var(--cream); }
.slot .t { font-size: 14px; font-weight: 600; }
.slot .sub { font-size: 9px; color: var(--faint); }
.slot.on { background: var(--teal-bright); border-color: var(--teal-bright); color: var(--on-teal); }
.slot.on .t { font-weight: 700; }
.slot.on .sub { color: var(--on-teal); font-weight: 700; letter-spacing: .5px; }
.slot.off { background: #1A1715; border-color: transparent; color: var(--ghost); cursor: default; }
.slot.off .t { color: var(--ghost); }
.slot.off .sub { color: var(--ghost); font-weight: 700; letter-spacing: .5px; }

/* margin-bottom because on checkout this sits directly above the cart
   summary and read as one merged block on a phone.
   Every checkout blocker and the payment error use this box, and so do
   plain asides ("Slots fill fast"). It was orange, which spent the
   discount's colour on bad news. It stands out by a leading rule and
   cream text instead, and the wording says whether it is a problem. */
.notice { margin-bottom: 14px; border-radius: var(--r); background: var(--surface-2);
          border: 1px solid var(--line-strong); border-left: 3px solid var(--body);
          padding: 13px 14px; display: flex; gap: 11px; font-size: 12px;
          color: var(--cream); line-height: 1.45; }
.notice .ico { color: var(--cream); flex-shrink: 0; margin-top: 1px; display: flex; }

/* The closed notice on the menu, in the row the old "Pickup time not set"
   used to occupy. It has to out-read the ordinary context row, because it
   is telling somebody not to bother rather than describing state. That
   is the leading rule and a heavier headline, not orange. */
.context-closed { border-left: 3px solid var(--body);
                  align-items: flex-start; padding: 12px 14px; }
.context-closed .ico { color: var(--cream); display: flex; margin-top: 1px; }
.context-closed strong { color: var(--cream); font-weight: 700; }
.context-closed .hours { font-size: 12px; }

/* Apple Pay sits above the card fields with a divider between, the
   conventional order: the one-tap route first, typing as the fallback. */
/* Height is CAPPED, not just floored. Clover mounts a cross-origin iframe
   and we cannot see inside it; on a browser where the wallet is
   unavailable it mounted something several hundred pixels tall and
   entirely blank, which pushed the card fields off the screen. A wallet
   button is ~48px in every design guideline either vendor publishes, so
   anything taller is a failure, not a big button. */
/* Clover exposes no styling for the Apple Pay button itself -- its
   appearance is fixed, and only this container is ours. The button is
   black, which on a near-black surface reads as a hole rather than a
   control, so the container carries the edge instead. Not a modification
   of the button: Apple's guidelines are about the asset, not what sits
   behind it.

   Height is CAPPED as well as floored. Clover's default is 40px with a
   64px maximum, and on a browser where the wallet was unavailable it once
   mounted several hundred pixels of nothing and pushed the card fields off
   the screen. 48 clears the 44px touch target and nothing taller is
   legitimate.

   Full width is a choice, not a requirement -- Apple sets a ~100pt
   minimum and no maximum. It matches the card fields and the Pay button
   below, which is the whole argument for it. */
#payment-request-button, #googlepay-button {
    max-height: 48px; overflow: hidden; margin-bottom: 4px;
    border: 1px solid var(--line-strong); border-radius: 8px;
    box-sizing: border-box; }
/* An iframe is inline by default, so it sits on a text baseline and leaves
   room underneath for descenders -- a few pixels of container visible below
   the button, which read as a misaligned border. display:block takes it out
   of inline layout entirely. */
#payment-request-button iframe, #googlepay-button iframe {
    display: block; width: 100%; }
/* Google mounts a 150px iframe and, left alone, centres a ~48px button in
   it -- so the cap above showed 48px of empty chrome and nothing else,
   which is the whole history of this button looking like a black hole.
   An explicit height gives buttonSizeMode:'fill' something to fill, and
   the iframe is pinned to it so the button and its frame stay the same
   size. Apple is deliberately not included: its button has a fixed
   appearance we do not control and it already renders correctly. */
#googlepay-button { height: 48px; }
#googlepay-button iframe { height: 100%; }
#payment-request-button:empty, #googlepay-button:empty { display: none; }
/* Visible but untappable until the details above are filled in. Hiding it
   instead meant a customer who wanted Apple Pay could not find it and had
   no way to learn what would reveal it. */
.wallet-locked { opacity: .4; pointer-events: none; }
#wallet-hint { margin: 6px 0 0; }
/* Google's brand guidelines set a 90x40 floor. Ours is 44 for the touch
   target, which clears it. */
#googlepay-button { min-width: 90px; }
.paydivider { display: flex; align-items: center; gap: 12px; margin: 14px 0 16px;
              color: var(--faint); font-size: 12px; }
.paydivider::before, .paydivider::after {
    content: ''; flex: 1; height: 1px; background: var(--line); }

/* A saved order, or a past one, with its action beside it. The row is not
   a link: the whole point is the button, and a row that is both a link and
   a form is a row where a mis-tap orders something. */
.fav { display: flex; align-items: center; gap: 10px; margin-bottom: 8px;
       min-height: var(--tap); padding: 10px 12px; border-radius: var(--r);
       background: var(--surface); border: 1px solid var(--line); }
.fav .grow { flex: 1; display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.fav strong { font-size: 13px; font-weight: 600; }
.fav small { font-size: 11px; color: var(--muted); line-height: 1.35;
             overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fav form { display: flex; }
.fav .fav-go { min-height: 36px; padding: 0 14px; font-size: 13px; }

/* Opening hours, rendered from BusinessHours rows rather than written out
   as prose in a template (Decision R). Used on the closed page and inside
   the checkout notice, so it has to read well on both. */
.hours { list-style: none; margin: 8px 0 0; padding: 0; }
.hours li { display: flex; justify-content: space-between; gap: 16px;
            padding: 3px 0; }
.hours-days { color: var(--muted); }
.hours-time { color: var(--body); white-space: nowrap; }
/* A one-off closure has to out-read the ordinary week sitting above it —
   the whole point is that today is not the usual Monday. Cream rather than
   --amber, which is reserved for discounts. */
.hours-exceptions { margin-top: 6px; padding-top: 6px; border-top: 1px solid var(--line); }
.hours-exceptions .hours-days,
.hours-exceptions .hours-time { color: var(--cream); }

/* --- checkout page --- */
.field { min-height: 56px; border-radius: var(--r); background: var(--surface);
         border: 1px solid var(--line); padding: 0 15px; width: 100%; font-size: 14px; }
.field::placeholder { color: var(--faint); }
.summary-row { min-height: 56px; border-radius: var(--r); background: var(--surface);
               border: 1px solid var(--line); display: flex; align-items: center;
               gap: 12px; padding: 12px 14px; }
.summary-row .grow { flex: 1; display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.summary-row strong { font-size: 14px; font-weight: 600; }
.summary-row small { font-size: 11px; color: var(--muted); }
.pill-choice { display: flex; gap: 4px; padding: 4px; height: 52px;
               border-radius: var(--r); background: var(--surface-2); border: 1px solid var(--line); }
.pill-choice label { flex: 1; border-radius: 11px; display: flex; align-items: center;
                     justify-content: center; gap: 7px; cursor: pointer;
                     font-size: 13px; color: var(--muted); }
.pill-choice input { position: absolute; opacity: 0; pointer-events: none; }
.pill-choice input:checked + label { background: #35302C; color: var(--cream); font-weight: 700; }
/* Inset: the pills sit 4px apart inside their track, and a ring drawn
   outside would run into the neighbouring pill and the track's edge. */
.pill-choice input:focus-visible + label { outline: 2px solid var(--teal-bright); outline-offset: -2px; }
/* Three methods share the width two used to have. The labels are already
   shortened in the template; this buys the rest, and on a narrow phone the
   icons go rather than let a label wrap inside a 52px-tall pill. */
.pill-choice.three-up label { font-size: 12px; gap: 5px; }
@media (max-width: 400px) {
  .pill-choice.three-up label { gap: 0; }
  .pill-choice.three-up label svg { display: none; }
}

/* --- Clover hosted fields ---
   The iframes paint their own light background, so their text must be dark.
   Styling them to match the dark page makes the customer's typing invisible
   — a real bug from Phase 0, not a hypothetical. */
.fieldlabel { display: block; font-size: 10px; letter-spacing: .6px;
              text-transform: uppercase; color: var(--faint);
              margin: 0 0 3px; font-weight: 700; }
/* 44px is the floor, not a preference: it is the minimum touch target, and
   these are the fields somebody taps on a phone with a card in their other
   hand. Shorter would look tidier and be worse. Every other input on this
   page is 56px, so these are already the most compact thing on it. */
.ccfield { height: 44px; border-radius: 8px; border: 1px solid var(--line-strong);
           /* Matches the style object handed to Clover in checkout.html. If
              the iframe ignores `body.background` this stays visible behind
              a transparent frame and the digits are still legible against
              it — so a failure looks like light text on the right colour,
              not text on white. */
           background: var(--surface); padding: 0 8px; overflow: hidden; }
/* Clover may wrap its input, so constrain any descendant, not just a
   direct child — and the container clips regardless. */
.ccfield iframe, .ccfield > div { height: 42px !important; width: 100% !important;
           display: block; border: 0; }
.ccrow { display: flex; gap: 8px; margin-top: 8px; }
.ccrow > div { flex: 1; min-width: 0; }
/* ZIP needs far less room than the other two. */
.ccrow > div:last-child { flex: 0 0 92px; }
#card-fields > .fieldlabel:first-child { margin-top: 0; }
.secure { display: flex; gap: 9px; margin-top: 12px; font-size: 11px;
          color: #7E8E8C; line-height: 1.45; }
.secure .ico { color: #6E8E8B; flex-shrink: 0; margin-top: 1px; display: flex; }

/* --- confirmation --- */
.hero-state { display: flex; flex-direction: column; align-items: center; gap: 12px;
              padding: 4px 0; text-align: center; }
.hero-state .ring { width: 68px; height: 68px; border-radius: 34px;
                    background: rgba(0,181,171,.15); border: 1.5px solid var(--teal-bright);
                    color: var(--teal-bright); display: flex; align-items: center;
                    justify-content: center; }
/* Refunded, unconfirmed or declined: not the teal of an order that went
   through, and not orange either. A heavier neutral ring, and the headline
   under it says which. */
.hero-state.cancelled .ring, .hero-state.pending .ring,
.hero-state.failed .ring { background: var(--raised); border: 2.5px solid var(--body);
                              color: var(--cream); }
.hero-state h1 { font: 700 25px/1.15 var(--serif); margin: 0; }
.hero-state .code { display: flex; align-items: center; gap: 8px; }
.hero-state .code span { font-size: 13px; color: var(--muted); }
.hero-state .code b { font-size: 17px; font-weight: 700; letter-spacing: 2px; color: var(--mint); }

.panel-card { border-radius: var(--r-lg); background: var(--surface);
              border: 1px solid var(--line); padding: 16px; }
.pickup-head { display: flex; flex-direction: column; gap: 3px; }
.eyebrow-sm { font-size: 11px; font-weight: 700; letter-spacing: .6px; color: var(--muted); }
.pickup-head strong { font: 700 21px/1.2 var(--serif); }
.pickup-head small { font-size: 12px; color: var(--muted); }

.timeline { list-style: none; margin: 0; padding: 0; }
.timeline li { display: flex; gap: 12px; padding-bottom: 16px; position: relative; }
.timeline li.last { padding-bottom: 0; }
.timeline li:not(.last)::before { content: ''; position: absolute; left: 7px; top: 17px;
                                  bottom: 2px; width: 1.5px; background: var(--line-strong); }
/* Not a control, so not --edge: a step not reached yet keeps a ring as
   quiet as the line joining it, and a reached one says so with a fill and
   a tick beside its words. */
.timeline .dot { width: 15px; height: 15px; border-radius: 8px; flex-shrink: 0;
                 border: 1.5px solid #4A433E; margin-top: 2px; }
.timeline li.done .dot { background: var(--teal-bright); border-color: var(--teal-bright);
                         color: var(--on-teal); display: flex; align-items: center;
                         justify-content: center; }
.timeline strong { display: block; font-size: 13px; font-weight: 600; }
.timeline small { font-size: 11px; color: var(--muted); line-height: 1.4; }
.timeline li:not(.done) strong { color: var(--body); }

.recap { display: flex; gap: 10px; padding: 3px 0; }
.recap .qty { font-size: 12px; color: var(--faint); width: 20px; flex-shrink: 0; }
.recap .what { flex: 1; font-size: 12px; color: var(--body); line-height: 1.4; }
.recap em { color: var(--mint); font-style: normal; }

/* --- forms --- */
.formfield { display: flex; flex-direction: column; gap: 6px; }
.formfield input { min-height: 56px; border-radius: var(--r); background: var(--surface);
                   border: 1px solid var(--line); padding: 0 15px; width: 100%;
                   font-size: 16px; color: var(--cream); }
.formfield input::placeholder { color: var(--faint); }
/* Django marks a field that failed with aria-invalid; the border says so
   to somebody who cannot hear it. Before :focus, so focus still wins. */
.formfield input[aria-invalid='true'] { border-color: var(--body); }
.formfield input:focus { border-color: var(--teal-bright); outline: none; }
/* Weight and a rule, the same mark as .msg.error. Was orange. */
.fielderror { margin: 0; font-size: 12px; font-weight: 600; color: var(--cream);
              border-left: 3px solid var(--body); padding-left: 8px; }
.formfield .hint { margin: 0; }
/* Django's password rules arrive as a <ul> inside the help text. */
.formfield .hint ul { margin: 0; padding-left: 16px; }
.divider { display: flex; align-items: center; gap: 12px; color: var(--faint); font-size: 11px; }
.divider::before, .divider::after { content: ''; flex: 1; height: 1px; background: var(--line); }
.linkbtn { background: none; border: 0; padding: 0; color: var(--mint);
           font-size: inherit; font-weight: 600; cursor: pointer; text-decoration: underline; }

/* --- discount code ---
   The staff verify page that shared this section went with Decision I's
   stopgap, once our Clover app read the code instead (discounts/views.py
   qr_png), and its .verify, .kv and .badge-staff rules have gone with it.
   Its "bad" state was full-bleed orange on a stylesheet nothing used. */
.qrcard { width: 268px; border-radius: 26px; background: var(--cream); padding: 24px;
          display: flex; flex-direction: column; align-items: center; gap: 16px; }
.qrcard img { display: block; width: 220px; height: 220px; image-rendering: pixelated; }
.qrrule { width: 100%; height: 1px; background: rgba(23,20,18,.12); }
/* Was #8A7F6E, 3.75:1 on the cream card at 10px. Same hue, 4.51:1. */
.qrtier { font-size: 10px; font-weight: 700; letter-spacing: 1px; color: #7C7263; }
.qrpercent { font: 700 28px/1 var(--serif); color: var(--ink); margin-top: 3px; }
.ttlbar { width: 180px; height: 4px; border-radius: 2px; background: var(--raised); overflow: hidden; }
.ttlbar > div { height: 4px; border-radius: 2px; background: var(--teal-bright); width: 100%;
                transition: width 1s linear; }

/* --- the discount card: the only place orange leads --- */
.discount-card { border-radius: 18px; padding: 18px;
                 background: linear-gradient(140deg, #35251A 0%, #241B16 100%);
                 border: 1px solid rgba(246,141,46,.35); }
.discount-card .tier { display: block; font-size: 10px; font-weight: 700;
                       letter-spacing: .8px; color: var(--amber); }
.discount-card .pct { display: block; font: 700 27px/1 var(--serif); margin: 5px 0; }
.discount-card .blurb { display: block; font-size: 12px; color: #C0AC9A; line-height: 1.4; }

/* --- grouped optional fields (birthday, consent) ---
   A bare <select> and a bare checkbox render as white boxes on this dark
   ground, because only `input` was ever styled. Both are handled here. */
.subform { border: 1px solid var(--line); border-radius: var(--r);
           padding: 14px; margin: 0; display: flex; flex-direction: column; gap: 10px; }
.subform > legend { display: flex; align-items: center; gap: 8px; padding: 0 6px;
                    font-size: 13px; font-weight: 700; color: var(--cream); }
.optional { font-size: 10px; font-weight: 700; letter-spacing: .5px;
            text-transform: uppercase; color: var(--muted);
            border: 1px solid var(--line-strong); border-radius: 4px; padding: 2px 6px; }

.pair { display: flex; gap: 10px; }
.pair > select { flex: 2; }
.pair > input { flex: 1; }

select.field, input.field { min-height: 52px; border-radius: var(--r-sm);
    background: var(--surface); border: 1px solid var(--line);
    color: var(--cream); font-size: 16px; padding: 0 14px; width: 100%; }
select.field {
    /* Native selects ignore most styling until appearance is cleared, which
       is why this one was rendering as a white bar. */
    -webkit-appearance: none; appearance: none; padding-right: 38px;
    background-image: linear-gradient(45deg, transparent 50%, var(--muted) 50%),
                      linear-gradient(135deg, var(--muted) 50%, transparent 50%);
    background-position: calc(100% - 20px) 55%, calc(100% - 14px) 55%;
    background-size: 6px 6px, 6px 6px; background-repeat: no-repeat; }
select.field:focus, input.field:focus { border-color: var(--teal-bright); outline: none; }
select.field option { background: var(--surface); color: var(--cream); }

.consent { display: flex; align-items: flex-start; gap: 12px; cursor: pointer;
           min-height: var(--tap); padding: 4px 0; }
.consent input { position: absolute; opacity: 0; pointer-events: none; }
.consent .box { width: 22px; height: 22px; flex-shrink: 0; margin-top: 1px;
                border: 1.5px solid var(--edge); border-radius: 6px; }
.consent input:checked + .box { background: var(--teal-bright); border-color: var(--teal-bright); }
.consent input:checked + .box::after { content: ''; display: block; width: 6px; height: 12px;
    margin: 2px auto; border: solid var(--on-teal); border-width: 0 2.5px 2.5px 0;
    transform: rotate(45deg); }
.consent input:focus-visible + .box { outline: 2px solid var(--teal-bright); outline-offset: 2px; }
.consent > span:last-child { font-size: 13px; color: var(--body); line-height: 1.45; }

.noted { display: flex; gap: 9px; margin: 0; font-size: 11.5px;
         color: var(--faint); line-height: 1.45; }
.noted svg { flex-shrink: 0; margin-top: 2px; color: var(--muted); }

/* --- an order they already have -------------------------------------
   Sits in the menu's context row, above the closed notice. Built on
   .context so it lines up with the one thing that already lives there,
   but it is an <a>, so the global link colour has to be taken back:
   `a { color: var(--mint) }` would tint the whole row like a link and
   fight the accent below. */
.context-order { color: var(--body); }
.context-order strong { color: var(--cream); }
.context-order .ico { color: var(--muted); display: flex; }
.context-order .go { font-size: 12px; font-weight: 700; color: var(--mint);
                     flex-shrink: 0; padding-left: 4px; }
/* Teal is the app's "this is a fact" colour and the kitchen is the only
   thing that can set it — nothing here lights from the clock. Same tint
   as .msg.success, deliberately: both mean something actually happened. */
.context-order.is-ready { background: rgba(0,181,171,.09);
                          border-color: rgba(0,181,171,.34); }
.context-order.is-ready .ico,
.context-order.is-ready strong { color: var(--mint); }

/* --- add to home screen ---------------------------------------------
   Hidden in the markup and revealed by static/js/pwa.js, which is the
   only thing that can tell an installable browser from one holding the
   icon already. */
.install { margin: 0 16px 12px; border-radius: var(--r);
           background: var(--surface-2); border: 1px dashed var(--line-strong);
           display: flex; align-items: center; gap: 10px; padding: 10px 8px 10px 14px; }
.install .ico { color: var(--mint); display: flex; flex-shrink: 0; }
.install .who { flex: 1; display: flex; flex-direction: column; gap: 1px; }
.install strong { font-size: 13px; font-weight: 600; color: var(--cream); }
.install small { font-size: 11px; color: var(--muted); }
.install-add { min-height: 34px; padding: 0 14px; border: 0; border-radius: var(--r-pill);
               background: var(--teal-bright); color: var(--on-teal);
               font-size: 13px; font-weight: 700; cursor: pointer; flex-shrink: 0; }
/* No ✕ in the sprite, and adding one for a single 16px button is not
   worth a symbol. A rotated plus IS an ✕, at any size, in any colour. */
.install-no { width: 34px; height: 34px; flex-shrink: 0; }
.install-no svg { transform: rotate(45deg); }

/* --- the iOS instructions sheet -------------------------------------
   Only Safari sees this. There is no install API on iOS, so the sheet
   describes where the button is instead of pretending to press it. */
.sheet { position: fixed; inset: 0; z-index: 40; background: rgba(10,8,7,.72);
         display: flex; align-items: flex-end; justify-content: center;
         padding: 16px; }
.sheet-card { width: 100%; max-width: 428px; border-radius: var(--r-lg);
              background: var(--raised); border: 1px solid var(--line-strong);
              padding: 20px 18px calc(18px + env(safe-area-inset-bottom, 0px)); }
.sheet-card h2 { font: 700 19px/1.25 var(--serif); color: var(--cream); margin: 0 0 16px; }
.steps { list-style: none; margin: 0 0 18px; padding: 0;
         display: flex; flex-direction: column; gap: 14px; }
.steps li { display: flex; gap: 12px; align-items: flex-start;
            font-size: 13.5px; color: var(--body); line-height: 1.45; }
.steps strong { color: var(--cream); font-weight: 600; }
.stepico { width: 32px; height: 32px; flex-shrink: 0; border-radius: var(--r-sm);
           background: var(--surface); border: 1px solid var(--line);
           color: var(--mint); display: flex; align-items: center; justify-content: center; }

/* Installed to the home screen there is no browser chrome beneath the
   dock, so the cart bar lands on top of the home indicator. Costs
   nothing in a browser tab, where the inset resolves to zero. */
.dock { padding-bottom: calc(16px + env(safe-area-inset-bottom, 0px)); }

/* --- the account hub (design_handoff_volunteer_account_hub, 2a) ---
   A short stack: discount card, a volunteer's card, then a list of links.
   The volunteer card's own styles are in volunteers/volunteers.css, which
   the hub loads only for a volunteer. */
.detail.hub { gap: 12px; }
.hub-list { border-radius: var(--r-lg); background: var(--surface);
            border: 1px solid var(--line); margin-top: 10px; overflow: hidden; }
.hub-row { display: flex; align-items: center; gap: 12px; min-height: 56px;
           padding: 10px 14px; color: inherit; text-decoration: none; }
.hub-row + .hub-row { border-top: 1px solid var(--line); }
.hub-row .grow { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.hub-row strong { font-size: 14px; font-weight: 600; color: var(--cream); }
.hub-row small { font-size: 11px; color: var(--muted); white-space: nowrap;
                 overflow: hidden; text-overflow: ellipsis; }
.hub-row .chev { transform: rotate(180deg); color: var(--faint); flex-shrink: 0; }
.hub-signout { margin-top: 10px; }

/* ---- Screen-reader only ------------------------------------------------
   A label a screen reader announces and the design does not show: for a
   field whose visible cue is its placeholder or its section heading. A
   placeholder alone is not a label -- it disappears on the first keystroke
   and some readers skip it. */
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
           overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%);
           white-space: nowrap; border: 0; }

/* --- the tab bar (design_handoff_cafe_usuals, item 1) -----------------
   Menu · Usuals · Cart · Account, on the pages that extend tab_page.html.
   The cart bar that used to float over the menu is gone from those pages:
   the Cart tab's badge carries the count. Fixed like .dock, and the home
   indicator's inset is added below it, as for the dock. */
.with-tabs .shell { padding-bottom: calc(96px + env(safe-area-inset-bottom, 0px)); }
.tabbar { position: fixed; left: 0; right: 0; bottom: 0; z-index: 20;
          background: var(--band); border-top: 1px solid var(--line);
          padding: 8px 8px calc(12px + env(safe-area-inset-bottom, 0px)); }
.tabbar-inner { max-width: 460px; margin: 0 auto; display: flex; }
.tab { flex: 1; min-height: 52px; display: flex; flex-direction: column;
       align-items: center; justify-content: center; gap: 3px;
       color: var(--muted); text-decoration: none; }
.tab-label { font-size: 12px; font-weight: 600; line-height: 1.2; }
.tab .pip { position: relative; width: 56px; height: 30px; border-radius: var(--r-pill);
            display: flex; align-items: center; justify-content: center; }
.tab[aria-current='page'] { color: var(--cream); }
.tab[aria-current='page'] .pip { background: var(--teal-bright); color: var(--on-teal); }
.tab .badge { position: absolute; top: -4px; right: 2px; min-width: 18px; height: 18px;
              padding: 0 5px; border-radius: var(--r-pill); background: var(--cream);
              color: var(--ink); font-size: 11px; font-weight: 700; line-height: 18px;
              text-align: center; }

/* --- a tab page's own heading: "Usuals" and its line under ---------------- */
.page-head { display: flex; align-items: flex-start; gap: 12px; padding: 18px 16px 4px; }
.page-head .grow { flex: 1; min-width: 0; }
.page-head h1 { font: 700 28px/1.15 var(--serif); margin: 0; }
.page-head p { font-size: 14px; color: var(--body); margin: 4px 0 0; }
.pill { min-height: var(--tap); padding: 0 18px; border-radius: var(--r-pill);
        font-size: 14px; font-weight: 700; display: inline-flex; align-items: center;
        justify-content: center; gap: 6px; white-space: nowrap; cursor: pointer;
        border: 0; text-decoration: none; flex-shrink: 0; }
.pill-primary { background: var(--teal-bright); color: var(--on-teal); }
.pill-ghost { background: none; border: 1px solid var(--edge); color: var(--cream); font-weight: 600; }
.textbtn { min-height: var(--tap); padding: 0 4px; background: none; border: 0;
           display: inline-flex; align-items: center; gap: 6px; cursor: pointer;
           color: var(--mint); font-size: 13px; font-weight: 600; }

/* --- the Usuals page (item 2) ---------------------------------------- */
.usuals { display: flex; flex-direction: column; padding-bottom: 8px; }
.usuals .context { margin-top: 12px; }
.section-label { margin: 18px 16px 8px; font-size: 13px; font-weight: 600;
                 letter-spacing: .06em; text-transform: uppercase; color: var(--muted); }
.cards { display: flex; flex-direction: column; gap: 10px; padding: 0 16px; }
.card { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-lg);
        padding: 14px 14px 14px 16px; }
.usual { display: flex; align-items: center; gap: 12px; }
.usual .grow, .past .grow { flex: 1; min-width: 0; }
.usual-name { font-size: 16px; font-weight: 600; color: var(--cream); overflow-wrap: anywhere; }
.usual-what { font-size: 13px; line-height: 18px; color: var(--body); margin-top: 2px;
              display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
              overflow: hidden; }
.usual-price { font-size: 13px; font-weight: 600; color: var(--mint); margin-top: 4px; }
.usual form, .past form { display: flex; }
.past { padding-bottom: 8px; }
.past-open { display: block; color: inherit; text-decoration: none; }
.past-head { display: flex; justify-content: space-between; gap: 12px;
             font-size: 13px; color: var(--body); }
.past-head b { color: var(--cream); font-weight: 600; white-space: nowrap; }
.past-what { display: block; font-size: 15px; line-height: 20px; color: var(--cream); margin-top: 4px; }
.past-acts { display: flex; align-items: center; justify-content: space-between; gap: 8px;
             margin-top: 6px; }
.past-acts.end { justify-content: flex-end; }
.saved-mark { display: inline-flex; align-items: center; gap: 6px; min-height: var(--tap);
              font-size: 13px; color: var(--mint); }
.footnote { font-size: 13px; line-height: 18px; color: var(--faint); margin: 10px 20px 0; }
.keep { margin: 26px 16px 0; background: var(--raised); border: 1px solid var(--line);
        border-radius: var(--r-lg); padding: 20px 18px; }
.keep .badge-ico { width: 44px; height: 44px; border-radius: var(--r); background: var(--surface);
                   color: var(--mint); display: flex; align-items: center; justify-content: center; }
.keep h2 { margin: 12px 0 0; font-size: 18px; font-weight: 700; }
.keep p { font-size: 14px; line-height: 20px; color: var(--body); margin: 4px 0 0; }
.keep .pair { display: flex; gap: 10px; margin-top: 16px; }
.keep .pair .pill { flex: 1; min-height: 48px; font-size: 15px; }

/* Edit mode (item 3): a handle, then rename and remove, each a full 44px. */
.usual.editing { gap: 2px; padding: 10px 4px; }
.usual.editing.renaming { border-color: var(--edge); flex-wrap: wrap; }
.usual.dragging { opacity: .85; border-color: var(--teal-bright); position: relative; z-index: 2; }
.handle { width: var(--tap); height: var(--tap); flex-shrink: 0; border: 0; background: none;
          color: var(--muted); display: flex; align-items: center; justify-content: center;
          cursor: grab; touch-action: none; border-radius: var(--r-sm); }
.handle:active { cursor: grabbing; }
.rename-form { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.rename-form label { font-size: 12px; font-weight: 600; color: var(--body); margin-bottom: 4px; }
.rename-form input { min-height: var(--tap); padding: 0 12px; border-radius: var(--r-sm);
                     border: 1.5px solid var(--teal-bright); background: var(--raised);
                     font-size: 16px; width: 100%; }
.rename-acts { display: flex; justify-content: flex-end; gap: 8px; margin-top: 8px; }
/* Move up and Move down: for a screen reader, and anybody without a pointer
   to drag with. Off screen until one of them has focus. */
.moves { display: flex; gap: 6px; }
.moves .pill:not(:focus):not(:focus-within) { position: absolute; width: 1px; height: 1px;
       overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
       padding: 0; border: 0; margin: -1px; }

/* --- a bottom sheet (items 4 and 7): the .sheet overlay, flush to the foot */
.sheet-card.bottom { max-width: 460px; border-radius: 24px 24px 0 0; background: var(--surface);
                     border-width: 1px 0 0; padding: 10px 16px calc(24px + env(safe-area-inset-bottom, 0px)); }
.sheet.flush { padding: 0; }
.grabber { width: 36px; height: 4px; border-radius: 4px; background: var(--line-strong);
           margin: 0 auto 6px; }
.sheet-head { display: flex; align-items: center; justify-content: space-between; }
.sheet-head h2 { margin: 0; font: 700 22px/1.25 var(--serif); }
.sheet-head h2:focus { outline: none; }
.sheet-close { margin-right: -8px; color: var(--body); }
.sheet-items { background: var(--raised); border: 1px solid var(--line); border-radius: var(--r);
               padding: 12px 14px; margin-top: 6px; }
.sheet-items div + div { margin-top: 8px; }
.sheet-items strong { display: block; font-size: 15px; font-weight: 600; }
.sheet-items small { display: block; font-size: 13px; line-height: 18px; color: var(--body); }
.sheet-field { display: block; font-size: 13px; font-weight: 600; color: var(--body); margin: 16px 0 6px; }
.sheet-input { width: 100%; min-height: 48px; padding: 0 14px; border-radius: var(--r);
               border: 1.5px solid var(--teal-bright); background: var(--raised); font-size: 16px; }
.sheet-note { font-size: 13px; line-height: 18px; color: var(--body); margin: 10px 0 0; }
.sheet-card .btn-primary { margin-top: 16px; border-radius: var(--r-pill); }
.sheet-card .btn-text { width: 100%; min-height: 48px; margin-top: 4px; background: none; border: 0;
                        color: var(--body); font-size: 15px; font-weight: 600; cursor: pointer;
                        display: flex; align-items: center; justify-content: center; }

/* The cart's own buttons, now that the tab bar has the foot of the page. */
.cart-acts { display: flex; flex-direction: column; gap: 10px; }
.cart-acts .btn { border-radius: var(--r-pill); }

/* --- Check and pay (items 7 to 9) ---------------------------------------
   The checkout as a sheet. It scrolls once the card form opens; the Pay
   button carries the amount, so the total is on screen when it is pressed. */
.pay-sheet { max-height: calc(100vh - 24px); max-height: calc(100dvh - 24px); overflow-y: auto;
             overscroll-behavior: contain; }
.pay-sheet .msgs { padding: 6px 0 0; }
.pay-sheet .notice { margin: 8px 0 0; }
.notice.changed { border: 1.5px solid var(--faint); background: var(--raised); color: var(--body); }
.notice.changed strong { display: block; color: var(--cream); font-weight: 700; }
.pay-list { background: var(--raised); border: 1px solid var(--line); border-radius: var(--r);
            margin-top: 10px; }
.pay-line { display: flex; justify-content: space-between; gap: 12px; padding: 12px 14px;
            border-bottom: 1px solid var(--line); }
.pay-line .grow, .pay-row .grow { flex: 1; min-width: 0; }
.pay-line strong, .pay-row strong { display: block; font-size: 15px; font-weight: 600; }
.pay-line small, .pay-row small { display: block; font-size: 13px; line-height: 18px; color: var(--body); }
.pay-price { font-size: 15px; white-space: nowrap; font-variant-numeric: tabular-nums; }
.pay-row { display: flex; align-items: center; gap: 10px; padding: 4px 6px 4px 14px; }
.pay-row + .pay-row { border-top: 1px solid var(--line); }
.pay-ico { color: var(--mint); display: flex; flex-shrink: 0; }
.pay-row .textbtn { padding: 0 12px; font-size: 14px; }
.pay-totals { padding: 14px 4px 0; }
#stripe-checkout .express { margin-top: 16px; }
#stripe-checkout #pay-with-card { margin-top: 10px; border-radius: var(--r-pill); }
#stripe-checkout #card-section { margin-top: 16px; }
.pay-sheet #pay { margin-top: 16px; border-radius: var(--r-pill); }
.pay-sheet #pay-error { margin-top: 12px; }
