/*
 * Custom "dimensions" question type — width / height / quantity inputs in a row.
 *
 * Pixel-matched to the client's live configurator (efkarahmen.de) "Größe und
 * Menge" step: each field is a number input with a gray unit-suffix box (mm / mm
 * / Stk.), bold labels, EFKA gray palette. Scoped entirely to .cb-dimensions so
 * it never leaks into other question types.
 *
 * Intentionally sets NO font-family — the EFKA theme (Poppins) is installed
 * separately and is inherited naturally once active. Colors/radii/spacing are
 * the values extracted from the reference design's computed styles.
 */

/* Row of the three fields. Wraps to a stack on narrow viewports.
   Capped, and left-aligned rather than justified: since the configurator moved into the
   full-width band on the product page, `flex: 1 1 0` stretched each field to ~430 px — three
   enormous boxes for a four-digit number, with the unit suffix marooned at the far right. */
.cb-dimensions .cb-dimensions-inputs {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-start;
    gap: 1.25rem;
    max-width: 44rem;
}

.cb-dimensions .cb-dimensions-field {
    /* Grow only up to a sane width for a number; keep wrapping on narrow screens. */
    flex: 0 1 13rem;
    min-width: 7rem;
    max-width: 15rem;
}

/* Input + unit suffix sit flush as a single control. The template wraps them in
   a Bootstrap .input-group; we override only within .cb-dimensions. */
.cb-dimensions .input-group {
    display: flex;
    width: 100%;
    flex-wrap: nowrap;
}

/* FLOATING LABELS (2026-08-25). The label lives INSIDE the input: .cb-dimensions-control is the
   ~2/3 share of the control and the positioning context; the label is absolutely positioned
   over the input's padding (the one place absolute positioning is the right tool) and floats
   up, smaller, on focus or once there is a value. `:not(:placeholder-shown)` with the
   template's BLANK placeholder is what tells "filled" from "empty" without a line of JS. */
.cb-dimensions .cb-dimensions-control {
    position: relative;
    flex: 1 1 66.666%;
    min-width: 0;
}

.cb-dimensions .cb-dimensions-control > label {
    position: absolute;
    top: 0;
    left: 0;
    height: 100%;
    max-width: 100%;
    margin: 0;
    padding: 1rem 12px;
    overflow: hidden;
    color: #6b6b6b;
    font-weight: 600;
    line-height: 1.25;
    white-space: nowrap;
    text-overflow: ellipsis;
    pointer-events: none;
    transform-origin: 0 0;
    transition: transform .1s ease-in-out, color .1s ease-in-out;
}

/* Floated: scaled to 78% from the top-left corner, so its LAYOUT width may be 1/.78 of the
   control before the scale brings it back to 100% — without that, "Maximum width" was
   ellipsised at "Maximum wi…" in the narrower division columns. */
.cb-dimensions .cb-dimensions-input:focus ~ label,
.cb-dimensions .cb-dimensions-input:not(:placeholder-shown) ~ label {
    transform: scale(.78) translateY(-.6rem);
    max-width: calc(100% / .78);
    color: #262626;
}

/* The number input: fills its control, tall enough to hold the floated label above the value,
   left-rounded only, gray border, no right border so it butts against the suffix box. */
.cb-dimensions .cb-dimensions-input,
.cb-dimensions .input-group .cb-dimensions-input.form-control {
    display: block;
    width: 100%;
    min-width: 0;
    height: 3.25rem;
    padding: 1.5rem 12px .5rem;
    color: #262626;
    background-color: #fff;
    border: 1px solid #cccccc;
    border-right: 0;
    border-radius: 4px 0 0 4px;
    line-height: 1.25;
    font-variant-numeric: tabular-nums;
    box-shadow: none;
}

/* Focus is the darkened border, doubled by an inset shadow so keyboard users can see where
   they are (the theme resets outlines; the old "no focus ring, like the reference" left Tab
   invisible). */
.cb-dimensions .cb-dimensions-input:focus,
.cb-dimensions .input-group .cb-dimensions-input.form-control:focus {
    border-color: #262626;
    outline: 0;
    box-shadow: inset 0 0 0 1px #262626;
}

/* Unit suffix box (mm / Stk.): a fixed 1/3 of the control, gray fill, bold,
   right-rounded — a 2:1 input:suffix split, matching the reference design. */
.cb-dimensions .input-group-append {
    display: flex;
    flex: 0 0 33.333%;
    width: 33.333%;
}

.cb-dimensions .input-group-append .input-group-text {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    color: #000;
    background-color: #f9f9f9;
    border: 1px solid #cccccc;
    border-radius: 0 4px 4px 0;
    font-weight: 700;
    padding: 0 .5rem;
}

/* A field without a suffix (e.g. width/height when no unit is set) keeps the
   input fully rounded so it doesn't look truncated. */
.cb-dimensions .cb-dimensions-control:last-child > .cb-dimensions-input {
    border-right: 1px solid #cccccc;
    border-radius: 4px;
}

/* VALIDATION. The server's message goes under the field it names (custom_questions.js matches
   the message's leading label to a field and fills that field's own slot), with the input,
   its label and its suffix box outlined red; a message naming no field marks every visible
   field and stays in the row-level target under the inputs. Both slots are empty by default
   and must not reserve space. */
.cb-dimensions .cb-dimensions-field.is-invalid .cb-dimensions-input,
.cb-dimensions .cb-dimensions-field.is-invalid .input-group-text {
    border-color: #d32f2f;
}

.cb-dimensions .cb-dimensions-field.is-invalid .cb-dimensions-input ~ label {
    color: #d32f2f;
}

.cb-dimensions .cb-dimensions-field-message {
    margin-top: .35rem;
    color: #d32f2f;
    font-size: .85em;
    line-height: 1.4;
}

.cb-dimensions .cb-dimensions-field-message:empty {
    display: none;
    margin-top: 0;
}

.cb-dimensions .validation-message-target {
    margin-top: .5rem;
    max-width: 44rem;
    color: #d32f2f;
}

.cb-dimensions .validation-message-target:empty {
    display: none;
    margin-top: 0;
}

/*
 * Reference-site behaviours: the minimum-cut-length advisory and the "Eigene
 * Teilung" (custom division) section. Same gray EFKA palette as above.
 */

/* The inputs and the advisory panel sit side by side on wide viewports, stacking
   on narrow ones. The inputs keep their own flex row; the warning sits beside them.
   Both are capped so the pair stays a readable block in the full-width band instead of
   spanning the whole page. */
.cb-dimensions .cb-dimensions-row {
    display: flex;
    flex-wrap: wrap;
    gap: 1.5rem;
    align-items: flex-start;
    max-width: 72rem;
}

.cb-dimensions .cb-dimensions-row > .cb-dimensions-inputs {
    flex: 0 1 44rem;
}

/* The SCHEMATIC (the question's decoration image), sharing the row with the inputs.
   Reference: efkarahmen.de 3d-rahmen/unbeleuchtet/carre-19, where a top-view line drawing
   labelled "Width: +19mm" / "Depth left" sits to the right of Breite/Höhe/Tiefe/Menge.

   THIS RULE IS ALSO THE LAYOUT. The inputs are a plain flex-wrap of ~13rem fields; the
   figure taking ~26rem of the row is what makes them fall two-per-line on a question that
   has a schematic, and leaves all three of a rectangle's fields on one line when it has
   none. There is deliberately no per-shape layout rule anywhere. */
.cb-dimensions .cb-dimensions-figure {
    flex: 1 1 22rem;
    /* Never grow past the drawing's own size — these are ~400px PNGs and upscaling a line
       drawing looks broken. */
    max-width: 26rem;
    align-self: center;
}

/* When a schematic shares the row, the inputs give up their 44rem basis and the two split
   the width — which is what puts the fields two per line (Breite/Höhe, then Tiefe/Menge),
   matching the reference. Without this the inputs keep the whole basis and still fit three. */
.cb-dimensions .cb-dimensions-row-with-figure > .cb-dimensions-inputs {
    flex: 1 1 28rem;
    max-width: 30rem;
}

.cb-dimensions .cb-dimensions-figure img {
    display: block;
    width: 100%;
    height: auto;
    /* A cap for the tall/portrait case: the field column is only ~2 rows high, and an image
       three times that turns the question into a picture with some inputs next to it. */
    max-height: 18rem;
    width: auto;
    max-width: 100%;
    margin: 0 auto;
}

/* One column on narrow screens: a 400px drawing beside a 13rem input is unreadable on a
   phone, and the drawing is a reference, not a control — it belongs under the fields there. */
@media (max-width: 767px) {
    .cb-dimensions .cb-dimensions-figure {
        flex: 1 1 100%;
        max-width: 100%;
        order: 2;
    }
}

/* Minimum-cut-length advisory panel: a light gray card to the right of the
   inputs. Purely informational — no error/red styling, since it never blocks. */
.cb-dimensions .cb-dimensions-cut-warning {
    /* flex-basis in px so the card keeps a sensible width regardless of the host
       theme's root font-size. */
    flex: 1 1 280px;
    align-self: stretch;
    background-color: #f9f9f9;
    border: 1px solid #e5e5e5;
    border-radius: 4px;
    /* em padding so the breathing room tracks the text size, not a small root. */
    padding: 1em 1.25em;
}

.cb-dimensions .cb-dimensions-cut-warning-heading {
    font-weight: 700;
    /* em (not rem): the host theme may set a small root font-size (Luma uses
       62.5% = 10px), which would shrink a rem heading below the body text. em
       scales from the inherited body size, so the heading stays proportionally
       larger in any theme. */
    font-size: 1.15em;
    color: #262626;
    margin-bottom: .5rem;
}

.cb-dimensions .cb-dimensions-cut-warning-body {
    color: #6b6b6b;
    line-height: 1.5;
}

/* Custom-division ("Eigene Teilung") section: a heading, an intro paragraph, then
   the two maxima inputs reusing the .cb-dimensions-inputs row styling. Separated
   from the main inputs by a top margin and a hairline rule. */
/* The division panel reuses .cb-dimensions-inputs for its two maxima, so it inherits the same
   width cap; the panel itself is capped to match the row above it. */
.cb-dimensions .cb-dimensions-division {
    max-width: 72rem;
    margin-top: 1.5rem;
    padding-top: 1.5rem;
    border-top: 1px solid #e5e5e5;
}

.cb-dimensions .cb-dimensions-division-heading {
    font-weight: 700;
    /* em, not rem — see the cut-warning heading note above. */
    font-size: 1.15em;
    color: #262626;
    margin-bottom: .5rem;
}

.cb-dimensions .cb-dimensions-division-intro {
    color: #6b6b6b;
    line-height: 1.5;
    margin-bottom: 1rem;
    max-width: 560px;
}

/* The two maxima SIDE BY SIDE: a two-column grid (the flex row above would wrap them onto
   two lines inside the old 360px cap), each column the same width a main field grows to. */
.cb-dimensions .cb-dimensions-division-inputs {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 13rem));
    gap: 1.25rem;
    max-width: 27.25rem;
}

.cb-dimensions .cb-dimensions-division-inputs > .cb-dimensions-field {
    min-width: 0;
    max-width: none;
}

/* Action row holding the toggle button. */
.cb-dimensions .cb-dimensions-actions {
    margin-top: 1.25rem;
}

/* The custom-division toggle: a bordered secondary button matching the reference's
   outline style (the primary "Weiter" lives outside this widget). */
.cb-dimensions .cb-dimensions-division-toggle {
    display: inline-block;
    color: #262626;
    background-color: #fff;
    border: 1px solid #cccccc;
    border-radius: 4px;
    padding: 8px 16px;
    font-weight: 700;
    cursor: pointer;
    line-height: 1.5;
}

.cb-dimensions .cb-dimensions-division-toggle:hover {
    background-color: #f9f9f9;
    border-color: #b3b3b3;
}

/* ============================================================
   Cable-outlet question type (.cb-cableoutlet)
   A frame rectangle with outlet points positioned by slot. Each point is a stock
   ConfigBox .answer (radio) styled as a dot; the per-slot class sets top/left.
   Geometry mirrors ConfigboxQuestionCableoutlet::getSlotDefinitions() (% of frame).
   ============================================================ */

.cb-cableoutlet {
    max-width: 460px;
}

.cb-cableoutlet .cb-cableoutlet-heading {
    font-weight: 700;
    margin-bottom: 12px;
}

/* Corner-distance note: light-gray informational card, never error-styled. */
.cb-cableoutlet .cb-cableoutlet-corner-note {
    background-color: #f5f5f5;
    border: 1px solid #e0e0e0;
    border-radius: 4px;
    padding: 10px 12px;
    margin-bottom: 16px;
    color: #555;
    font-size: 13px;
    line-height: 1.4;
}

/* The frame. A neutral 4:3-ish box; aspect via padding-top so it scales. */
.cb-cableoutlet .cb-cableoutlet-frame {
    position: relative;
    width: 100%;
    padding-top: 80%; /* height relative to width */
    border: 2px solid #4a90a4;
    border-radius: 4px;
    background-color: #fafafa;
    margin: 28px 0;
}

/* Edge orientation labels. */
.cb-cableoutlet .cb-cableoutlet-edge-label {
    position: absolute;
    font-size: 12px;
    color: #888;
    pointer-events: none;
}
.cb-cableoutlet .cb-cableoutlet-edge-top    { top: -20px;  left: 50%; transform: translateX(-50%); }
.cb-cableoutlet .cb-cableoutlet-edge-bottom { bottom: -20px; left: 50%; transform: translateX(-50%); }
.cb-cableoutlet .cb-cableoutlet-edge-left   { left: -34px; top: 50%; transform: translateY(-50%); }
.cb-cableoutlet .cb-cableoutlet-edge-right  { right: -40px; top: 50%; transform: translateY(-50%); }

/* Each point (a stock .answer). Positioned absolutely by its per-slot class. */
.cb-cableoutlet .cb-outlet-point {
    position: absolute;
    width: 0;
    height: 0;
}

.cb-cableoutlet .cb-outlet-point label {
    position: absolute;
    top: 0;
    left: 0;
    transform: translate(-50%, -50%);
    margin: 0;
    cursor: pointer;
}

/* Hide the actual radio; the dot is the visible control. */
.cb-cableoutlet .cb-outlet-point input[type=radio] {
    position: absolute;
    opacity: 0;
    width: 0;
    height: 0;
    margin: 0;
}

/* The visible dot. */
.cb-cableoutlet .cb-outlet-point .cb-outlet-dot {
    display: block;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    background-color: #fff;
    border: 2px solid #4a90a4;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
    transition: background-color 0.12s, border-color 0.12s, transform 0.12s;
}

.cb-cableoutlet .cb-outlet-point label:hover .cb-outlet-dot {
    border-color: #2c6b7d;
    transform: scale(1.12);
}

/* Selected state: filled green, like the reference's "on" toggle. */
.cb-cableoutlet .cb-outlet-point.selected .cb-outlet-dot,
.cb-cableoutlet .cb-outlet-point input[type=radio]:checked + .cb-outlet-dot {
    background-color: #4caf50;
    border-color: #388e3c;
}

/* Disabled points (control disabled while question inactive). */
.cb-cableoutlet .cb-outlet-point input[type=radio]:disabled + .cb-outlet-dot {
    opacity: 0.4;
    cursor: default;
}

/* Rule-hidden points must DISAPPEAR (not grey out). ConfigBox marks a point that should
   hide-when-hidden with the STATIC 'hide-non-applying' class (from display_while_disabled
   ='hide') AND flags the live rule state with 'non-applying-answer' (present = currently
   hidden) / 'applying-answer' (present = currently shown). 'hide-non-applying' alone is
   just the marker — an APPLYING point carries it too — so hiding on it alone made every
   point vanish except the one that happened to apply. Hide only when the point is BOTH
   marked-to-hide AND currently non-applying; and explicitly KEEP an applying point shown
   even though it still carries the marker. */
.cb-cableoutlet .cb-outlet-point.hide-non-applying.non-applying-answer {
    display: none;
}
.cb-cableoutlet .cb-outlet-point.hide-non-applying.applying-answer {
    display: block;
}

/* Per-slot positions are set INLINE by the template from the server model geometry
   (ConfigboxQuestionCableoutlet::getSlotDefinitions()), so there are no per-slot CSS
   position classes here — one source of truth, no drift. */

/* sr-only utility (if the theme lacks it). */
.cb-cableoutlet .sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* ==================================================================
   Stabilizer question type
   ==================================================================
   Two steppers (horizontal / vertical bar count) beside a live visual
   of the frame. Responsive: frame side-by-side with the steppers on
   desktop; frame stacked ABOVE the steppers on mobile. The frame is a
   near-square schematic (not to scale) with evenly-distributed bars.
   Bar positions are set INLINE by the template/JS from the counts, so
   there are no per-bar position classes here. */

.cb-stabilizer .cb-stabilizer-advisory {
    background: #f6f6f6;
    border: 1px solid #e2e2e2;
    border-radius: 4px;
    padding: 10px 14px;
    margin-bottom: 14px;
    color: #555;
    font-size: 0.9em;
    line-height: 1.4;
}

.cb-stabilizer .cb-stabilizer-panel-heading {
    font-weight: 600;
    margin-bottom: 12px;
}

/* Responsive body: row on desktop (frame first, then controls), column
   on mobile (frame stacks on top because it is the first DOM child). */
.cb-stabilizer .cb-stabilizer-body {
    display: flex;
    flex-direction: row;
    align-items: flex-start;
    gap: 24px;
    flex-wrap: wrap;
}

@media (max-width: 600px) {
    .cb-stabilizer .cb-stabilizer-body {
        flex-direction: column;
        align-items: stretch;
    }
    .cb-stabilizer .cb-stabilizer-frame {
        margin: 0 auto;
    }
}

/* Near-square frame; the schematic of "how many bars", not a scale drawing. */
.cb-stabilizer .cb-stabilizer-frame {
    position: relative;
    box-sizing: border-box;
    width: 100%;
    max-width: 260px;
    aspect-ratio: 1 / 1;
    border: 2px solid #bcbcbc;
    border-radius: 3px;
    background: #fafafa;
    flex: 0 0 auto;
}

/* A stabilizer bar. Horizontal bars span the width at a given top;
   vertical bars span the height at a given left. Thin, evenly spaced. */
.cb-stabilizer .cb-stabilizer-bar {
    position: absolute;
    background: #bcbcbc;
}

.cb-stabilizer .cb-stabilizer-bar-h {
    left: 0;
    right: 0;
    height: 4px;
    transform: translateY(-50%);
}

.cb-stabilizer .cb-stabilizer-bar-v {
    top: 0;
    bottom: 0;
    width: 4px;
    transform: translateX(-50%);
}

.cb-stabilizer .cb-stabilizer-controls {
    flex: 1 1 auto;
    min-width: 180px;
}

.cb-stabilizer .cb-stabilizer-stepper {
    margin-bottom: 14px;
}

.cb-stabilizer .cb-stabilizer-stepper > label {
    display: block;
    margin-bottom: 4px;
    font-weight: 500;
}

.cb-stabilizer .cb-stabilizer-stepper-controls {
    display: inline-flex;
    align-items: stretch;
    border: 1px solid #cccccc;
    border-radius: 4px;
    overflow: hidden;
}

.cb-stabilizer .cb-stabilizer-dec,
.cb-stabilizer .cb-stabilizer-inc {
    border: 0;
    background: #f2f2f2;
    width: 40px;
    font-size: 1.1em;
    line-height: 1;
    cursor: pointer;
    padding: 8px 0;
}

.cb-stabilizer .cb-stabilizer-dec:hover,
.cb-stabilizer .cb-stabilizer-inc:hover {
    background: #e6e6e6;
}

.cb-stabilizer .cb-stabilizer-dec:disabled,
.cb-stabilizer .cb-stabilizer-inc:disabled {
    opacity: 0.5;
    cursor: default;
}

.cb-stabilizer .cb-stabilizer-value {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 48px;
    padding: 8px 4px;
    border-left: 1px solid #cccccc;
    border-right: 1px solid #cccccc;
    background: #ffffff;
    font-variant-numeric: tabular-nums;
}

.cb-stabilizer .cb-stabilizer-actions {
    margin-top: 4px;
}

.cb-stabilizer .cb-stabilizer-reset {
    border: 1px solid #cccccc;
    background: #ffffff;
    border-radius: 4px;
    padding: 6px 14px;
    cursor: pointer;
    font-size: 0.9em;
}

.cb-stabilizer .cb-stabilizer-reset:hover {
    background: #f2f2f2;
}

/* ------------------------------------------------------------------
   Selections-download link (configurator page)
   The server-rendered link under the questions that downloads the
   current configuration as the efka.selections JSON document.
   See docs/legacy-configurator-json-export.md and the template
   override view/customizations/templates/configuratorpage/default.php.
   ------------------------------------------------------------------ */

.cbx-seldl-wrap {
    margin: 18px 0 6px;
    text-align: right;
}

.cbx-seldl-link {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 8px 16px;
    border: 1px solid #cccccc;
    border-radius: 4px;
    background: #ffffff;
    color: #333333;
    font-size: 0.9em;
    text-decoration: none;
    transition: background 0.15s ease, border-color 0.15s ease;
}

.cbx-seldl-link:hover,
.cbx-seldl-link:focus {
    background: #f2f2f2;
    border-color: #b3b3b3;
    color: #111111;
    text-decoration: none;
}

.cbx-seldl-icon {
    flex: none;
}

/* ------------------------------------------------------------------
   Accessory question type
   ------------------------------------------------------------------
   A responsive grid of accessory cards, each with a quantity stepper.

   DELIBERATELY NO :hover STATE AND NO CHOSEN-STATE BORDER. The reference site
   highlights a card once its quantity leaves zero; that was reviewed and dropped —
   the number in the stepper already says what was chosen, and a card that changes
   appearance as a number crosses zero reads as noise. Do not "restore" it as a
   missing feature. See docs/question-type-accessory.md §1.1.
   ------------------------------------------------------------------ */

.cb-accessory-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 16px;
}

@media (min-width: 768px) {
    .cb-accessory-grid {
        grid-template-columns: repeat(2, 1fr);
    }
}

@media (min-width: 992px) {
    .cb-accessory-grid {
        grid-template-columns: repeat(3, 1fr);
    }
}

/* A flex column of three regions: .cb-accessory-card-top (heading + advice flag),
   .cb-accessory-image, and .cb-accessory-card-bottom (stepper, reset, description). Cards in
   a grid row stretch to the tallest, and the bottom region's margin-top:auto absorbs the
   difference — so every card in a row has its heading on the top edge and its controls on
   the bottom edge, whatever its title wraps to and however tall its image is. Everything
   stays in flow: no position:absolute, so a long description simply grows the card. */
.cb-accessory-card {
    position: relative;
    display: flex;
    flex-direction: column;
    padding: 12px;
    border: 1px solid #cccccc;
    border-radius: 4px;
    background: #ffffff;
}

/* A rule-hidden accessory must DISAPPEAR. Same trap the cable-outlet points hit above:
   'hide-non-applying' is the STATIC marker from display_while_disabled='hide' and an
   APPLYING card carries it too, so hiding on it alone made every card vanish. Hide only
   when the card is BOTH marked-to-hide AND currently non-applying, and explicitly keep an
   applying card shown. (The price side is handled server-side — getEffectiveQuantities()
   zeroes any accessory whose answer does not apply.) */
.cb-accessory-card.hide-non-applying.non-applying-answer {
    display: none;
}
.cb-accessory-card.hide-non-applying.applying-answer {
    display: flex;
}

.cb-accessory-card-top {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding-bottom: 10px;
}

.cb-accessory-card-header {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 6px;
}

.cb-accessory-title {
    font-weight: 600;
    flex: 1 1 auto;
}

.cb-accessory-sku {
    color: #767676;
    font-size: 0.9em;
}

.cb-accessory-price {
    margin-left: auto;
    white-space: nowrap;
}

.cb-accessory-flag {
    align-self: flex-start;
    padding: 2px 8px;
    border-radius: 3px;
    background: #f0ad4e;
    color: #ffffff;
    font-size: 0.8em;
}

/* The picture runs the FULL card width at its natural height — no fixed box, no letterboxing,
   no cropping (an earlier 150px box was dropped: it shrank every product shot to a thumbnail).
   What keeps a row's cards level is the admin, not CSS: the upload field's tooltip says to use
   square images and to bake any padding into the image itself. The top border is the subtle
   rule between heading and image.

   margin-top:auto is what BOTTOM-ALIGNS the image, together with the controls under it: the
   images of one question share a ratio, the headings do not (a flag, a wrapping title), so the
   leftover height of a stretched card goes between heading and image, and image bottoms,
   rules and steppers all sit on one line across the row. */
.cb-accessory-image {
    margin-top: auto;
    border-top: 1px solid #e5e5e5;
    padding: 10px 0;
}

.cb-accessory-image img {
    display: block;
    width: 100%;
    height: auto;
}

/* The bottom region sits directly under the image, which is already pinned to the bottom (see
   .cb-accessory-image). Its top border is the rule above the stepper. Exactly ONE auto margin
   per column — two would split the leftover height and knock the row out of line — so only a
   card WITHOUT an image (bottom follows top directly) gives the auto margin to this region. */
.cb-accessory-card-bottom {
    display: flex;
    flex-direction: column;
    gap: 8px;
    border-top: 1px solid #e5e5e5;
    padding-top: 10px;
}

.cb-accessory-card-top + .cb-accessory-card-bottom {
    margin-top: auto;
}

/* The stepper is centred in the card: (−) [n] (+) per frame, as one group. */
.cb-accessory-stepper {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
}

/* Round − / + buttons, the same 32px height as the quantity input beside them. Scoped under
   the card so the theme's `.btn` cannot restyle them. */
.cb-accessory-card .cb-accessory-dec,
.cb-accessory-card .cb-accessory-inc {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    padding: 0;
    border: 1px solid #cccccc;
    border-radius: 50%;
    background: #ffffff;
    color: #262626;
    font-size: 1.1em;
    line-height: 1;
    cursor: pointer;
}

.cb-accessory-card .cb-accessory-dec:hover,
.cb-accessory-card .cb-accessory-inc:hover {
    background: #f2f2f2;
    border-color: #b3b3b3;
}

.cb-accessory-card .cb-accessory-dec:disabled,
.cb-accessory-card .cb-accessory-inc:disabled {
    opacity: 0.5;
    cursor: default;
}

/* The quantity is a real text input (keyboard-reachable and typeable); `font: inherit` and the
   explicit padding/border override the theme's form-plugin defaults for [type=text]. */
.cb-accessory-card .cb-accessory-value {
    width: 3.5em;
    height: 32px;
    padding: 0 6px;
    border: 1px solid #cccccc;
    border-radius: 4px;
    background: #ffffff;
    color: inherit;
    font: inherit;
    font-variant-numeric: tabular-nums;
    text-align: center;
}

/* Keyboard focus must be VISIBLE on every control — the theme resets outlines, and a Tab that
   lands on an invisible focus reads as "Tab does not work". :focus-visible keeps the ring off
   mouse clicks. */
.cb-accessory-card .cb-accessory-dec:focus-visible,
.cb-accessory-card .cb-accessory-inc:focus-visible,
.cb-accessory-card .cb-accessory-value:focus-visible,
.cb-accessory-card .cb-accessory-reset:focus-visible {
    outline: 2px solid #262626;
    outline-offset: 2px;
}

/* nowrap: the unit is two words ("per frame" / "pro Rahmen") and wrapped to two lines inside
   the stepper row, which made the control look broken. */
.cb-accessory-unit {
    color: #767676;
    font-size: 0.9em;
    white-space: nowrap;
}

.cb-accessory-description {
    color: #555555;
    font-size: 0.9em;
}

/* Reserved row for the reset button, directly under the stepper. min-height keeps the space
   whether or not the button is showing — 34px is the button's own height, see below. The
   bottom region is pinned to the card's bottom edge, so an unreserved button appearing on the
   first + would push the STEPPER up, out from under the cursor; reserved, nothing moves, and
   the steppers of a row's cards stay on one line. */
.cb-accessory-actions {
    min-height: 34px;
    text-align: center; /* under the centred stepper */
}

/* A real secondary button — the same outline treatment as the stabilizer's reset and the
   dimensions' division toggle. Scoped under the card so it wins over any theme `.btn` rule at
   equal order. Fixed line-height: 20 + 2×6 padding + 2×1 border = the 34px the row reserves. */
.cb-accessory-card .cb-accessory-reset {
    display: inline-block;
    padding: 6px 12px;
    border: 1px solid #cccccc;
    border-radius: 4px;
    background: #ffffff;
    color: #262626;
    font-size: 0.85em;
    line-height: 20px;
    cursor: pointer;
}

.cb-accessory-card .cb-accessory-reset:hover {
    background: #f2f2f2;
    border-color: #b3b3b3;
}


/* ================================================================================================
   Cards question type  (docs/question-type-cards.md)

   A grid of selectable cards: title + code, image, caption, optional "recommended" badge. The
   Bootstrap column classes come from the question's own per-breakpoint settings and are rendered
   server-side, so there is nothing responsive to do here beyond making the card itself behave.
   ================================================================================================ */

.cards-grid {
    align-items: stretch;
}

.cards-cell {
    position: relative;
    margin-bottom: 1rem;
    display: flex;
}

/* The whole card is the label, so any click selects. Column, so the caption can push to the
   bottom and every card in a row ends up the same height. */
.cards-card {
    position: relative;
    display: flex;
    flex-direction: column;
    width: 100%;
    margin: 0;
    border: 2px solid #dddddd;
    border-radius: 6px;
    background: #ffffff;
    overflow: hidden;
    cursor: pointer;
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.cards-card:hover {
    border-color: #b3b3b3;
}

/* Selection is shown by the border, which is why the radio can be hidden. :focus-within keeps
   keyboard users oriented when the input itself is invisible. */
/* Selection is ONE solid stroke. Previously this set border-color plus an inset 1px box-shadow,
   which reads as a double line. Every card carries a 2px border from the start (grey when
   unselected) so switching colour cannot shift the layout by a pixel. */
.cards-card:has(.cards-input:checked) {
    border-color: #2b6777;
}

.cards-card:focus-within {
    outline: 2px solid #2b6777;
    outline-offset: 2px;
}

/* When the radio IS shown it must sit INSIDE the card, not straddle its top-left corner: the input
   is the first child of the label, so in normal flow it lands on the border. Pinned into the corner
   with the header indented to clear it. */
/* Centre it on the header WITHOUT resizing it. Setting height on a radio stretches the control
   itself into a tall ellipse — it has no inner box to fill, unlike the <a> info icon, which is why
   the same trick is fine there and wrong here. top = half the header, then pull back by half the
   control's own height. */
.cards-card .cards-input:not(.cards-input-hidden) {
    position: absolute;
    /* Aligned to the TITLE'S FIRST LINE, not the header's centre. The header has a two-line
       min-height and the code often wraps below the title, so its geometric centre falls between
       the two lines — measured 11px below the title, which reads as misaligned. header padding-top
       (0.6rem) + half a line (0.75em) lands on the title's line whatever follows it. */
    top: calc(0.6rem + 0.75em);
    left: calc(var(--bs-gutter-x, 1.5rem) * 0.5 + 0.7rem);
    transform: translateY(-50%);
    z-index: 2;
    margin: 0;
}

.cards-grid:not(.cards-radio-hidden) .cards-header {
    padding-left: 2.1rem;
}

/* Hidden, NOT display:none — a display:none input cannot be focused or announced, which would make
   the card mouse-only. This clips it instead, so it stays in the tab order. */
.cards-input-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* The header is a flex row so the title, the code and the two corner affordances all sit on one
   optical line. min-height is TWO lines of title plus the padding: within a question every card
   then has the same header height, so the images below them line up even when one title wraps and
   its neighbours do not. Cards are laid out independently (one per grid column), so there is no
   way to equalise them from the content alone. */
.cards-header {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    min-height: calc(3em + 1.2rem);
    padding: 0.6rem 0.75rem;
    border-bottom: 1px solid #eeeeee;
}

/* Same reason as .cards-code: at 6 columns a single long word ("Anodised") is wider than the card
   and gets clipped by the border. Let it break rather than stick out. */
.cards-cell:has(.cards-info) .cards-header {
    padding-right: 2rem;
}

.cards-title {
    font-weight: 700;
    overflow-wrap: anywhere;
}

/* NOT white-space:nowrap. At 6 columns a code like "(RAL-9016M)" is wider than the card and simply
   overflowed the border — found by rendering the densest setting an admin can actually choose. It
   wraps to its own line instead, and breaks mid-token rather than sticking out. */
.cards-code {
    margin-left: 0.35em;
    color: #777777;
    font-size: 0.85em;
    overflow-wrap: anywhere;
}

.cards-media {
    position: relative;
    display: block;
    padding: 0.75rem;
    text-align: center;
}

.cards-image {
    max-width: 100%;
    height: auto;
}

/* Top-right of the image area, bleeding to the card edge — matching the reference. Rounded on the
   left only, shrink-to-fit, so a longer wording ("Our advice" vs "Most chosen") just gets wider. */
.cards-badge {
    position: absolute;
    top: 0;
    right: 0;
    z-index: 1;
    padding: 0.3rem 0.7rem;
    border-bottom-left-radius: 6px;
    background: #dda94a;
    color: #ffffff;
    font-size: 0.8rem;
    font-weight: 700;
    line-height: 1.2;
}

/* margin-top:auto pins the caption to the bottom so cards of differing text length still line up. */
.cards-caption {
    display: block;
    margin-top: auto;
    padding: 0.6rem 0.75rem;
    border-top: 1px solid #eeeeee;
    color: #555555;
    font-size: 0.9em;
}

.cards-price {
    display: block;
    padding: 0 0.75rem 0.6rem;
}

.cards-availability {
    display: block;
    padding: 0 0.75rem 0.6rem;
    font-size: 0.85em;
}

/* The popover/modal trigger is a SIBLING of the card's <label>, not a child — an <a> inside a
   label would toggle the input on click. So it is positioned into the card's bottom-right corner
   instead. Without this it renders in the grid gutter, visually detached from any card. */
/* Top-right of the card, level with the title — where an info affordance is looked for. It is a
   SIBLING of the card's <label> (an <a> inside a label toggles the input), so it is positioned
   against .cards-cell; that box includes Bootstrap's half-gutter of column padding, which is why
   the offset has to add it back or the icon lands on the card's border. */
.cards-info {
    position: absolute;
    right: calc(var(--bs-gutter-x, 1.5rem) * 0.5 + 0.55rem);
    top: 0;
    height: calc(3em + 1.2rem);
    display: flex;
    align-items: center;
    z-index: 2;
    margin: 0;
    color: #2b6777;
    cursor: pointer;
}

/* Room for the icon so it never sits on top of the caption or the price. */
.cards-card {
    padding-bottom: 1.6rem;
}

/* Rule-disabled. Dimmed and not interactive, but deliberately NOT overlaid with text on top of the
   caption — the reference site does that and the two overlap illegibly. */
.cards-card-disabled {
    cursor: not-allowed;
    background: #fafafa;
    border-style: dashed;
}

.cards-card-disabled .cards-header,
.cards-card-disabled .cards-media,
.cards-card-disabled .cards-caption {
    opacity: 0.45;
}

.cards-card-disabled:hover {
    border-color: #dddddd;
}

/* --- Cards: rule-disabled state ------------------------------------------------------------- */

.cards-unavailable {
    display: block;
    padding: 0.4rem 0.75rem 0;
    color: #8a6d3b;
    font-size: 0.85em;
    font-weight: 700;
}

/* Must sit outside the <label> in the markup (a button inside a label would toggle the input), but
   it has to READ as part of the card — left in flow it lands in the grid gutter beside the card,
   visually attached to nothing. So it is positioned back inside the cell, bottom-LEFT: .cards-info
   already owns bottom-right, and a disabled answer with a description shows both at once. */
.cards-why {
    position: absolute;
    left: calc(var(--bs-gutter-x, 1.5rem) * 0.5 + 0.75rem);
    bottom: 0.6rem;
    z-index: 2;
    color: #2b6777;
    font-size: 0.85em;
    text-decoration: underline;
    cursor: pointer;
}

/* Room for whichever of the two corner affordances is present, so neither ever covers the caption
   or the availability line. */
.cards-cell:has(.cards-why) .cards-card {
    padding-bottom: 1.9rem;
}

/* The stock modal is an unstyled white box with a stray x. Give it the header / body / footer
   structure the rest of the storefront uses, so an "option blocked" message does not look like a
   rendering accident at the exact moment the customer is being told no. */
.cards-why-modal .modal-content {
    border: 0;
    border-radius: 8px;
    box-shadow: 0 12px 40px rgba(0, 0, 0, 0.25);
    overflow: hidden;
}

.cards-why-modal .modal-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.9rem 1.25rem;
    border-bottom: 1px solid #e7e7e7;
    background: #f7f7f7;
}

.cards-why-modal .modal-title {
    margin: 0;
    font-size: 1.1rem;
    font-weight: 700;
}

.cards-why-modal .modal-header .close {
    flex: none;
    padding: 0 0.25rem;
    border: 0;
    background: none;
    color: #777777;
    font-size: 1.5rem;
    line-height: 1;
    cursor: pointer;
}

.cards-why-modal .modal-header .close:hover {
    color: #222222;
}

.cards-why-modal .modal-body {
    padding: 1.25rem;
}

.cards-why-modal .modal-footer {
    display: flex;
    justify-content: flex-end;
    padding: 0.9rem 1.25rem;
    border-top: 1px solid #e7e7e7;
    background: #fbfbfb;
}

.cards-why-close {
    padding: 0.5rem 1.4rem;
    border: 0;
    border-radius: 4px;
    background: #2b6777;
    color: #ffffff;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.02em;
    cursor: pointer;
}

.cards-why-close:hover {
    background: #235767;
}

.cards-why-heading {
    margin: 0 0 0.5rem;
    font-size: 1rem;
    font-weight: 700;
}

.cards-why-reason {
    margin-bottom: 1rem;
}

.cards-why-support {
    margin-bottom: 0.75rem;
    font-weight: 700;
}

/* Contact block, mirroring the client's own: icon + value per line, phone and mail actionable. */
.cards-why-contact {
    margin: 0;
    padding: 0;
    list-style: none;
}

.cards-why-contact li {
    display: flex;
    align-items: flex-start;
    gap: 0.6rem;
    padding: 0.2rem 0;
}

.cards-why-contact i {
    flex: none;
    width: 1.1em;
    margin-top: 0.15em;
    color: #c8102e;
    text-align: center;
}

.cards-why-contact a {
    color: inherit;
    text-decoration: none;
}

.cards-why-contact a:hover {
    text-decoration: underline;
}

/* --- Admin: the rule-explanation field ------------------------------------------------------ */

.cards-reason-warning {
    margin-bottom: 0.5rem;
    padding: 0.5rem 0.75rem;
    border-left: 4px solid #dda94a;
    border-radius: 3px;
    background: #fdf6e7;
    color: #6b5424;
    font-size: 0.9em;
}

.cards-reason-warning--orphaned {
    border-left-color: #c0392b;
    background: #fdecea;
    color: #7a2820;
}

.cards-reason-actions {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-top: 0.4rem;
}

.cards-reason-generate {
    padding: 0.3rem 0.7rem;
    border: 1px solid #b3b3b3;
    border-radius: 4px;
    background: #ffffff;
    cursor: pointer;
}

/* The button is a plain Bootstrap .btn.btn-sm.btn-outline-secondary, exactly like the rule
   property's own Change / Delete / Copy above it — so there is no skin to write here. All that is
   left is the busy/failed state machine: the two labels, the spinner and the failure message are
   rendered server-side and swapped by class, so no user-facing wording is ever built in JS. */
.cards-reason-generate {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
}

.cards-reason-hint--failed,
.cards-reason-generate-label-busy {
    display: none;
}

/* The spinner's hidden state must OUT-SPECIFY Bootstrap, not merely follow it.
   `.cb-content .spinner-border { display: inline-block }` in bootstrap-namespaced.css is (0,2,0);
   `.cards-reason-generate .cards-reason-spinner` is (0,2,0) too, so which one wins came down to
   stylesheet order — and where custom.css did not happen to load last, the spinner ran
   permanently. Adding .spinner-border to our own selectors makes them (0,3,0)/(0,4,0), which wins
   in either order. */
.cards-reason-generate .cards-reason-spinner.spinner-border {
    display: none;
}

.cards-reason-field--failed .cards-reason-hint--failed {
    display: inline;
    color: #b02a37;
    font-size: 0.85em;
}

/* Busy: the spinner appears BESIDE the label rather than replacing it, and the label says what is
   happening — a spinner on its own leaves the state to be guessed. */
.cards-reason-generate.is-busy .cards-reason-generate-label {
    display: none;
}

.cards-reason-generate.is-busy .cards-reason-generate-label-busy {
    display: inline;
}

.cards-reason-generate.is-busy .cards-reason-spinner.spinner-border {
    display: inline-block;
}

/* The live "your rule just changed" reminder. Bootstrap styles .alert-danger in the admin already;
   these two lines only size it down to field scale. */
.cards-reason-rule-changed {
    margin-bottom: 0.5rem;
    font-size: 0.9em;
}

/* The question's own intro paragraph sat hard against the first row of cards. Scoped to cards so it
   cannot shift the spacing of every other question type in the shop. */
.question.type-cards .question-description {
    margin-bottom: 1.25rem;
}

/* Long-word edge case. overflow-wrap was only on the title and the code, so a caption (or a badge,
   or the unavailable marker) containing one very long unbroken word still pushed past the card
   border — reproduced at 6 columns with "Donaudampfschifffahrtsgesellschaftskapitaenspatent".
   Every text node in a card can receive admin-entered content, so every one of them has to be able
   to break. */
.cards-caption,
.cards-badge,
.cards-unavailable,
.cards-why,
.cards-availability {
    overflow-wrap: anywhere;
}

/* A pathological title cannot be allowed to make one card several times taller than its
   neighbours; the header scrolls its overflow away rather than dragging the whole row with it.
   min-height still equalises the normal case (titles of one or two lines). */
.cards-header {
    max-height: calc(6em + 1.2rem);
    overflow: hidden;
}

/* ---------------------------------------------------------------------------------------------
   Chat advisor panel — restore the values ConfigBox's own chatadvisor.css asks for.

   The panel renders inside the kenedo view wrapper, so ConfigBox's Bootstrap 5 bundle applies to
   it — and that bundle is namespaced, which makes every one of its rules `.cb-content .card` /
   `.cb-content .btn` (0,2,0). chatadvisor.css styles the panel with `.chatadvisor-toggle` (0,1,0)
   and `.chatadvisor-panel .chatadvisor-window` (0,2,0), and loads BEFORE the bundle. So Bootstrap
   wins on specificity for the toggle and on load order for the window, and the panel is left with
   the wrong geometry rather than the geometry it declares. chatadvisor.css already hit this once —
   its `display` rules carry !important with a comment about exactly this — but only `display` was
   covered.

   What Bootstrap was taking, measured on the product page:

     .cb-content .card  position: relative   <- the window must be `absolute`. In flow it made the
                                               fixed panel 320px tall instead of 38px, and the open
                                               window then sat ON TOP OF ITS OWN TOGGLE, hiding it.
     .cb-content .card  height: var(--bs-card-height)  <- unset, so `auto`: the window collapsed to
                                               282px instead of 480px, leaving a 130px message pane.
     .cb-content .btn   display / padding / border-radius  <- the toggle lost its pill shape and
                                               came out a flat rectangle at Bootstrap's own metrics.
     .cb-content .btn.btn-primary (general.css, 0,3,0)  box-shadow: none  <- and its drop shadow.
     .cb-content .btn   border-radius / text-align  <- quick replies lost their pill + left align.

   Fixed by specificity, not !important, and without leaning on `.cb-content` or on load order:
   adding the element's own Bootstrap class takes each selector one step above the rule that was
   beating it. Values are copied from chatadvisor.css, not invented — this restores the upstream
   design, it does not restyle it.

   REMOVABLE once the same specificity fix lands in chatadvisor.css upstream and the cbx pin here
   moves past it. */
/* `padding: 0` is a THIRD collision, and not a Bootstrap one — it is OUR OWN THEME.

   Hyva's styles.css defines a `.card` component of its own (in `@layer components`) giving it
   `padding-block`/`padding-inline: 24px`, plus a border, background and radius. The panel's window
   ships `class="chatadvisor-window card"` — meaning BOOTSTRAP's card — so the theme's component
   lands on it too and insets the whole chat by 24px on every side: a 360px window with 310px of
   usable width, and 48px eaten out of a height budget that is a fixed 480px.

   The window must have NO padding of its own: the header, message list and form each carry their
   own, which is what chatadvisor.css's 480px is measured against. The theme's border, background
   and radius are left alone — the window is meant to look like a card, it just must not be padded
   like one.

   Winning here is not about specificity: a rule inside `@layer components` loses to any UNLAYERED
   rule regardless of how specific it is, and this file is unlayered. Note also that the theme sets
   the logical `padding-block`/`padding-inline` rather than `padding`, which is why a probe that
   only asks for `padding` comes back empty while the computed value is plainly 24px. */
.chatadvisor-panel .chatadvisor-window.card {
    position: absolute;
    height: 480px;
    padding: 0;
}

.chatadvisor-panel .chatadvisor-toggle.btn.btn-primary {
    display: inline-flex;
    padding: 10px 18px;
    border-radius: 999px;
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.25);
}

.chatadvisor-panel .chatadvisor-quick-reply.btn {
    border-radius: 999px;
    white-space: normal;
    text-align: left;
}
