/* assets/charm-builder.css
   Scoped styles for the Charm Builder ("Custom Charm Necklace" PDP).
   Colour tokens per Figma (node 13227:34643 — DESKTOP DESIGN PG1):
   preview panel #faf2ff, picker panel #faefe2 (close enough to read as
   one background, not the quiz palette's more saturated #f1dffa/#fbf4ed
   this used before), borders/text #69001a, pill (inactive) white /
   (active) #d7b8e2. */

.charm-builder {
  display: block;
  color: #69001a;
}

/* The builder opens as a modal (not an embedded page section) — wide
   enough for the 50/50 split at desktop, edge-to-edge so the preview/
   panel colour blocks reach the dialog's own rounded corners rather than
   floating inside a padded inset. `.dialog__inner` (component-non-
   critical.css) provides the scrollable area (`v-scrollable`, in the
   markup) that `.charm-builder__preview`'s sticky positioning below is
   relative to. */
.charm-builder__dialog {
  /* Per Figma (node 13227:34643): spans the page, not a centred card —
     .dialog--modal's own width is calc(100% - 3.2rem), which still
     leaves a 1.6rem sliver down each side no matter how high
     --dialog-max-width goes (that's a separate cap, not this base
     width rule) — has to be overridden directly to close that gap.
     Square corners: every
     dialog in the theme (cart drawer, quick-add, ...) shares one
     merchant-configurable --dialog-radius (snippets/css-variables.liquid,
     settings.dialog_radius) that .dialog--modal falls back to — so
     removing this rule entirely would still pick up whatever that
     theme-wide setting is, not 0. Has to be zeroed explicitly here. */
  width: 100%;
  max-width: 100%;
  --dialog-max-width: 300rem;
  border-radius: 0;
  overflow: hidden;
  /* Figma docks this directly under the real site header — no floating
     centred card, no dimmed backdrop, the header stays fully visible
     and bright above it (client: "it almost connects to the nav bar").
     The theme's own `dialog { margin: auto }` (component-non-critical.
     css) is what centres every other dialog; zeroing it here, plus an
     explicit `top`, is what stops that. `--header-height` is the
     theme's own tracked header height (theme.js, used the same way
     elsewhere for "position below the sticky header"), not a value
     invented for this component. Width is now a flat 100% (see above),
     so there's no leftover horizontal gap for margin to centre within
     anyway — this can be a plain 0, not just margin-block. */
  margin: 0;
  /* Measured header bottom, refreshed when the header or viewport
     resizes. Includes any visible announcement bar above navigation. */
  top: var(--charm-builder-header-offset, 8rem);
  height: calc(100dvh - var(--charm-builder-header-offset, 8rem));
  max-height: calc(100dvh - var(--charm-builder-header-offset, 8rem));
}

/* No dimmed backdrop — per Figma this reads as a continuation of the
   page below the header, not a classic modal-over-dimmed-content. Only
   this dialog's own backdrop is affected (`::backdrop` scopes to the
   element it's chained off), every other dialog in the theme keeps its
   normal dimming. */
.charm-builder__dialog::backdrop {
  background: transparent;
}

.charm-builder__dialog .dialog__inner {
  border-radius: inherit;
  /* The builder's top border is drawn by ::before below rather than by the
     two panels inside, so that it stays pinned under the site header no
     matter how far down the picker column you are (client: "there should
     be always a border here at the top even on scroll"). Put on either
     panel instead, it scrolls away with the first section, which is what
     was reported. `.charm-builder__preview` and `.charm-builder__panel`
     therefore both zero their own `border-block-start`. */
  /* `.v-scrollable` (component-non-critical.css) also sets
     `scroll-snap-type: y mandatory`, meant for paginated/carousel-style
     content — with none of our children opting into a snap point, it
     instead made the *initial* focus-triggered scrollIntoView (dialog.js
     autofocuses the first focusable element on open) land ~650px down
     the panel instead of at the top. Confirmed by disabling snap alone. */
  scroll-snap-type: none;
}

/* The pinned top border itself. Deliberately a sticky child rather than a
   plain `border-block-start` on the scroll container: a border paints on
   the *border box*, which includes the scrollbar gutter, so it ran the
   scrollbar's width (6px here) past where the panels' own right border
   stops and left a stub poking out of the top-right corner (client: "the
   border in the corner is a bit broken"). A block-level child is laid out
   in the *content* box, so it ends exactly flush with the panels beneath
   it — corner closed — while `position: sticky` keeps it parked at the top
   of the scrollport. `height: 0` plus the negative bottom margin means it
   takes no space in the flow, so it draws over the panels' first pixel
   instead of pushing them down. */
.charm-builder__dialog .dialog__inner::before {
  content: "";
  display: block;
  position: sticky;
  top: 0;
  z-index: 3;
  height: 0;
  margin-block-end: -0.1rem;
  border-block-start: 0.1rem solid #69001a;
}

/* Build screen: 50/50 split per Figma (DESKTOP - DESIGN PG1) — two
   full-height, edge-to-edge colour panels, not a floating rounded card
   (that was this project's own earlier design, before the Figma
   reference existed). Stacked on mobile/tablet. */

.charm-builder__build {
  display: flex;
  flex-direction: column;
}

@media (min-width: 1024px) {
  .charm-builder__build {
    flex-direction: row;
    align-items: stretch;
  }
}

/* "How to build" box + Start Your Design button — lives on the real PDP
   (blocks/charm-builder-start.liquid), not inside <charm-builder> itself,
   but shares this stylesheet so its card matches the builder below it. */

.charm-builder-start {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 1.6rem;
  width: 100%;
}

/* Per Figma (node 13227:34293): full width of the buy-box column, not a
   fixed-width card — #ede2f4 (not the picker's #efd3fc pill colour) with
   a maroon border, and much tighter padding than this box originally had. */
.charm-builder__intro-box {
  width: 100%;
  background-color: #ede2f4;
  border: 0.1rem solid #69001a;
  border-radius: 2rem;
  padding: 1.6rem 2rem;
  text-align: left;
}

.charm-builder__intro-heading {
  margin-block-end: 0.4rem;
}

.charm-builder__intro-steps {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 1rem;
  /* Poppins Bold per Figma (node 13227:34530). Something in the PDP's
     details column resolves plain inherited text to Akzidenz-Grotesk, so
     name the theme's body family explicitly (client feedback, 2026-09-17:
     "the text beneath 'how to build' doesn't seem to have the right font"). */
  font-family: var(--font-body--family);
  font-weight: 700;
  font-size: 1.5rem;
  text-transform: uppercase;
}

/* The theme's pickup-availability block renders an empty shell (its own
   15px top padding and bottom margin, nothing inside) whenever the product
   can't be added to cart — true of this $0 builder product — which opened a
   ~50px hole between "Secure Checkout" and the Stack & Save pill on mobile
   (client feedback, 2026-09-17). Hide the shell when it has no content;
   it reappears untouched once the store gives this product pickup stock. */
.product-information local-pickup:not(:has(.pickup-availabilities__info)) {
  display: none;
}

/* Per Figma (node 13227:34524): a full-width, chunky pill button — not
   the theme's default auto-width .btn sizing. */
.charm-builder-start__button {
  width: 100%;
  height: 6.1rem;
  border-radius: 3.2rem;
  text-transform: uppercase;
}

/* Per Figma (node 13227:34551): small centred reassurance line under the
   Start button. */
.charm-builder-start__secure {
  margin: -0.4rem 0 0;
  text-align: center;
  font-size: 1.4rem;
}

/* Build screen: preview panel (sticky above the picker on mobile) */

.charm-builder__preview {
  position: relative;
  flex: 1 1 0;
  min-width: 0;
  width: 100%;
  background-color: #faf2ff;
  border: 0.1rem solid #69001a;
  /* See .charm-builder__panel — the top border is drawn once, by the
     scroll container, so it survives scrolling for both columns. */
  border-block-start: 0;
  /* No top padding: .charm-builder__preview-main runs to the panel's top
     edge and the Clear Design button floats over it (see below). */
  padding: 0 1.6rem 3.2rem;
  display: flex;
  flex-direction: column;
  gap: 1.6rem;
}

@media (min-width: 768px) {
  .charm-builder__preview {
    padding: 0 3rem 4rem;
  }

  .charm-builder__preview {
    --charm-builder-preview-inset-y: 4rem;
    --charm-builder-preview-inset-x: 3rem;
  }
}

@media (min-width: 1024px) {
  .charm-builder__preview {
    padding: 0 5rem 6rem;
    position: sticky;
    /* No site header inside the dialog — sticks to the top of the
       dialog's own scroll container (.dialog__inner.v-scrollable), not
       the page. */
    top: 0;
    align-self: flex-start;
    /* `align-self: flex-start` (not stretch) is what lets this panel
       actually *stick* — it has to stay shorter than the (much taller)
       picker column for there to be anything to scroll past. But that
       also means its height was purely "however tall its own content is"
       (Clear Design button + image box + thumbnail strip), which left a
       gap of bare background below a merely-square image box. Pinning it
       to the same height the dialog itself is capped at — rather than
       the picker's height — gives .charm-builder__preview-main's
       flex-grow below real room to fill, without breaking the sticky
       trick. Must stay identical to .charm-builder__dialog's own
       height formula (charm-builder.css, top of file) or this panel
       can end up taller than the dialog itself, clipped by its
       overflow: hidden with no way to scroll to the rest — that's what
       caused the necklace image to visibly cut off after the dialog
       was docked under the header instead of centred with a flat
       6.4rem inset. */
    height: calc(100dvh - var(--charm-builder-header-offset, 8rem));
  }
  .charm-builder__preview {
    --charm-builder-preview-inset-y: 6rem;
    --charm-builder-preview-inset-x: 5rem;
  }
}

/* Floats over the top-left corner of the preview instead of taking a
   row of its own: the chain photo runs up behind it to the panel's top
   edge (client, 2026-09-17: the strip above the necklace where this
   button sat was "unused space we can use to show more of the
   necklace"). Insets match the panel's old padding at each breakpoint so
   the button lands exactly where it used to. */
.charm-builder__clear-design {
  position: absolute;
  z-index: 2;
  /* The insets are custom properties set per breakpoint on
     .charm-builder__preview (above) because those media rules sit
     earlier in this file than this one and would otherwise lose. */
  top: var(--charm-builder-preview-inset-y, 3.2rem);
  left: var(--charm-builder-preview-inset-x, 1.6rem);
  background-color: #ffffff;
  border: 0.1rem solid #69001a;
  border-radius: 3.2rem;
  padding: 0.8rem 1.6rem;
  font-size: 1.2rem;
  font-weight: 700;
  text-transform: uppercase;
  cursor: pointer;
  color: #69001a;
}

.charm-builder__preview-main {
  width: 100%;
  aspect-ratio: 1;
  /* No separate tint from the panel behind it — per Figma the necklace
     image sits directly on the one panel background, not in its own
     coloured box (client feedback: "the whole background is one
     colour"). */
  background-color: transparent;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  /* The .preview-viewport child clips the framed chain photo itself
     (see below); nothing here needs to overflow, but `visible` keeps
     the placeholder text safe. */
  overflow: visible;
}

@media (min-width: 1024px) {
  .charm-builder__preview-main {
    /* Grow to fill whatever's left of .charm-builder__preview's own
       fixed height (above) once the Clear Design button and thumbnail
       strip have taken their share, instead of sitting at a fixed square
       size with empty background below it. */
    aspect-ratio: auto;
    flex: 1 1 auto;
    min-height: 0;
  }
}

/* Query-container for .charm-builder__preview-canvas below — its own
   box has a definite width AND height once the flex rules above apply
   (a requirement for container queries), which is what lets that child
   ask "how big must the square be so the framed slice of it fills my
   height, without its chain overflowing my width" via cqw/cqh. */
.charm-builder__preview-main {
  container-type: size;
}

@media (max-width: 1023.98px) {
  .charm-builder__dialog {
    /* Cover the site navigation while the mobile builder is open. */
    --charm-builder-header-offset: 0px;
    /* Leave room for the choices and review button on short screens. */
    --charm-builder-mobile-preview-height: min(38.4rem, calc((100dvh - var(--charm-builder-header-offset, 8rem)) * 0.48));
  }

  .charm-builder__dialog > .dialog__inner {
    scroll-padding-block-start: var(--charm-builder-mobile-preview-height);
  }

  .charm-builder__preview {
    position: sticky;
    top: 0;
    z-index: 3;
    flex: 0 0 auto;
    height: var(--charm-builder-mobile-preview-height);
    padding-block-end: 1.6rem;
    --charm-builder-preview-inset-y: 2rem;
  }

  .charm-builder__preview-main {
    aspect-ratio: auto;
    flex: 1 1 auto;
    min-height: 0;
  }

  .charm-builder__dialog > .dialog__close {
    z-index: 4;
  }
}

/* Centred in the panel — with the Clear Design button now floating over
   the top-left, a top-aligned placeholder collided with it on mobile. */
.charm-builder__preview-main:has(.charm-builder__preview-main-placeholder) {
  align-items: center;
}

.charm-builder__preview-main-placeholder {
  margin: auto;
  padding: 2rem;
  text-align: center;
  color: #69001a;
  font-size: 1.4rem;
}

/* The window onto the chain photo. Fills the panel and clips: the
   square canvas inside is deliberately BIGGER than this box and shifted
   up, so the top of the chain is out of view and the hoop end — where
   the charms hang — is what fills the panel. Client (2026-09-17):
   "is there any way we can have the necklace raised higher? Even if
   it's cutting off maybe half of the necklace?" — with charms drawn at
   their real size (~2cm droplets on a ~40cm chain) the whole-photo
   framing left them as specks under a big empty loop. */
.charm-builder__preview-viewport {
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden;
}

/* Square canvas — every chain photo is a square PNG (2380x2380), and
   the charms are positioned in percentages of this square, so keeping
   it square means those percentages map 1:1 onto the photo.

   Framing is three custom properties set inline by
   assets/charm-builder.js #updatePreview, all fractions of the square's
   side:
     --charm-builder-frame-top     where the visible slice starts
     --charm-builder-frame-height  how tall the visible slice is
     --charm-builder-frame-width   widest thing that must fit (chain or
                                   charm cluster, with margin)
   The square's side is the largest value for which the slice fits the
   panel's height AND that width fits the panel's width; the slice is
   then centred vertically (it fills the height unless the width cap
   won) and shifted up by frame-top so the slice's top is what the
   viewport shows. The defaults describe "whole photo plus a fifth
   below" — the old framing — so nothing breaks before JS measures. */
.charm-builder__preview-canvas {
  --charm-builder-frame-top: 0;
  --charm-builder-frame-height: 1.22;
  --charm-builder-frame-width: 1;
  position: absolute;
  bottom: 0;
  left: 50%;
  width: min(
    calc(100cqw / var(--charm-builder-frame-width)),
    calc(100cqh / var(--charm-builder-frame-height))
  );
  height: min(
    calc(100cqw / var(--charm-builder-frame-width)),
    calc(100cqh / var(--charm-builder-frame-height))
  );
  /* Anchored to the BOTTOM of the viewport, not centred: the slice's
     bottom edge (frame-top + frame-height, i.e. just under the deepest
     charm) is pinned to the panel's bottom, and whatever chain the
     panel's height has room for above that is shown — up to the panel's
     top edge, behind the floating Clear Design button. Centring left
     equal empty bands above and below whenever the width cap won
     (client, 2026-09-17: "a block of unused space ... we can use to show
     more of the necklace"). Percentages in translate() resolve against
     this box's OWN size — the square's side — which is exactly the unit
     the frame variables are in. */
  transform: translate(
    -50%,
    calc((1 - (var(--charm-builder-frame-top) + var(--charm-builder-frame-height))) * 100%)
  );
}

.charm-builder__preview-chain-img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
}

/* `top: 88%` here is only the FALLBACK — Curator's own measured ring
   position (opaque pixels start ~86% down its 1293px square canvas —
   see memory project_charm_builder_metaobject_catalog.md), used if a
   chain's metaobject entry has no `hoop_y` set. In practice
   #updatePreview (charm-builder.js) sets `top` as an inline style from
   the *selected chain's own* `hoop_y` every time, because chains are
   not all the same shape: Lockheart's heart clasp and Signature's
   ring-less chain (its clasp is at the *top* of the photo) sit at
   different heights than Curator's round ring.

   This is a plain positioning anchor now, not a flex row — `width: 100%`
   here (not on the flex-row's *children*) is what gives each
   .preview-charm-img's own `left: N%` (set inline per-charm in JS) a
   definite containing-block width to resolve against. Flex + negative
   margin was the original approach and had to be abandoned: rotating a
   charm inflates its *axis-aligned bounding box* (a rotated rectangle's
   bbox is wider than the rectangle itself), and margin-based spacing
   reacts to that inflated box — so increasing rotation silently widened
   the whole row even though the margins hadn't changed, and past a
   certain negative margin the layout order visually reversed (a
   teammate session measured DOM-first charms rendering rightmost).
   Positioning each charm by an explicit `left: %` centre-point plus
   `translateX(-50%)` makes horizontal spacing depend only on that
   percentage, never on the charm's own (rotation-dependent) size. */
.charm-builder__preview-charms {
  position: absolute;
  top: 88%;
  left: 0;
  width: 100%;
  height: 0;
  pointer-events: none;
}

.charm-builder__preview-charms:empty {
  display: none;
}

/* Normalized to a fixed share of the canvas width rather than each
   image's own intrinsic pixel size — the source crops vary a lot in how
   tightly they hug each charm, so intrinsic size carries no real-world
   size information (a tall snake charm and a squat medallion would
   otherwise render wildly different sizes side by side). Charms are
   meant to overlap and converge on the ring (client: "ok to overlap,
   but they all need to appear to be touching the ring in the middle so
   they appear attached to the chain") — `left`/`transform` (centre
   position + rotation) are set inline per-charm in #updatePreview (JS);
   this rule only carries what's the same for every charm. */
.charm-builder__preview-charm-img {
  position: absolute;
  top: 0;
  width: 17%;
  height: auto;
  object-fit: contain;
  /* Pivots from the bail at the top rather than the image's centre, so
     a tilted charm still reads as hanging from that point. */
  transform-origin: 50% 0%;
}

/* Build screen: picker panel (right) */

.charm-builder__panel {
  /* Exposed as custom properties, not just as a `padding` shorthand,
     because .charm-builder__review-row below has to negate these exact
     values to bleed out to the panel's own side borders. Keeping one
     source of truth means the breakout stays correct at all three
     breakpoints without repeating the numbers. */
  --charm-builder-panel-pad-block: 3.2rem;
  --charm-builder-panel-pad-inline: 1.6rem;
  flex: 1 1 0;
  min-width: 0;
  background-color: #faefe2;
  border: 0.1rem solid #69001a;
  /* No top border: it's drawn by the dialog's scroll container instead
     (see `.charm-builder__dialog .dialog__inner`, top of file) so that it
     stays pinned to the top of the builder while this panel's content
     scrolls underneath, rather than scrolling away with the first
     section. */
  border-block-start: 0;
  padding: var(--charm-builder-panel-pad-block) var(--charm-builder-panel-pad-inline);
  display: flex;
  flex-direction: column;
  gap: 0;
}

@media (min-width: 768px) {
  .charm-builder__panel {
    --charm-builder-panel-pad-block: 4rem;
    --charm-builder-panel-pad-inline: 3rem;
  }
}

@media (min-width: 1024px) {
  .charm-builder__panel {
    --charm-builder-panel-pad-block: 6rem;
    --charm-builder-panel-pad-inline: 5rem;
    /* Room for the out-of-flow sticky review bar (see
       .charm-builder__review-row) so the last row of cards clears it. */
    padding-block-end: calc(var(--charm-builder-panel-pad-block) + 7.6rem);
  }
}

/* Stack & Save bar at the top of the picker — same look as the cart
   drawer's (.bh2o-stack-progress, assets/cart-modules.css), restated
   here so the builder doesn't depend on the drawer's stylesheet. Right
   padding clears the dialog's absolute close button. */
.charm-builder__stack {
  /* Sticks to the top of the builder's scroll container (.dialog__inner)
     so the progress stays in view while the customer scrolls the picker
     — the close button it lines up with is outside that scroller, so the
     two stay level. Solid panel background + z-index so the cards
     scroll underneath it, below the pinned top border (z-index 3). */
  position: sticky;
  top: 0;
  z-index: 2;
  background-color: #faefe2;
  padding-block: 2rem 1.2rem;
  /* Full width (client feedback, 2026-09-17: "the progress bar ... would
     look better if it was full width"): the track spans the whole panel;
     only the centred message line pads itself clear of the dialog's
     absolute close button where the two share a row (desktop). */
  padding-inline-end: 0;
  margin-block-end: 0.4rem;
  /* Pull it up out of the panel's top padding so it sits on the same row
     as the dialog's absolute close button (2rem from the top on mobile,
     2.4rem from 768px — see .dialog__close--absolute, component-non-
     critical.css). */
  margin-block-start: calc(-1 * var(--charm-builder-panel-pad-block));
}

@media (min-width: 768px) {
  .charm-builder__stack {
    padding-block-start: 2.4rem;
  }
}

.charm-builder__stack:empty {
  display: none;
}

@media (max-width: 1023.98px) {
  .charm-builder__stack {
    /* Let progress scroll with the choices so it cannot cover section
       headings beneath the pinned preview, especially in landscape. */
    position: static;
  }
}

.charm-builder__stack-message {
  min-height: 1.7rem;
  margin: 0 0 0.7rem;
  padding-inline: 4.4rem;
  color: #69001a;
  font-family: var(--font-body--family);
  font-size: 1.2rem;
  font-weight: 700;
  line-height: 1.4;
  text-align: center;
}

.charm-builder__stack-track {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.5rem;
  height: 1.1rem;
}

.charm-builder__stack-segment {
  display: block;
  background: #efd3fc;
  border-radius: 0.5rem;
}

.charm-builder__stack-segment.is-complete {
  background: #c9a4cd;
}

.charm-builder__stack-labels {
  display: flex;
  justify-content: space-between;
  margin-top: 0.25rem;
  color: #69001a;
  font-family: var(--font-body--family);
  font-size: 1rem;
  font-weight: 600;
  line-height: 1.2;
}

/* Old price (struck) next to the Stack & Save price — cards, review
   items and the review totals all use these. */
.charm-builder__price-was,
.charm-builder__review-total-was {
  font-weight: 500;
  opacity: 0.6;
  margin-inline-end: 0.3rem;
}

.charm-builder__review-total-was[hidden] {
  display: none;
}

@media (min-width: 1024px) {
  .charm-builder__review-total-was {
    font-size: 0.5em;
  }
}

.charm-builder__section {
  /* Per Figma: a darker divider (matching the border colour used
     throughout, not the light pill tint) — client feedback: "more
     border sectioning each part (darker)". */
  border-top: 0.1rem solid #69001a;
  padding-block: 2.4rem;
}

/* The first section drops its divider and top padding. The second
   selector covers the Stack & Save bar being rendered but hidden
   (sections/charm-builder.liquid, `show_stack_progress` off): it is still
   the panel's first child, so :first-child alone left a stray rule and a
   2.4rem gap above "1. Choose Your Chain" (client, 2026-09-18). */
.charm-builder__section:first-child,
.charm-builder__stack[hidden] + .charm-builder__section {
  border-top: none;
  padding-block-start: 0;
}

.charm-builder__section-summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.6rem;
  cursor: pointer;
  list-style: none;
}

.charm-builder__section-summary::-webkit-details-marker {
  display: none;
}

.charm-builder__section-summary-main {
  display: flex;
  align-items: center;
  gap: 1.6rem;
  min-width: 0;
  /* Fill the summary row so the heading can push the "‹ ›" scroll
     buttons to the right edge, beside the collapse toggle, instead of
     leaving them tucked against the heading text (client, 2026-09-18:
     "these arrows should be right aligned"). */
  flex: 1 1 auto;
}

.charm-builder__section-summary-main .charm-builder__section-heading {
  flex: 1 1 auto;
}

.charm-builder__section-heading {
  color: #69001a;
  /* Flex, so the "(x of 5 added)" span is its own item: when the panel
     is too narrow for it to share the heading's line, it wraps onto a row
     only as tall as its own small text. As a plain inline it wrapped
     into a full heading-height line box, leaving a ~60px hole between
     the title and the count (client, 2026-09-18). */
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  column-gap: 0.35em;
  row-gap: 0.2rem;
}

@media (max-width: 1023.98px) {
  .charm-builder__section-heading {
    font-size: 28px;
  }
}

/* "(x of 5 added)" after the droplet/charm headings — body face, smaller
   and lighter than the serif heading so it reads as a status, not part
   of the title. */
.charm-builder__section-count {
  font-family: var(--font-body--family);
  /* A fixed size, not a share of the heading: the mobile heading is big
     enough that 0.5em made "(3 of 5 added)" read as a second title
     (client feedback, 2026-09-17). */
  font-size: 1.3rem;
  vertical-align: middle;
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  opacity: 0.7;
  white-space: nowrap;
}

@media (min-width: 1024px) {
  .charm-builder__section-count {
    font-size: 1.4rem;
  }
}

/* "‹"/"›" scroll buttons — the chain section (--always) keeps them at
   every width since it's always a horizontal-scroll row; droplet/charm
   only need them on mobile, where they're also scroll rows — at the
   1024px breakpoint those two switch to a wrapping grid instead (see
   .charm-builder__grid below), so their buttons hide there. */
.charm-builder__section-nav {
  display: inline-flex;
  align-items: center;
  gap: 0.8rem;
  flex-shrink: 0;
}

.charm-builder__nav-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 3.2rem;
  height: 3.2rem;
  flex-shrink: 0;
  border-radius: 50%;
  border: 0.1rem solid #69001a;
  background: none;
  color: #69001a;
  padding: 0;
  cursor: pointer;
}

.charm-builder__section-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 3.2rem;
  height: 3.2rem;
  flex-shrink: 0;
  border-radius: 50%;
  border: 0.1rem solid #69001a;
}

.charm-builder__section-icon--closed {
  display: none;
}

.charm-builder__section[open] .charm-builder__section-icon--open {
  display: none;
}

.charm-builder__section[open] .charm-builder__section-icon--closed {
  display: block;
}

/* Desktop (per Figma): every section is always open with no collapse
   affordance at all — hide the toggle circle and the mobile-only nav
   buttons. The <summary> stays clickable (native <details> semantics
   need that for keyboard activation too) — handleSectionToggle in
   charm-builder.js immediately reopens any section a click/key closes,
   so desktop nets out at "always open" without disabling the control. */
@media (min-width: 1024px) {
  .charm-builder__section-toggle {
    display: none;
  }

  .charm-builder__section-nav:not(.charm-builder__section-nav--always) {
    display: none;
  }

  .charm-builder__section-summary {
    cursor: default;
  }
}

.charm-builder__section-content {
  padding-block-start: 2rem;
  display: flex;
  flex-direction: column;
  gap: 1.6rem;
}

.charm-builder__metal-toggle {
  display: inline-flex;
  gap: 0.8rem;
}

.charm-builder__metal-btn {
  background-color: #ffffff;
  border: 0.1rem solid #efd3fc;
  border-radius: 3.2rem;
  padding: 0.8rem 2rem;
  font-size: 1.3rem;
  font-weight: 700;
  text-transform: uppercase;
  cursor: pointer;
  color: #69001a;
}

.charm-builder__metal-btn.is-active {
  background-color: #d7b8e2;
  border-color: #c9a4cd;
}

/* Every grid is a horizontal-scroll row by default (mobile, and always
   for chain — see .charm-builder__grid--scroll) — matches the Figma
   mobile frames, where all three sections scroll with "‹"/"›" buttons
   rather than wrapping. Plain scroll-snap, not the theme's carousel-
   slider component: these grids' contents are replaced wholesale by
   #renderGrid on every selection, and re-initializing a stateful
   carousel on every click is more fragile than it's worth here. */
.charm-builder__grid {
  display: flex;
  gap: 1.3rem;
  overflow-x: auto;
  scroll-snap-type: x proximity;
  scrollbar-width: none;
  /* `overflow-x: auto` with no explicit overflow-y forces the y-axis to
     also clip (per spec, a non-"visible" x forces y out of "visible"
     too) — without top padding, a hovered/focused card's
     translateY(-0.2rem) lift (.charm-builder__option-card, below) gets
     its top edge cut flat by that clip instead of lifting cleanly. */
  padding-block: 0.6rem 0.4rem;
}

.charm-builder__grid::-webkit-scrollbar {
  display: none;
}

.charm-builder__grid .charm-builder__option,
.charm-builder__grid .charm-builder__option-slot {
  flex: 0 0 13.4rem;
  scroll-snap-align: start;
}

/* Card button + the controls under it (a "−"/"+" picker for droplet/
   charm, Length swatches for a chain), stacked. A grid rather than a
   column flexbox: a stretched grid item's flex children won't grow into
   its height in Chrome, so the card button never filled the slot and the
   prices sat at different heights across a row. With the card row as
   `1fr`, every card in the row is the same height and its price sits at
   the bottom of it. */
.charm-builder__option-slot {
  display: grid;
  grid-template-rows: minmax(0, 1fr) auto;
  gap: 0.6rem;
  min-width: 0;
}

/* Droplet/charm: always reserve the picker's row (its height, even when
   the card isn't selected) so prices line up across selected and
   unselected cards alike. */
.charm-builder__grid:not(.charm-builder__grid--scroll) .charm-builder__option-slot {
  grid-template-rows: minmax(0, 1fr) minmax(2.6rem, auto);
}

/* Chain cards are wider than droplet/charm cards on desktop only. On
   mobile they take the same 13.4rem as the droplets: a 20.9rem chain card
   filled most of the phone's height, so the shopper was pushed a long way
   down the picker and lost sight of the preview up top (client feedback,
   2026-09-17: "make the boxes for choose your chain the same size as the
   charm ones so people don't get pushed too far down the page"). */
@media (min-width: 1024px) {
  .charm-builder__grid--scroll .charm-builder__option,
  .charm-builder__grid--scroll .charm-builder__option-slot {
    flex-basis: 20.9rem;
  }
}

/* Inside a slot the card button is a column-flex child: let it grow so
   every slot in a row is the same height, with the price (and the
   picker/swatches after it) pushed to the bottom regardless of how many
   lines the name takes. */
.charm-builder__option-slot .charm-builder__option {
  height: 100%;
}

.charm-builder__option-slot .charm-builder__option-info {
  flex: 1 1 auto;
}

.charm-builder__option-slot .charm-builder__option-price {
  margin-top: auto;
}

/* Length swatches under each chain card — one pill per variant of the
   active metal. Sold-out lengths stay visible but greyed and struck
   through so the customer can see what exists. */
.charm-builder__sizes {
  justify-self: start;
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-left: 0.5rem;
}

.charm-builder__size {
  background-color: #ffffff;
  border: 0.1rem solid #69001a;
  border-radius: 3.2rem;
  padding: 0.4rem 1rem;
  font-size: 1.1rem;
  font-weight: 700;
  line-height: 1.2;
  color: #69001a;
  cursor: pointer;
  white-space: nowrap;
}

.charm-builder__size:hover:not(:disabled),
.charm-builder__size:focus-visible {
  background-color: #efd3fc;
}

.charm-builder__size.is-active {
  background-color: #d7b8e2;
  border-color: #c9a4cd;
}

.charm-builder__size:disabled {
  opacity: 0.4;
  text-decoration: line-through;
  cursor: not-allowed;
  background-color: #f3eeee;
  border-color: #b9a3a8;
}

/* Droplet/charm switch to a wrapping multi-column grid at desktop (per
   Figma); chain (--scroll) stays a horizontal row at every width. */
@media (min-width: 1024px) {
  .charm-builder__grid:not(.charm-builder__grid--scroll) {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
    overflow: visible;
  }

  .charm-builder__grid:not(.charm-builder__grid--scroll) .charm-builder__option,
  .charm-builder__grid:not(.charm-builder__grid--scroll) .charm-builder__option-slot {
    flex: initial;
  }
}

/* "−  2  +" under a selected droplet/charm card. Same pill language as
   the Gold/Silver toggle above the grid. */
.charm-builder__qty {
  display: inline-flex;
  /* The slot is a grid, which would stretch this to the card's full
     width — keep it at its own size, left-aligned under the price. */
  justify-self: start;
  align-self: start;
  align-items: center;
  gap: 0;
  margin-left: 0.5rem;
  background-color: #ffffff;
  border: 0.1rem solid #69001a;
  border-radius: 3.2rem;
  padding: 0.1rem;
}

.charm-builder__qty-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.2rem;
  height: 2.2rem;
  border-radius: 50%;
  border: none;
  background: none;
  color: #69001a;
  font-size: 1.6rem;
  font-weight: 700;
  line-height: 1;
  padding: 0;
  cursor: pointer;
}

.charm-builder__qty-btn:hover:not(:disabled),
.charm-builder__qty-btn:focus-visible {
  background-color: #efd3fc;
}

.charm-builder__qty-btn:disabled {
  opacity: 0.35;
  cursor: not-allowed;
}

.charm-builder__qty-value {
  min-width: 1.8rem;
  text-align: center;
  font-size: 1.2rem;
  font-weight: 700;
  color: #69001a;
}

/* Per Figma (node 13240:10352 and its droplet/charm equivalents): the
   photo sits in its own white, maroon-bordered card, and the name/price
   live in a separate left-aligned block underneath it — not one bordered
   card wrapping everything, and not centered text (this project's
   earlier, pre-Figma design). */
.charm-builder__option {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.6rem;
  width: 100%;
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  text-align: left;
}

.charm-builder__option-card {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  aspect-ratio: 134 / 152;
  background-color: #ffffff;
  border: 0.1rem solid #69001a;
  border-radius: 2rem;
  padding: 1.2rem 1.6rem;
  overflow: hidden;
  transition: transform 0.2s ease-out;
}

.charm-builder__option:not(:disabled):hover .charm-builder__option-card,
.charm-builder__option:not(:disabled):focus-visible .charm-builder__option-card {
  transform: translateY(-0.2rem);
}

.charm-builder__option.is-selected .charm-builder__option-card {
  position: relative;
  border-width: 0.2rem;
}

/* Selected cards get a soft lilac wash over the photo (client: "a small
   purple overlay on the image of the selected items in theme with the
   site colours") — the brand lilac #efd3fc at partial opacity, so the
   piece still reads clearly underneath. Drawn as a pseudo-element over
   the card, inside its own overflow clip, so it follows the rounded
   corners and the chain images' scale transform can't push it about. */
.charm-builder__option.is-selected .charm-builder__option-card::after {
  content: "";
  position: absolute;
  inset: 0;
  background-color: rgb(239 211 252 / 45%);
  pointer-events: none;
}

/* Sold-out cards stay visible but cannot be selected or opened. */
.charm-builder__option[aria-disabled="true"] {
  opacity: 0.4;
  cursor: not-allowed;
}

.charm-builder__option-image {
  width: 100%;
  height: 100%;
  /* `contain`, not `cover`: the cutouts are square and the card is
     portrait, so `cover` cropped a strip off both sides of every chain
     (the loop of the Curator chain was cut off). The whole image now
     fits inside the card. */
  object-fit: contain;
  /* Chain cards get an inline `transform: scale()` from #renderCard
     (assets/charm-builder.js) to even out the cutouts' padding; the
     card's own overflow: hidden clips the excess. */
  transform-origin: center;
}

.charm-builder__option-info {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  padding-left: 0.5rem;
  width: 100%;
}

.charm-builder__option-label {
  font-weight: 700;
  font-size: 1.1rem;
  text-transform: uppercase;
  color: #69001a;
}

.charm-builder__option-price {
  font-weight: 700;
  font-size: 1.1rem;
  text-transform: uppercase;
  color: #69001a;
}

/* Chain cards only: the length line between name and price, since each
   length is its own card (see #renderGrid in assets/charm-builder.js). */
.charm-builder__option-meta {
  font-weight: 500;
  font-size: 1.1rem;
  text-transform: uppercase;
  color: #69001a;
  opacity: 0.8;
}

/* Keep the next step and running total visible throughout the builder.
   This is a sibling of the build panels so the mobile preview cannot
   push it below the viewport. Its normal flow space keeps the final
   choices reachable above the bar at the end of the scroll. */
.charm-builder__review-row {
  position: sticky;
  bottom: 0;
  z-index: 4;
  background-color: #faefe2;
  border: 0.1rem solid #69001a;
  padding: 1.6rem;
  padding-block-end: max(1.6rem, env(safe-area-inset-bottom));
  display: flex;
  justify-content: center;
}

/* Desktop: the bar belongs to the picker column only (user request), so
   it's pushed to the right half and takes no flow space — the panel gets
   matching bottom padding instead (below) so the last cards still clear
   it. Taking it out of flow is what lets the sticky preview on the left
   reach the very bottom of the dialog: as a full-width sibling it both
   covered the preview's bottom edge and, being in flow, pushed the
   preview up by its own height at the end of the scroll. */
@media (min-width: 1024px) {
  .charm-builder__review-row {
    --charm-builder-review-row-height: 7.6rem;
    box-sizing: border-box;
    height: var(--charm-builder-review-row-height);
    margin-block-start: calc(-1 * var(--charm-builder-review-row-height));
    margin-inline-start: 50%;
    width: 50%;
    border-inline-start: 0;
  }
}

.charm-builder__review-btn {
  /* Figma: 604x42, fully-pilled 32px radius, 14px bold uppercase label.
     Driven through the theme's own button custom properties (theme.css
     `.btn`) rather than by overriding height/border-radius directly, so
     .btn's internal padding/line-height maths stays consistent with every
     other button. `width: 100%` + a max-width is what lands exactly 604px
     at desktop while letting it shrink to the panel on narrow screens —
     .btn's `--button-width` is a fixed value, not a cap, so it can't do
     both. */
  width: 100%;
  max-width: 60.4rem;
  --button-height: 4.2rem;
  --button-corner-radius: 3.2rem;
  font-size: 1.4rem;
  font-weight: 700;
  text-transform: uppercase;
}

/* Running total on the Review button, separated from the label by a
   bar: "Review Your Design | $289.00". */
.charm-builder__review-btn-price::before {
  content: "|";
  margin-inline: 0.8rem;
  opacity: 0.6;
}

.charm-builder__review-btn[aria-disabled="true"] {
  opacity: 0.5;
  pointer-events: none;
}

/* Review Your Design dialog — per Figma desktop (node 13240:10015) and
   mobile (node 13227:36674). The two breakpoints are deliberately
   different layouts, not just a resize: desktop shows Necklace/Charms as
   two side-by-side columns with a standalone "Total Price" heading above
   small, right-aligned action buttons; mobile stacks Necklace above
   Charms (divided by a rule) and folds the total into the Add to Cart
   button's own label instead, with full-width buttons. */

.charm-builder__review {
  /* Figma's frame is 1190px wide with a 35px radius and a real maroon
     border — unlike the *build* dialog, which the client had squared off
     and pushed full-bleed, this one stays a centred, rounded card. */
  max-width: 119rem;
  width: 100%;
  /* Figma's 35px is measured on the desktop card; mobile renders this
     sheet edge-to-edge, where that much rounding reads as a bubble
     rather than a panel — so the full radius is desktop-only, below. */
  border-radius: 2rem;
  border: 0.1rem solid #69001a;
  padding: 0;
  color: #69001a;
  background-color: #fbf4ed;
  /* Header and footer stay put; only the item list scrolls. Without
     this the whole dialog scrolled as one, so with 4–5 charms selected
     the Total Price and Add to Cart button sat below the fold — the CTA
     was unreachable without scrolling past every card. `.dialog--modal`
     already caps height at calc(100dvh - 6.4rem), which is what gives
     the flex child below something to scroll within.
     `display` is scoped to [open] below, NOT set here: an author-origin
     `display` on a <dialog> beats the UA sheet's
     `dialog:not([open]) { display: none }` (author normal wins over UA
     normal regardless of specificity), so declaring it unconditionally
     laid the closed review dialog out in the page — it was visible
     mid-scroll on the PDP without anyone opening it. */
  flex-direction: column;
  overflow: hidden;
}

/* [open] survives the exit animation — dialog.js's closeDialog() adds
   .dialog-closing, awaits onAnimationEnd, and only then calls
   dialog.close() — so this alone keeps the dialog laid out for the
   scale-out and still collapses it the moment it's actually closed. */
.charm-builder__review[open] {
  display: flex;
}

.charm-builder__review-header {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 1.6rem;
  padding: 1.6rem 2rem;
  border-bottom: 0.1rem solid #69001a;
  flex-shrink: 0;
}

.charm-builder__review-back {
  justify-self: start;
  background: none;
  border: none;
  font-weight: 700;
  font-size: 1.6rem;
  cursor: pointer;
  color: #69001a;
}

.charm-builder__review-header .dialog__close {
  justify-self: end;
}

.charm-builder__review-heading {
  justify-self: center;
  margin: 0;
  text-align: center;
  font-family: var(--font-heading--family);
  font-weight: 700;
  font-size: 2.4rem;
  line-height: 1.1;
}

@media (min-width: 1024px) {
  .charm-builder__review {
    border-radius: 3.5rem;
  }

  .charm-builder__review-header {
    padding: 2.4rem 6rem;
  }

  .charm-builder__review-back {
    font-size: 2.4rem;
  }

  /* Figma sets 69px flat, but that's measured against its own fixed
     1190px frame — clamped here so it still fits when the dialog is
     narrower than that, reaching the full 6.9rem around 1400px+. */
  .charm-builder__review-heading {
    font-size: clamp(3.2rem, 4.8vw, 6.9rem);
  }
}

.charm-builder__review-body {
  padding: 2.4rem 2rem;
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
}

@media (min-width: 1024px) {
  .charm-builder__review-body {
    padding: 3.2rem 6rem;
  }
}

.charm-builder__review-columns {
  display: flex;
  flex-direction: column;
  gap: 2.4rem;
}

@media (min-width: 1024px) {
  .charm-builder__review-columns {
    flex-direction: row;
    align-items: flex-start;
    /* Gap between the necklace column and the charm grid. Figma's 207px
       was drawn for 2 charms; with 5 charm cards across (user request)
       the gap is kept modest so the cards stay a usable size. Must match
       the value used in .charm-builder__review-group--necklace's width. */
    gap: clamp(3.2rem, 4vw, 6rem);
  }
}

.charm-builder__review-group--necklace {
  padding-block-end: 2.4rem;
  border-block-end: 0.1rem solid #69001a;
}

@media (min-width: 1024px) {
  .charm-builder__review-group--necklace {
    /* Sized so the necklace card equals a charm card (user: "all the
       same size"): the row holds the necklace column, the column gap
       (.charm-builder__review-columns, clamp(3.2rem, 4vw, 6rem)), and
       five charm cards separated by four 1.6rem gaps — six equal cards
       once the gaps are taken out. */
    flex: 0 0 calc((100% - clamp(3.2rem, 4vw, 6rem) - 6.4rem) / 6);
    padding-block-end: 0;
    border-block-end: none;
  }

  .charm-builder__review-group--charms {
    flex: 1 1 auto;
    min-width: 0;
  }
}

.charm-builder__review-group {
  display: flex;
  flex-direction: column;
  gap: 2.2rem;
}

.charm-builder__review-group-header {
  display: flex;
  align-items: center;
  gap: 1rem;
}

.charm-builder__review-group-title {
  font-weight: 700;
  text-transform: uppercase;
  font-size: 1.4rem;
  white-space: nowrap;
}

.charm-builder__review-edit {
  background: none;
  border: none;
  text-decoration: underline;
  text-transform: uppercase;
  font-size: 1.4rem;
  cursor: pointer;
  color: #69001a;
}

/* Four cards per row on mobile, five at desktop (user request: smaller
   cards, a full build of 5 on one row), sized by the row rather than a
   fixed card width. The necklace list is the same grid so its single
   card is the same size as a charm card; at desktop it sits in its own
   narrow column (see .charm-builder__review-group--necklace) as one
   column. */
.charm-builder__review-items {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 1.6rem 1.2rem;
}

@media (min-width: 1024px) {
  .charm-builder__review-items {
    grid-template-columns: repeat(5, minmax(0, 1fr));
  }

  .charm-builder__review-group--necklace .charm-builder__review-items {
    grid-template-columns: minmax(0, 1fr);
  }
}

@media (min-width: 1024px) {
  /* Figma spaces the charm cards 42px apart. Row gap stays tighter —
     that spacing is for cards sitting side by side, and 4+ charms wrap
     to a second row where 42px of vertical air just looks disconnected
     from the heading above it. */
  .charm-builder__review-items {
    gap: 2rem 1.6rem;
  }
}

/* Review cards reuse the same white/maroon-border/rounded treatment as
   the picker's own option cards (assets/charm-builder.css, .charm-
   builder__option-card), just larger per Figma (~21rem vs the picker's
   13.4–20.9rem). */
.charm-builder__review-item {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.8rem;
  width: auto;
  min-width: 0;
}

.charm-builder__review-item-card {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  aspect-ratio: 209 / 236;
  background-color: #ffffff;
  border: 0.1rem solid #69001a;
  border-radius: 1.4rem;
  padding: 1.2rem 1.6rem;
  overflow: hidden;
}

.charm-builder__review-item-image {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Charm/droplet pictures on the review screen read too large next to
   the necklace (client: "reduce by 30%, mobile and desktop") — the card
   stays the same size, the picture inside it is 70% of it, so the card
   keeps more white space around each charm. No media query: the same
   percentage applies at every width. The necklace card is untouched. */
[ref="reviewExtraItems"] .charm-builder__review-item-image {
  width: 70%;
  height: 70%;
}

.charm-builder__review-item-info {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  padding-left: 0.3rem;
  min-width: 0;
}

.charm-builder__review-item-name,
.charm-builder__review-item-meta,
.charm-builder__review-item-price {
  font-weight: 700;
  font-size: 1.1rem;
  line-height: 1.15;
  text-transform: uppercase;
  color: #69001a;
}

.charm-builder__review-footer {
  padding: 2.4rem 2rem;
  border-block-start: 0.1rem solid #69001a;
  display: flex;
  flex-direction: column;
  gap: 1.8rem;
  flex-shrink: 0;
}

@media (min-width: 1024px) {
  .charm-builder__review-footer {
    padding: 3.2rem 6rem 5.2rem;
  }
}

/* Desktop-only "Total Price" heading — hidden at mobile, where the same
   total instead appears inside the Add to Cart button's own label. */
.charm-builder__review-total {
  display: none;
}

@media (min-width: 1024px) {
  .charm-builder__review-total {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1.6rem;
    font-family: var(--font-heading--family);
    font-weight: 700;
    /* Same scale as the dialog heading per Figma — both are the 69px
       display face, and they should read as a matched pair. */
    font-size: clamp(3.2rem, 4.8vw, 6.9rem);
    line-height: 1.15;
  }
}

.charm-builder__review-actions {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.2rem;
}

@media (min-width: 1024px) {
  /* Figma stacks Add to Cart and Restart flush (two 42px rows, no gap
     between them), right-aligned, both the same 352px width. */
  .charm-builder__review-actions {
    align-items: flex-end;
    gap: 0;
  }
}

.charm-builder__add-to-cart-btn {
  width: 100%;
  height: 4.2rem;
  border-radius: 3.2rem;
  /* Figma labels this "ADD TO CART"; the theme's own .btn otherwise
     renders it title-cased ("Add To Cart"). */
  text-transform: uppercase;
}

@media (min-width: 1024px) {
  .charm-builder__add-to-cart-btn {
    width: 35.2rem;
    max-width: 100%;
  }

  /* The total already has its own heading at desktop — don't repeat it
     inside the button label too. */
  .charm-builder__add-to-cart-price {
    display: none;
  }
}

.charm-builder__restart-link {
  background: none;
  border: none;
  text-decoration: underline;
  font-weight: 700;
  text-transform: uppercase;
  font-size: 1.4rem;
  cursor: pointer;
  color: #69001a;
}

@media (min-width: 1024px) {
  /* Matches the Add to Cart button's own footprint so the two read as
     one stacked control, per Figma (both 352.12px, text centred). */
  .charm-builder__restart-link {
    width: 35.2rem;
    max-width: 100%;
    height: 4.2rem;
    text-align: center;
  }
}
