Two cart surfaces that share the same line-item vocabulary. The drawer is a bottom sheet on mobile and a slide-from-right panel on desktop. The dedicated cart page is the same line-item rendering with breathing room, plus shipping selector, totals breakdown, and the B2B quote-request entry. Both render fixed bundles as parent + indented children with rolled-up pricing, and configurable bundle add-ons as tagged children. No B2B order-approval gate — that was an earlier misroute and stays out of the cart flow.
The drawer is the instant-feedback affordance — tap "Add to cart" on a PDP and the sheet slides up so you can confirm the addition without losing your place. No route change, no scroll loss. Two CTAs out: "View cart" goes to the full page; "Checkout" jumps straight into the three-step flow.
40% (collapsed preview), 78% (default), and 96% (immersive).rgba(28,26,71,0.55) scrim and a faint blur to denote modal context.cart_items and joins cart_item_components for each item where the parent product has is_bundle = true. Fixed-bundle children render with line-price free; configurable bundle children render with delta pricing per the price_strategy on each bundle_items row. Bundle-end footer is the sum of selected components, displayed as the bundle's effective cart price.
shipping_rates, computed server-side. When the threshold is crossed, the strip swaps to "Free express delivery unlocked".Turn this cart into a B2B quote — volume pricing, NET 30 terms (v1.1), and a PO workflow for your team.
The page is for the long stare — promo codes, shipping choices, tax transparency, and the B2B off-ramp. Same line-item vocabulary as the drawer; everything else is page-level chrome.
draft → submitted → under_review).CartLineList). The drawer mounts it inside BottomSheet (web) / @gorhom/bottom-sheet (RN). The page mounts it inside a scrolling layout. Same JSON in, same component, two enclosures.