/* ==========================================================================
   Slowpoke Coffee Co. — order-builder UI kit
   The modal shell, buttons, animated cup, and modifier-group styling for the
   staff POS drink-builder modal (pos.php + pos.js). Kept out of pos.css so the
   builder's look can be read and changed on its own, separate from the
   register's frame and ticket panel. Every rule here only references
   custom properties that both style.css and pos.css define (--surface,
   --surface-2, --text, --text-soft, --border, --border-strong, --accent,
   --accent-contrast, --avocado, --cream, --cocoa-700, --font-heading,
   --radius-*, --shadow-*), so this file picks up the right theme on
   whichever stylesheet loaded alongside it.
   ========================================================================== */

/* ---------- Buttons ---------- */
.pos-btn {
  border: none; cursor: pointer; font-family: var(--font-heading); font-weight: 700; font-size: 0.92rem;
  padding: 13px 14px; border-radius: var(--radius-md); min-height: 46px;
  letter-spacing: 0.2px;
  transition: transform 0.12s ease, box-shadow 0.12s ease, opacity 0.12s ease, background 0.15s ease;
}
.pos-btn:active { transform: scale(0.97); }
.pos-btn:disabled { opacity: 0.4; cursor: not-allowed; box-shadow: none; }
/* The two committing actions (Close & Pay, Send to Barista) carry a colored
   shadow in their own hue, so they read as raised and as THE thing to hit. */
.pos-btn-primary {
  background: linear-gradient(180deg, var(--accent), var(--accent-hover));
  color: var(--accent-contrast);
  box-shadow: var(--shadow-sm), 0 4px 14px rgba(182, 71, 42, 0.28);
}
.pos-btn-primary:hover:not(:disabled) { background: var(--accent-hover); box-shadow: var(--shadow-md), 0 6px 18px rgba(182, 71, 42, 0.34); }
.pos-btn-accent {
  background: linear-gradient(180deg, var(--avocado), var(--avocado-700, var(--avocado)));
  color: #fffaf0;
  box-shadow: var(--shadow-sm), 0 4px 14px rgba(91, 111, 58, 0.28);
}
.pos-btn-accent:hover:not(:disabled) { background: var(--avocado-700, var(--avocado)); box-shadow: var(--shadow-md), 0 6px 18px rgba(91, 111, 58, 0.34); }
.pos-btn-outline { background: transparent; border: 2px solid var(--border-strong); color: var(--text); }
.pos-btn-outline:hover:not(:disabled) { border-color: var(--accent); color: var(--accent); }
.pos-btn-danger { background: transparent; border: 2px solid var(--danger, #c1443a); color: var(--danger, #c1443a); }
.pos-btn-danger:hover:not(:disabled) { background: var(--danger, #c1443a); color: #fff; }
.pos-btn-sm { padding: 8px 12px; min-height: 36px; font-size: 0.8rem; border-radius: var(--radius-sm); }

/* ---------- Generic modal shell ---------- */
.pos-modal-backdrop {
  position: fixed; inset: 0; background: rgba(20,14,8,0.55); z-index: 900;
  opacity: 0; pointer-events: none; transition: opacity 0.2s ease;
}
.pos-modal-backdrop.visible { opacity: 1; pointer-events: auto; }
.pos-modal {
  position: fixed; inset: 0; z-index: 901; display: flex; align-items: center; justify-content: center;
  padding: 16px; opacity: 0; pointer-events: none; transition: opacity 0.2s ease;
}
.pos-modal.open { opacity: 1; pointer-events: auto; }
.pos-modal-panel {
  background: var(--surface); border-radius: var(--radius-lg); max-width: 620px; width: 100%;
  max-height: 90vh; max-height: 90dvh; /* dvh so the sheet is not taller than iOS Safari's real viewport */
  overflow-y: auto; padding: 26px; box-shadow: var(--shadow-lg); position: relative;
  -webkit-overflow-scrolling: touch; overscroll-behavior: contain;
}
.pos-modal-panel.wide { max-width: 820px; }
.pos-modal-close {
  position: absolute; top: 10px; right: 10px; background: none; border: none; cursor: pointer;
  font-size: 1.2rem; color: var(--text-soft); width: 44px; height: 44px; border-radius: var(--radius-full);
  z-index: 4;
}
.pos-modal-close:hover { background: var(--surface-2); }
.pos-modal-kicker { font-family: var(--font-heading); text-transform: uppercase; letter-spacing: 1.5px; font-size: 0.72rem; color: var(--rust-500); font-weight: 700; margin-bottom: 4px; }
.pos-modal-title { font-size: 1.35rem; margin-bottom: 4px; }
.pos-modal-sub { color: var(--text-soft); font-size: 0.88rem; margin-bottom: 16px; }

/* ==================== Drink builder modal (the "game" bit) ==================== */
.builder-modal-layout {
  display: grid;
  grid-template-columns: 220px 1fr;
  gap: 22px;
  align-items: start;
}
@media (max-width: 720px) {
  .builder-modal-layout { grid-template-columns: 1fr; }
}

/* -- Animated cup --
   The cup is the best thing on this screen, so it gets a stage instead of
   floating on the panel: a warm sunset wash, a hairline edge, and a soft
   contact shadow under the cup. Purely a backdrop; every fill/foam/steam
   animation still comes from cup-builder.js mutating the cup's own nodes. */
.cup-builder-wrap {
  position: sticky; top: 0; display: flex; flex-direction: column; align-items: center; gap: 10px;
  padding: 18px 12px 14px; border-radius: var(--radius-lg);
  background:
    radial-gradient(120% 90% at 50% 0%, rgba(232, 163, 61, 0.20), rgba(232, 163, 61, 0) 62%),
    radial-gradient(100% 80% at 50% 100%, rgba(217, 98, 43, 0.12), rgba(217, 98, 43, 0) 60%),
    var(--surface-2);
  border: 1px solid var(--border);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.35);
}
:root[data-theme="dark"] .cup-builder-wrap { box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05); }
@media (prefers-color-scheme: dark) { .cup-builder-wrap { box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05); } }
/* Contact shadow so the cup sits ON the stage rather than in front of it. */
.cup-builder-wrap .cup-builder::after {
  content: ''; position: absolute; left: 50%; bottom: -10px; transform: translateX(-50%);
  width: 76%; height: 14px; border-radius: 50%;
  background: radial-gradient(ellipse at center, rgba(20, 14, 8, 0.22), rgba(20, 14, 8, 0) 70%);
  pointer-events: none; z-index: 0;
}
.cup-builder {
  position: relative;
  width: 168px;
  height: 220px;
  /* --cb-scale comes from the selected size tile's "scale" value in
     menu-data.js (cup-builder.js sets it as a custom property). zoom scales
     the whole node's rendering AND its layout footprint together, which is
     what order-builder.css already learned the hard way at the phone
     breakpoint below: this shape is built from fixed-offset children and a
     clip-path, so resizing width/height alone squashes it out of shape.
     Scaling the whole node with zoom (or transform) is the fix, here as much
     as there. */
  zoom: var(--cb-scale, 1);
  transition: transform 0.25s cubic-bezier(.34,1.56,.64,1), zoom 0.3s ease;
}
.cup-builder.bump { animation: cupBump 0.32s ease; }
@keyframes cupBump {
  0% { transform: scale(1); }
  40% { transform: scale(1.08) rotate(-2deg); }
  100% { transform: scale(1) rotate(0deg); }
}
.cup-builder .cb-steam {
  position: absolute; top: -34px; left: 50%; transform: translateX(-50%);
  display: flex; gap: 10px; opacity: 0; transition: opacity 0.3s ease;
  pointer-events: none;
}
.cup-builder.is-hot .cb-steam { opacity: 0.8; }
.cup-builder .cb-steam span {
  width: 6px; height: 26px; border-radius: 6px;
  background: linear-gradient(to top, rgba(255,255,255,0), rgba(180,180,180,0.6));
  animation: steamRise 2.2s ease-in-out infinite;
}
.cup-builder .cb-steam span:nth-child(2) { animation-delay: -0.7s; }
.cup-builder .cb-steam span:nth-child(3) { animation-delay: -1.4s; }
@keyframes steamRise {
  0% { transform: translateY(6px) scaleY(0.7); opacity: 0; }
  30% { opacity: 0.8; }
  100% { transform: translateY(-22px) scaleY(1.1); opacity: 0; }
}

.cup-builder .cb-body {
  position: absolute; left: 24px; right: 24px; bottom: 6px; top: 40px;
  clip-path: polygon(10% 0%, 90% 0%, 80% 100%, 20% 100%);
  background: var(--cream);
  box-shadow: inset 0 -14px 22px rgba(0,0,0,0.10), 0 4px 10px rgba(0,0,0,0.16);
  overflow: hidden;
  transition: clip-path 0.4s ease;
}
:root[data-theme="dark"] .cup-builder .cb-body { background: #2c2013; }
@media (prefers-color-scheme: dark) { .cup-builder .cb-body { background: #2c2013; } }

.cup-builder .cb-fill {
  position: absolute; left: 0; right: 0; bottom: 0; height: 0%;
  background: var(--cb-liquid, #6f4e37);
  transition: height 0.5s cubic-bezier(.22,.9,.32,1.1), background 0.4s ease;
}
/* --cb-fill-pct is set live from the current size + extra-shots count, so a
   bigger order visibly reads as a fuller cup instead of one fixed fill. */
.cup-builder.filled .cb-fill { height: var(--cb-fill-pct, 86%); }
.cup-builder .cb-foam {
  position: absolute; left: 0; right: 0; height: 0; bottom: 86%;
  background: var(--cb-foam, #f3e6d2);
  border-radius: 0 0 40% 40% / 0 0 60% 60%;
  transition: height 0.45s cubic-bezier(.22,.9,.32,1.1), bottom 0.5s ease, background 0.4s ease, opacity 0.3s ease;
  opacity: 0;
}
.cup-builder.filled .cb-foam { bottom: calc(var(--cb-fill-pct, 86%) - 8%); }
.cup-builder.has-foam .cb-foam { height: 16%; opacity: 1; }
.cup-builder .cb-ice {
  position: absolute; left: 8%; right: 8%; bottom: 8%; display: flex; flex-wrap: wrap; gap: 4px;
  opacity: 0; transition: opacity 0.3s ease; pointer-events: none;
}
.cup-builder.is-iced .cb-ice { opacity: 1; }
/* Cubes are always in the DOM (up to 8); .on is what the current Ice Level
   selection actually lights up, so "Extra Ice" visibly shows more cubes than
   "Light Ice" instead of the same fixed handful every time. */
.cup-builder .cb-ice span {
  width: 15px; height: 15px; border-radius: 3px;
  background: linear-gradient(135deg, rgba(255,255,255,0.9), rgba(200,225,230,0.55));
  border: 1px solid rgba(255,255,255,0.8);
  transform: rotate(var(--r, 8deg)) scale(0.5);
  opacity: 0; transition: opacity 0.2s ease, transform 0.25s cubic-bezier(.34,1.56,.64,1);
}
.cup-builder .cb-ice span.on { opacity: 0.95; transform: rotate(var(--r, 8deg)) scale(1); }
.cup-builder .cb-whip {
  position: absolute; left: 14%; right: 14%; bottom: 86%; height: 0;
  background: #fff9ee;
  border-radius: 50% 50% 40% 40% / 70% 70% 30% 30%;
  box-shadow: 0 -2px 4px rgba(0,0,0,0.08) inset;
  opacity: 0; transition: height 0.35s ease, bottom 0.5s ease, opacity 0.3s ease;
}
.cup-builder.filled .cb-whip { bottom: calc(var(--cb-fill-pct, 86%) - 8%); }
.cup-builder.has-whip .cb-whip { height: 22px; opacity: 1; }
.cup-builder.has-whip.has-foam .cb-whip { bottom: calc(var(--cb-fill-pct, 86%) + 4%); }

/* ---------- Frozen / blended texture ----------
   Frozen needs to read as visibly different from both hot (steam) and iced
   (cubes) at a glance: a diagonal slushy streak pattern over a frostier,
   lighter-tinted fill (see liquidColorFor's frozen mix), plus a straw
   instead of a sleeve. No ice cubes: the ice is already blended in. */
.cup-builder .cb-frozen-texture {
  position: absolute; inset: 0; opacity: 0; transition: opacity 0.3s ease;
  background: repeating-linear-gradient(
    -35deg,
    rgba(255,255,255,0.32) 0 7px,
    rgba(255,255,255,0.05) 7px 16px
  );
  mix-blend-mode: soft-light;
}
.cup-builder.is-frozen .cb-frozen-texture { opacity: 1; }
.cup-builder .cb-straw {
  position: absolute; left: 62%; top: -30px; width: 10px; height: 68px;
  background: repeating-linear-gradient(180deg, var(--rust-500, #d9622b) 0 8px, var(--cream-50, #fbf1de) 8px 16px);
  border-radius: 4px; transform: rotate(14deg); transform-origin: bottom center;
  opacity: 0; transition: opacity 0.3s ease; box-shadow: 0 2px 4px rgba(0,0,0,0.18);
}
.cup-builder.is-frozen .cb-straw { opacity: 1; }
.cup-builder .cb-drizzle {
  position: absolute; top: 8px; left: 0; right: 0; text-align: center; font-size: 1.1rem;
  opacity: 0; transition: opacity 0.3s ease; pointer-events: none;
}
.cup-builder.has-drizzle .cb-drizzle { opacity: 1; }
.cup-builder .cb-pumps {
  position: absolute; right: -14px; top: 44px; display: flex; flex-direction: column; gap: 3px;
}
.cup-builder .cb-pumps span {
  width: 9px; height: 9px; border-radius: 50%; background: var(--cb-pump, #e8a33d);
  opacity: 0; transform: scale(0.4); transition: opacity 0.2s ease, transform 0.25s cubic-bezier(.34,1.56,.64,1);
  box-shadow: 0 1px 2px rgba(0,0,0,0.25);
}
.cup-builder .cb-pumps span.on { opacity: 1; transform: scale(1); }
.cup-builder .cb-lid {
  position: absolute; left: 18px; right: 18px; top: 30px; height: 16px; border-radius: 8px 8px 2px 2px;
  background: var(--cocoa-700); opacity: 0; transition: opacity 0.3s ease;
}
/* Every cold drink leaves the bar with a lid on, whether or not it has ice in
   it (nitro and the frappe do not). */
.cup-builder.is-cold .cb-lid { opacity: 1; }

/* ---------- Espresso ----------
   A doppio is not a 12oz cup with a splash in the bottom: it is a small cup,
   mostly full. Shrinking the cup body and raising the fill floor renders that
   honestly without a second cup implementation. */
.cup-builder.is-espresso .cb-body {
  left: 52px; right: 52px; top: 104px; bottom: 24px;
  clip-path: polygon(6% 0%, 94% 0%, 86% 100%, 14% 100%);
}
/* Fill/foam/whip heights come from --cb-fill-pct (set in cup-builder.js with
   a lower espresso baseline), same generic rules as every other mode. */
.cup-builder.is-espresso.has-whip .cb-whip { height: 16px; }
/* A demitasse has no sleeve, no lid, and no room for six pump dots. */
.cup-builder.is-espresso .cb-sleeve,
.cup-builder.is-espresso .cb-lid { opacity: 0; }
.cup-builder.is-espresso .cb-steam { top: 62px; }
.cup-builder.is-espresso .cb-decaf-tag { bottom: 4px; }
.cup-builder .cb-sleeve {
  position: absolute; left: 20px; right: 20px; top: 108px; height: 46px; border-radius: 4px;
  background: repeating-linear-gradient(135deg, rgba(59,42,30,0.16) 0 6px, rgba(59,42,30,0.05) 6px 12px);
  opacity: 0; transition: opacity 0.3s ease;
}
.cup-builder.is-hot .cb-sleeve { opacity: 1; }
.cup-builder .cb-decaf-tag {
  position: absolute; left: 50%; bottom: 30px; transform: translateX(-50%); font-size: 0.62rem; font-weight: 800;
  font-family: var(--font-heading); letter-spacing: 0.5px; color: #fff; background: var(--avocado-600);
  padding: 2px 8px; border-radius: var(--radius-full); opacity: 0; transition: opacity 0.25s ease; white-space: nowrap;
}
.cup-builder.is-decaf .cb-decaf-tag { opacity: 1; }

/* ---------- Name on the cup ----------
   A short handwritten-style label near the cup's shoulder, like a marker
   scrawl on a to-go cup. Baloo 2 italic + a slight rotation stands in for
   handwriting without pulling in a new font. Truncates with an ellipsis
   rather than wrapping or overflowing the cup. */
.cup-builder .cb-name-tag {
  position: absolute; top: 96px; left: 30px; right: 30px; text-align: center;
  font-family: var(--font-heading); font-style: italic; font-weight: 700; font-size: 0.86rem;
  color: rgba(36, 20, 10, 0.72); transform: rotate(-4deg);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  text-shadow: 0 1px 0 rgba(255,255,255,0.35);
  pointer-events: none; z-index: 2;
}
.cup-builder.is-espresso .cb-name-tag { top: 118px; font-size: 0.72rem; }

.cup-builder-name { font-family: var(--font-heading); font-weight: 700; text-align: center; font-size: 0.95rem; }
/* The live price ticks on every modifier tap, so it is the readout of the whole
   builder: large, accent, and tabular so the digits do not jitter as it moves. */
.cup-builder-price {
  font-family: var(--font-heading); font-size: 1.6rem; font-weight: 700; color: var(--accent);
  font-variant-numeric: tabular-nums; letter-spacing: 0.3px;
}

/* -- Modifier groups --
   Real registers (Square, Toast, Clover) build a drink from a grid of square
   tappable tiles organized by labeled section, rather than a scrolling list
   of pill rows. Each .mod-group here IS one of those labeled sections; the
   tiles inside it lay out as a proper grid of squares that fill/highlight
   the instant they are tapped, so the barista can read the whole build at a
   glance instead of hunting through a long vertical list. */
.mod-group { margin-bottom: 18px; }
.mod-group-label { font-family: var(--font-heading); font-weight: 600; font-size: 0.9rem; margin-bottom: 8px; }
/* auto-fill + minmax(...,1fr) sizes columns; grid rows default to "auto" and
   size to whichever tile in that row is tallest, so a two-line label never
   needs a fixed row height to fit into. */
/* 128px (not a smaller value like 92px) is deliberate: auto-fill always
   packs in as many columns as the minimum allows, so a smaller minimum does
   not make tiles more compact, it just makes each one narrower. At 92px a
   two-word option with a price tag ("Mini Marshmallows (+$0.40)") does not
   have room to wrap at the space between words and word-break splits the
   word itself instead ("Marshmallo" / "ws"). 128px keeps that same label to
   two clean lines (label, then price) on every width this register runs at,
   phone through iPad. */
.mod-options { display: grid; grid-template-columns: repeat(auto-fill, minmax(128px, 1fr)); gap: 8px; }
/* Column direction (not the flex default row) is what actually matters here:
   a row-direction flex button puts the label and the "(+$0.40)" price tag
   SIDE BY SIDE fighting for the same width, which is what let a two-word
   label like "Mini Marshmallows" push its price tag (and itself) past the
   tile's edge. Stacked in a column, the label wraps within the tile's own
   width, the price sits on its own line under it, and min-height is a floor
   the button is free to grow past — never a ceiling that clips content. */
.mod-option {
  display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; gap: 2px;
  padding: 10px 8px; border-radius: var(--radius-md); min-height: 60px; height: auto;
  border: 2px solid var(--border); background: var(--surface-2); color: var(--text);
  cursor: pointer; font-size: 0.82rem; font-weight: 600; line-height: 1.25;
  overflow-wrap: break-word; word-break: break-word; hyphens: auto;
  transition: transform 0.1s ease, border-color 0.14s ease, box-shadow 0.14s ease, background 0.14s ease;
}
.mod-option:hover { border-color: var(--border-strong); }
.mod-option:active { transform: scale(0.95); }
/* A selected modifier has to be unmistakable at a glance from across the
   counter, so it fills with the accent and carries a halo, not just a border. */
.mod-option.selected {
  border-color: var(--accent); background: var(--accent); color: var(--accent-contrast);
  box-shadow: var(--shadow-sm), var(--ring, 0 0 0 3px rgba(182, 71, 42, 0.18));
}
.mod-option.selected:hover { border-color: var(--accent); }
.mod-option .delta-tag { font-size: 0.7rem; opacity: 0.85; display: block; margin-top: 1px; }

/* ---------- Hot / Iced (/ Frozen) toggle ----------
   A two-state pill, tapped exactly like every other tile, that decides which
   size group and which finishing groups (Milk Temp/Foam vs Ice/Cold Foam)
   are even shown below it. */
.serve-toggle-group { margin-bottom: 18px; }
.serve-toggle { display: grid; grid-template-columns: repeat(auto-fit, minmax(100px, 1fr)); gap: 8px; }
.serve-toggle-btn {
  display: flex; align-items: center; justify-content: center; gap: 6px;
  padding: 12px 10px; min-height: 48px; border-radius: var(--radius-md);
  border: 2px solid var(--border-strong); background: var(--surface-2); color: var(--text);
  font-family: var(--font-heading); font-weight: 700; font-size: 0.92rem; cursor: pointer;
  transition: transform 0.1s ease, border-color 0.14s ease, box-shadow 0.14s ease, background 0.14s ease;
}
.serve-toggle-btn:active { transform: scale(0.96); }
.serve-toggle-btn.selected {
  border-color: var(--accent); background: var(--accent); color: var(--accent-contrast);
  box-shadow: var(--shadow-sm), var(--ring, 0 0 0 3px rgba(182, 71, 42, 0.18));
}

/* ---------- Name for the Cup (inside the builder) ---------- */
.mod-name-input {
  width: 100%; padding: 12px 14px; border-radius: var(--radius-sm); border: 1px solid var(--border-strong);
  background: var(--surface); color: var(--text); font-family: inherit;
  font-size: 16px; /* below 16px iOS zooms the page in on focus (see .promo-input) */
  min-height: 44px;
}
.mod-name-input:focus { outline: none; border-color: var(--accent); }

.mod-stepper-row { display: flex; align-items: center; gap: 14px; }
/* 44px is the Apple HIG touch-target minimum, and this register runs on
   iPad as its primary device, not just phones: this cannot be a phone-only
   breakpoint override, it has to be the actual default everywhere. */
.mod-stepper-btn {
  width: 44px; height: 44px; border-radius: var(--radius-full); border: 1px solid var(--border-strong);
  background: var(--surface-2); font-size: 1.2rem; font-weight: 700; cursor: pointer; transition: transform 0.1s ease;
}
.mod-stepper-btn:active { transform: scale(0.9); }
.mod-stepper-btn:disabled { opacity: 0.35; cursor: not-allowed; }
.mod-stepper-value { font-family: var(--font-heading); font-size: 1.05rem; min-width: 120px; text-align: center; }
.mod-stepper-hint { font-size: 0.76rem; color: var(--text-soft); margin-top: 4px; }

.mod-instructions textarea {
  width: 100%; min-height: 64px; padding: 10px 12px; border-radius: var(--radius-sm);
  border: 1px solid var(--border-strong); background: var(--surface); color: var(--text);
  font-family: inherit; resize: vertical;
  /* Under 16px, iOS Safari zooms the page in the moment this is focused and
     does not zoom back out. */
  font-size: 16px;
}
.mod-qty-row { display: flex; align-items: center; justify-content: space-between; margin: 16px 0; }
.mod-qty { display: flex; align-items: center; gap: 12px; }
.mod-qty-btn {
  width: 44px; height: 44px; border-radius: var(--radius-full); border: 1px solid var(--border-strong);
  background: var(--surface-2); font-size: 1.2rem; font-weight: 700; cursor: pointer; transition: transform 0.1s ease;
}
.mod-qty-btn:active { transform: scale(0.9); }
.mod-qty-value { font-family: var(--font-heading); font-size: 1.2rem; min-width: 24px; text-align: center; }
.mod-live-total { font-family: var(--font-heading); font-size: 1.3rem; }
.mod-confirm-row { display: flex; gap: 10px; margin-top: 10px; }
.mod-confirm-row .pos-btn { flex: 1; }

/* ---------- Toast (shared between the POS register and the guest sheet) ---------- */
.pos-toast {
  position: fixed; bottom: 90px; left: 50%; transform: translateX(-50%) translateY(20px);
  background: var(--cocoa-900); color: var(--cream-50); padding: 12px 20px; border-radius: var(--radius-full);
  font-weight: 700; font-size: 0.88rem; box-shadow: var(--shadow-lg); z-index: 950;
  opacity: 0; pointer-events: none; transition: opacity 0.2s ease, transform 0.2s ease;
}
.pos-toast.visible { opacity: 1; transform: translateX(-50%) translateY(0); }

@media (prefers-reduced-motion: reduce) {
  .cup-builder, .cup-builder * { animation: none !important; transition-duration: 0.01ms !important; }
}

/* ==================== Phone layout for the builder sheet ====================
   These override the base cup/confirm rules above, so they must stay last in
   this file: a media query adds no specificity, and an equal-specificity rule
   later in the source order would otherwise win. */
@media (max-width: 720px) {
  /* Stacked at full size, the cup fills an entire phone screen before a single
     option is visible. Sit it beside its name and price so the first choice
     lands above the fold. */
  .cup-builder-wrap {
    position: static;
    flex-direction: row;
    justify-content: center;
    gap: 18px;
  }
  /* Scale rather than resize: the cup's internals (body, fill, foam, ice) are
     positioned with fixed pixel offsets tuned to the full 168x220 box, so
     shrinking width/height alone squashes them out of shape. zoom scales the
     rendered art and its layout footprint together, and composes with the
     bump animation's transform. Multiplied against --cb-scale (the live
     per-size zoom from cup-builder.js) rather than overriding it, so a Venti
     still visibly renders bigger than a Short on a phone too. */
  .cup-builder { zoom: calc(0.55 * var(--cb-scale, 1)); flex: none; }
  .cup-builder .cb-steam { display: none; }
  .cup-builder-name,
  .cup-builder-price { margin: 0; align-self: center; }

  /* Pin the primary action to the foot of the sheet so it stays reachable
     without scrolling past every group first. The negative margins let it span
     the panel's own 26px padding. */
  .mod-confirm-row {
    position: sticky;
    bottom: -26px;
    margin: 0 -26px -26px;
    padding: 12px 26px calc(12px + env(safe-area-inset-bottom, 0px));
    background: var(--surface);
    box-shadow: 0 -12px 20px -14px rgba(0, 0, 0, 0.55);
    z-index: 3;
  }
}

/* ---------- Phone touch targets ----------
   Apple's HIG minimum is 44x44. The option pills and steppers are what a
   barista actually hammers on, so they get it. */
@media (max-width: 560px) {
  .pos-modal { padding: 8px; }
  .pos-modal-panel {
    padding: 20px 16px;
    /* Pull the sheet clear of the notch and the home indicator. */
    max-height: calc(100dvh - 16px - env(safe-area-inset-top) - env(safe-area-inset-bottom));
    margin-top: env(safe-area-inset-top);
  }
  .mod-option { min-height: 44px; padding: 10px 14px; }
  .mod-stepper-btn, .mod-qty-btn { width: 44px; height: 44px; }
  .mod-stepper-value { min-width: 96px; }
  .pos-btn { min-height: 48px; }
  /* The sticky footer's negative margins have to match the panel's padding,
     which just changed from 26px to 16px. */
  .mod-confirm-row {
    bottom: -20px;
    margin: 0 -16px -20px;
    padding: 12px 16px calc(12px + env(safe-area-inset-bottom, 0px));
  }
}
