/* Cruise Hub - built by tools/build-css-bundles.php, do not edit. Sources: assets/*.css */

/* search.css */
.hub-cs-search {
    /* Overridden inline (see hub-cruise-search.php) only when the agent explicitly
       picks a color in Cruise Hub → Wygląd. Otherwise every value below is a live
       var() reference into the host theme's own button tokens — never a color
       captured/copied at build time — so it tracks whatever the agent's theme
       actually renders, including if they change themes or repaint their palette
       later. --theme-button-* is Blocksy's (the test site's theme) own semantic
       hook for "what a button looks like"; --wp--preset--color-- is the generic
       block-theme (theme.json) equivalent. Text pairs with its own background
       (button text-on-accent isn't always white — Blocksy's is black), and hover
       is its own separate pair since a theme's hover state is very often not just
       a lighter/darker tint of the base color. */
    --hub-cs-accent: var(--theme-button-background-initial-color, var(--wp--preset--color--primary, #0a6b58));
    --hub-cs-accent-text: var(--theme-button-text-initial-color, #fff);
    --hub-cs-accent-hover: var(--theme-button-background-hover-color, var(--hub-cs-accent));
    --hub-cs-accent-text-hover: var(--theme-button-text-hover-color, var(--hub-cs-accent-text));
    /* Every font-size below is calc(var(--hub-cs-base-font) * ratio) instead of a
       flat rem value — rem is ALWAYS relative to <html>, but Blocksy's own font-size
       customizer never touches <html>, only `body` + its own selector list (via
       --theme-font-size, regenerated live in blocksy-dynamic-global-css.php whenever
       the agent changes the setting). rem therefore silently ignored the customizer
       entirely; this tracks the theme's real, current value instead. Defined once
       here (not per-declaration) so nested elements don't compound multiple relative
       steps into each other the way plain em would. */
    --hub-cs-base-font: var(--theme-font-size, 1rem);
    font-family: inherit;
}

.hub-cs-layout {
    display: flex;
    align-items: flex-start;
    gap: 24px;
}

.hub-cs-sidebar {
    /* +50px per request — .hub-cs-main is flex:1, so widening this automatically
       narrows the listing rows by the same 50px, no separate change needed there. */
    flex: 0 0 290px;
    display: flex;
    flex-direction: column;
    gap: 14px;
    padding: 16px;
    background: #f7f7f7;
    border-radius: 8px;
}

/* Not sticky: with the expanded filter set the sidebar can be taller than the
   viewport, and a stuck (position: sticky) sidebar pins its top edge to the
   viewport while its own bottom portion — last filter options, the Termin
   popup's confirm buttons — scrolls off-screen with no way to reach it. The
   sidebar instead just scrolls up together with the listing cards, like the
   stacked mobile layout below (900px breakpoint) already does. */

.hub-cs-main {
    flex: 1 1 0%;
    min-width: 0;
}

.hub-cs-filter {
    display: flex;
    flex-direction: column;
    gap: 4px;
    font-size: calc(var(--hub-cs-base-font) * 0.8125);
}

.hub-cs-filter label {
    font-weight: 600;
    color: #444;
}

.hub-cs-filter-icon {
    height: 1em;
    width: 1em;
    object-fit: contain;
    vertical-align: -0.15em;
    margin-right: 0.4em;
}

.hub-cs-filter input,
.hub-cs-filter select,
.hub-cs-filter textarea {
    padding: 8px 10px;
    border: 1px solid #ccc;
    border-radius: 5px;
    font-size: calc(var(--hub-cs-base-font) * 0.875);
    width: 100%;
}

/* ---- custom <select> dropdown (see enhanceSelect() in search.js) ----
   The real <select> (.hub-cs-select-native) stays in the DOM as the actual
   form field, just not rendered — its own native option-list popup is the
   browser/OS's own UI and can't be restyled via CSS in any browser, which is
   what made every filter dropdown look like a stock OS control dropped into
   an otherwise custom-designed page. This trigger/popup pair is deliberately
   styled to match .hub-cs-daterange-toggle/-popup exactly (same padding,
   border, radius, shadow) — the Termin field already established this visual
   language for "a custom dropdown in this sidebar", so a plain select dropdown
   reads as the same kind of control, not a third, different-looking one. */
.hub-cs-select {
    position: relative;
}

.hub-cs-select-native {
    display: none;
}

.hub-cs-select-btn {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    width: 100%;
    padding: 8px 10px;
    border: 1px solid #ccc;
    border-radius: 5px;
    background: #fff;
    font-family: inherit;
    font-size: calc(var(--hub-cs-base-font) * 0.875);
    text-align: left;
    color: inherit;
    cursor: pointer;
}

.hub-cs-select-btn span {
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

.hub-cs-select-btn::after {
    /* A real CSS-drawn triangle instead of the Unicode "▾" glyph — a font
       character's rendered size can't be pinned to an exact pixel width via
       font-size (it also varies by font/OS), which is why the old glyph read
       as barely visible regardless of how its font-size was tuned. Border-
       triangle width is exact and independent of any font, and picks up the
       real theme accent instead of a fixed grey. */
    content: '';
    flex: 0 0 auto;
    width: 0;
    height: 0;
    border-left: 5px solid transparent;
    border-right: 5px solid transparent;
    border-top: 6px solid var(--hub-cs-accent);
    transition: transform 0.15s ease;
}

.hub-cs-select-btn.is-open::after {
    transform: rotate(180deg);
}

.hub-cs-select-popup {
    position: absolute;
    z-index: 20;
    top: calc(100% + 4px);
    left: 0;
    width: 100%;
    max-height: 280px;
    overflow-y: auto;
    background: #fff;
    border: 1px solid #ccc;
    border-radius: 8px;
    box-shadow: 0 8px 24px rgba(0, 0, 0, .12);
    padding: 4px;
}

.hub-cs-select-option {
    padding: 7px 10px;
    border-radius: 5px;
    font-size: calc(var(--hub-cs-base-font) * 0.875);
    cursor: pointer;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.hub-cs-select-option:hover,
.hub-cs-select-option.is-active {
    /* Same tint used for the Termin calendar's own day-hover state — one
       consistent "this is the hovered/focused thing in a dropdown" language
       across both custom dropdowns in this sidebar. */
    background: color-mix(in srgb, var(--hub-cs-accent) 25%, #fff);
}

.hub-cs-select-option.is-selected {
    font-weight: 700;
}

.hub-cs-select-option.is-selected::before {
    content: '✓ ';
    color: var(--hub-cs-accent);
}

.hub-cs-filter-operator { position: relative; }
.hub-cs-filter-operator-popup { width: min(620px, calc(100vw - 40px)); max-height: none; overflow: visible; padding: 12px; }
.hub-cs-filter-operator-popup .hub-cs-operator-columns { display: flex; gap: 16px; }
.hub-cs-filter-operator-popup .hub-cs-operator-column { display: flex; max-height: 300px; min-width: 0; flex: 1 1 50%; flex-direction: column; gap: 2px; overflow-y: auto; }
.hub-cs-filter-operator-popup .hub-cs-operator-column-ships { padding-left: 16px; border-left: 1px solid #eee; }
.hub-cs-filter-operator-popup .hub-cs-operator-option { display: block; width: 100%; padding: 7px 8px; border: 0; border-radius: 5px; color: inherit; background: none; font: inherit; text-align: left; cursor: pointer; }
.hub-cs-filter-operator-popup .hub-cs-operator-option:hover { background: color-mix(in srgb, var(--hub-cs-accent) 15%, #fff); }
.hub-cs-filter-operator-popup .hub-cs-operator-option.is-selected { color: var(--hub-cs-accent-text); background: var(--hub-cs-accent); }
.hub-cs-filter-operator-popup .hub-cs-ship-option { display: flex; align-items: center; gap: 8px; padding: 7px 8px; border-radius: 5px; cursor: pointer; }
.hub-cs-filter-operator-popup .hub-cs-ship-option.is-checked { background: color-mix(in srgb, var(--hub-cs-accent) 30%, #fff); font-weight: 600; }
.hub-cs-filter-operator-popup .hub-cs-ship-option input { width: auto; accent-color: var(--hub-cs-accent); }
.hub-cs-filter-operator-popup .hub-cs-operator-ships-empty { margin: 0; padding: 7px 8px; color: #777; }
.hub-cs-filter-operator-popup .hub-cs-operator-search { display: block; width: 100%; box-sizing: border-box; margin: 0 0 10px; padding: 8px 10px; border: 1px solid #ccc; border-radius: 5px; font: inherit; color: inherit; background: #fff; }
.hub-cs-filter-operator-popup .hub-cs-operator-search-results { display: flex; max-height: 300px; flex-direction: column; gap: 2px; overflow-y: auto; }
.hub-cs-filter-operator-popup .hub-cs-operator-search-option { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; width: 100%; padding: 7px 8px; border: 0; border-radius: 5px; color: inherit; background: none; font: inherit; text-align: left; cursor: pointer; }
.hub-cs-filter-operator-popup .hub-cs-operator-search-option:hover { background: color-mix(in srgb, var(--hub-cs-accent) 15%, #fff); }
.hub-cs-filter-operator-popup .hub-cs-operator-search-operator { flex-shrink: 0; font-size: .85em; color: #777; }
/* The columns and the search results swap places; both are display:flex above,
   which would otherwise beat the [hidden] attribute. */
.hub-cs-filter-operator-popup .hub-cs-operator-columns[hidden],
.hub-cs-filter-operator-popup .hub-cs-operator-search-results[hidden] { display: none; }
.hub-cs-filter-operator-popup .hub-cs-daterange-actions { margin-top: 12px; }

@media (max-width: 700px) {
    .hub-cs-filter-operator-popup { position: static; width: 100%; margin-top: 6px; }
    .hub-cs-filter-operator-popup .hub-cs-operator-columns { flex-direction: row; }
}

/* ---- Port wypłynięcia / Port na trasie type-to-filter input (see
   initTypeahead() in search.js) — the suggestion list reuses
   .hub-cs-select-popup/-option's own look (same border/shadow/hover tint) so
   it reads as the same "dropdown suggestions" language as the select-based
   filters above, just triggered by typing instead of a click. */
.hub-cs-typeahead {
    position: relative;
}

/* Styled explicitly to match .hub-cs-daterange-toggle/.hub-cs-select-btn's own
   look (same padding/border/radius/font). Qualified with both the parent
   .hub-cs-typeahead wrapper AND the `input` type (specificity 0-2-1) rather
   than the class alone (0-1-0) — Blocksy's own generic text-input rule is
   `input:is([type=text], [type=email], ...)`, which resolves to 0-1-1 (an
   attribute selector inside :is() counts same as a class), so a bare single
   class here lost to it outright: found live, border/border-radius/padding/
   background were all still the theme's own var(--theme-form-field-*)
   defaults (a much rounder, greyed-out pill) despite this rule's values
   being individually correct. Same fix already used elsewhere in this
   codebase for the identical Blocksy-beats-a-single-class-selector shape
   of bug (see the row-title/row-region margin fix). */
.hub-cs-typeahead input.hub-cs-typeahead-input {
    display: block;
    box-sizing: border-box;
    /* Blocksy's own input:is([type=text], ...) rule (the one this whole
       selector exists to beat, see the comment above) also sets a fixed
       height: var(--theme-form-field-height, 40px) — a property this rule
       never used to touch at all, so it kept applying even after border/
       radius/padding/background here started winning. The result: same
       padding value on paper, but a shorter, more cramped-looking box than
       every sibling field here, all of which are <button>s the theme's
       input-only rule never touches and so size themselves purely from
       their own padding + line-height (found live: still visibly shorter
       after the first specificity fix, next to Kierunek/Termin/Armator). */
    height: auto;
    width: 100%;
    padding: 8px 10px;
    border: 1px solid #ccc;
    border-radius: 5px;
    font-family: inherit;
    font-size: calc(var(--hub-cs-base-font) * 0.875);
    background: #fff;
    color: inherit;
}

.hub-cs-typeahead-suggestions {
    position: absolute;
    z-index: 20;
    top: calc(100% + 4px);
    left: 0;
    width: 100%;
    max-height: 240px;
    overflow-y: auto;
    background: #fff;
    border: 1px solid #ccc;
    border-radius: 8px;
    box-shadow: 0 8px 24px rgba(0, 0, 0, .12);
    padding: 4px;
}

.hub-cs-typeahead-option {
    display: block;
    width: 100%;
    padding: 7px 10px;
    border: 0;
    border-radius: 5px;
    background: none;
    font-family: inherit;
    font-size: calc(var(--hub-cs-base-font) * 0.875);
    text-align: left;
    color: inherit;
    cursor: pointer;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.hub-cs-typeahead-option:hover {
    background: color-mix(in srgb, var(--hub-cs-accent) 25%, #fff);
}

/* Port typeaheads: a country row ("Włochy · 12 portów") above the ports, the
   port's own country in grey on the right, and a heading over one country's
   list (assets/port-countries.js). */
.hub-cs-typeahead-option:has(.hub-cs-typeahead-option-meta) {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px;
}

.hub-cs-typeahead-option-name {
    overflow: hidden;
    text-overflow: ellipsis;
}

.hub-cs-typeahead-option-meta {
    flex-shrink: 0;
    font-size: .85em;
    color: #777;
}

.hub-cs-typeahead-country {
    font-weight: 600;
}

.hub-cs-typeahead-country::before {
    content: "";
    display: inline-block;
    width: 1em;
    height: 1em;
    margin-right: 6px;
    vertical-align: -0.15em;
    background: currentColor;
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M3 12h18M12 3a14 14 0 0 1 0 18M12 3a14 14 0 0 0 0 18'/%3E%3C/svg%3E") center / contain no-repeat;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M3 12h18M12 3a14 14 0 0 1 0 18M12 3a14 14 0 0 0 0 18'/%3E%3C/svg%3E") center / contain no-repeat;
}

.hub-cs-typeahead-country + .hub-cs-typeahead-option:not(.hub-cs-typeahead-country) {
    margin-top: 4px;
    border-top: 1px solid #eee;
    border-radius: 0 0 5px 5px;
}

.hub-cs-typeahead-all {
    font-weight: 600;
    color: var(--hub-cs-accent);
    border-bottom: 1px solid #eee;
    border-radius: 5px 5px 0 0;
    margin-bottom: 4px;
}

.hub-cs-typeahead-heading {
    padding: 6px 10px 4px;
    font-size: calc(var(--hub-cs-base-font) * 0.75);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: #777;
}

/* Multi-port refinement used only by "Port na trasie". Selected ports remain
   directly under the input as compact removable chips, so the current AND
   criteria are visible without reopening anything. */
.hub-cs-route-port-multi .hub-cs-typeahead-suggestions {
    position: relative;
    top: auto;
    margin-top: 4px;
}

.hub-cs-modal-open {
    overflow: hidden;
}

.hub-cs-route-port-backdrop {
    position: fixed;
    z-index: 999998;
    inset: 0;
    background: rgba(15, 31, 48, .46);
}

.hub-cs-route-port-modal {
    position: fixed;
    z-index: 999999;
    top: 50%;
    left: 50%;
    width: min(820px, calc(100vw - 32px));
    max-height: min(680px, calc(100vh - 32px));
    overflow: auto;
    transform: translate(-50%, -50%);
    border: 1px solid var(--theme-border-color, #d8dee5);
    border-radius: 16px;
    background: #fff;
    box-shadow: 0 24px 70px rgba(15, 31, 48, .24);
    color: var(--theme-text-color, inherit);
}

.hub-cs-route-port-backdrop[hidden],
.hub-cs-route-port-modal[hidden] {
    display: none !important;
}

.hub-cs-route-port-modal-head,
.hub-cs-route-port-modal-actions,
.hub-cs-route-port-selected-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
}

.hub-cs-route-port-modal-head {
    padding: 20px 22px;
    border-bottom: 1px solid var(--theme-border-color, #d8dee5);
}

.hub-cs-route-port-modal-head strong {
    display: block;
    color: var(--theme-heading-color, inherit);
    font-size: 1.2em;
}

.hub-cs-route-port-modal-head span {
    display: block;
    margin-top: 3px;
    opacity: .72;
    font-size: .82em;
}

.hub-cs-route-port-modal-head > button {
    flex: 0 0 44px;
    width: 44px;
    height: 44px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: var(--theme-palette-color-6, #f2f5f7);
    color: inherit;
    font: inherit;
    font-size: 24px;
    cursor: pointer;
}

.hub-cs-route-port-modal-columns {
    display: grid;
    grid-template-columns: minmax(0, 1.08fr) minmax(260px, .92fr);
    min-height: 350px;
}

.hub-cs-route-port-modal-column {
    padding: 22px;
}

.hub-cs-route-port-modal-column + .hub-cs-route-port-modal-column {
    border-left: 1px solid var(--theme-border-color, #d8dee5);
    background: var(--theme-palette-color-7, #fafbfc);
}

.hub-cs-route-port-modal-selected > div:last-child {
    display: grid;
    gap: 7px;
    margin-top: 12px;
}

.hub-cs-route-port-selected-head span {
    opacity: .7;
    font-size: .78em;
}

.hub-cs-route-port-selected-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    min-height: 40px;
    padding: 3px 5px 3px 11px;
    border: 1px solid var(--theme-border-color, #d8dee5);
    border-radius: 8px;
    background: #fff;
    font-size: .84em;
}

/* "Port wypłynięcia" window (search.js initEmbarkRegionPorts): a Kierunek's ports in columns. */
.hub-cs-embark-modal {
    width: min(640px, calc(100vw - 32px));
}

.hub-cs-embark-modal-body {
    padding: 14px 18px;
}

.hub-cs-embark-modal-body > input[type="search"] {
    width: 100%;
    margin-bottom: 10px;
}

.hub-cs-embark-modal-list {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(170px, 1fr));
    gap: 2px 10px;
    max-height: 50vh;
    overflow: auto;
}

.hub-cs-embark-modal-list .hub-cs-typeahead-option {
    white-space: normal;
}

.hub-cs-embark-modal-list .hub-cs-typeahead-option.is-picked {
    background: color-mix(in srgb, var(--hub-cs-accent) 25%, #fff);
    font-weight: 600;
}

.hub-cs-embark-modal-empty {
    margin: 6px 0;
    opacity: .75;
}

.hub-cs-typeahead.is-region-limited .hub-cs-typeahead-input {
    cursor: pointer;
}

.hub-cs-route-port-modal-actions {
    padding: 15px 22px;
    border-top: 1px solid var(--theme-border-color, #d8dee5);
}

@media (max-width: 640px) {
    .hub-cs-route-port-modal {
        width: calc(100vw - 20px);
        max-height: calc(100vh - 20px);
        border-radius: 12px;
    }

    .hub-cs-route-port-modal-head,
    .hub-cs-route-port-modal-column,
    .hub-cs-route-port-modal-actions {
        padding: 16px;
    }

    .hub-cs-route-port-modal-columns {
        grid-template-columns: 1fr;
        min-height: 0;
    }

    .hub-cs-route-port-modal-column + .hub-cs-route-port-modal-column {
        border-top: 1px solid var(--theme-border-color, #d8dee5);
        border-left: 0;
    }
}

.hub-cs-route-port-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 7px;
}

.hub-cs-route-port-chips[hidden],
.hub-cs-route-port-limit[hidden] {
    display: none !important;
}

.hub-cs-route-port-chip {
    display: inline-flex;
    align-items: center;
    max-width: 100%;
    min-height: 30px;
    padding: 2px 3px 2px 9px;
    border: 1px solid color-mix(in srgb, var(--hub-cs-accent) 42%, #d8dee5);
    border-radius: 999px;
    background: color-mix(in srgb, var(--hub-cs-accent) 10%, #fff);
    font-size: calc(var(--hub-cs-base-font) * 0.75);
    line-height: 1.25;
}

.hub-cs-route-port-chip-label {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.hub-cs-route-port-remove {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 26px;
    width: 26px;
    height: 26px;
    margin-left: 3px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: transparent;
    color: inherit;
    font: inherit;
    font-size: 18px;
    line-height: 1;
    cursor: pointer;
}

.hub-cs-route-port-remove:hover,
.hub-cs-route-port-remove:focus-visible {
    background: color-mix(in srgb, var(--hub-cs-accent) 24%, #fff);
    outline: none;
}

.hub-cs-route-port-limit {
    margin: 6px 0 0;
    color: #b42318;
    font-size: calc(var(--hub-cs-base-font) * 0.75);
}

.hub-cs-filter-checkbox label {
    display: flex;
    align-items: center;
    gap: 6px;
    font-weight: 400;
    color: #333;
    cursor: pointer;
}

.hub-cs-filter-checkbox input[type="checkbox"] {
    width: auto;
    padding: 0;
}

/* Subregion "sorter" — see initSubregionSorter() in search.js. Options list
   has the same look as the polski pilot checkbox right below it (plain
   label/input pairs, no boxed input), on purpose: a radio list here reads as
   a lightweight in-page refinement, not another dropdown-style filter
   competing with Kierunek. */
.hub-cs-subregion {
    /* The divider belongs to this whole block (not just the options list) so
       it sits right before the sidebar's own 14px gap to whichever filter
       comes next — reading as "end of the subregion group", not a line stuck
       mid-way through it. */
    padding-bottom: 14px;
    border-bottom: 2px solid color-mix(in srgb, var(--hub-cs-accent) 55%, transparent);
}

/* A plain `display` declaration on a class always beats the UA stylesheet's
   `[hidden] { display: none }` (author origin wins ties regardless of
   specificity) — .hub-cs-subregion also carries .hub-cs-filter, whose own
   unconditional `display: flex` was winning that tie, so the chip + divider
   above kept rendering (empty label, but still a solid-colored pill and
   line) even with the `hidden` attribute set and no region chosen. Same bug,
   same fix, as .hub-cs-daterange-popup[hidden] above. */
.hub-cs-subregion[hidden] {
    display: none;
}

.hub-cs-subregion .hub-cs-subregion-label {
    /* Same pill treatment as the region badge on listing cards
       (.hub-cs-row-region) — rounded, solid theme-accent background, real
       button-pair colors, not invented ones. Two-class selector on purpose:
       .hub-cs-filter label (0,1,1) otherwise beats a single-class
       .hub-cs-subregion-label (0,1,0) regardless of source order and keeps
       its own plain color:#444. */
    display: inline-flex;
    align-items: center;
    margin: 0 0 8px;
    padding: 3px 12px;
    border-radius: 999px;
    background: var(--hub-cs-accent);
    color: var(--hub-cs-accent-text);
    font-size: calc(var(--hub-cs-base-font) * 0.75);
    font-weight: 600;
}

.hub-cs-subregion-options {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.hub-cs-subregion-option {
    display: flex;
    align-items: center;
    gap: 6px;
    /* Same ratio as .hub-cs-row-ship (the ship-name line on listing cards), per
       request. Set explicitly rather than left to inherit from .hub-cs-filter's
       own font-size — a <label> wrapping a form control doesn't reliably
       inherit font-size the way plain text does in every browser, which is
       what actually caused this to fall back to a UA default here despite
       .hub-cs-filter already declaring the same ratio one level up.  */
    font-size: calc(var(--hub-cs-base-font) * 0.8125);
    font-weight: 400;
    color: #333;
    cursor: pointer;
}

.hub-cs-subregion-option input[type="radio"] {
    width: auto;
}

.hub-cs-filter-actions {
    display: flex;
    gap: 8px;
    margin-top: 4px;
}

/* Mobile/tablet filter drawer chrome — all of this is a no-op above 900px
   (see the max-width: 900px block near the bottom for the actual drawer
   behavior): the sidebar is never off-canvas at desktop, so its close
   button/backdrop/the Filtruj pill have nothing to do there. Hidden here at
   the base level (not just left unstyled) so they can never flash visible
   before the mobile rules load, and so nothing here has to also be undone
   in a min-width: 901px override. */
.hub-cs-filter-backdrop,
.hub-cs-sidebar-close,
.hub-cs-pill-btn {
    display: none;
}

.hub-cs-daterange {
    position: relative;
}

.hub-cs-daterange-toggle {
    display: block;
    width: 100%;
    padding: 8px 10px;
    border: 1px solid #ccc;
    border-radius: 5px;
    font-size: calc(var(--hub-cs-base-font) * 0.875);
    text-align: left;
    background: #fff;
    cursor: pointer;
    color: inherit;
}

.hub-cs-daterange-popup {
    position: absolute;
    z-index: 20;
    top: 0;
    /* Opens rightward into the results column rather than downward over the narrow
       240px sidebar — a two-month calendar needs more width than the sidebar has. */
    left: 100%;
    margin-left: 10px;
    width: max-content;
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding: 14px;
    background: #fff;
    border: 1px solid #ccc;
    border-radius: 8px;
    box-shadow: 0 8px 24px rgba(0, 0, 0, .12);
}

/* A plain `display` declaration on a class always beats the UA stylesheet's
   `[hidden] { display: none }` (author origin wins ties regardless of specificity),
   so toggling the `hidden` attribute from JS silently did nothing on its own — this
   rule's higher specificity (class + attribute) is what actually makes it take
   effect. Found live: the popup stayed visible after Zastosuj despite `hidden` being
   set, because nothing was overriding the unconditional `display: flex` above. */
.hub-cs-daterange-popup[hidden] {
    display: none;
}

.hub-cs-daterange-actions {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
    margin-top: 2px;
}

.hub-cs-calendar-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
}

.hub-cs-calendar-nav {
    width: 26px;
    height: 26px;
    border: 1px solid #ccc;
    border-radius: 4px;
    background: #fff;
    cursor: pointer;
    font-size: calc(var(--hub-cs-base-font) * 0.875);
    line-height: 1;
    padding: 0;
}

.hub-cs-calendar-months {
    display: flex;
    gap: 18px;
}

.hub-cs-calendar-month {
    width: 200px;
}

.hub-cs-calendar-month-title {
    text-align: center;
    font-weight: 600;
    font-size: calc(var(--hub-cs-base-font) * 0.8125);
    margin-bottom: 6px;
    text-transform: capitalize;
}

.hub-cs-calendar-weekdays {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    font-size: calc(var(--hub-cs-base-font) * 0.6875);
    color: #888;
    text-align: center;
    margin-bottom: 4px;
}

.hub-cs-calendar-days {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 2px;
}

.hub-cs-calendar-day {
    aspect-ratio: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: calc(var(--hub-cs-base-font) * 0.75);
    border: none;
    border-radius: 4px;
    background: none;
    color: inherit;
    cursor: pointer;
    padding: 0;
}

.hub-cs-calendar-day.is-empty {
    visibility: hidden;
    cursor: default;
}

.hub-cs-calendar-day:disabled {
    color: #ccc;
    cursor: default;
}

.hub-cs-calendar-day:hover:not(:disabled):not(.is-selected) {
    background: color-mix(in srgb, var(--hub-cs-accent) 25%, #fff);
}

.hub-cs-calendar-day.is-selected {
    background: var(--hub-cs-accent);
    color: var(--hub-cs-accent-text);
    font-weight: 700;
}

.hub-cs-calendar-day.is-in-range {
    background: color-mix(in srgb, var(--hub-cs-accent) 15%, #fff);
    border-radius: 0;
}

@media (max-width: 600px) {
    .hub-cs-daterange-popup {
        left: 0;
        top: calc(100% + 6px);
        margin-left: 0;
        width: 260px;
    }

    .hub-cs-calendar-months {
        flex-direction: column;
        gap: 14px;
    }

    .hub-cs-calendar-month {
        width: 100%;
    }
}

.hub-cs-btn {
    padding: 9px 18px;
    border-radius: 5px;
    border: 1px solid #ccc;
    background: #fff;
    cursor: pointer;
    /* Same reasoning as --hub-cs-accent: a real theme button's own font-size,
       not a guess. Found live (not by design): a plain <button> stayed at the
       0.875rem fallback while <button type="submit"> escaped to Blocksy's real
       --theme-button-font-size, purely because [type="submit"] happened to win a
       CSS specificity tie — i.e. the "wrong" one was accidentally the properly
       inherited one. Made deliberate and consistent for every button here instead
       of leaving it up to a selector-specificity coincidence. */
    font-size: var(--theme-button-font-size, 0.875rem);
}

.hub-cs-btn-primary {
    background: var(--hub-cs-accent);
    border-color: var(--hub-cs-accent);
    color: var(--hub-cs-accent-text);
}

.hub-cs-btn-primary:hover {
    background: var(--hub-cs-accent-hover);
    border-color: var(--hub-cs-accent-hover);
    color: var(--hub-cs-accent-text-hover);
}

.hub-cs-toolbar {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 14px;
    margin-bottom: 16px;
}

/* display: contents at desktop — a transparent wrapper so Sortuj (its only
   child there, .hub-cs-pill-btn stays display: none) lays out exactly as if
   this div weren't there at all. Mobile/tablet override this to a real flex
   row of two matched pill buttons — see the max-width: 900px block. */
.hub-cs-toolbar-actions {
    display: contents;
}

.hub-cs-sort {
    flex: 0 0 220px;
}

.hub-cs-status {
    color: #555;
    font-size: calc(var(--hub-cs-base-font) * 0.875);
}

.hub-cs-list {
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.hub-cs-row {
    display: flex;
    align-items: stretch;
    /* Back to the original 250px — 270px was a guess made without live
       verification and turned out unnecessary once the image sizing below
       stopped ballooning its own width (see that rule's comment). */
    height: 250px;
    border: 1px solid #e2e2e2;
    border-radius: 8px;
    overflow: hidden;
    text-decoration: none;
    color: inherit;
    background: #fff;
    transition: box-shadow 0.15s ease;
}

.hub-cs-row:hover {
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.08);
}

.hub-cs-row-image {
    /* Fixed WIDTH now (was flex: 0 0 auto, letting aspect-ratio derive width
       from the row's stretched height) — at 16/9 that meant a much wider
       image than 4/3 used to produce at the same 250px height (~444px vs
       333px), which starved .hub-cs-row-body's own width badly enough that
       its title/route/fact-boxes rendered cramped (found live via
       screenshot: "everything looks tiny"). A fixed width sidesteps that —
       .hub-cs-row's own align-items: stretch still stretches this element's
       HEIGHT to the row's 250px regardless (flex-basis only ever set WIDTH
       in a row-direction flex container), and object-fit: cover on the real
       <img> below crops to fill whatever box results, so aspect-ratio is
       still doing real work here — just for MOBILE, where .hub-cs-row
       switches to flex-direction: column and flex-basis: auto (see that
       media query) flips this into controlling HEIGHT instead, at which
       point aspect-ratio is what makes a full-width mobile thumbnail read
       as 16:9 rather than some arbitrary intrinsic size. */
    position: relative;
    flex: 0 0 380px;
    aspect-ratio: 16 / 9;
    background: #eee;
    overflow: hidden;
}

.hub-cs-row-image img:not(.hub-cs-row-image-logo) {
    /* :not() excludes the logo overlay — it's also a direct <img> child of
       .hub-cs-row-image, so a plain `.hub-cs-row-image img` selector matched both
       and this rule (declared first, same specificity) was winning the tie,
       stretching the logo to fill the whole photo box instead of a small corner
       badge — found live via screenshot, not obvious from source. */
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.hub-cs-row-image-logo {
    position: absolute;
    top: 3px;
    left: 3px;
    width: 25%;
    height: auto;
    border-radius: 3px;
}

.hub-cs-row-body {
    flex: 1 1 0%;
    min-width: 0;
    min-height: 0;
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 14px 18px;
    overflow: hidden;
}

/* +10% of the date line's own font-size — still used by the admin picker's
   own compact date line (renderPickerCard()'s buildDateLine() call), even
   though this listing row moved to fact boxes below and no longer needs it
   itself. */
.hub-cs-date-icon {
    height: 1.1em;
    width: auto;
    vertical-align: -0.15em;
    margin-right: 0.35em;
}

.hub-cs-row-body .hub-cs-row-title {
    /* No font-size/color here on purpose — it's a real <h3>. A class-scoped rule
       here would have HIGHER specificity than the theme's own bare `h3 {...}`
       rule and would beat it, silently overriding the theme's real heading
       size/color (found live, back when this was h2: a 1.25x-ratio "fix" here
       was itself still blocking real inheritance, just with a friendlier-
       looking wrong value instead of an obviously wrong one). Leaving these
       unset lets the theme's own heading CSS win outright. */
    flex-shrink: 0;
    margin: 0;
    /* Blocksy sets margin-block-end (a logical property, not margin-bottom) on
       every heading via a selector whose real specificity ties this rule's own —
       same bug found on .hub-cs-row-region-chip, same fix: qualify with the
       actual parent to break the tie, and target the exact same logical
       property name. */
    margin-block-end: 0;
    line-height: 1.25;
    /* Reserves the full 2-line height regardless of whether THIS title actually
       wraps to 2 lines — without it, a 1-line title left the fact boxes below
       sitting higher than in a neighboring mobile-slider card whose title
       wrapped further (same alignment bug already found and fixed on
       [hub_boxy]'s card). */
    min-height: 2.5em;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.hub-cs-row-route {
    /* Sized to match .hub-cs-row-ship's font (per request) rather than the real
       theme <p> size — confirmed live that the real size DOES genuinely inherit
       correctly (identical font-size/line-height/color to a real theme paragraph),
       this is a deliberate visual-consistency choice, not a fallback for a broken
       inheritance. */
    font-size: calc(var(--hub-cs-base-font) * 0.8125);
    line-height: 1.4;
    flex-shrink: 0;
    margin: 0;
    /* Same reservation as the title above, same reason. */
    min-height: 2.8em;
    display: -webkit-box;
    /* Reduced from 4 to 2 lines — the redesigned card shows a region chip and
       three fact boxes below this, which a 4-line route no longer leaves room
       for at this row's height; a long route now trims visually the same way
       [hub_boxy]'s card's does (2-line clamp, ellipsis only past that). */
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.hub-cs-route-port {
    /* No color anywhere here on purpose (per request: bold, no accent) — stays
       whatever color this <p> already has, only weight/scale move. inline-block
       + transform (not a dot marker) is what actually moved smoothly live — the
       earlier absolutely-positioned dot needed live position measurement and
       came out misaligned/jumpy instead of gliding under the text. */
    display: inline-block;
    transform-origin: center bottom;
    transition: transform 0.35s ease, opacity 0.35s ease;
}

.hub-cs-route-port.is-active {
    font-weight: 700;
    transform: scale(1.12);
}

.hub-cs-route-port.is-trail {
    /* Fades via opacity rather than a color mix, so it stays accent-free too. */
    opacity: 0.55;
}

@media (prefers-reduced-motion: reduce) {
    .hub-cs-route-port {
        transition: none;
    }
}

.hub-cs-row-region-chip {
    /* A category-pill badge (matching the theme's own blog category pill
       style: rounded, solid background) reads as a tag/label, not body-of-
       text content — unlike the plain-text real headings elsewhere in this
       plugin, a badge is expected to have its own compact size, so unlike
       those this one DOES set font-size deliberately. Colors still aren't
       invented: background/text are the same var(--hub-cs-accent)/
       var(--hub-cs-accent-text) pair the theme's own buttons resolve to. A
       <span>, not a heading, so none of the Blocksy margin-tie footguns
       documented on .hub-cs-row-title/.hub-cs-row-price-value apply here. */
    align-self: flex-start;
    flex-shrink: 0;
    padding: 3px 12px;
    border-radius: 999px;
    background: var(--hub-cs-accent);
    color: var(--hub-cs-accent-text);
    font-size: calc(var(--hub-cs-base-font) * 0.75);
    line-height: 1.4;
    font-weight: 600;
}

/* Region + transport chips in one line, same pill style for both. */
.hub-cs-row-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    flex-shrink: 0;
}

/* Same equal-width-columns approach as [hub_boxy]'s own fact boxes
   (Hub_CS_Offer_Card_Renderer/boxes.css) — CSS Grid with minmax(0, 1fr) on
   the OD/DO tracks, not flex, because a flex item's default min-width: auto
   would otherwise size each date box off its OWN text ("23.09.2026" wider
   than "5.09.2026") instead of matching its sibling. Duplicated rather than
   shared across search.css/boxes.css since those are independently loaded
   stylesheets for two different shortcodes (same reasoning as every other
   search.js/frontsearch.js duplication in this codebase). */
.hub-cs-row-facts {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) minmax(0, 1fr);
    gap: 8px;
    flex-shrink: 0;
    /* .hub-cs-row-body has no justify-content, so any height the fixed
       250px row leaves unused past title+route+chip's own natural size
       was just collecting as dead space AFTER this, the last child (found
       live via screenshot: a big gap under the fact boxes, and — same
       symptom, same cause — too little visual separation between the
       region chip and this row, since 6px was true everywhere). margin-top:
       auto claims all of that leftover space for itself instead, pushing
       this row flush to the body's bottom edge and turning the slack into
       breathing room right above it. */
    margin-top: auto;
}

.hub-cs-row-fact {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    padding: 4px 8px;
    border: 1.5px solid var(--hub-cs-accent);
    border-radius: 8px;
    text-align: center;
    min-width: 0;
    /* Safety net: minmax(0, 1fr) above deliberately allows this box to
       shrink narrower than its own date text's natural width (that's what
       makes the two date boxes match each other) — this clips instead of
       letting the text spill past the border on a narrow mobile-slider card. */
    overflow: hidden;
}

.hub-cs-row-fact span {
    font-size: 0.6875rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: #888;
}

.hub-cs-row-fact b {
    font-size: 0.8125rem;
    white-space: nowrap;
}

.hub-cs-row-fact-nights {
    min-width: 50px;
}

.hub-cs-row-fact-nights b {
    font-size: 1.125rem;
    line-height: 1.1;
}

.hub-cs-row-side {
    flex: 0 0 190px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 10px;
    padding: 14px 18px;
    border-left: 1px solid #eee;
    text-align: center;
}

/* Icon above the name (same treatment as [hub_boxy]'s own card), centered —
   align-self: stretch on the name span below is what still gives it a
   definite width to ellipsize against despite the column's align-items:
   center (which sizes the icon to its own content, exactly as intended). */
.hub-cs-row-ship {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    max-width: 100%;
    font-size: calc(var(--hub-cs-base-font) * 0.8125);
}

.hub-cs-row-ship img {
    height: 2.2em;
    width: auto;
}

.hub-cs-row-ship-name {
    align-self: stretch;
    min-width: 0;
    font-weight: 700;
    /* Explicit, not theme-derived — see the matching, live-verified comment on
       [hub_boxy]'s own .hub-cs-box-card-ship-name in boxes.css: this site's
       real --theme-link-initial-color resolves to black, not blue. */
    color: #004aad;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.hub-cs-row-price {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2px;
}

.hub-cs-row-price .hub-cs-row-price-value {
    /* No font-size here — real h3, theme's own size wins outright, full stop.
       margin-block-start/end set explicitly (not just margin:0) and the selector
       qualified with its parent for extra specificity — same fix as
       .hub-cs-row-title: Blocksy's own heading rule sets these as logical
       properties on every h1-h6, which tie in specificity with a bare margin:0
       here and (loaded later) win, padding the price out with extra space
       above/below. */
    margin-block-start: 0;
    margin-block-end: 0;
    margin: 0;
}

.hub-cs-row-price-eur {
    font-size: 0.8125rem;
    color: #767676;
}

.hub-cs-row-cta {
    /* Can't be a real <button>/<a> — it already sits inside .hub-cs-row's own <a>,
       and nesting interactive content inside interactive content is invalid HTML.
       A real button-sized/-shaped block now (per the reference card design),
       not the small text link this used to be. */
    padding: 10px 22px;
    border-radius: 8px;
    font-weight: 700;
    font-size: calc(var(--hub-cs-base-font) * 0.8125);
    color: var(--hub-cs-accent-text);
    background: var(--hub-cs-accent);
    white-space: nowrap;
}

.hub-cs-row:hover .hub-cs-row-cta {
    background: var(--hub-cs-accent-hover);
    color: var(--hub-cs-accent-text-hover);
}

.hub-cs-pagination {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 20px;
}

.hub-cs-page-btn {
    padding: 6px 12px;
    border: 1px solid #ccc;
    border-radius: 4px;
    background: #fff;
    cursor: pointer;
    font-size: var(--theme-button-font-size, 0.875rem);
}

.hub-cs-page-btn.is-active {
    background: var(--hub-cs-accent);
    border-color: var(--hub-cs-accent);
    color: var(--hub-cs-accent-text);
}

.hub-cs-page-btn:disabled {
    cursor: default;
    opacity: .4;
}

.hub-cs-page-ellipsis {
    padding: 6px 4px;
    color: #999;
}

@media (max-width: 900px) {
    body.hub-cs-filter-drawer-open { overflow: hidden; }
    .hub-cs-layout {
        flex-direction: column;
    }

    /* .hub-cs-layout has align-items: flex-start (correct at desktop, where
       the cross axis is height and the sidebar/results column genuinely
       shouldn't stretch to match each other's height) — flex-direction:
       column above flips the cross axis to WIDTH, and flex-start on that
       axis means "don't stretch," so without an explicit width here this
       element sized itself off its own content's natural/preferred width
       instead of the viewport (confirmed live via an on-page measurement:
       3400px rendered width at a 402px viewport — the .hub-cs-boxes-grid
       slider's own width: 100% inside it was correctly computed, just
       against this wrong, unconstrained 3400px basis). .hub-cs-sidebar
       right below already has its own explicit width: 100% for the exact
       same reason — this was the one part of that fix that got missed. */
    .hub-cs-main {
        width: 100%;
    }

    /* Sidebar becomes an off-canvas drawer, not an inline wrapped row of
       filters (that was this rule's previous behavior) — opened via the
       Filtruj pill below, closed via the X inside it
       (data-hub-cs-filter-close), the backdrop, or submitting the form (see
       search.js). translateX (not display: none) so the slide transition
       has something to animate — width itself is set per-breakpoint further
       down (100% phone, 50% tablet, per request), not here. */
    .hub-cs-sidebar {
        position: fixed;
        top: 0;
        left: 0;
        bottom: 0;
        z-index: 2147483000;
        flex-basis: auto;
        flex-wrap: nowrap;
        overflow-y: auto;
        border-radius: 0;
        transform: translateX(-100%);
        transition: transform 0.25s ease;
        box-shadow: 4px 0 24px rgba(0, 0, 0, 0.18);
    }

    .hub-cs-search.is-filter-open .hub-cs-sidebar {
        transform: translateX(0);
    }

    .hub-cs-sidebar-close {
        display: flex;
        align-self: flex-end;
        align-items: center;
        justify-content: center;
        width: 32px;
        height: 32px;
        margin-bottom: 4px;
        border: none;
        border-radius: 999px;
        background: #ececec;
        color: inherit;
        font-size: 20px;
        line-height: 1;
        cursor: pointer;
    }

    .hub-cs-search.is-filter-open .hub-cs-filter-backdrop {
        display: block;
        position: fixed;
        inset: 0;
        z-index: 2147482999;
        background: rgba(0, 0, 0, 0.4);
    }

    /* Sortuj's own trigger (built by enhanceSelect(), see search.js) restyled
       to match the Filtruj pill right next to it — a leading icon via
       ::before (this select's own ::after triangle is hidden, redundant
       next to a fixed "Sortuj" label that never shows the live value, see
       updateLabel()'s data-hub-cs-static-label branch) rather than the
       left-aligned dropdown-with-current-value look this same class has at
       every OTHER field. */
    .hub-cs-toolbar-actions {
        display: flex;
        gap: 10px;
        width: 100%;
    }

    .hub-cs-pill-btn,
    .hub-cs-sort {
        flex: 1 1 0%;
    }

    .hub-cs-pill-btn {
        display: flex;
        align-items: center;
        justify-content: center;
        gap: 6px;
        padding: 9px 14px;
        border: 1px solid #ccc;
        border-radius: 999px;
        background: #fff;
        font-family: inherit;
        font-size: calc(var(--hub-cs-base-font) * 0.875);
        font-weight: 600;
        color: inherit;
        cursor: pointer;
    }

    .hub-cs-sort label {
        display: none;
    }

    .hub-cs-sort .hub-cs-select-btn {
        justify-content: center;
        border-radius: 999px;
        font-weight: 600;
    }

    .hub-cs-sort .hub-cs-select-btn::before {
        content: '⇅';
    }

    .hub-cs-sort .hub-cs-select-btn::after {
        display: none;
    }

    /* No .hub-cs-row/.hub-cs-list mobile rules here anymore — <=900px never
       renders either of those anymore. search.js's renderResults() switches
       to renderBoxStyleCard() and the results container's class to
       .hub-cs-boxes-grid at this same breakpoint (mobileCardsMql), so the
       mobile slider comes entirely from boxes.css's own .hub-cs-boxes-grid
       rules — see that file, and renderBoxStyleCard()'s comment in
       search.js for why a reflow of THIS shape was never going to produce
       [hub_boxy]'s card. */
}

/* Tablet: drawer opens to half the screen width. */
@media (min-width: 601px) and (max-width: 900px) {
    .hub-cs-sidebar {
        width: 50%;
    }
}

@media (max-width: 600px) {
    .hub-cs-toolbar {
        flex-direction: column;
        align-items: stretch;
    }

    /* Phone: drawer opens to the full screen width. */
    .hub-cs-sidebar {
        width: 100%;
    }
}

/* "Szukaj opisowo" (natural-language search) — a fixed tab at the right edge of the
   viewport, visible at EVERY breakpoint. Deliberately not .hub-cs-pill-btn (that
   class is display:none above 900px, base rule near the top of this file, because
   its target — the sidebar — is already shown inline on desktop and the pill has
   nothing to toggle there); this drawer has no "always visible inline" desktop
   equivalent, so its trigger stays visible everywhere. The drawer itself reuses the
   same off-canvas translateX() slide technique as .hub-cs-sidebar's own mobile
   drawer (max-width: 900px block above), just mirrored to the right. */
html.hub-cs-modal-open {
    overflow: hidden;
}

.hub-cs-nlp-tab {
    position: fixed;
    right: 0;
    top: 50%;
    transform: translateY(-50%);
    z-index: 2147481000;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    padding: 14px 8px;
    border: none;
    border-radius: 8px 0 0 8px;
    background: var(--hub-cs-accent);
    color: var(--hub-cs-accent-text);
    cursor: pointer;
    box-shadow: -2px 2px 10px rgba(0, 0, 0, 0.18);
    writing-mode: vertical-rl;
    text-orientation: mixed;
    font: inherit;
    font-size: calc(var(--hub-cs-base-font) * 0.85);
}

.hub-cs-nlp-tab:hover {
    background: var(--hub-cs-accent-hover);
    color: var(--hub-cs-accent-text-hover);
}

.hub-cs-nlp-tab svg {
    transform: rotate(90deg);
}

.hub-cs-nlp-drawer {
    position: fixed;
    inset: 0;
    z-index: 2147483000;
}

.hub-cs-nlp-drawer[hidden] {
    display: none;
}

.hub-cs-nlp-backdrop {
    position: absolute;
    inset: 0;
    background: rgba(0, 0, 0, 0.45);
}

.hub-cs-nlp-panel {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    width: min(420px, 100%);
    display: flex;
    flex-direction: column;
    background: #fff;
    box-shadow: -4px 0 24px rgba(0, 0, 0, 0.18);
    outline: none;
    transform: translateX(100%);
    transition: transform 0.25s ease;
}

/* .is-open (not [hidden] alone — see nlp-chat.js's openDrawer()) is what actually
   drives the slide-in: deferred to the next animation frame so the transition has
   something to animate from. */
.hub-cs-nlp-drawer.is-open .hub-cs-nlp-panel {
    transform: translateX(0);
}

.hub-cs-nlp-close {
    position: absolute;
    top: 12px;
    right: 12px;
    width: 32px;
    height: 32px;
    border: none;
    border-radius: 999px;
    background: #ececec;
    color: inherit;
    font-size: 20px;
    line-height: 1;
    cursor: pointer;
    z-index: 1;
}

.hub-cs-nlp-header {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 20px 48px 14px 20px;
    border-bottom: 1px solid #eee;
    flex: 0 0 auto;
}

.hub-cs-nlp-header strong {
    font-size: calc(var(--hub-cs-base-font) * 1.05);
}

.hub-cs-nlp-header-avatar,
.hub-cs-nlp-msg-avatar {
    flex: 0 0 auto;
    width: 32px;
    height: 32px;
    border-radius: 999px;
    overflow: hidden;
    background: color-mix(in srgb, var(--hub-cs-accent) 15%, #fff);
    color: var(--hub-cs-accent);
    display: flex;
    align-items: center;
    justify-content: center;
}

.hub-cs-nlp-header-avatar img,
.hub-cs-nlp-msg-avatar img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.hub-cs-nlp-header-avatar svg,
.hub-cs-nlp-msg-avatar svg {
    width: 60%;
    height: 60%;
}

.hub-cs-nlp-messages {
    flex: 1 1 auto;
    overflow-y: auto;
    padding: 16px 20px;
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.hub-cs-nlp-msg {
    display: flex;
    align-items: flex-end;
    gap: 8px;
    max-width: 88%;
}

.hub-cs-nlp-msg.is-user {
    align-self: flex-end;
    flex-direction: row-reverse;
}

.hub-cs-nlp-msg.is-assistant {
    align-self: flex-start;
}

.hub-cs-nlp-bubble {
    padding: 9px 14px;
    border-radius: 16px;
    font-size: calc(var(--hub-cs-base-font) * 0.9);
    line-height: 1.4;
    white-space: pre-wrap;
}

.hub-cs-nlp-msg.is-user .hub-cs-nlp-bubble {
    background: var(--hub-cs-accent);
    color: var(--hub-cs-accent-text);
    border-bottom-right-radius: 4px;
}

.hub-cs-nlp-msg.is-assistant .hub-cs-nlp-bubble {
    background: #f0f0f0;
    color: #222;
    border-bottom-left-radius: 4px;
}

.hub-cs-nlp-composer {
    flex: 0 0 auto;
    display: flex;
    gap: 8px;
    padding: 14px 20px;
    border-top: 1px solid #eee;
}

.hub-cs-nlp-input {
    flex: 1 1 auto;
    padding: 9px 12px;
    border: 1px solid #ccc;
    border-radius: 999px;
    font: inherit;
    box-sizing: border-box;
}

.hub-cs-nlp-submit {
    margin: 0 20px 16px;
}

@media (max-width: 600px) {
    .hub-cs-nlp-panel {
        width: 100%;
    }
}

/* Grouped listing: how many fare variants this one card stands for. */
.hub-cs-row-variants,
.hub-cs-box-card-variants {
    display: inline-block;
    margin-top: 4px;
    font-size: 0.8125rem;
    font-weight: 600;
    color: #0b6b3a;
}

.hub-cs-box-card-variants {
    margin: 0 0 6px;
}

/* Direction pages (/rejsy/<direction>/, Hub_CS_Directions) and the links to them under the listing. */
.hub-cs-direction .hub-cs-wx-crumbs { font-size: .875em; opacity: .75; margin-bottom: .75em; }
.hub-cs-direction .hub-cs-wx-crumbs a { color: inherit; }
.hub-cs-direction-title { margin: 0 0 .5em; }
.hub-cs-direction-lead { font-size: 1.05em; margin: 0 0 .8em; }
.hub-cs-direction-children,
.hub-cs-direction-season,
.hub-cs-direction-ports { margin: 0 0 .6em; }
.hub-cs-direction-hero { margin: 0 0 1em; }
.hub-cs-direction-hero-img { display: block; width: 100%; height: auto; max-height: 460px; object-fit: cover; border-radius: 12px; }
.hub-cs-direction-text { margin: 0 0 1em; }
.hub-cs-direction-gallery { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 10px; margin: 0 0 1.2em; }
.hub-cs-direction-gallery figure { margin: 0; }
.hub-cs-direction-gallery img { display: block; width: 100%; height: auto; aspect-ratio: 3 / 2; object-fit: cover; border-radius: 8px; }
.hub-cs-direction-offers { margin-top: 1.4em; }
.hub-cs-direction-more { text-align: center; margin: 1.2em 0; }
.hub-cs-direction-index { margin: 2em 0 1em; line-height: 1.8; }

/* Room for the results before search.js fills them: the "Kierunki rejsów" links
   below don't jump down when the cards arrive (CLS 0.5 on a phone, 15.10). */
.hub-cs-search .hub-cs-list:empty { min-height: 100vh; }


/* boxes.css */
/*
 * [hub_boxy] — curated offer-box grid. Dedicated card design (.hub-cs-box-card-*),
 * not a reuse of [hub_szukaj]'s .hub-cs-row — depends on search.css only for the
 * shared --hub-cs-accent/--hub-cs-base-font theme-inheriting variables (see that
 * file's :root), not for any of its row/card classes.
 */

.hub-cs-boxes-grid {
    /* Explicit width: 100% + box-sizing: border-box — this plugin has no
       global box-sizing reset, so left implicit this is content-box, and a
       shrink-to-fit-vs-fill-parent ambiguity on the SLIDER container itself
       (not just its .hub-cs-box-card children, already fixed) turned out to
       be part of why the mobile card was overflowing the viewport: the
       calc(100% - ...) flex-basis on each card only means what it says if
       this container's OWN 100% is unambiguously the actual visible width. */
    width: 100%;
    max-width: 100%;
    box-sizing: border-box;
    display: grid;
    /* Every box is 1/4 of the container (1/3 below 1100px) however many
       boxes the block has, so 1-3 boxes keep the same size and are not
       stretched across the page. auto-fill keeps the empty tracks; a track
       never drops under 220px, so a narrow container (sidebar, column)
       simply gets fewer columns. */
    grid-template-columns: repeat(auto-fill, minmax(max(220px, (100% - 61px) / 4), 1fr));
    gap: 20px;
}

@media (max-width: 1100px) {
    .hub-cs-boxes-grid {
        grid-template-columns: repeat(auto-fill, minmax(max(220px, (100% - 41px) / 3), 1fr));
    }
}

/*
 * Tablet/phone switch from a wrapping grid to a horizontal scroll-snap
 * slider — one row, native touch swipe (no JS needed), each card sized so
 * the NEXT one peeks in ~10% on the right edge as a visual invitation to
 * swipe, per request: 2 full cards + 10% of a 3rd on tablet, 1 full card +
 * 10% of the 2nd on phone. box-width * 1.1 = container width is the
 * relationship that makes "10% of the box" and "the sliver left over past N
 * full boxes" the same number, hence the /1.1 and /2.1 divisors below.
 */
@media (max-width: 900px) {
    .hub-cs-boxes-grid {
        display: flex;
        overflow-x: auto;
        scroll-snap-type: x mandatory;
        -webkit-overflow-scrolling: touch;
        gap: 16px;
        /* Room so each card's own :hover box-shadow doesn't clip against the
           scroll container's edge, and for platforms that render a visible
           horizontal scrollbar. */
        padding-bottom: 6px;
        /* Hides that scrollbar where the browser allows it — a swipeable
           row reads as a carousel, a scrollbar under it reads as a bug. */
        scrollbar-width: none;
    }

    .hub-cs-boxes-grid::-webkit-scrollbar {
        display: none;
    }

    .hub-cs-boxes-grid .hub-cs-box-card {
        scroll-snap-align: start;
        flex: 0 0 calc((100% - 2 * 16px) / 2.1);
    }
}

@media (max-width: 600px) {
    .hub-cs-boxes-grid .hub-cs-box-card {
        flex: 0 0 calc((100% - 16px) / 1.1);
    }

    /* Tighter than the desktop/tablet sizing — the narrowest slider card
       width is what was letting a date's own text outgrow its (equal-width,
       min-width: 0) box in the first place; this reduces how often the
       overflow: hidden safety net above actually has anything to clip. */
    .hub-cs-box-card-fact {
        padding: 6px 4px;
    }

    .hub-cs-box-card-fact b {
        font-size: 0.8125rem;
    }
}

.hub-cs-box-card {
    display: flex;
    flex-direction: column;
    /* A flex/grid item's default min-width is auto, not 0 — it refuses to
       shrink below its own content's natural width. A real cruise-ship photo
       is easily 1200-2000px+ wide, so without this, the card sized itself off
       THAT instead of its assigned flex-basis/grid track (found live: "the
       mobile card is at ~700% of screen width" in the horizontal slider,
       where flex: 0 0 calc(...) was being ignored entirely for exactly this
       reason). Set on the base rule, not just the mobile slider override, so
       the desktop grid (grid-template-columns: repeat(4, 1fr), which has the
       exact same footgun for a plain 1fr track) can't hit this either. */
    min-width: 0;
    /* The 1px border below would otherwise add to a calc()-based flex-basis
       width (content-box is the default here — no global reset in this
       plugin) instead of being absorbed into it. Small on its own (2px),
       included as part of the same box-sizing audit as the container fix
       above rather than leaving it as the one remaining implicit case. */
    box-sizing: border-box;
    border: 1px solid #e2e2e2;
    border-radius: 14px;
    overflow: hidden;
    text-decoration: none;
    color: inherit;
    background: #fff;
    transition: box-shadow 0.15s ease;
}

.hub-cs-box-card:hover {
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.1);
}

.hub-cs-box-card-media {
    position: relative;
    /* Explicit width: 100% (not left to flex's align-items: stretch to
       supply it) is what makes aspect-ratio reliably compute a height from
       it — .hub-cs-box-card is flex-direction: column, and an item's cross-
       axis stretch + aspect-ratio interaction is a newer, less consistently
       implemented part of the spec than "definite width -> aspect-ratio
       height", which every current browser handles the same way. Without
       this, the height side of the ratio wasn't resolving in the mobile
       stacked layout, so the <img> below (height: 100%, a percentage that's
       only meaningful against a PARENT with a definite height) fell back to
       its own raw intrinsic size instead — a real photo can easily be
       2000px+ tall, which is exactly what rendered (found live via
       screenshot: a single photo taller than the whole visible screen). */
    width: 100%;
    aspect-ratio: 16 / 10;
    /* Unconditional hard cap, independent of whether aspect-ratio above
       resolves correctly at all — two rounds of fixing the aspect-ratio/
       stretch computation itself (see the comment above) made zero visible
       difference per live testing, so this stops trusting that computation
       and just forbids the box from ever exceeding this height outright.
       max-height has no complex spec interactions to get wrong the way
       aspect-ratio+flex-stretch apparently does — combined with the
       existing overflow: hidden + the photo's own object-fit: cover, a
       genuinely huge intrinsic image just gets cropped, never renders at
       its raw size. */
    max-height: 220px;
    background: #eee;
    overflow: hidden;
}

.hub-cs-box-card-media img:not(.hub-cs-box-card-logo) {
    /* Absolutely positioned against .hub-cs-box-card-media's own position:
       relative box instead of a plain width/height: 100% — sidesteps the
       percentage-height-needs-a-definite-height-parent question entirely
       (belt-and-suspenders on top of the width: 100% fix above, not a
       replacement for it: something already this defensive shouldn't need
       a THIRD occurrence of this exact bug to get found). */
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.hub-cs-box-card-logo {
    position: absolute;
    top: 10px;
    left: 10px;
    /* -30% of the previous 30%/110px, per request. */
    width: 21%;
    max-width: 77px;
    height: auto;
    border-radius: 4px;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.25);
}

/* A cruise with a Polish guide: a small Polish flag in the photo's top right
   corner (map note 18.10.2026). Drawn, not an emoji: Windows shows the flag
   emoji as the letters "PL". Same rule in offer.css for "Podobne rejsy". */
.hub-cs-pilot-flag {
    position: absolute;
    top: 10px;
    right: 10px;
    width: 27px;
    height: 18px;
    border-radius: 3px;
    background: linear-gradient(#fff 0 50%, #dc143c 50% 100%);
    box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.12), 0 1px 4px rgba(0, 0, 0, 0.3);
    pointer-events: auto;
    z-index: 1;
}

/* "Na zdjęciu etykieta z ceną" — overlaid on the photo itself (per request),
   not in its own section like the [hub_szukaj] row. No EUR hint line here at
   all, even for a non-EUR price — that conversion hint is a listing-only
   thing (see search.js), not shown on a box regardless of currency. */
.hub-cs-box-card-price {
    position: absolute;
    right: 10px;
    bottom: 10px;
    /* Fixed, not content-sized — otherwise "179 EUR" and "88 503 EUR" badges
       land at different widths/positions across cards in the same row. Wide
       enough for a realistic worst case ("123 456 EUR") at this font-size. */
    width: 150px;
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 2px;
    padding: 8px 14px;
    border-radius: 10px;
    background: var(--hub-cs-accent);
    color: var(--hub-cs-accent-text);
}

.hub-cs-box-card-price-label {
    font-size: 0.75rem;
    opacity: 0.85;
}

.hub-cs-box-card-price-value {
    font-size: 1.25rem;
    font-weight: 700;
    line-height: 1.1;
    white-space: nowrap;
}

.hub-cs-box-card-body {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 16px 18px 18px;
}

.hub-cs-box-card-region {
    align-self: flex-start;
    padding: 4px 12px;
    border-radius: 999px;
    background: var(--hub-cs-accent);
    color: var(--hub-cs-accent-text);
    font-size: 0.75rem;
    font-weight: 600;
    line-height: 1.4;
}

/* Region + transport chips in one line, same pill style for both. */
.hub-cs-box-card-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

/* Parent-qualified (not just .hub-cs-box-card-title) and margin-block-*
   explicitly reset, not just margin: 0 — a bare single-class selector on a
   real <h3> ties in specificity with Blocksy's own
   `:is(.is-layout-flow,.is-layout-constrained) :where(h1..h6)` margin rule
   (its :where() contributes zero specificity, landing it at exactly one
   class), and a tie goes to whichever loads later (the theme) — the exact
   bug already found and fixed for search.css's own .hub-cs-row-title. */
.hub-cs-box-card-body .hub-cs-box-card-title {
    margin: 0;
    margin-block-start: 0;
    margin-block-end: 0;
    /* Reserves the full 2-line height regardless of whether THIS title
       actually wraps to 2 lines — without it, a 1-line title left everything
       below (route, fact boxes, footer) sitting higher than in a neighboring
       card whose title/route wrapped further, so the fact boxes across a row
       ended up at different Y positions instead of aligning (found live). */
    min-height: 2.6em;
    font-size: 1.0625rem;
    font-weight: 700;
    line-height: 1.3;
    text-transform: uppercase;
    /* Clamped to 2 lines — only shows an ellipsis when it actually doesn't
       fit, never cuts a title that already fits in two lines. */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.hub-cs-box-card-route {
    margin: 0;
    /* Same reservation as the title above, same reason — a 1-line route
       (e.g. "Keelung → Busan") must take up as much vertical space as a
       2-line one, or the fact boxes below it drift up. */
    min-height: 2.8em;
    font-size: 0.8125rem;
    color: #555;
    line-height: 1.4;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

/* CSS Grid, not flex — a flex item's default min-width is auto, meaning it
   won't shrink below its own content's width even at equal flex-grow, so the
   OD/DO boxes ended up sized by their OWN date text ("23.09.2026" wider than
   "5.09.2026") instead of matching each other (found live). Grid's `1fr`
   tracks don't have that footgun IF paired with minmax(0, 1fr) — that's what
   actually forces both date columns to the same width regardless of their
   text, without touching the card's own outer padding at all. */
.hub-cs-box-card-facts {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) minmax(0, 1fr);
    gap: 8px;
    margin: 4px 0 2px;
}

.hub-cs-box-card-fact {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    padding: 6px 8px;
    border: 1.5px solid var(--hub-cs-accent);
    border-radius: 8px;
    text-align: center;
    min-width: 0;
    /* minmax(0, 1fr) on the grid track above deliberately allows this box to
       shrink narrower than its own date text's natural width (that's what
       makes the two date boxes match each other regardless of content) — on
       a narrow slider card that shrink can go far enough that the date
       spilled visually past this border instead of just being clipped by it
       (found live). This is the safety net for that case. */
    overflow: hidden;
}

.hub-cs-box-card-fact span {
    font-size: 0.6875rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: #888;
}

.hub-cs-box-card-fact b {
    font-size: 0.9375rem;
    white-space: nowrap;
}

.hub-cs-box-card-fact-nights {
    min-width: 60px;
}

.hub-cs-box-card-fact-nights b {
    font-size: 1.375rem;
    line-height: 1.1;
}

.hub-cs-box-card-footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    margin-top: 8px;
}

/* Icon ABOVE the name (per the reference screenshot), not beside it — a
   centered column, not a row. flex: 0 1 auto (grow: 0) is what actually
   fixes the huge left/right "padding" look from the previous version: with
   flex-grow: 1 this column claimed ALL leftover space in the footer row
   (the CTA button is flex: 0 0 auto and never grows), so a short name like
   "Mein Schiff 2" sat centered inside a column much wider than it needed —
   reading as oversized padding even though no padding was ever set (found
   live via a DevTools screenshot). flex-shrink stays 1 + min-width: 0 so a
   genuinely long name still shrinks/ellipsizes against the button instead
   of pushing it off — it just no longer grows past its own content first.
   font-size set here (not just on the name span) so the icon's own em
   height below means exactly what was asked: relative to the name's own
   text height, not some unrelated inherited size. */
.hub-cs-box-card-ship {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 5px;
    flex: 0 1 auto;
    min-width: 0;
    font-size: 0.875rem;
}

.hub-cs-box-card-ship img {
    /* -20% of the previous 2.8em, per request. */
    height: 2.24em;
    width: auto;
    /* The width="122" height="66" attributes give this ratio before it loads (no jump). */
    aspect-ratio: 122 / 66;
}

.hub-cs-box-card-ship-name {
    /* align-items: center above sizes everything to its own content by
       default — fine for the icon, but the name then has no definite width
       to ellipsize against (content that's free to be as wide as it wants
       never overflows itself). align-self: stretch overrides just this one
       child back to the column's full (already width-constrained) size, and
       text-align centers whatever text ends up inside that box. */
    align-self: stretch;
    min-width: 0;
    font-size: 1em;
    font-weight: 700;
    text-align: center;
    /* Explicit, not theme-derived — this site's own --theme-link-initial-color
       resolves to black (verified live against Blocksy's actual generated
       CSS), which isn't blue at all; requested specifically as this exact hex
       rather than whatever the theme's real link color happens to be. */
    color: #004aad;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.hub-cs-box-card-cta {
    flex: 0 0 auto;
    /* -10px each side from the original 20px, per request — frees up room
       for the ship name before it has to ellipsize. */
    padding: 10px 10px;
    border-radius: 8px;
    background: var(--hub-cs-accent);
    color: var(--hub-cs-accent-text);
    font-weight: 700;
    font-size: 0.875rem;
    white-space: nowrap;
}

.hub-cs-box-card:hover .hub-cs-box-card-cta {
    background: var(--hub-cs-accent-hover);
    color: var(--hub-cs-accent-text-hover);
}


/* tray.css */
/* Compare and recently viewed (assets/tray.js). Floating parts live on <body>,
   outside any .hub-cs-* scope, so the accent is defined here once more. */
.hub-cs-compare-fab,
.hub-cs-viewed-fab,
.hub-cs-tray-modal,
.hub-cs-compare-add,
.hub-cs-tray-toast {
    --hub-cs-tray-accent: var(--hub-cs-accent, var(--theme-button-background-initial-color, var(--wp--preset--color--primary, #0a6b58)));
    --hub-cs-tray-accent-text: var(--hub-cs-accent-text, var(--theme-button-text-initial-color, #fff));
    font-family: var(--hub-cs-font-family, inherit);
    box-sizing: border-box;
}

/* ---- "+" on cards ---- */
.hub-cs-row,
.hub-cs-box-card {
    position: relative;
}

.hub-cs-compare-add {
    position: absolute;
    top: 10px;
    right: 10px;
    z-index: 3;
    width: 34px;
    height: 34px;
    padding: 0;
    margin: 0;
    border: 2px solid var(--hub-cs-tray-accent);
    border-radius: 50%;
    background: #fff;
    color: var(--hub-cs-tray-accent);
    font-size: 22px;
    font-weight: 700;
    line-height: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    box-shadow: 0 2px 8px rgba(0, 0, 0, .18);
    transition: background .15s, color .15s, transform .15s;
}

.hub-cs-compare-add:hover,
.hub-cs-compare-add:focus-visible {
    transform: scale(1.08);
}

.hub-cs-compare-add.is-added {
    background: var(--hub-cs-tray-accent);
    color: var(--hub-cs-tray-accent-text);
    font-size: 17px;
}

/* Tooltip: below the button, inside the card (cards clip their overflow). */
.hub-cs-compare-add::after,
.hub-cs-compare-fab::after {
    content: attr(data-tip);
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    padding: 5px 9px;
    border-radius: 6px;
    background: #1d2733;
    color: #fff;
    font-size: 12px;
    font-weight: 500;
    line-height: 1.3;
    white-space: nowrap;
    pointer-events: none;
    opacity: 0;
    transition: opacity .15s;
}

.hub-cs-compare-add:hover::after,
.hub-cs-compare-add:focus-visible::after,
.hub-cs-compare-fab:hover::after,
.hub-cs-compare-fab:focus-visible::after {
    opacity: 1;
}

/* Listing row: the button sits over the ship/price column, which gets room for it. */
.hub-cs-row .hub-cs-row-side {
    padding-top: 40px;
}

/* Offer page: top right corner of the title/price/"Zapytaj" block. */
.hub-cs-booking {
    position: relative;
}

.hub-cs-booking > .hub-cs-compare-add {
    top: 0;
    right: 0;
}

.hub-cs-booking > .hub-cs-booking-chips,
.hub-cs-booking > .hub-cs-booking-title {
    padding-right: 44px;
}

/* ---- Floating buttons ---- */
.hub-cs-compare-fab {
    position: fixed;
    top: 110px;
    right: 18px;
    z-index: 9990;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 64px;
    height: 64px;
    padding: 0;
    border: 1px solid rgba(0, 0, 0, .08);
    border-radius: 16px;
    background: #fff;
    box-shadow: 0 6px 22px rgba(0, 0, 0, .18);
    cursor: pointer;
}

.hub-cs-compare-fab[hidden],
.hub-cs-viewed-fab[hidden] {
    display: none;
}

.hub-cs-compare-fab img {
    width: 40px;
    height: auto;
    display: block;
}

.hub-cs-compare-count {
    position: absolute;
    top: -8px;
    right: -8px;
    min-width: 24px;
    height: 24px;
    padding: 0 6px;
    border-radius: 12px;
    background: var(--hub-cs-tray-accent);
    color: var(--hub-cs-tray-accent-text);
    font-size: 13px;
    font-weight: 700;
    line-height: 24px;
    text-align: center;
    box-shadow: 0 0 0 2px #fff;
}

.hub-cs-viewed-fab {
    position: fixed;
    left: 0;
    top: 50%;
    z-index: 9990;
    transform: translateY(-50%);
    writing-mode: vertical-rl;
    rotate: 180deg;
    padding: 16px 10px;
    border: 0;
    background: var(--hub-cs-tray-accent);
    color: var(--hub-cs-tray-accent-text);
    font-size: 14px;
    font-weight: 600;
    letter-spacing: .02em;
    cursor: pointer;
    box-shadow: 0 4px 16px rgba(0, 0, 0, .18);
}

/* rotate: 180deg (text read bottom to top) flips the corners too: these land on the screen's right. */
.hub-cs-viewed-fab {
    border-radius: 10px 0 0 10px;
}

@media (max-width: 600px) {
    .hub-cs-compare-fab {
        top: auto;
        bottom: 84px;
        right: 12px;
        width: 54px;
        height: 54px;
    }

    .hub-cs-compare-fab img {
        width: 34px;
    }

    .hub-cs-viewed-fab {
        padding: 12px 8px;
        font-size: 12px;
    }
}

/* ---- Dialogs ---- */
html.hub-cs-tray-locked {
    overflow: hidden;
}

.hub-cs-tray-modal {
    position: fixed;
    inset: 0;
    z-index: 99999;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 16px;
}

.hub-cs-tray-backdrop {
    position: absolute;
    inset: 0;
    background: rgba(10, 20, 30, .55);
}

.hub-cs-tray-dialog {
    position: relative;
    width: min(1000px, 100%);
    max-height: calc(100vh - 32px);
    display: flex;
    flex-direction: column;
    border-radius: 14px;
    background: #fff;
    color: #1d2733;
    box-shadow: 0 20px 60px rgba(0, 0, 0, .3);
    overflow: hidden;
}

.hub-cs-viewed-modal .hub-cs-tray-dialog {
    width: min(560px, 100%);
}

.hub-cs-tray-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 16px 20px;
    border-bottom: 1px solid #e8ebee;
}

.hub-cs-tray-head h2 {
    margin: 0;
    font-size: 20px;
    line-height: 1.2;
}

.hub-cs-tray-close {
    width: 36px;
    height: 36px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: #f1f3f5;
    color: #1d2733;
    font-size: 24px;
    line-height: 1;
    cursor: pointer;
}

.hub-cs-tray-body {
    padding: 16px 20px 20px;
    overflow: auto;
}

.hub-cs-tray-empty,
.hub-cs-tray-note {
    margin: 0;
    color: #5b6670;
}

.hub-cs-tray-note {
    margin-top: 12px;
    font-size: 14px;
}

/* Comparison table: one column per cruise, scrolls sideways on a phone. */
.hub-cs-compare-wrap {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}

.hub-cs-compare-table {
    width: 100%;
    min-width: 560px;
    border-collapse: collapse;
    table-layout: fixed;
    font-size: 14px;
}

.hub-cs-compare-table th,
.hub-cs-compare-table td {
    padding: 9px 10px;
    border-bottom: 1px solid #eef0f2;
    text-align: left;
    vertical-align: top;
}

.hub-cs-compare-table th {
    width: 120px;
    color: #5b6670;
    font-weight: 600;
}

.hub-cs-compare-table tr:last-child th,
.hub-cs-compare-table tr:last-child td {
    border-bottom: 0;
}

.hub-cs-compare-slot {
    display: flex;
    align-items: center;
    justify-content: center;
    aspect-ratio: 3 / 2;
    padding: 8px;
    border: 2px dashed #d5dbe1;
    border-radius: 10px;
    color: #8a96a3;
    font-size: 13px;
    text-align: center;
}

.hub-cs-compare-photo {
    position: relative;
    aspect-ratio: 3 / 2;
    border-radius: 10px;
    overflow: hidden;
    background: #eef1f4;
}

.hub-cs-compare-photo img {
    width: 100% !important;
    height: 100% !important;
    max-width: none !important;
    object-fit: cover;
    display: block;
}

.hub-cs-compare-remove {
    position: absolute;
    top: 6px;
    right: 6px;
    width: 28px;
    height: 28px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: rgba(255, 255, 255, .92);
    color: #1d2733;
    font-size: 20px;
    line-height: 1;
    cursor: pointer;
}

.hub-cs-compare-title {
    color: inherit;
    font-weight: 700;
    text-decoration: none;
}

.hub-cs-compare-title:hover {
    text-decoration: underline;
}

.hub-cs-compare-price {
    color: var(--hub-cs-tray-accent);
    font-size: 17px;
}

.hub-cs-tray-modal .hub-cs-compare-cta {
    display: inline-block;
    padding: 9px 14px;
    border-radius: var(--hub-cs-button-radius, 5px);
    background: var(--hub-cs-tray-accent);
    color: var(--hub-cs-tray-accent-text);
    font-weight: 600;
    text-decoration: none;
}

/* Recently viewed list. */
.hub-cs-viewed-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: 8px;
}

.hub-cs-viewed-item {
    display: flex;
    gap: 12px;
    align-items: center;
    padding: 8px;
    border-radius: 10px;
    color: inherit;
    text-decoration: none;
}

.hub-cs-viewed-item:hover {
    background: #f3f5f7;
}

.hub-cs-viewed-photo {
    flex: 0 0 96px;
    height: 64px;
    border-radius: 8px;
    overflow: hidden;
    background: #eef1f4;
}

.hub-cs-viewed-photo img {
    width: 100% !important;
    height: 100% !important;
    max-width: none !important;
    object-fit: cover;
    display: block;
}

.hub-cs-viewed-text {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
    font-size: 13px;
    color: #5b6670;
}

.hub-cs-viewed-text strong {
    color: #1d2733;
    font-size: 15px;
    line-height: 1.3;
}

.hub-cs-viewed-price {
    color: var(--hub-cs-tray-accent);
    font-weight: 700;
}

.hub-cs-tray-clear {
    margin-top: 12px;
    padding: 0;
    border: 0;
    background: none;
    color: #5b6670;
    font-size: 13px;
    text-decoration: underline;
    cursor: pointer;
}

.hub-cs-tray-toast {
    position: fixed;
    left: 50%;
    bottom: 24px;
    z-index: 100000;
    transform: translateX(-50%);
    max-width: calc(100% - 32px);
    padding: 12px 18px;
    border-radius: 10px;
    background: #1d2733;
    color: #fff;
    font-size: 14px;
    box-shadow: 0 8px 24px rgba(0, 0, 0, .25);
    transition: opacity .5s;
}

.hub-cs-tray-toast.is-gone {
    opacity: 0;
}

/* Footer of both dialogs: share the list and download it as PDF (map note
   17.10.2026). Colours come from the theme's button colour like the rest of
   the tray (--hub-cs-tray-accent) — yellow, orange or blue, whatever the site uses. */
.hub-cs-tray-foot {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 12px 18px;
    padding: 14px 20px;
    border-top: 1px solid #e8ebee;
    background: #fafbfc;
}

.hub-cs-tray-share {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

.hub-cs-tray-share-label {
    margin-right: 2px;
    color: #44505c;
    font-size: 14px;
}

.hub-cs-tray-modal .hub-cs-tray-share-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 38px;
    margin: 0;
    padding: 0;
    border: 1px solid #dfe3e8;
    border-radius: 50%;
    background: #fff;
    color: #1d2733;
    cursor: pointer;
    transition: border-color .15s ease, box-shadow .15s ease;
}

.hub-cs-tray-modal .hub-cs-tray-share-icon:hover,
.hub-cs-tray-modal .hub-cs-tray-share-icon:focus-visible {
    border-color: var(--hub-cs-tray-accent);
    box-shadow: 0 0 0 1px var(--hub-cs-tray-accent) inset;
    color: #1d2733;
    background: #fff;
}

.hub-cs-tray-modal .hub-cs-tray-share-icon svg,
.hub-cs-tray-modal .hub-cs-tray-native-share svg,
.hub-cs-tray-modal .hub-cs-tray-pdf svg {
    width: 18px;
    height: 18px;
    fill: currentColor;
    flex: none;
}

.hub-cs-tray-modal .hub-cs-tray-pdf {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    margin: 0;
    padding: 12px 18px;
    border: 0;
    border-radius: var(--hub-cs-button-radius, 5px);
    background: var(--hub-cs-tray-accent);
    color: var(--hub-cs-tray-accent-text);
    font: inherit;
    font-size: 15px;
    font-weight: 700;
    text-transform: none;
    letter-spacing: normal;
    cursor: pointer;
}

.hub-cs-tray-modal .hub-cs-tray-pdf:hover {
    background: var(--hub-cs-tray-accent);
    color: var(--hub-cs-tray-accent-text);
    filter: brightness(.95);
}

.hub-cs-tray-modal .hub-cs-tray-pdf.is-busy {
    cursor: progress;
    opacity: .85;
}

.hub-cs-tray-modal .hub-cs-tray-pdf.is-busy svg {
    display: none;
}

.hub-cs-tray-modal .hub-cs-tray-pdf.is-busy::before {
    content: "";
    width: 16px;
    height: 16px;
    border: 2px solid currentColor;
    border-right-color: transparent;
    border-radius: 50%;
    animation: hub-cs-tray-spin .8s linear infinite;
}

@keyframes hub-cs-tray-spin {
    to { transform: rotate(360deg); }
}

.hub-cs-tray-modal .hub-cs-tray-native-share {
    display: none;
}

.hub-cs-tray-shared {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    margin: 0 0 14px;
    padding: 10px 14px;
    border-radius: 10px;
    background: color-mix(in srgb, var(--hub-cs-tray-accent) 12%, #fff);
    font-size: 14px;
}

.hub-cs-tray-shared button {
    margin: 0;
    padding: 7px 12px;
    border: 1px solid #1d2733;
    border-radius: var(--hub-cs-button-radius, 5px);
    background: #fff;
    color: #1d2733;
    font: inherit;
    font-weight: 600;
    text-transform: none;
    cursor: pointer;
}

@media (max-width: 640px) {
    .hub-cs-tray-foot {
        flex-direction: column;
        align-items: stretch;
    }

    .hub-cs-tray-modal .hub-cs-tray-pdf {
        order: 1;
        justify-content: center;
        width: 100%;
    }

    .hub-cs-tray-share {
        order: 2;
        justify-content: center;
    }

    /* With the phone's own share sheet, one button instead of the icons. */
    .hub-cs-tray-foot.has-native-share .hub-cs-tray-share-label,
    .hub-cs-tray-foot.has-native-share .hub-cs-tray-share-icon {
        display: none;
    }

    .hub-cs-tray-foot.has-native-share .hub-cs-tray-native-share {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        gap: 8px;
        width: 100%;
        margin: 0;
        padding: 12px;
        border: 1px solid #dfe3e8;
        border-radius: var(--hub-cs-button-radius, 5px);
        background: #fff;
        color: #1d2733;
        font: inherit;
        font-size: 15px;
        font-weight: 700;
        text-transform: none;
        cursor: pointer;
    }
}

/* "×" on each recently viewed row (map note 17.10.2026). */
.hub-cs-viewed-list > li {
    position: relative;
}

.hub-cs-viewed-list > li > .hub-cs-viewed-item {
    padding-right: 44px;
}

.hub-cs-tray-modal .hub-cs-viewed-remove {
    position: absolute;
    top: 50%;
    right: 8px;
    width: 30px;
    height: 30px;
    margin: -15px 0 0;
    padding: 0;
    border: 1px solid #dfe3e8;
    border-radius: 50%;
    background: #fff;
    color: #5b6670;
    font: inherit;
    font-size: 19px;
    line-height: 1;
    cursor: pointer;
}

.hub-cs-tray-modal .hub-cs-viewed-remove:hover,
.hub-cs-tray-modal .hub-cs-viewed-remove:focus-visible {
    border-color: #b33;
    background: #fff;
    color: #b33;
}


/* appearance.css */
/* User-configurable presentation layer. Empty variables keep component/theme defaults. */
.hub-cs-search,
.hub-cs-frontsearch,
.hub-cs-offer {
    font-family: var(--hub-cs-font-family, inherit);
    color: var(--hub-cs-text-custom, inherit);
}

.hub-cs-btn,
.hub-cs-box-card-cta,
.hub-cs-offer button,
.hub-cs-offer input[type="submit"] {
    border-radius: var(--hub-cs-button-radius, 5px);
}

.hub-cs-row,
.hub-cs-box-card {
    border-radius: var(--hub-cs-card-radius, 14px);
    background: var(--hub-cs-surface-custom, #fff);
    box-shadow: var(--hub-cs-card-shadow, none);
}

.hub-cs-row:hover,
.hub-cs-box-card:hover {
    box-shadow: var(--hub-cs-card-shadow, 0 4px 14px rgba(0,0,0,.1));
}

.hub-cs-sidebar,
.hub-cs-booking,
.hub-cs-accordion,
.hub-cs-cabin-group,
.hub-cs-inquiry,
.hub-cs-offer-section {
    border-radius: var(--hub-cs-card-radius, 12px);
}

.hub-cs-booking,
.hub-cs-accordion,
.hub-cs-cabin-group,
.hub-cs-inquiry {
    background: var(--hub-cs-surface-custom, #fff);
    box-shadow: var(--hub-cs-card-shadow, none);
}

