/*
 * Shell around the Wheelsys booking engine.
 *
 * Rule: nothing in this file may target an element inside #wheelsbook. The vendor
 * owns that subtree and changes it without notice. We style only our own chrome.
 *
 * Expanded is the no-JS default, so a script failure can never hide the engine.
 */

/*
 * The wheego palette, declared once for the shell AND the engine. It lives here, on our
 * own element, because #wheelsbook is inside .wheelsys-shell: the engine inherits these,
 * while a declaration on #wheelsbook (where wheelsys-theme.css used to keep them) is
 * invisible to the toggle, which sits beside the engine rather than inside it. That
 * forced the shell to write its colours out as literals until 2026-10-20.
 * wheelsys-theme.css is enqueued with this file as a dependency, so they are always here.
 */
.wheelsys-shell {
    --wg-purple: #46397C;
    --wg-purple-dark: #362C63;
    --wg-purple-tint: #F4F2F9;
    --wg-purple-line: #DCD7EA;
    --wg-purple-line-hover: #B9B2D3;
    --wg-yellow: #FFD23F;
    --wg-yellow-dark: #F5C400;
    --wg-text: #2A2540;
    --wg-muted: #6F6A85;            /* labels and prompts; 5.1:1 on white */
    --wg-error: #D64545;

    position: relative;
}

/*
 * The animation needs both halves to agree. This transition times the movement; the
 * script supplies the pixel heights it moves between, because max-height cannot
 * interpolate to or from `none`. Keep the 0.28s here in step with COLLAPSE_MS in
 * wheelsys-shell.js, which is when the script releases its height cap.
 *
 * Expanding: visibility switches at 0s, so the content is there to be revealed.
 */
.wheelsys-shell__body {
    overflow: hidden;
    transition: max-height 0.28s ease, visibility 0s linear 0s;
}

/*
 * `.is-enhanced` is deliberately part of this selector, not just the toggle's.
 * It is added by JS and never appears in served HTML, so a "remove unused CSS"
 * optimizer (WP Rocket, Perfmatters - common on Divi sites) could strip the
 * toggle's rule while keeping a rule keyed only on data-state, which IS in the
 * markup. That would collapse the body with no visible way to reopen it. Tying
 * both rules to the same class makes collapse impossible unless the toggle is
 * also displayable.
 *
 * `visibility: hidden` is load-bearing, not decoration. Collapsing with
 * `max-height` alone leaves the clipped form controls in the tab order: measured
 * on the live engine, 9 of them still took focus while invisible, and focusing one
 * scrolled the clipped form back into view. visibility removes them from the tab
 * order and from the accessibility tree, so aria-expanded="false" tells the truth.
 *
 * It is specifically NOT `display: none`. The vendor's engine measures its own
 * layout, and display:none would report zero dimensions to it. visibility keeps
 * the boxes laid out - verified on the live page: the search form still reports
 * offsetWidth 335 / offsetHeight 707 while collapsed.
 *
 * The cost, accepted deliberately: the vendor's "Already Booked? / Manage your
 * booking" bar is a sibling inside the same vendor subtree, so it disappears too.
 * Returning customers reach it by expanding the shell first. Keeping it visible
 * and removing the keyboard trap are mutually exclusive without writing rules
 * inside #wheelsbook, which this file may not do.
 */
.wheelsys-shell.is-enhanced[data-state="collapsed"] .wheelsys-shell__body {
    max-height: 0;
    visibility: hidden;
    /*
     * Collapsing: hold visibility until the movement has finished. Without the delay
     * the content disappears on the first frame and only an empty box animates shut.
     */
    transition: max-height 0.28s ease, visibility 0s linear 0.28s;
}

/* Added by JS. Without it the toggle stays hidden and the shell stays expanded. */
.wheelsys-shell__toggle {
    display: none;
}

/*
 * A tab hanging off the bottom edge of the engine's white panel: icon only, no
 * visible label, in the engine's own line colour with its soft purple shadow. The
 * button's accessible name is on aria-label, set by the script.
 *
 * The engine leaves a 10px margin under its white panel - vendor spacing this file
 * may not restyle - so the script measures it and pulls the tab up by it. The seating
 * is JS because the number is the vendor's and can change; the two shapes below are
 * CSS because they depend only on our own state.
 */
.wheelsys-shell.is-enhanced .wheelsys-shell__toggle {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 72px;
    height: 36px;
    margin: 0 auto;
    padding: 0;
    border: 1px solid var(--wg-purple-line);
    border-radius: 14px;
    background: #fff;
    color: var(--wg-purple);
    cursor: pointer;
    box-shadow: 0 4px 14px rgba(70, 57, 124, 0.10);
    transition: background-color 0.15s ease, box-shadow 0.15s ease, transform 0.15s ease;
}

.wheelsys-shell.is-enhanced .wheelsys-shell__toggle:hover {
    background: var(--wg-purple-tint);
    box-shadow: 0 6px 18px rgba(70, 57, 124, 0.16);
}

.wheelsys-shell.is-enhanced .wheelsys-shell__toggle:active {
    transform: translateY(1px);
}

/*
 * Expanded: the tab is seated against the card, so it continues that card's edge
 * downward - no top border to double the card's own line, and only the bottom
 * corners rounded.
 */
.wheelsys-shell.is-enhanced[data-state="expanded"] .wheelsys-shell__toggle {
    border-top: 0;
    border-radius: 0 0 14px 14px;
}

/*
 * Collapsed: nothing above it and nothing around it, so the tab is the entire widget.
 *
 * It is a card with a field sitting in it - the engine's own arrangement, which is a
 * white panel carrying white bordered inputs. The button is the card: white, lifted,
 * no line of its own. The field inside it is what carries the border. Expanding then
 * reads as that field growing a form around itself rather than being swapped for one.
 *
 * Three earlier shapes, for the record. The same 72x36 chevron box in both states,
 * which on a phone left the whole widget as an unlabelled white square in empty page;
 * then a hugging, centred pill reading "Mietwagen finden"; then a single flat box with
 * the border on the button itself, which read as a wide button with a caption in it -
 * one layer cannot be both the card and the control.
 *
 * ONE DELIBERATE INFIDELITY: the card is lifted. The engine's panel is flat, because
 * it sits on the page's own white. This one sits on a hero photograph, where the
 * shadow is what holds the edge.
 *
 * Capped at 420px rather than filling the column. Full width is right on a phone and
 * wrong on a desktop, where the widget's column would make a 1000px trough holding 18
 * characters of grey text. 420 is also about the width of the engine's own compact
 * sidebar form, so the widget never shows a field wider than one it draws itself.
 *
 * The 14px radius and the 6px padding are chosen together: the field's own 6px radius
 * plus the padding around it equals the card's, so the two curves are concentric. A
 * pill-shaped card cannot hold a 6px field at all - at 24px of radius the field's top
 * corner lands outside the card's curve.
 */
.wheelsys-shell.is-enhanced[data-state="collapsed"] .wheelsys-shell__toggle {
    width: 100%;
    max-width: 420px;
    height: auto;
    gap: 14px;
    padding: 6px;
    border-color: transparent;
    border-radius: 14px;
    justify-content: flex-start;
}

/*
 * The fake field. Everything here is the engine's real .wbeInputContainer: 1px
 * #DCD7EA, 6px radius, white fill, an icon at the leading edge and the prompt beside
 * it. 44px rather than their 46 so the card around it lands on 56 total, and it is the
 * card that has to clear the 44px touch minimum.
 *
 * min-width: 0 so the label's ellipsis can work - a flex item will not shrink below its
 * content width without it, whatever overflow the child declares.
 */
.wheelsys-shell__field {
    display: none;
}

.wheelsys-shell.is-enhanced[data-state="collapsed"] .wheelsys-shell__field {
    display: flex;
    flex: 1 1 auto;
    min-width: 0;
    align-items: center;
    gap: 10px;
    height: 44px;
    padding: 0 14px;
    border: 1px solid var(--wg-purple-line);
    border-radius: 6px;
    background: #fff;
    transition: border-color 0.15s ease;
}

/*
 * Hover darkens the field's line and nothing else - the engine's own hover on these.
 * The tinted fill the expanded tab uses would read as a pressed state on something
 * shaped like an input, and it would fill the card rather than the control.
 */
.wheelsys-shell.is-enhanced[data-state="collapsed"] .wheelsys-shell__toggle:hover {
    background: #fff;
}

.wheelsys-shell.is-enhanced[data-state="collapsed"] .wheelsys-shell__toggle:hover
    .wheelsys-shell__field {
    border-color: var(--wg-purple-line-hover);
}

/*
 * The chevron is the field's sibling, so it sits on the card next to the field and
 * never inside it. Inside, it would make the box a <select>; on the card, it is what
 * it is - the disclosure marker for the whole control.
 *
 * Which is also why it is spaced the way it is. At gap 6 it sat 3.9px off the field and
 * 15px off the card's edge - measured, because a rotated square's bounding box is not
 * where its ink is - and read as part of the field. The separation has to be the larger
 * of the two for it to belong to the card.
 */
.wheelsys-shell.is-enhanced[data-state="collapsed"] .wheelsys-shell__chevron {
    flex: 0 0 auto;
    margin-right: 6px;
    animation: wheelsys-chevron-yoyo 1.8s ease-in-out infinite;
}

/*
 * A 2px yoyo, forever, while the tab is closed - the collapsed card's only moving
 * part, and the only thing on it that says "this opens".
 *
 * IT MOVES `translate`, NOT `transform`. transform on this element is already
 * spoken for: it is the 45deg rotation that makes a square into a chevron, and it is
 * transitioned to -135deg on the state flip. A keyframe touching transform would
 * overwrite the rotation and animate a tilting square. The individual translate
 * property composes with transform instead of replacing it, and because it is applied
 * outside the rotation, 2px is 2px down the screen rather than 2px along the glyph's
 * own tilted axis.
 *
 * 2px against a 10px glyph is deliberately below the threshold where a permanent
 * animation starts to nag; 1.8s is a shade faster than a resting heartbeat. A loop this close
 * to a line of text is a real cost, chosen knowingly on 2026-09-25 over a burst that
 * plays twice and stops. If it ever reads as restless, shrink the amplitude before
 * touching the period - the travel is what the eye catches.
 */
@keyframes wheelsys-chevron-yoyo {
    0%, 100% { translate: 0 0; }
    50%      { translate: 0 2px; }
}

/*
 * The label names the widget, so it is only ever shown when nothing else does.
 * Expanded, the form is right there and this is the 21-character German compound
 * that was removed as noise - see the shortcode in the PHP.
 *
 * font-family: inherit keeps it on the page's own face. This file may not reach into
 * #wheelsbook, so it cannot borrow the engine's, and hard-coding one would be the
 * only typeface in the plugin that answers to nothing.
 */
.wheelsys-shell__label {
    display: none;
}

/*
 * A call to action, not a placeholder: "... jetzt buchen!" in the primary purple at 600.
 * It was the prompt's grey at 400 until 2026-10-20, kept from the days this read
 * "Mietwagen-Abholort"; at 400 it read as a hint, and in grey it still did, so it took
 * the car's purple and the two now read as one mark. Quicksand ships every weight from
 * 300 to 700 on this site, so 600 is a real face, not a synthesised bold.
 */
.wheelsys-shell.is-enhanced[data-state="collapsed"] .wheelsys-shell__label {
    display: block;
    font-family: inherit;
    font-size: 15px;
    font-weight: 600;
    line-height: 1;
    color: var(--wg-purple);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/*
 * The car, shown on the same terms as the label: only when the tab is the whole widget.
 *
 * It is the glyph the sibling widget's "AUTOS" chip uses, and scaleX(-1) is what puts it
 * the same way round - that widget mirrors it too. Matching the direction matters more
 * than it sounds: the two controls sit on the same brand's pages and a car facing the
 * other way reads as a different mark rather than the same one.
 *
 * flex: 0 0 auto so the label's ellipsis can never eat into it. A squeezed car is worse
 * than a truncated word, and the label is the part that can afford to lose a character.
 */
.wheelsys-shell__symbol {
    display: none;
}

.wheelsys-shell.is-enhanced[data-state="collapsed"] .wheelsys-shell__symbol {
    display: block;
    flex: 0 0 auto;
    width: 20px;
    height: 20px;
    transform: scaleX(-1);
}

.wheelsys-shell__toggle:focus-visible {
    outline: 2px solid var(--wg-purple);
    outline-offset: 2px;
}

.wheelsys-shell__chevron {
    width: 10px;
    height: 10px;
    /* Optically centred: a chevron's mass sits above its point. */
    margin-top: -3px;
    border-right: 2px solid currentColor;
    border-bottom: 2px solid currentColor;
    transform: rotate(45deg);
    transition: transform 0.25s ease;
}

.wheelsys-shell[data-state="expanded"] .wheelsys-shell__chevron {
    margin-top: 3px;
    transform: rotate(-135deg);
}

/*
 * Booking views: the engine has left the search form behind, so the page hides
 * around it and the collapse affordance goes away.
 *
 * Applied by JS when the engine's own hash says it has moved past search. The
 * un-sticking that goes with this canNOT live here - Divi writes
 * `position: fixed !important` inline, which outranks any stylesheet rule - so the
 * script removes Divi's inline style and sticky classes instead.
 */
.wheelsys-hidden {
    display: none !important;
}

/* The label reads "open/close the search form"; it is meaningless over a checkout. */
.wheelsys-shell.is-booking .wheelsys-shell__toggle {
    display: none !important;
}

/*
 * Never let a collapse rule clip results or a payment step.
 *
 * `overflow` has to go too, and for a second reason: an ancestor with `overflow: hidden`
 * is the classic `position: sticky` killer. It makes that ancestor the sticky element's
 * scrollport, and since this one never scrolls, nothing inside it can ever stick to the
 * viewport. The theme pins the compact search form with `position: sticky; top: 120px`,
 * and this rule's own `overflow: hidden` - there for the collapse animation - was
 * silently cancelling it: measured on a 7653px Krakow result list, the sidebar tracked
 * the page 1:1 and had scrolled 6969px off the top by the end. Computed position still
 * read `sticky`, which is why it looked fine from the styles alone.
 *
 * Releasing it costs nothing here. Booking views hide the toggle and force max-height to
 * none, so there is no collapse left to clip.
 */
.wheelsys-shell.is-booking .wheelsys-shell__body {
    max-height: none !important;
    visibility: visible !important;
    overflow: visible !important;
}

@media (prefers-reduced-motion: reduce) {
    .wheelsys-shell__body,
    .wheelsys-shell__chevron {
        transition: none;
    }

    /*
     * The yoyo stops completely - a perpetual animation is exactly what this setting
     * is asked for.
     *
     * THE SELECTOR IS REPEATED IN FULL ON PURPOSE. A media query adds no specificity,
     * so `animation: none` on the bare `.wheelsys-shell__chevron` above would lose to
     * the collapsed rule's two classes and attribute and the chevron would keep
     * bobbing. Matching the selector and coming later in the file is what wins.
     */
    .wheelsys-shell.is-enhanced[data-state="collapsed"] .wheelsys-shell__chevron {
        animation: none;
    }
}
