html, body { margin: 0; }
body { background: var(--bg-elevated); }
.visually-hidden {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap;
}
/* ---- Screen transition ----
   The clip MUST sit on this wrapper, not on the sliding element: overflow
   clips an element's contents, never its own transform. The assessment hit
   exactly this (see chimeAssessment.html) — with the rule on the moving node
   the offset frames still widened the page past the viewport at 390px.
   `clip` rather than `hidden` so overflow-y stays visible and nothing traps
   the page scroll. */
.cart-viewport { overflow-x: clip; }
@supports not (overflow-x: clip) { .cart-viewport { overflow-x: hidden; } }
/* Fallback only — used when GSAP fails to load; reduced motion drops it. */
.cart-anim { animation: cartIn 460ms var(--ease-in-out, ease) both; }
@keyframes cartIn {
  from { opacity: 0; transform: translateY(12px); }
  to { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) { .cart-anim { animation: none; } }

.cart-wrap { max-width: 900px; margin: 0 auto; padding: 0 var(--spacing-5); }
.cart-section { padding: clamp(48px, 7vw, 88px) 0; }
/* Step 1 and Step 2 are one continuous choice, so the gap between them is one
   band of air rather than both sections' full padding stacked — 176px read as
   a page break, not as a step. */
.cart-section + .cart-section { padding-top: clamp(24px, 3.5vw, 44px); }
.cart-h2 {
  margin: 0 0 var(--spacing-6); text-align: center;
  font-size: var(--text-3xl); font-weight: var(--font-weight-medium);
  letter-spacing: -0.01em; color: var(--text-default);
}
/* Checkout stacks four titled blocks inside one .cart-wrap, so the air between
   them has to come from the heading — there is no section wrapper to carry it.
   :not(:first-child) keeps the first heading tight against the section padding
   instead of doubling it. */
.cart-h2:not(:first-child) { margin-top: clamp(48px, 6vw, 80px); }
.cart-h2-sub {
  /* Pulls up by exactly the h2's own margin-bottom, so the sub reads as part
     of the heading rather than as the block's first paragraph. */
  margin: calc(var(--spacing-6) * -1) 0 var(--spacing-6);
  text-align: center; font-size: var(--text-sm); color: var(--text-muted);
}
.cart-back:focus-visible, .cart-input:focus-visible,
.cart-treatment:focus-visible, .cart-method:focus-within {
  outline: 3px solid var(--focus-ring); outline-offset: 2px;
}
.cart-input:focus-visible { border-color: var(--accent-default); }

/* ---- Hero bento (screen 1) ----
   Mirrors .wlh-bento / .wnh-bento on the Weight Loss and Wellness landings:
   same 1280 max-width, 12-column grid, --spacing-3 gap and 2xl tile radius,
   so the cart's first screen sits in the same furniture as the rest of the
   site. See the note in CartFlow.jsx for the one intentional divergence
   (--accent-strong ground, for AA on the sub and note lines). */
.cart-hero-back { max-width: 1280px; margin: 0 auto; padding: var(--spacing-4) var(--spacing-6) 0; }
.cart-bento {
  max-width: 1280px; margin: 0 auto;
  padding: var(--spacing-2) var(--spacing-6) 0;
  display: grid; grid-template-columns: repeat(12, 1fr); gap: var(--spacing-3);
}
.cart-tile-text {
  grid-column: span 8; box-sizing: border-box;
  background: var(--accent-strong); border-radius: var(--radius-2xl);
  padding: var(--spacing-10) var(--spacing-8);
  display: flex; flex-direction: column; justify-content: space-between;
  align-items: flex-start; gap: var(--spacing-6);
}
.cart-tile-text h1 {
  margin: 0; font-size: var(--text-5xl); font-weight: 300;
  line-height: 1.12; color: var(--color-white); max-width: 14em; text-wrap: pretty;
}
.cart-hero-sub {
  margin: var(--spacing-4) 0 0; font-size: var(--text-xl);
  line-height: 1.5; color: var(--accent-subtle); max-width: 22em;
}
.cart-hero-note { margin: 0; font-size: var(--text-sm); color: var(--accent-subtle); }
/* 5:4, not the WL/Wellness 3:4 — the media tile sets the row height, and this
   tile's text column carries three lines rather than their four-part stack
   (headline · sub · CTA · fine print). At 3:4 the copy occupied about a third
   of its own panel. */
.cart-tile-media {
  grid-column: span 4; position: relative; aspect-ratio: 5 / 4;
  background: var(--accent-subtle); border-radius: var(--radius-2xl); overflow: hidden;
}
/* The asset is a transparent cut-out, so the tile's own tint becomes her
   background — the mockup's composition, no masking needed.
   Anchored to the TOP, not the bottom, and allowed to overrun the tile: the
   tile clips her lower body the way the WL hero's model is clipped mid-calf,
   which is what lets her fill the width. Anchor her at the bottom instead and
   the overflow lands on her head. `contain` was the other option and it fits
   the whole figure, but a 0.60 portrait inside a 3:4 tile then leaves wide
   tint gutters and she reads as a thumbnail. */
.cart-hero-model {
  position: absolute; left: 50%; top: var(--spacing-4); transform: translateX(-50%);
  /* 68%, down from 86%: the tile is shorter now, so a wide figure would be
     clipped at the collarbone. Narrower keeps the crop below her folded arms,
     which is where the pose reads. */
  width: 68%; height: auto; max-width: none;
  filter: drop-shadow(0 18px 36px rgba(0, 0, 0, 0.18));
}

/* ---- Step 1: treatments ---- */
/* Three cards (NAD+, GLP-1, Tirzepatide) for the extracted cart-app. */
.cart-treatments {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--spacing-4); max-width: 960px; margin: 0 auto;
}

/* ---- Step 2: treatment configurator ----
   Replaces the ladder of big plan cards. One panel per chosen treatment; a
   term is an option inside it, not a card of its own. See the note on
   CartTreatmentConfig for what this fixes and why. */
.cart-configs { max-width: 620px; margin: 0 auto; display: flex; flex-direction: column; gap: var(--spacing-5); }
.cart-config {
  background: var(--bg-elevated); border: 1px solid var(--border-default);
  border-radius: var(--radius-xl); padding: var(--spacing-5);
}
.cart-config-head {
  display: grid; grid-template-columns: 46px minmax(0, 1fr) auto;
  align-items: center; gap: var(--spacing-3);
}
.cart-config-vial { display: block; width: 100%; height: auto; }
.cart-config-id { min-width: 0; }
.cart-config-name {
  margin: 0; font-size: var(--text-lg); font-weight: var(--font-weight-bold);
  color: var(--text-default); letter-spacing: -0.01em;
}
.cart-config-claim { margin: 2px 0 0; font-size: var(--text-xs); color: var(--text-muted); }
/* 44px min-height, not the 28px this started at. Measured on a phone it was
   63x28 — over WCAG 2.5.8's 24px floor but under the 44px this page already
   holds itself to (see the back button), and it is the one control here that
   throws work away. The underline is on the text, not the button, so the
   larger hit area does not drag a 44px-tall rule across the panel. */
.cart-config-remove {
  background: none; border: 0; cursor: pointer;
  /* inline-flex + centred, so the 44px is hit area only — text-decoration
     follows the TEXT, not the box, so the underline stays on the word. */
  min-height: 44px; display: inline-flex; align-items: center;
  padding: 0 var(--spacing-2); margin-right: calc(var(--spacing-2) * -1);
  font: var(--font-weight-semibold) var(--text-xs)/1 var(--font-family-base);
  color: var(--text-muted); text-decoration: underline; text-underline-offset: 3px;
}
.cart-config-remove:hover { color: var(--text-default); }
.cart-config-remove:focus-visible { outline: 3px solid var(--focus-ring); outline-offset: 2px; border-radius: var(--radius-md); }

/* Every term visible, stacked in one row — the guidance is to show them all
   at four or fewer, and four is our longest ladder. auto-fit so NAD+'s two
   terms fill the row instead of leaving holes. */
.cart-terms {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(96px, 1fr));
  gap: var(--spacing-2); margin-top: var(--spacing-4);
}
.cart-term {
  position: relative; cursor: pointer; text-align: center;
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  padding: var(--spacing-3) var(--spacing-2);
  background: var(--bg-secondary); color: var(--text-default);
  border: 2px solid transparent; border-radius: var(--radius-lg);
  font-family: var(--font-family-base);
  transition: border-color var(--transition-base) var(--ease-in-out),
              background var(--transition-base) var(--ease-in-out);
}
.cart-term:hover { background: var(--accent-subtle); }
.cart-term.is-on { background: var(--accent-subtle); border-color: var(--accent-default); }
.cart-term:focus-visible { outline: 3px solid var(--focus-ring); outline-offset: 2px; }
.cart-term-name { font-size: var(--text-xs); font-weight: var(--font-weight-semibold); }
/* The comparable figure. tabular-nums so the rates line up as a column and
   can actually be read against each other. */
.cart-term-rate {
  font-size: var(--text-base); font-weight: var(--font-weight-bold);
  color: var(--accent-strong); font-variant-numeric: tabular-nums;
}
.cart-term-rate i { font-style: normal; font-size: var(--text-xs); font-weight: var(--font-weight-semibold); }
.cart-term-badge {
  margin-top: 2px; font-size: 9.5px; letter-spacing: 0.08em; text-transform: uppercase;
  font-weight: var(--font-weight-bold); color: var(--accent-onSubtle);
  background: var(--bg-elevated); border-radius: var(--radius-4xl);
  padding: 2px var(--spacing-2); white-space: nowrap;
}

.cart-config-detail {
  margin: var(--spacing-3) 0 0; padding-top: var(--spacing-3);
  border-top: 1px solid var(--border-default);
  font-size: var(--text-sm); line-height: 1.6; color: var(--text-secondary);
}
.cart-config-detail b { color: var(--text-default); font-weight: var(--font-weight-bold); }
.cart-config-detail b.is-free { color: var(--accent-strong); }
.cart-config-detail b.is-save { color: var(--success-default); }
/* The comparison baseline earns less weight than the saving itself — it is
   the reference, not the claim. */
.cart-config-vs { font-size: var(--text-xs); color: var(--text-muted); }
.cart-config-prompt {
  margin: var(--spacing-4) 0 0; padding-top: var(--spacing-4);
  border-top: 1px solid var(--border-default);
  font-size: var(--text-sm); color: var(--text-muted);
}

/* ---- Step 2: running order + the step's CTA, in one bar ----
   Merged deliberately. As two stacked blocks the total sat ~100px above the
   button it authorises, which pushed Continue FURTHER from the step heading
   than the old card ladder did — the opposite of what the rework was for. */
.cart-checkout-bar {
  max-width: 620px; margin: clamp(28px, 4vw, 40px) auto 0;
  padding: var(--spacing-4) var(--spacing-5);
  background: var(--bg-secondary); border-radius: var(--radius-xl);
}
/* ---- Discount code ----
   Kept quiet on purpose. A loud coupon field is a documented way to send
   customers off the page hunting for a code they do not have; this one is a
   line of text until someone who has a code opens it. */
.cart-code-slot {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: var(--spacing-4); flex-wrap: wrap;
  margin-top: var(--spacing-3); padding-top: var(--spacing-3);
  border-top: 1px solid var(--border-default);
}
.cart-code-toggle,
.cart-code-clear {
  background: none; border: 0; cursor: pointer; padding: 0;
  /* 44px of hit area, matching the rest of the page's touch standard, with
     the underline still on the word rather than stretched down the box. */
  min-height: 44px; display: inline-flex; align-items: center;
  font: var(--font-weight-semibold) var(--text-sm)/1 var(--font-family-base);
  color: var(--text-muted); text-decoration: underline; text-underline-offset: 3px;
}
.cart-code-toggle:hover, .cart-code-clear:hover { color: var(--text-default); }
.cart-code-toggle:focus-visible, .cart-code-clear:focus-visible {
  outline: 3px solid var(--focus-ring); outline-offset: 2px; border-radius: var(--radius-md);
}
.cart-code-form { display: flex; flex-wrap: wrap; gap: var(--spacing-2); align-items: center; }
/* Both controls hold the 44px this page standardised on. The compact button
   size renders 36px and the trimmed input 35px, which is over WCAG 2.5.8's
   24px floor but under the bar the rest of the cart meets. */
.cart-code-form > button { min-height: 44px; }
/* The full field treatment has to be restated here. `.cart-input` is only a
   focus hook — every other field on this page gets its border, ground and
   type from inline styles in CartField, which this input does not use. Left
   to the class alone it rendered as a raw browser input, taller than the
   button beside it and in a different type family. */
.cart-code-input {
  flex: 1 1 150px; min-width: 0; max-width: 220px;
  box-sizing: border-box; min-height: 44px;
  padding: var(--spacing-2) var(--spacing-3);
  border: 1px solid var(--border-default); border-radius: var(--radius-lg);
  background: var(--bg-elevated); color: var(--text-default);
  font: var(--font-weight-semibold) var(--text-sm)/1.4 var(--font-family-base);
  text-transform: uppercase; letter-spacing: 0.06em;
}
.cart-code-input::placeholder {
  color: var(--text-muted); font-weight: var(--font-weight-medium); letter-spacing: 0.02em;
}
.cart-code-input[aria-invalid="true"] { border-color: var(--error-default); }
.cart-code-error {
  flex: 1 0 100%; margin: 0; font-size: var(--text-xs); color: var(--error-default);
}
.cart-code-on {
  margin: 0; display: flex; align-items: center; gap: var(--spacing-3);
  flex-wrap: wrap; font-size: var(--text-sm); color: var(--text-secondary);
}
.cart-code-on b { color: var(--success-default); font-weight: var(--font-weight-bold); }
.cart-running-note {
  margin: var(--spacing-2) 0 0; text-align: right;
  font-size: var(--text-xs); color: var(--text-muted);
}

.cart-bar-foot {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--spacing-4); flex-wrap: wrap;
}
/* With nothing chosen there is no total, so the lone button centres rather
   than sitting hard left against an empty row. */
.cart-bar-foot:only-child { justify-content: center; }
.cart-running-title {
  margin: 0 0 var(--spacing-3); font-size: var(--text-xs);
  text-transform: uppercase; letter-spacing: 0.1em;
  font-weight: var(--font-weight-bold); color: var(--text-muted);
}
.cart-running-lines { list-style: none; margin: 0; padding: 0; }
.cart-running-lines li,
.cart-running-total {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: var(--spacing-4); font-size: var(--text-sm); color: var(--text-secondary);
}
.cart-running-lines li { padding: var(--spacing-1) 0; }
.cart-running-lines b, .cart-running-total b { font-variant-numeric: tabular-nums; color: var(--text-default); }
.cart-running-total {
  margin: 0; flex: 1 1 auto; min-width: 0;
  font-size: var(--text-base); font-weight: var(--font-weight-bold); color: var(--text-default);
}
/* Once discounts are itemised above it, this row is what the customer pays —
   given a step up in size so it reads as the conclusion of the column rather
   than one more line in it.
   `flex: 0 1 auto` overrides the base `1 1 auto` ONLY here. Grown, this row
   pushes its figure to the right edge of whatever space the CTA leaves — which
   lands ~240px short of the dollar column directly above it, so the total
   looked like a column entry that had slipped its column. Shrunk to content,
   label and figure read as one statement and there is no false column to
   mis-align. Desktop only: the mobile rule below stretches the foot's children
   full-width, where the total DOES line up with the rows it sums. */
.cart-running-total-final {
  flex: 0 1 auto; font-size: var(--text-lg);
}
.cart-running-total-final b { color: var(--accent-strong); }

/* ---- Discount rows ----
   Subtotal, then one row per reduction. Same grid as .cart-running-lines so
   the dollar column stays aligned all the way down the bar. */
.cart-running-adjust {
  list-style: none; margin: var(--spacing-3) 0 0; padding: var(--spacing-3) 0 0;
  border-top: 1px solid var(--border-default);
}
.cart-running-adjust li {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: var(--spacing-4); padding: var(--spacing-1) 0;
  font-size: var(--text-sm); color: var(--text-secondary);
}
.cart-running-adjust b { font-variant-numeric: tabular-nums; color: var(--text-default); }
/* Money coming OFF, coloured as a gain rather than the neutral of the figure
   it reduces. The minus sign carries it for anyone who cannot see the hue. */
.cart-adjust-off b { color: var(--success-default); }

/* The rule sits on the bar's foot, not the total, so it still spans the full
   width when the button shares the row.
   Every selector is needed — the block directly above the foot changes with
   the order. The code slot slides in once there is something to discount, and
   the adjust list slides in below THAT once a discount actually applies; an
   adjacent-sibling rule naming only the lines silently stopped matching and
   left the subtotal touching the code field. Add a selector here whenever a
   new block can end up last before .cart-bar-foot.
   .cart-running-adjust is the exception: it draws its own top border and the
   foot follows it with no second rule, so the total is not fenced off from
   the reductions that produce it. */
.cart-running-lines + .cart-bar-foot,
.cart-code-slot + .cart-bar-foot {
  margin-top: var(--spacing-3); padding-top: var(--spacing-3);
  border-top: 1px solid var(--border-default);
}
.cart-running-adjust + .cart-bar-foot { margin-top: var(--spacing-2); }

.cart-includes { margin: clamp(56px, 7vw, 88px) auto 0; max-width: 560px; text-align: center; }
.cart-includes h3, .cart-how h3 {
  margin: 0 0 var(--spacing-5); font-size: var(--text-base);
  font-weight: var(--font-weight-bold); color: var(--text-default);
}
.cart-includes ul {
  list-style: none; margin: 0; padding: 0; text-align: left;
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--spacing-3) var(--spacing-6);
}
.cart-how { margin: clamp(40px, 5vw, 64px) auto 0; max-width: 520px; text-align: center; }
.cart-how p { margin: 0; font-size: var(--text-sm); line-height: 1.7; color: var(--text-secondary); }

.cart-trust { margin: clamp(40px, 5vw, 64px) auto 0; max-width: 520px; text-align: center; }
.cart-trust-label {
  margin: 0 0 var(--spacing-3); font-size: var(--text-sm);
  font-weight: var(--font-weight-bold); color: var(--text-default);
}
.cart-hsa {
  display: flex; align-items: center; justify-content: center; gap: var(--spacing-2);
  margin: var(--spacing-6) 0 0; font-size: var(--text-sm);
  font-weight: var(--font-weight-bold); color: var(--text-default);
}

/* ---- Checkout: summary card ----
   Screen 2 has no hero, so it keeps the tinted band the comp draws behind the
   treatment card rather than borrowing the bento. */
.cart-band {
  background: linear-gradient(100deg, var(--accent-subtle) 0%, var(--color-white) 100%);
  padding: var(--spacing-5) 0 0;
}
.cart-band-inner { max-width: 1180px; margin: 0 auto; padding: 0 var(--spacing-5); }
.cart-band-checkout { padding-bottom: var(--spacing-10); }
.cart-empty {
  margin: 0; text-align: center; font-size: var(--text-sm); color: var(--text-muted);
}
.cart-continue-note {
  margin: var(--spacing-3) 0 0; text-align: center;
  font-size: var(--text-sm); color: var(--text-muted);
}

/* ---- Checkout: order totals ----
   Sits under the per-treatment panels and carries what belongs to the ORDER
   rather than to any one line: subtotal, the code, and the figure charged. */
.cart-order {
  margin-top: var(--spacing-5); padding-top: var(--spacing-4);
  border-top: 1px solid var(--glass-border); text-align: left;
}
/* The one figure on this card the customer is charged. Every row here was
   14px, which set it at the size of the shipping label; it now carries the
   hierarchy the decision deserves. text-align stays left with the rows above
   so the numbers still form a readable column. */
.cart-order-total {
  margin-top: var(--spacing-3); padding-top: var(--spacing-4);
  border-top: 1px solid var(--glass-border);
}
.cart-order-label {
  margin: 0; font-size: var(--text-xs); text-transform: uppercase;
  letter-spacing: 0.09em; font-weight: var(--font-weight-bold); opacity: 0.75;
}
.cart-order-figure {
  margin: var(--spacing-1) 0 0; display: flex; align-items: baseline;
  gap: var(--spacing-3); line-height: 1.05;
}
.cart-order-figure b {
  font-size: var(--text-4xl); font-weight: var(--font-weight-bold);
  letter-spacing: -0.02em; font-variant-numeric: tabular-nums;
}
.cart-order-was {
  font-size: var(--text-base); text-decoration: line-through;
  opacity: 0.55; font-variant-numeric: tabular-nums;
}
.cart-order-permo {
  margin: var(--spacing-2) 0 0; font-size: var(--text-sm); opacity: 0.85;
  font-variant-numeric: tabular-nums;
}
.cart-summary-panel + .cart-summary-panel { margin-top: var(--spacing-3); }

/* ---- Checkout: two rows ----
   Row 1 is the summary beside the form; row 2 is the disclaimer under both.
   `align-items: start` matters — without it the summary card stretches down
   the form's much taller column and its $0-due footer detaches from the card.
   minmax(0, …) on both tracks, or the form's widest child (the card-number
   row) sets an implicit min-content floor and pushes the grid past its
   container instead of wrapping. */
.cart-checkout-grid {
  display: grid; grid-template-columns: minmax(0, 430px) minmax(0, 1fr);
  gap: clamp(24px, 4vw, 64px); align-items: start;
}
.cart-formcol { min-width: 0; padding-top: var(--spacing-6); }
/* The form's first heading would otherwise take the 48–80px lead-in meant to
   separate stacked blocks, starting the right column below the left one. */
.cart-formcol .cart-h2:first-child { margin-top: 0; }
.cart-disclaimer {
  max-width: 900px; margin: clamp(32px, 5vw, 64px) auto 0;
  padding-top: var(--spacing-6); border-top: 1px solid var(--border-default);
}
/* Right-aligned made sense when this line trailed the summary card; centred
   under a centred legal block is what row 2 needs. */
.cart-disclaimer .cart-hipaa { text-align: center; margin-top: var(--spacing-4); }
.cart-disclaimer .cart-legal { margin-top: 0; }

.cart-summary {
  /* border-box, or max-width caps the CONTENT and the card renders 478px —
     its 24px side padding added on twice. This page has no global reset, so
     every element that pads and constrains has to say so itself. */
  max-width: 430px; box-sizing: border-box; margin: var(--spacing-6) auto 0;
  background: var(--glass-solid); color: var(--color-white);
  border-radius: var(--radius-2xl); box-shadow: var(--shadow-xl);
  overflow: hidden; padding: var(--spacing-8) var(--spacing-6) 0; text-align: center;
}
/* Carried over from the plan card the user chose — same colours, same
   full-width band, same uppercase label. Negative margins take it out of the
   card's own padding and up to its top edge, the same trick .cart-due uses to
   reach the bottom one; the card's overflow: hidden clips it to the radius. */
.cart-summary-ribbon {
  margin: calc(var(--spacing-8) * -1) calc(var(--spacing-6) * -1) var(--spacing-6);
  padding: var(--spacing-2) var(--spacing-3);
  background: var(--bg-secondary); color: var(--text-default);
  font-size: var(--text-xs); font-weight: var(--font-weight-bold);
  letter-spacing: 0.1em; text-transform: uppercase;
}
.cart-summary-ribbon.is-featured {
  background: var(--accent-subtle); color: var(--accent-onSubtle);
}
.cart-summary-title {
  margin: 0 0 var(--spacing-6); font-size: var(--text-2xl);
  font-weight: var(--font-weight-medium); letter-spacing: -0.01em;
}
.cart-summary-panel {
  display: grid; grid-template-columns: 92px minmax(0, 1fr);
  gap: var(--spacing-4); align-items: center; text-align: left;
  /* A lighter inset on the same ink, so the panel separates from the card
     without introducing a second color. */
  background: rgb(255 255 255 / 0.09);
  border-radius: var(--radius-xl); padding: var(--spacing-4);
}
.cart-summary-panel img { display: block; width: 100%; height: auto; }
.cart-saving-line {
  margin: var(--spacing-5) 0 0; font-size: var(--text-sm); line-height: 1.5;
}
/* The entered code's row in the totals. Only the FIGURE greens up — the label
   stays in the column's voice, so the row still scans with its neighbours
   while the money that came off is unmistakable. */
.cart-order-coderow span:last-child { color: var(--success-default) !important; }

/* The entered code's confirmation. Success tone, not accent: it has to read
   as "this worked" and stay distinct from the automatic CODE APPLIED chip
   directly beneath it, which is a different kind of claim. */
.cart-code-win {
  display: inline-flex; align-items: center; gap: var(--spacing-2);
  margin: var(--spacing-4) 0 0; padding: var(--spacing-2) var(--spacing-4);
  /* green-800 on green-100 measures 6.49:1. The system has --success-default
     and --success-subtle but no --success-onSubtle to pair with them, so the
     ink is named here rather than left to a fallback that would have applied
     silently. Green is a semantic signal, not the accent, so it does not
     follow data-theme and the theme contract is intact. */
  background: var(--success-subtle); color: var(--color-green-800);
  border-radius: var(--radius-lg);
  font-size: var(--text-sm); font-weight: var(--font-weight-semibold);
  text-align: left;
}
.cart-code-win-tick { display: flex; flex: none; color: var(--success-default); }
.cart-code-win b { font-weight: var(--font-weight-bold); letter-spacing: 0.02em; }
.cart-code-win-amt {
  margin-left: var(--spacing-2); font-weight: var(--font-weight-bold);
  color: var(--success-default); font-variant-numeric: tabular-nums;
}

.cart-code {
  display: inline-block; margin: var(--spacing-4) 0 0;
  background: var(--accent-subtle); color: var(--accent-onSubtle);
  border-radius: var(--radius-lg); padding: var(--spacing-2) var(--spacing-5);
  font-size: var(--text-base); font-weight: var(--font-weight-semibold); letter-spacing: 0.02em;
}
.cart-hold {
  margin: var(--spacing-2) 0 0; font-size: var(--text-xs);
  font-weight: var(--font-weight-bold);
}
/* ---- Checkout: hold sticker ----
   One custom property drives the whole seal: the box is sized from it AND
   font-size is set to it, so every label inside can be an em fraction and the
   sticker scales as a unit. Changing it in the media query below is the only
   responsive rule this component needs. */
.cart-sticker {
  --cart-sticker-size: 132px;
  position: relative; display: inline-grid; place-items: center;
  width: var(--cart-sticker-size); height: var(--cart-sticker-size);
  font-size: var(--cart-sticker-size); margin: var(--spacing-4) 0 0;
  /* Individual `rotate`, not transform: the pulse below animates `scale`, and
     a combined transform would have to restate the tilt in every keyframe. */
  rotate: -8deg;
  animation: cart-sticker-pulse 2.4s ease-in-out infinite;
}
/* Low amplitude and slow on purpose. This is the one element on a healthcare
   checkout that counts down, so it gets enough motion to find and not enough
   to nag — and none at all for anyone who asked for less. */
@keyframes cart-sticker-pulse { 50% { scale: 1.035; } }
.cart-sticker-burst {
  position: absolute; inset: 0; width: 100%; height: 100%; display: block;
  filter: drop-shadow(0 6px 14px rgb(0 0 0 / 0.35));
}
.cart-sticker-burst polygon { fill: var(--warning-default); }
.cart-sticker-text {
  position: relative; display: flex; flex-direction: column;
  align-items: center; line-height: 1; color: var(--color-black);
}
.cart-sticker-lead { font-size: 0.076em; letter-spacing: 0.14em; font-weight: var(--font-weight-bold); }
.cart-sticker-time {
  font-size: 0.227em; font-weight: var(--font-weight-bold); margin: 0.02em 0;
  /* Tabular figures, or the seal twitches every second as the glyph widths
     change under it — the one animation nobody asked for. */
  font-variant-numeric: tabular-nums;
}
.cart-sticker-foot { font-size: 0.068em; letter-spacing: 0.14em; font-weight: var(--font-weight-bold); }
/* Spent, not alarming: the seal stays put and goes quiet rather than turning
   red, because an expired hold is not an error the user made. */
.cart-sticker.is-expired { animation: none; }
.cart-sticker.is-expired .cart-sticker-burst { filter: none; }
.cart-sticker.is-expired polygon { fill: rgb(255 255 255 / 0.16); }
.cart-sticker.is-expired .cart-sticker-text { color: var(--color-white); opacity: 0.75; }
.cart-sticker-time.is-word { font-size: 0.115em; letter-spacing: 0.04em; }
@media (prefers-reduced-motion: reduce) {
  .cart-sticker { animation: none; }
}
.cart-assurances {
  list-style: none; margin: var(--spacing-6) 0 0; padding: 0;
  font-size: var(--text-sm); line-height: 1.5;
}
.cart-assurances li { padding: var(--spacing-3) 0; border-top: 1px solid var(--glass-border); }
.cart-assurances li:first-child { border-top: 0; }
.cart-due {
  background: rgb(255 255 255 / 0.10); margin: var(--spacing-6) calc(var(--spacing-6) * -1) 0;
  padding: var(--spacing-5) var(--spacing-6);
}
.cart-due-title { margin: 0; font-size: var(--text-xl); font-weight: var(--font-weight-bold); }
.cart-due-note { margin: var(--spacing-1) 0 0; font-size: var(--text-xs); opacity: 0.85; }
.cart-hipaa {
  margin: var(--spacing-5) 0 0; text-align: right;
  font-size: var(--text-xs); color: var(--text-muted);
}

/* ---- Checkout: form ---- */
.cart-methods {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: var(--spacing-5); max-width: 620px; margin: 0 auto;
}
.cart-method {
  display: flex; flex-direction: column; align-items: center; gap: var(--spacing-3);
  background: var(--accent-subtle); border: 2px solid transparent;
  border-radius: var(--radius-xl); padding: var(--spacing-5); cursor: pointer;
  transition: border-color var(--transition-base) var(--ease-in-out);
}
.cart-method.is-on { border-color: var(--accent-default); }
.cart-method-title {
  font-size: var(--text-sm); font-weight: var(--font-weight-bold); color: var(--text-default);
}
.cart-form {
  display: flex; flex-direction: column; gap: var(--spacing-3);
  max-width: 400px; margin: 0 auto;
}
.cart-form-card { max-width: 400px; }
.cart-row-2 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--spacing-3); }
/* Errors are marked on the field, not just announced once: :placeholder-shown
   is a proxy for "still empty", so a field the user fills clears itself
   without another submit. :required is load-bearing — without it the optional
   "Address line 2" reddens alongside the fields that are genuinely missing.
   !important is equally load-bearing: CartField sets the `border` shorthand
   inline, which otherwise wins and leaves this rule matching but invisible. */
.cart-form.has-error .cart-input:required:placeholder-shown {
  border-color: var(--error-default) !important;
}
.cart-error {
  max-width: 400px; margin: var(--spacing-4) auto 0; text-align: center;
  font-size: var(--text-sm); color: var(--error-default);
}
/* min-height 44px: the label IS the hit target (the box itself is 16px), and
   measured on a phone this row was 335x22 — under WCAG 2.5.8's 24px floor,
   let alone the 44px the rest of this page holds to. The margin absorbs the
   extra height so the field above does not gain 22px of air. */
.cart-check {
  display: flex; align-items: center; gap: var(--spacing-2);
  min-height: 44px; margin-top: calc(var(--spacing-2) - 11px);
  font-size: var(--text-sm); color: var(--text-secondary); cursor: pointer;
}
.cart-check input { accent-color: var(--accent-default); width: 16px; height: 16px; flex: none; }
.cart-check:focus-within { outline: 3px solid var(--focus-ring); outline-offset: 2px; border-radius: var(--radius-md); }
.cart-fine, .cart-bnpl-note {
  margin: var(--spacing-4) auto 0; max-width: 34em; text-align: center;
  font-size: var(--text-xs); line-height: 1.6; color: var(--text-muted);
}
.cart-submit { margin-top: var(--spacing-10); text-align: center; }
.cart-secure { margin: var(--spacing-3) 0 0; font-size: var(--text-xs); color: var(--text-muted); }
/* Pre-payment policy links: same voice as .cart-fine, sitting on the pay
   button rather than the card block, since they bind the whole order. */
.cart-policy-links {
  margin: 0 auto var(--spacing-4); max-width: 34em;
  font-size: var(--text-xs); line-height: 1.6; color: var(--text-muted);
}
.cart-policy-links a { color: var(--accent-strong); }
/* Disclosure notes on the dark summary card: inherit its ink, sit at the
   same volume as .cart-due-note. */
.cart-notes {
  margin: var(--spacing-5) 0 0; padding-inline-start: var(--spacing-5);
  display: grid; row-gap: var(--spacing-2);
  font-size: var(--text-xs); line-height: 1.6; opacity: 0.85;
}
.cart-legal {
  margin: clamp(40px, 5vw, 64px) auto 0; max-width: 640px; text-align: center;
  font-size: 11px; line-height: 1.6; color: var(--text-muted);
}
.cart-placed { text-align: center; max-width: 480px; }
.cart-placed h2 {
  margin: var(--spacing-4) 0 var(--spacing-3); font-size: var(--text-3xl);
  font-weight: var(--font-weight-medium); color: var(--text-default);
}
.cart-placed p { margin: 0 0 var(--spacing-4); font-size: var(--text-sm); line-height: 1.6; color: var(--text-secondary); }
/* Now a block of one <p> per treatment plus the order total, not a single
   joined line — the rule moves to the children so multi-line orders keep the
   spacing the one-liner had. */
.cart-placed-sum { font-weight: var(--font-weight-bold); color: var(--text-default) !important; }
.cart-placed-sum p { margin: var(--spacing-1) 0 0; }
.cart-placed-sum p:first-child { margin-top: 0; }

/* ---- Payment brand marks ----
   Third-party trademark colors. They live here, not in the JSX, because they
   are page configuration rather than component color decisions — which is
   also what keeps ui_kits/cart at zero theme-guard warnings.
   TODO(brand): typographic stand-ins. Replace with each network's official
   artwork before launch; their brand guidelines require the real mark. */
.pay-chip {
  display: inline-flex; align-items: center; justify-content: center;
  height: 26px; min-width: 42px; padding: 0 7px; box-sizing: border-box;
  border-radius: var(--radius-sm); background: var(--color-white);
  border: 1px solid var(--border-default);
  font-family: var(--font-family-base); font-size: 9px;
  font-weight: var(--font-weight-bold); letter-spacing: 0.02em; white-space: nowrap;
}
.pay-visa    { color: #1A1F71; font-size: 13px; font-style: italic; letter-spacing: -0.02em; }
.pay-amex    { background: #006FCF; border-color: #006FCF; color: var(--color-white); }
.pay-discover{ color: #4D4D4D; font-size: 7.5px; }
.pay-applepay{ color: #000000; font-size: 11px; }
.pay-gpay    { color: #5F6368; font-size: 11px; }
.pay-afterpay{ background: #B2FCE4; border-color: #B2FCE4; color: #000000; font-size: 10px; }
.pay-klarna  { background: #FFB3C7; border-color: #FFB3C7; color: #0B051D; font-size: 10px; }
.pay-affirm  { color: #4A4AF4; font-size: 11px; }
.pay-mc { position: relative; display: block; width: 26px; height: 16px; }
.pay-mc i { position: absolute; top: 0; width: 16px; height: 16px; border-radius: 50%; }
.pay-mc i:first-child { left: 0; background: #EB001B; }
/* multiply gives the overlap its darker orange without a third element */
.pay-mc i:last-child  { right: 0; background: #F79E1B; mix-blend-mode: multiply; }

/* ---- Narrow viewports ---- */
/* Same breakpoint the WL/Wellness bentos collapse at, so all three heroes
   change shape together rather than at three different widths. */
@media (max-width: 960px) {
  .cart-bento > div { grid-column: span 12 !important; }
  .cart-tile-text { padding: var(--spacing-8) var(--spacing-6); }
  .cart-tile-text h1 { font-size: var(--text-4xl); }
  /* The media tile leads on a stacked layout: the photograph sets the mood
     before the offer, and a 3:4 portrait below a full-width text tile would
     otherwise push the first plan card most of a screen further down. */
  .cart-tile-media { order: -1; aspect-ratio: 4 / 3; }
  .cart-hipaa { text-align: center; }
  /* Row 1 collapses back to the original stack — a 430px summary next to a
     form leaves neither enough width, and the form's own two-up rows
     (State/ZIP, Expiry/CVC) break first. Same breakpoint as the bento above,
     so the page changes shape once rather than twice. */
  .cart-checkout-grid { grid-template-columns: minmax(0, 1fr); }
  .cart-formcol { padding-top: 0; }
  .cart-formcol .cart-h2:first-child { margin-top: clamp(48px, 6vw, 80px); }
}
@media (max-width: 560px) {
  /* Squarer again — at 390px a 4:3 tile is still 290px of chrome before the
     headline, and the figure is legible well below that. */
  .cart-tile-media { aspect-ratio: 1 / 1; }
  .cart-tile-text h1 { font-size: var(--text-3xl); }
  .cart-hero-sub { font-size: var(--text-lg); }
}
@media (max-width: 900px) {
  .cart-treatments { grid-template-columns: 1fr; max-width: 420px; }
}
@media (max-width: 620px) {
  .cart-treatments { grid-template-columns: 1fr; max-width: 420px; }
  .cart-includes ul { grid-template-columns: 1fr; max-width: 300px; margin: 0 auto; }
  /* Two terms per row rather than four across — at 390px a 4-up row gives
     each term about 78px, which clips "12 Months" and squeezes the rate. */
  .cart-terms { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* The bar's row wraps at this width, which left the button stranded and
     left-aligned under a full-width total. Full-width is the phone
     convention for the action that ends a step, and it is a bigger target. */
  .cart-bar-foot { flex-direction: column; align-items: stretch; gap: var(--spacing-3); }
  .cart-bar-foot > button { width: 100%; }
  /* The four card marks INSIDE the card field repeat the ones on the payment
     tile a hundred pixels above, and at 390px they take 207px of a 335px
     field — enough that the placeholder is cut mid-digit ("1234 1234 1234
     123"). Drop them on phones; the tile above still says which cards are
     taken. !important because the padding they reserve is an inline style. */
  .cart-input-marks { display: none !important; }
  .cart-input.has-marks { padding-right: var(--spacing-4) !important; }
  .cart-summary-panel { grid-template-columns: 72px minmax(0, 1fr); gap: var(--spacing-3); }
  .cart-sticker { --cart-sticker-size: 112px; }
}
@media (max-width: 380px) {
  /* State/ZIP and Expiry/CVC stop fitting side by side once the field's own
     padding eats the column. */
  .cart-row-2 { grid-template-columns: 1fr; }
}
