/*
 * What: Every structural rule the CPQ elements need, for all six of them.
 * Why:  ONE stylesheet, not one per element. This file is enqueued by every element's
 *       dependencies(), so it is present whatever the author placed; a per-element `default.css`
 *       only ships when that element is on the page, which left a page carrying a Price but no Slot
 *       with no rules at all. It had also already drifted: this file and BssCpqSlot/default.css both
 *       defined `.bss-cpq-option`, both loaded on the same page, and only one of them had been kept
 *       up to date. Every element's `defaultCss()` now returns '' and this is the single source.
 * How:  Structure and state only — no colour, type scale or breakpoints. Those belong to the
 *       Breakdance theme, so a configurator inherits the site's look instead of imposing its own.
 *       The few visual declarations here are all INHERITING ones (currentColor, transparent,
 *       em-relative sizes): they make a button read as a button without deciding anything the theme
 *       has an opinion about.
 *
 *       BUSINESS RULE: every rule here is written at ONE class of specificity lower than the Design
 *       panel's output, which Breakdance scopes as `%%SELECTOR%% .bss-cpq-...`. That is what lets
 *       css.twig override any of this without !important. Adding a rule here more specific than its
 *       css.twig counterpart would produce a design control that visibly does nothing.
 */

/* ---- configurator root ---- */

/*
 * `.bss-cpq-root`, matching BssCpqConfigurator::className().
 *
 * This rule was written as `.bss-cpq` and therefore matched nothing at all: the wrapper Breakdance
 * emits carries `bss-cpq-root`, so the configurator had no layout of its own and its controls
 * stacked as plain blocks. A `.bss-cpq--unconfigured` rule sat beside it, for a class nothing has
 * ever set; that one is gone rather than renamed.
 */
.bss-cpq-root {
  display: flex;
  flex-direction: column;
  gap: var(--bss-cpq-gap, 1.5rem);
}

/* ---- slot group ---- */

/*
 * `.bss-cpq-group`, matching BssCpqGroup::className(). A card wrapping several slots that share one
 * requirement — "Storage: select at least one" across an NVMe bay and a SATA bay.
 */
.bss-cpq-group {
  display: flex;
  flex-direction: column;
  gap: var(--bss-cpq-gap, 1.5rem);
}

.bss-cpq-group__header {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
}

/*
 * Both strings are optional, and the header renders whether or not they are set so that css.twig
 * and the runtime always have the same nodes to address. Empty ones collapse instead of leaving a
 * gap the author cannot see the cause of.
 */
.bss-cpq-group__heading:empty,
.bss-cpq-group__requirement:empty {
  display: none;
}

.bss-cpq-group__requirement {
  font-size: 0.875em;
  opacity: 0.75;
}

/* ---- dynamic slots ---- */

/*
 * `.bss-cpq-dynamic-slots`, matching BssCpqDynamicSlots::className(). One block renders every slot
 * a profile has, each as a sibling `[data-bss-cpq-control='slot']`, so — unlike a hand-placed
 * BssCpqSlot, which the author drops into whatever layout already surrounds it — this wrapper needs
 * a sensible arrangement of its OWN by default, or an untouched instance is N slots in plain block
 * flow with no space between them (BUSINESS RULE: an untouched Design panel must still render
 * something reasonable — see this file's own header note).
 *
 * `flex-direction: column` rather than a grid: a form that reads top to bottom is the safe default
 * for slots of very different shapes (a chassis picker beside a memory dropdown), and it is what
 * every existing hand-built page already looks like. css.twig's own Layout section turns this into
 * a real grid the moment an author asks for columns — see its own note on why `gap` needs a
 * flex/grid container present here already, unlike `.bss-cpq-slot__options--cards` below, which the
 * Layout section can lean on because ITS default is already a grid.
 */
.bss-cpq-dynamic-slots {
  display: flex;
  flex-direction: column;
  gap: var(--bss-cpq-gap, 1.5rem);
}

/*
 * `.bss-cpq-dynamic-slots__grid` — Phase 3, per-profile layout — wraps every slot, ONE level inside
 * `.bss-cpq-dynamic-slots` above. `display: contents` by default is what makes it invisible to the
 * box model: with no layout preset resolved for this profile, the slot divs stay direct children of
 * `.bss-cpq-dynamic-slots` exactly as before this wrapper existed, so the element's own instance-level
 * "Slots per row"/"Gap" Design controls (targeting THAT outer node, which ssr.php cannot itself add a
 * class to — Breakdance emits it) keep working completely unchanged.
 *
 * A resolved layout preset is compiled from THIS SAME element's own css.twig with its selector forced
 * to `.bde-preset-{id}` (Breakdance's own Design Preset mechanism), so its `display: grid` rule always
 * wins the cascade here on specificity alone (`.breakdance .bde-preset-{id}` beats a bare one-class
 * selector) — never a stylesheet-order race. The moment one is stamped on this wrapper, IT becomes the
 * real grid container, and the outer node's own per_row/gap becomes a harmless 1-child no-op.
 */
.bss-cpq-dynamic-slots__grid {
  display: contents;
}

/* ---- slot picker ---- */

.bss-cpq-slot__header {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  margin-bottom: 0.5rem;
}

/*
 * The label cascade: a group decides for the slots inside it, and a slot may override.
 *
 * BUSINESS RULE: resolved HERE, in CSS, and never in PHP. Breakdance hands ssr.php a
 * `$parentPropertiesData`, but that is the IMMEDIATE parent — put a Breakdance container between
 * the card and its slots and a PHP-resolved cascade silently stops applying. A descendant selector
 * does not care how deep the slots sit.
 *
 * BUSINESS RULE: `display: none` on the header only. The slot's label is also the `aria-label` of
 * its radiogroup or select, written by render.php and controls.ts, so hiding the header costs
 * nothing in the accessibility tree — the control keeps its accessible name.
 *
 * The slot's own attribute is absent unless the author chose Show or Hide explicitly (see
 * BssCpqSlot::attributes()), so `inherit` genuinely defers rather than winning on specificity.
 */
[data-bss-slot-labels='hide'] .bss-cpq-slot__header {
  display: none;
}

[data-bss-slot-labels='hide'] [data-bss-label='show'] .bss-cpq-slot__header {
  display: flex;
}

[data-bss-label='hide'] .bss-cpq-slot__header {
  display: none;
}

.bss-cpq-slot__required {
  font-size: 0.75em;
  opacity: 0.7;
}

/*
 * The author's own control.
 *
 * BUSINESS RULE: the CONTAINER is ours and the item is theirs, so this styles only the pool. The
 * same auto-fit grid as cards, because a template still has to sit in a row that reflows — and
 * because an author who wants a different arrangement has the Slot element's Design panel, which
 * is a better place to decide it than a default nobody chose.
 *
 * Nothing here reaches inside `.bss-cpq-option`. A rule that did would style markup this plugin
 * did not write, and would fight the author's own on every page that used it.
 */
.bss-cpq-slot__options--template {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 14rem), 1fr));
  gap: 0.5rem;
}

.bss-cpq-slot__options--cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 14rem), 1fr));
  gap: 0.5rem;
}

/*
 * A slot offering one thing you may decline, as a switch.
 *
 * The track and the knob are pseudo-elements on the option itself, so the markup is the same option
 * wrapper every other control renders — only the role differs. `data-selected` is the same
 * attribute the cards and the chips are styled by, which is what keeps one state contract across
 * every control (foundation rule 4).
 */
.bss-cpq-slot__options--toggle .bss-cpq-option {
  /*
   * The knob is absolutely positioned, so the option has to be its containing block. Without this
   * the knob resolves against the initial containing block and lands somewhere near the top-left of
   * the page — a bug that looks like the switch simply not rendering.
   */
  position: relative;
  flex-direction: row;
  align-items: center;
  gap: 0.6rem;
  border: 0;
  padding: 0.35rem 0;
}

.bss-cpq-slot__options--toggle .bss-cpq-option::before {
  content: '';
  flex: none;
  width: 2.2rem;
  height: 1.2rem;
  border: 1px solid currentColor;
  border-radius: 1rem;
  opacity: 0.5;
  transition: opacity 0.15s ease;
}

.bss-cpq-slot__options--toggle .bss-cpq-option::after {
  content: '';
  position: absolute;
  width: 0.8rem;
  height: 0.8rem;
  margin-left: 0.2rem;
  border-radius: 50%;
  background: currentColor;
  transition: transform 0.15s ease;
}

.bss-cpq-slot__options--toggle .bss-cpq-option[data-selected='true'] {
  /* The outline every other control uses to mean "chosen" would draw a box round a switch. */
  outline: none;
}

.bss-cpq-slot__options--toggle .bss-cpq-option[data-selected='true']::before {
  opacity: 1;
}

.bss-cpq-slot__options--toggle .bss-cpq-option[data-selected='true']::after {
  transform: translateX(1rem);
}

.bss-cpq-slot__options--toggle .bss-cpq-option__price {
  margin-left: auto;
}

/*
 * The control that opens a capped pool.
 *
 * A plain button that reads as a link, sitting under the options rather than among them — it is a
 * sibling of the radiogroup, never a member of it. Hidden entirely when nothing is capped, which
 * the runtime decides after every evaluation: a rule that rules three options out can leave a pool
 * inside its own cap, and a button offering to reveal nothing is worse than no button.
 */
.bss-cpq-slot__more {
  align-self: flex-start;
  margin-top: 0.5rem;
  padding: 0.25rem 0;
  border: 0;
  background: none;
  font: inherit;
  color: inherit;
  text-decoration: underline;
  cursor: pointer;
}

/*
 * Text swatches: the same option markup as cards, laid out as a wrapping strip of chips.
 *
 * BUSINESS RULE: a swatch shows less because of the two rules below, NOT because a second renderer
 * writes shorter markup. `render_option_list()` and `buildList()` emit one thing; the spec line
 * stays in the DOM and in the accessibility tree, and only its box is taken away. That is what
 * makes 'show the spec line on swatches' a future toggle rather than a renderer change.
 *
 * Specificity is deliberate: `.bss-cpq-slot__options--text-swatches .bss-cpq-option` is (0,2,0),
 * the same as the Design panel's `%%SELECTOR%% .bss-cpq-option`, and the panel's CSS loads after
 * this file — so an author who sets padding or a border on options wins, which is the way round it
 * must be. Raising these to (0,3,0) would silently make the swatch defaults unoverridable.
 */
.bss-cpq-slot__options--text-swatches {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
}

.bss-cpq-slot__options--text-swatches .bss-cpq-option {
  flex-direction: row;
  align-items: baseline;
  gap: 0.35rem;
  padding: 0.35rem 0.6rem;
  text-align: center;
}

/*
 * BUSINESS RULE: clipped, never `display: none`.
 *
 * A chip has no room for "DDR4-2400 · 1 × 16GB", but that is a LAYOUT decision, not a decision that
 * the detail does not matter — and `display: none` takes the text out of the accessibility tree
 * with it, so a screen-reader user loses the one thing the chip could not show. This is the
 * standard visually-hidden box: present, measured at a pixel, clipped away.
 *
 * An earlier version of this rule used `display: none` while the comment beside it claimed a screen
 * reader still read the text. It did not.
 */
.bss-cpq-slot__options--text-swatches .bss-cpq-option__spec {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/*
 * Image swatches: a wrapping strip of pictures, each with its label beneath it.
 *
 * BUSINESS RULE: the same option markup as cards, exactly as text swatches are. The picture is one
 * extra node that `option_contents()` writes for the controls the registry marks `shows_image`, and
 * everything below is layout. There is no image-specific renderer, and there must not be one.
 *
 * The spec line is clipped rather than removed, for the reason the text-swatch block gives at
 * length: `display: none` would take it out of the accessibility tree, and a screen-reader user
 * choosing between pictures has nothing else to go on.
 *
 * Specificity is deliberate and matches the text-swatch block: (0,2,0), the same as the Design
 * panel's `%%SELECTOR%% .bss-cpq-option`, whose CSS loads after this file — so an author's settings
 * win, which is the way round it must be.
 */
.bss-cpq-slot__options--image-swatches {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.bss-cpq-slot__options--image-swatches .bss-cpq-option {
  align-items: center;
  gap: 0.3rem;
  padding: 0.4rem;
  text-align: center;
}

.bss-cpq-slot__options--image-swatches .bss-cpq-option__spec {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/*
 * Image cards: a picture above everything a choice card already shows.
 *
 * A grid rather than a strip, and the same auto-fit floor `--cards` uses, so the two arrange
 * identically and the Layout section means one thing across both.
 */
.bss-cpq-slot__options--image-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 12rem), 1fr));
  gap: 0.6rem;
}

/*
 * The picture itself.
 *
 * `object-fit: cover` with a fixed height is what makes a pool of photographs shot at different
 * sizes read as one row of tiles. `width: 100%` fills whatever the layout gave the option — the
 * width is the Layout section's business, and a picture that set its own would fight it.
 *
 * The `width`/`height` ATTRIBUTES on the element are a 1:1 aspect ratio, not a size: they exist so
 * the browser reserves a box before the file arrives. These two lines are what actually size it,
 * and they override the attributes exactly as they are meant to.
 */
/*
 * The positioning context the hover picture is stacked against.
 *
 * Deliberately its own element rather than `.bss-cpq-option`: the option's padding is the author's,
 * set in the Breakdance Design panel, so a hover image positioned against the option would sit
 * correctly only while that padding is what it happens to be today. The wrapper hugs the picture,
 * so it is right whatever the author does. It is emitted for every option a picture control renders,
 * with or without a hover image, so the markup does not change shape as the mirror fills in.
 */
.bss-cpq-option__media {
  position: relative;
  display: block;
  width: 100%;
  /* Same reason as the picture below: the option wrapper is a flex column. */
  flex-shrink: 0;
}

.bss-cpq-option__image {
  display: block;
  width: 100%;
  height: 7rem;
  object-fit: cover;
  /*
   * A picture inside a flex column would otherwise be squashed to fit rather than keeping the
   * height set above — `flex-shrink` defaults to 1, and the option wrapper is a flex column.
   */
  flex-shrink: 0;
}

/*
 * The hover picture sits exactly over the primary and is revealed, never inserted — laying it out
 * in flow and toggling `display` would reflow the option under the customer's cursor.
 *
 * `opacity` rather than `visibility` or `display: none` on purpose: the element is in the layout
 * from the start, so the file is fetched and decoded before the pointer arrives rather than at the
 * moment of the swap, which is what makes the change read as instant.
 */
.bss-cpq-option__image--hover {
  position: absolute;
  inset: 0;
  opacity: 0;
}

/*
 * BUSINESS RULE: hover only where hover exists.
 *
 * A touch device reports `:hover` on tap and then STAYS in that state until the customer taps
 * something else, so without this guard the second picture would appear on selection and stick
 * there — a state with no way out on the device where most of these pages are read. `(hover: hover)`
 * is the only thing that distinguishes a real pointer; a width breakpoint would get tablets wrong
 * in both directions.
 *
 * No transition: the swap is a change of picture, not a motion, and an instant one needs no
 * `prefers-reduced-motion` branch to be correct for everybody.
 */
@media (hover: hover) {
  .bss-cpq-option:hover .bss-cpq-option__image--hover {
    opacity: 1;
  }
}

.bss-cpq-option {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.15rem;
  padding: 0.75rem;
  border: 1px solid currentColor;
  background: transparent;
  cursor: pointer;
  text-align: left;
  font: inherit;
  color: inherit;
  /*
   * A grid or flex item's minimum width defaults to its content's, so a long unbroken option name
   * ("Intel® Core™ i3-6100T") forced the card wider than its column and ran into the next card at
   * 375 px (trial 2.12). min-width: 0 lets the card take the column it was given.
   */
  min-width: 0;
  box-sizing: border-box;
}

/*
 * The name wraps, anywhere if it must, and stops at two lines. The clamp is visual only: the full
 * name stays in the markup, so screen readers and the order still carry all of it.
 */
.bss-cpq-option__label {
  max-width: 100%;
  overflow-wrap: anywhere;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
}

.bss-cpq-option[data-selected='true'] {
  outline: 2px solid currentColor;
  outline-offset: -2px;
}

/* Deprioritised by a rule, still selectable — visually distinct from out of stock, which is not a
   rule outcome at all. */
.bss-cpq-option[data-greyed-out='true'] {
  opacity: 0.55;
}

/* Ruled out by the current selection. The node stays in the DOM — the runtime re-states it rather
   than rebuilding the pool (Step 4), and the server rendered it before any rule had been evaluated.
   Hidden by default because that is what the customer saw before; the "Ruled out" design panel can
   put it back on screen. */
.bss-cpq-option[data-unavailable] {
  display: none;
}

/*
 * A pool laid out as one row the customer scrolls, instead of one that wraps.
 *
 * BUSINESS RULE: this block sits AFTER `--cards` and `--text-swatches` on purpose. All three are
 * one class, so nothing but source order decides which `display` wins, and a scroller declared
 * above the grid it has to beat is a setting that silently does nothing.
 *
 * `flex-direction: row` is not redundant either: it undoes a "Stacked" arrangement left over on a
 * slot whose author later switched to side-scrolling, which would otherwise stack the options
 * inside a horizontal scroller and show exactly one of them.
 */
.bss-cpq-slot__options--scroll {
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  overflow-x: auto;
  /*
   * Without this, scrolling past the end of the strip is handed to the page, and on a touchpad
   * that is the browser's back gesture — the customer loses the configuration they were building
   * by swiping one option too far.
   */
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  /*
   * Arrow clicks and `scrollIntoView()` both animate from here rather than from a `behavior`
   * argument, so the preference below actually turns them off. A JavaScript `behavior: 'smooth'`
   * overrides a reduced-motion setting instead of respecting it.
   */
  scroll-behavior: smooth;
  /* A scroll container clips its children, and the focus ring is drawn outside the option. */
  padding-block: 2px;
}

@media (prefers-reduced-motion: reduce) {
  .bss-cpq-slot__options--scroll {
    scroll-behavior: auto;
  }
}

.bss-cpq-slot__options--scroll .bss-cpq-option {
  /* Its own width, never a share of the row: a flex child's default is to shrink to fit. */
  flex: 0 0 auto;
  scroll-snap-align: start;
}

.bss-cpq-slot__scroller {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 0.25rem;
}

/*
 * The arrows flank the strip rather than floating over it. An overlay would cover the first and
 * last option — the two the customer is most likely to be reading — and would need a background to
 * stay legible over them, which is a second thing for an author to style into agreement.
 *
 * `min-width: 0` on the strip is what makes the flex row work at all: a flex child's default
 * minimum is its content, so an unconstrained strip grows to the full width of its options and
 * pushes the end arrow off the page instead of scrolling.
 */
.bss-cpq-slot__scroller .bss-cpq-slot__options--scroll {
  flex: 1 1 auto;
  min-width: 0;
}

.bss-cpq-slot__scroll {
  flex: none;
  padding: 0.25rem 0.4rem;
  border: 0;
  background: none;
  font: inherit;
  color: inherit;
  line-height: 1;
  cursor: pointer;
}

/*
 * The glyph, in one place. Written as a pseudo-element rather than a text node so neither runtime
 * carries a copy of it and no translation layer can rewrite an arrow into a word.
 */
.bss-cpq-slot__scroll--start::before {
  content: '\2039';
}

.bss-cpq-slot__scroll--end::before {
  content: '\203A';
}

.bss-cpq-slot__scroll[disabled] {
  opacity: 0.35;
  cursor: default;
}

/*
 * A pool too long to browse: a field, and a popup listing what matches.
 *
 * The popup is positioned against this container, so it has to be the containing block. Without
 * `position: relative` the list resolves against the page and lands somewhere near the top-left,
 * which looks like the control failing to render rather than a positioning bug.
 */
.bss-cpq-slot__options--combobox {
  position: relative;
  display: block;
}

.bss-cpq-combobox__input {
  width: 100%;
  padding: 0.4rem 0.6rem;
  border: 1px solid currentColor;
  border-radius: 2px;
  background: transparent;
  font: inherit;
  color: inherit;
}

/*
 * BUSINESS RULE: the one place this stylesheet sets a background it was not asked to.
 *
 * Everywhere else an unset colour is left to the theme, because imposing one is the failure mode
 * the whole Breakdance-first approach exists to avoid. A popup is the exception: it floats over
 * page content, and a transparent one renders the options and whatever is beneath them in the same
 * space. That is not a style the author chose, it is text that cannot be read — and the Design
 * panel can still override it, because `%%SELECTOR%% .bss-cpq-combobox__list` outranks this.
 *
 * `Canvas` is the system colour that follows the reader's own light or dark preference; the plain
 * white before it is what a browser too old to know the keyword falls back to.
 */
.bss-cpq-combobox__list {
  position: absolute;
  z-index: 20;
  right: 0;
  left: 0;
  max-height: 18rem;
  overflow-y: auto;
  /* Reaching the end of the popup must not start scrolling the page behind it. */
  overscroll-behavior-y: contain;
  border: 1px solid currentColor;
  background: #fff;
  background: Canvas;
  color: CanvasText;
}

.bss-cpq-combobox__list .bss-cpq-option {
  border: 0;
  border-radius: 0;
  cursor: pointer;
}

/*
 * The row the keyboard is on, which is NOT the row that is chosen — the customer arrows through
 * the results without committing to any of them, and a list that showed only the selection would
 * leave arrow keys doing nothing visible at all.
 *
 * `data-selected` keeps the outline every other control uses; this is a fill behind it, so a row
 * that is both reads as both.
 */
.bss-cpq-combobox__list .bss-cpq-option[data-bss-active],
.bss-cpq-combobox__clear[data-bss-active] {
  background: color-mix(in srgb, currentColor 12%, transparent);
}

.bss-cpq-combobox__clear {
  display: block;
  padding: 0.4rem 0.6rem;
  cursor: pointer;
  opacity: 0.75;
}

.bss-cpq-combobox__empty {
  margin: 0;
  padding: 0.4rem 0.6rem;
  opacity: 0.75;
}

/*
 * BUSINESS RULE: `!important` here, and only here.
 *
 * The runtime uses the native `hidden` attribute to close a group in the two-step picker and to put
 * away the option list while a slot is blocked. `hidden` is `display: none` in the USER-AGENT
 * stylesheet, which any author-origin `display` rule outranks — including our own
 * `.bss-cpq-option { display: flex }` and anything the Design panel emits. Without this, a closed
 * group renders every one of its members.
 */
/*
 * The explicit way to say no.
 *
 * Almost nothing here on purpose: it IS an option wrapper, so it takes the author's option styling
 * and the selected outline along with every other choice in the set — which is the point of it
 * being one. Only the two-step picker needs a rule at all, because its decline sits above the tabs
 * rather than inside a list that already has spacing.
 */
.bss-cpq-tree__decline {
  margin-bottom: 0.5rem;
}

/*
 * What a shared link could not rebuild. Deliberately plain: it is a sentence, and the Configurator
 * element's Design panel is where an author decides what it looks like.
 */
.bss-cpq-restore {
  display: block;
  margin: 0 0 0.75rem;
  padding: 0.5rem 0.75rem;
}

.bss-cpq-option[hidden],
.bss-cpq-restore[hidden],
.bss-cpq-combobox__clear[hidden],
.bss-cpq-combobox__list[hidden],
.bss-cpq-combobox__empty[hidden],
.bss-cpq-tree__group[hidden],
.bss-cpq-slot__scroll[hidden],
/* The wrapper, not the list: hiding the list alone leaves two arrows over the explanation. */
.bss-cpq-slot__scroller[hidden],
.bss-cpq-slot__options[hidden] {
  display: none !important;
}

.bss-cpq-option[data-out-of-stock='true'] {
  opacity: 0.45;
  cursor: not-allowed;
}

.bss-cpq-option__spec {
  font-size: 0.85em;
  opacity: 0.75;
}

.bss-cpq-option__price {
  font-variant-numeric: tabular-nums;
}

.bss-cpq-option__badge {
  font-size: 0.7em;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.bss-cpq-tree__groups {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin-bottom: 0.6rem;
}

.bss-cpq-tree__group {
  padding: 0.4rem 0.8rem;
  border: 1px solid currentColor;
  background: transparent;
  cursor: pointer;
  font: inherit;
  color: inherit;
}

.bss-cpq-tree__group[data-selected='true'] {
  outline: 2px solid currentColor;
  outline-offset: -2px;
}

.bss-cpq-tree__members {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 14rem), 1fr));
  gap: 0.5rem;
}

.bss-cpq-slot__note {
  font-size: 0.9em;
  opacity: 0.8;
  margin: 0.35rem 0 0;
}

.bss-cpq-select {
  width: 100%;
  font: inherit;
  color: inherit;
  padding: 0.5rem;
}

/* ---- summary ---- */

.bss-cpq-summary {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.25rem 1rem;
  margin: 0;
}

.bss-cpq-summary__slot {
  opacity: 0.7;
}

.bss-cpq-summary__value {
  margin: 0;
}

/* ---- price ---- */

.bss-cpq-price__amount {
  font-variant-numeric: tabular-nums;
}

/* ---- validation notice ---- */

.bss-cpq-notice__list {
  margin: 0;
  padding-left: 1.1rem;
}

.bss-cpq-notice__item {
  margin: 0;
}

/*
 * A ready build should not shout at the customer; an invalid one should.
 *
 * Scoped to the notice element on purpose: `data-bss-state` is a generic-looking attribute and an
 * unscoped `[data-bss-state='ready']` would hide anything on the page that happened to carry it.
 */
.bss-cpq-notice[data-bss-state='ready'] {
  display: none;
}

/* ---- presets ---- */

.bss-cpq-presets__row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

/*
 * Structural only. Colour, radius and typography are the author's, set on the element — this file
 * ships the geometry every storefront needs and none of the taste any one of them wants.
 */
.bss-cpq-preset {
  display: inline-flex;
  align-items: baseline;
  gap: 0.375rem;
  cursor: pointer;
}

/*
 * The chip the build currently sits on. An attribute rather than a class because the runtime writes
 * it as data — the same way a slot option carries `data-selected` — so one convention covers both.
 */
.bss-cpq-preset[data-bss-active='true'] {
  font-weight: 600;
}

.bss-cpq-preset__state {
  font-size: 0.8em;
  opacity: 0.75;
}

.bss-cpq-presets__reason {
  margin: 0.5rem 0 0;
}

/* ---- comparison table ---- */

/*
 * The table scrolls sideways inside its own container rather than widening the page. Four columns
 * of specifications do not fit a phone, and a page that scrolls horizontally as a whole is broken
 * everywhere else on it, not just here.
 */
.bss-cpq-compare {
  overflow-x: auto;
}

.bss-cpq-compare__table {
  border-collapse: collapse;
  width: 100%;
}

.bss-cpq-compare__head,
.bss-cpq-compare__cell,
.bss-cpq-compare__rowhead {
  text-align: left;
  vertical-align: top;
}

.bss-cpq-compare__take {
  cursor: pointer;
}

/*
 * Structural only. Which column looks chosen, and what a hero column looks like, are the author's
 * — this file ships the geometry every storefront needs and none of the taste any one wants.
 */
.bss-cpq-compare__tagline,
.bss-cpq-compare__reason {
  margin: 0.25rem 0 0;
}

.bss-cpq-compare__select {
  max-width: 100%;
}

/*
 * A column is a header PANEL, its cells and a footer PANEL. The panel stacks whichever parts the
 * author put in it; which parts those are is theirs, the order within one is not.
 *
 * flex-start rather than the default stretch: a badge is a pill, not a full-width bar, and a title
 * that stretched would take its background the whole width of the column. A part that WANTS the
 * full width says so through the Design tab.
 */
.bss-cpq-compare__panel {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}

.bss-cpq-compare__foot {
  text-align: left;
  vertical-align: top;
}

/*
 * The delta sits under the value rather than beside it: option labels run long enough to wrap, and
 * a figure that wrapped with them would end up on a line of its own anyway, unpredictably.
 */
.bss-cpq-compare__delta {
  display: block;
}
