/* ============================================================================
   NAUTIKA · Search result tickets (public site)
   ----------------------------------------------------------------------------
   The sailing card on /book/search, styled to match the Agency and BackOffice
   New Booking results so the two read as one product.

   These rules are LIFTED from GoNautika.Web.Shared's ferry-search-panel.css
   rather than that stylesheet being loaded, because it and this site's design
   system define 40 classes in common — the whole search deck among them
   (.bk-field, .trip-leg, .swap-btn, .nk-dropdown...) — so loading it whole
   would restyle the dark hero deck into the admin panel's light one.

   What is taken is every rule anchored to a ticket class, compound selectors
   included: ".nk-ticket.fsp-ticket" cannot match anything but a ticket, and it
   is what turns the card into a column. A rule that could reach the rest of the
   site is left behind, and each @media block keeps its own rules — flattening
   those into the base is what put a full-width mobile Book Now on the desktop.

   Keep in step with ferry-search-panel.css if the portals' ticket changes.
   ========================================================================== */

/* --_fsp-picked is the ring the CHOSEN sailing wears (see .rs-ticket-picked below): always whichever of
   the two accents the resting border is not, declared on the same two rules that decide the resting
   colour, since the pair can only ever be read together. */
.nk-ticket.fsp-ticket { padding: 1rem 1.1rem; display: flex; flex-direction: column; gap: .9rem; border-color: var(--nk-primary); border-width: 1.5px; --_fsp-picked: var(--nk-secondary); }
[data-theme="dusk"] .nk-ticket.fsp-ticket { border-color: var(--nk-secondary); --_fsp-picked: var(--nk-primary); }
.nk-ticket.fsp-ticket + .nk-ticket.fsp-ticket { margin-top: .9rem; }
.fsp-ticket-head { display: flex; align-items: center; gap: .8rem; }
.fsp-ticket-badge-row { display: flex; align-items: center; flex-wrap: wrap; gap: .5rem; }
.fsp-ticket-head-date { flex: 0 0 auto; white-space: nowrap; }
.fsp-ticket-info-text { min-width: 0; flex: 1 1 auto; }
.fsp-ticket-info-text .nk-route-port, .fsp-ticket-info-text .nk-route-name, .fsp-ticket-info-text .nk-route-time, .fsp-via-leg-row .nk-route-port, .fsp-via-leg-row .nk-route-name, .fsp-via-leg-row .nk-route-time { min-width: 0; }
.fsp-ticket-row { display: flex; flex-wrap: wrap; align-items: center; gap: .85rem 1.25rem; }
.fsp-ticket-info { display: flex; align-items: center; gap: .8rem; flex: 1 1 auto; min-width: 14rem; }
.fsp-booknow-col { flex: 0 0 auto; }
.fsp-booknow-col .nk-btn { min-width: 9rem; }
.fsp-booknow-row { justify-content: flex-end; border-top: 1px solid var(--nk-line); padding-top: .85rem; }
.fsp-via-badge { display: inline-flex; align-items: center; gap: .3rem; font-size: var(--nk-text-xs); font-weight: 600; font-family: var(--nk-font-body); color: var(--nk-primary-700); background: var(--nk-primary-50); border: 1px solid var(--nk-primary-200); border-radius: var(--nk-radius-pill); padding: .1rem .55rem; margin: .3rem 0 .15rem; max-width: 100%; }
.fsp-via-badge-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fsp-via-badge-secondary { color: var(--nk-secondary-700); background: var(--nk-secondary-50); border-color: var(--nk-secondary-200); }
.fsp-via-badge-neutral { color: var(--nk-ink-soft); background: var(--nk-surface-2); border-color: var(--nk-line); }
/* The (i) on a "Via …" pill (search results). These were the portals' .nk-tooltip rules, ported with
   no markup to style and resting on an .nk-tooltip base this site's design system does not have — so
   the badge fell back to a bare title attribute and showed no icon at all. It carries the same
   popover as the seat-class and surcharge icons now (booking.info-popover.js), sized down to a badge:
   the default 1.3rem button is built for a table head and overflows a pill of this padding. */
.fsp-via-badge .fsp-info-popover { flex: 0 0 auto; }
.fsp-via-badge .fsp-info-btn { width: 1rem; height: 1rem; margin-right: -.15rem; color: inherit; }
.fsp-via-badge .fsp-info-btn .material-symbols-outlined { font-size: .95rem; }
/* Hover keeps the badge's own colour rather than the default primary, which would put a blue icon in
   a secondary-coloured pill. */
.fsp-via-badge .fsp-info-btn:hover { color: inherit; background: var(--nk-secondary-200); }
.fsp-via-legs { display: grid; grid-template-columns: minmax(12rem, 1fr) max-content; align-items: center; row-gap: .6rem; column-gap: 1.25rem; }
.fsp-via-legs .fsp-via-leg-row { display: contents; }
.fsp-via-leg-row .nk-route.fsp-via-route { min-width: 12rem; padding: .1rem 0; }
.fsp-via-route .nk-route-path { height: auto; min-height: 2rem; padding-block: .2rem; }
.fsp-via-route .nk-route-path > span { flex-direction: column; gap: .05rem; line-height: 1.2; }
.fsp-via-leg-vessel { font-size: .6rem; font-weight: 600; color: var(--nk-muted); text-transform: uppercase; letter-spacing: .03em; }
.fsp-via-leg-duration { font-size: var(--nk-text-xs); font-weight: 700; color: var(--nk-ink-soft); }
.fsp-via-connector { display: flex; align-items: center; gap: .35rem; font-size: var(--nk-text-xs); color: var(--nk-ink-soft); padding-left: .1rem; border-left: 2px dashed var(--nk-line-strong); margin-left: .35rem; padding: .1rem 0 .1rem .6rem; grid-column: 1 / -1; }
.fsp-via-connector .material-symbols-outlined { font-size: 1rem; }
.fsp-via-total { font-size: var(--nk-text-xs); color: var(--nk-ink-soft); margin-top: .1rem; }
.op-mark { width: 2.5rem; height: 2.5rem; border-radius: var(--nk-radius-sm); display: flex; align-items: center; justify-content: center; color: #fff; flex-shrink: 0; font-size: 1.2rem; }
.fsp-ticket-classes { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: .6rem; flex: 0 0 auto; border-left: 2px dashed var(--nk-line-strong); padding-left: 1.1rem; }
.fsp-class-col { position: relative; z-index: 1; cursor: pointer; display: flex; flex-direction: column; align-items: stretch; text-align: left; gap: .35rem; padding: .35rem .55rem; border: 1px solid var(--nk-line); border-radius: var(--nk-radius-sm); min-width: 8rem; max-width: 11rem; flex: 0 1 8rem; transition: border-color var(--nk-dur-fast), background var(--nk-dur-fast); }
.fsp-class-col:hover { border-color: var(--nk-primary-200); }
.fsp-class-col.is-full { opacity: .55; cursor: not-allowed; }
.fsp-class-col.is-selected { background: var(--nk-primary-50); border-color: var(--nk-primary-200); }
.fsp-class-col.fsp-info-active { z-index: 2; }
.fsp-class-col-head { display: flex; align-items: center; gap: .3rem; }
.fsp-class-col-radio { flex-shrink: 0; }
/* The (i) is pinned to the column's right edge rather than trailing the name, so the icons line up down
   a list of tickets instead of stepping in and out with the length of each class name.
   The radio and the icon are fixed-size controls, so the name is the only part that may give ground
   when a column is narrow — and it gives it by ellipsising, which is why the icon is its SIBLING and
   not nested inside it: a name that is one long word ("Business") cannot wrap, so with the icon inside
   it something always had to spill past the column's border. */
.fsp-class-col-head { min-width: 0; }
.fsp-class-name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fsp-class-col-head > .fsp-info-popover { flex: 0 0 auto; margin-left: auto; }
.fsp-class-name { display: flex; align-items: center; gap: .25rem; font-weight: 700; font-size: var(--nk-text-xs); font-family: var(--nk-font-display); }
.fsp-class-price { font-family: var(--nk-font-display); font-weight: 800; font-size: var(--nk-text-sm); font-variant-numeric: tabular-nums; }
.fsp-class-col-meta { display: flex; align-items: baseline; justify-content: space-between; gap: .6rem; }
.fsp-class-col-seats { font-size: var(--nk-text-xs); white-space: nowrap; }
.fsp-class-col-seats.fsp-seats-good { color: var(--nk-success-700); }
.fsp-class-col-seats.fsp-seats-low { color: var(--nk-warning-700); }
.fsp-class-col-seats.fsp-seats-critical { color: var(--nk-error-700); }
/* ---- Tab bars: the search results' journeys, and the seat step's trips and legs --------------
   Three bars, one set of rules, lifted from the portals' ferry-search-panel.css so the wizard reads
   the same in all three apps:
     .fsp-query-tabs  — one tab per journey on /book/search, the Select-then-Book-Now sequence;
     .fsp-step2-tabs  — one tab per journey on /book/trip's seat step (a real .nk-tabs);
     .fsp-leg-tabs    — one tab per leg within a journey that changes boats (ours, not the
                        framework's — see the comment in Views/Booking/Trip.cshtml).
   Every one of them scrolls sideways rather than wrapping onto a second row, which on a phone with
   three journeys was the whole reason the bar was two rows tall. */
.fsp-tabs-scroll-wrap { display: flex; align-items: center; gap: .4rem; margin-bottom: 1.1rem; }
.fsp-query-tabs .nk-tabs-nav, .fsp-step2-tabs-nav, .fsp-leg-tabs-nav {
  margin-bottom: 0; flex-wrap: nowrap; overflow-x: auto; scroll-behavior: smooth;
  scrollbar-width: none; -ms-overflow-style: none; flex: 1 1 auto; min-width: 0;
}
.fsp-query-tabs .nk-tabs-nav::-webkit-scrollbar,
.fsp-step2-tabs-nav::-webkit-scrollbar, .fsp-leg-tabs-nav::-webkit-scrollbar { display: none; }
.fsp-query-tabs .nk-tabs-nav .nk-tab,
.fsp-step2-tabs-nav .nk-tab, .fsp-leg-tabs-nav .nk-tab { flex: 0 0 auto; white-space: nowrap; }
.fsp-tabs-scroll-btn {
  flex: 0 0 auto; width: 2rem; height: 2rem; border-radius: 50%; display: flex; align-items: center;
  justify-content: center; border: 1px solid var(--nk-line); background: var(--nk-surface);
  color: var(--nk-ink-soft); cursor: pointer; transition: color var(--nk-dur-fast), border-color var(--nk-dur-fast);
}
.fsp-tabs-scroll-btn:hover { border-color: var(--nk-primary); color: var(--nk-primary); }
.fsp-tabs-scroll-btn:disabled { opacity: .35; cursor: default; }
.fsp-tabs-scroll-btn .material-symbols-outlined { font-size: 1.2rem; }

/* A journey still to be decided keeps the ordinary tab look; "done" is a checkmark inside it rather
   than a recolour, so the bar reads as one connected tracker instead of a row of states. */
.fsp-tab-check {
  display: none; font-size: 1.05em; line-height: 1; vertical-align: -2px; margin-right: .3rem;
  color: var(--nk-success-700);
}
.fsp-tabs-sequential .nk-tab.is-picked .fsp-tab-check { display: inline-block; }
/* Locked: a journey the visitor has not reached yet — no sailing picked, and not the one being
   decided — is inert, reachable only by the auto-advance after Select. A journey already decided
   stays clickable, so an earlier choice can be reviewed or changed mid-sequence; once every one has
   a pick the whole bar unlocks. */
.fsp-tabs-locked .nk-tabs-nav .nk-tab:not(.is-picked):not(.nk-active) { pointer-events: none; opacity: .6; }
/* Which SAILING within a decided journey was chosen — the tick on its own Select/Book Now button.
   The secondary-to-primary swap beside it is a plain class change in the page script, so it matches
   those buttons everywhere else without a rule here. */
.fsp-select-check { display: none; margin-right: .35rem; }
[data-book-now].is-picked .fsp-select-check { display: inline-block; }

/* And the whole card, ringed. A tick on a button in the bottom corner of a tall card is not what the eye
   finds when a passenger comes back from Seats & Passengers to change their mind — the sailing they
   settled on has to be identifiable at a glance down the list. The mark is restored on arrival from
   sessionStorage — see restorePicks in Search.cshtml.

   The ring is a DIFFERENT accent per theme, and one colour for both will not do: the resting border is
   primary in light and secondary in dusk, so either accent collides with it in one theme or the other.
   Nor is there a third to reach for — success, warning and error are the seats-left meter inside each
   class column on this very card (.fsp-class-col-seats), so a green ring would put one accent at two
   scales meaning two different things. Hence --_fsp-picked's swap rather than a constant. */
.nk-ticket.fsp-ticket.rs-ticket-picked {
  border-color: var(--_fsp-picked); border-width: 2.5px;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--_fsp-picked) 30%, transparent);
}

.fsp-leg-tabs-nav { margin-bottom: 0; }
/* .nk-tabs normally draws its active tab's underline with a separate .nk-tabs-ink element the
   framework positions in JS — skipped here, since this bar is not driven by initTabs. A plain border
   gives the same "active tab is underlined" look without it. */
.fsp-leg-tab.nk-active { border-bottom: 2px solid var(--nk-primary); margin-bottom: -1px; }
.fsp-leg-tabs .nk-tabs-panels { padding-top: 1rem; }

/* ---- The seat step's trip tabs: always in view, and taken in order -----------------------------
   The bar of trips (and, inside a trip that changes boats, the bar of legs) sticks under the progress
   rail while the deck plan scrolls beneath it, so a passenger deep in one boat's seats still sees which
   crossing they are seating. It is the only thing that sticks there: the class picker and the legend
   scroll with the deck they belong to. It sticks within its own tab container, so it lets go once the
   decks are scrolled past. --fsp-trip-tabs-h is the trip bar's measured height, which is where the leg
   bar has to sit; see measureRail in nautika.booking-trip.js.

   Tabs are shown at every width. They used to be dropped below 900px, with every deck stacked, because
   switching away could hide a deck that still had seats to pick; now a trip cannot be left until it
   is fully seated (below), which removes the reason, and a stacked page had no bar to keep in view. */
.fsp-step2-tabs > .fsp-tabs-scroll-wrap,
.fsp-leg-tabs > .fsp-tabs-scroll-wrap {
  position: sticky; z-index: 30; top: calc(var(--fsp-topbar-h, 0rem) + var(--fsp-rail-h, 0px));
  background: var(--nk-surface); padding-block: .35rem; box-shadow: 0 10px 10px -10px rgb(0 0 0 / .18);
}
.fsp-step2-tabs .fsp-leg-tabs > .fsp-tabs-scroll-wrap {
  z-index: 29; top: calc(var(--fsp-topbar-h, 0rem) + var(--fsp-rail-h, 0px) + var(--fsp-trip-tabs-h, 0px));
}
/* A trip is taken in order: one not yet reached is locked until every trip before it is fully seated,
   and is reached by the automatic move on (refreshSeatGates in nautika.booking-trip.js). A trip already
   seated keeps its tick and stays clickable, so a seat can be changed on the way. */
.fsp-tab-lock { display: none; font-size: 1.05em; line-height: 1; vertical-align: -2px; margin-right: .3rem; }
.fsp-step2-tabs-nav .nk-tab.is-locked, .fsp-leg-tabs-nav .nk-tab.is-locked { opacity: .55; cursor: not-allowed; }
.nk-tab.is-locked .fsp-tab-lock { display: inline-block; }
.fsp-step2-tabs-nav .nk-tab.is-picked .fsp-tab-check,
.fsp-leg-tabs-nav .nk-tab.is-picked .fsp-tab-check { display: inline-block; }

@media (max-width: 767px) {
  .fsp-ticket-row { flex-direction: column; align-items: stretch; }
  .fsp-via-legs { grid-template-columns: 1fr; row-gap: .85rem; }
  .fsp-ticket-info, .fsp-via-leg-row .nk-route.fsp-via-route { flex: 0 0 auto; width: 100%; min-width: 0; }
  .fsp-booknow-row { justify-content: flex-start; }
  .fsp-ticket-classes { border-left: none; padding-left: 0; flex-basis: 100%; width: 100%; min-width: 0; }
  .fsp-class-col { min-width: 100%; max-width: none; }
  .fsp-booknow-col { margin-left: 0; width: 100%; }
  .fsp-booknow-col .nk-btn { width: 100%; }
  .fsp-ticket-head .nk-route-path, .fsp-ticket-info .nk-route-path { flex-direction: column; justify-content: flex-start; height: 2.2rem; gap: .3rem; }
  .fsp-ticket-head .nk-route-path::before, .fsp-ticket-info .nk-route-path::before { top: auto; bottom: 0; margin-top: 0; }
  .fsp-ticket-head .nk-route-path::after, .fsp-ticket-info .nk-route-path::after { top: auto; bottom: -3px; margin-top: 0; }
  .fsp-ticket-head .nk-route-path > span, .fsp-ticket-info .nk-route-path > span { background: none; border: none; padding: 0; font-size: var(--nk-text-xs); color: var(--nk-muted); }
}

@media (min-width: 900px) and (max-height: 820px) {
  .nk-ticket.fsp-ticket { padding: .75rem .9rem; gap: .6rem; }
  .nk-ticket.fsp-ticket + .nk-ticket.fsp-ticket { margin-top: .7rem; }
  .fsp-booknow-row { padding-top: .6rem; }
}

@media (min-width: 900px) {
  .nk-ticket.fsp-ticket > .fsp-booknow-row { padding-top: .5rem; }
}

@media (min-width: 900px) {
  .nk-ticket.fsp-ticket { padding: .55rem .85rem .6rem; gap: .35rem; }
  .nk-ticket.fsp-ticket + .nk-ticket.fsp-ticket { margin-top: .6rem; }
  .fsp-ticket-head { gap: .55rem; }
  .fsp-ticket-head .op-mark { width: 1.9rem; height: 1.9rem; border-radius: 7px; }
  .fsp-ticket-head .op-mark .material-symbols-outlined { font-size: 1.1rem; }
  .fsp-ticket-head > .fsp-ticket-info-text { display: flex; align-items: center; gap: .55rem; min-width: 0; }
  .fsp-ticket-head > .fsp-ticket-info-text > .nk-truncate { flex: 0 1 auto; font-size: var(--nk-text-sm); }
  .fsp-ticket-badge-row { flex-wrap: nowrap; gap: .35rem; }
  .fsp-ticket .nk-route-time { font-size: var(--nk-text-lg); }
  .fsp-ticket .nk-route-path { height: 1.5rem; }
  .fsp-ticket .nk-route { gap: .75rem; }
  .fsp-ticket-row { gap: .6rem 1rem; }
  .fsp-booknow-col .nk-btn { padding: .6em 1.1em; min-width: 7.5rem; }
  .fsp-ticket-classes { gap: .45rem; padding-left: .85rem; }
  /* 8rem, not 7: the class name now carries the (i) beside it, and the portals found the same — their
     own comment on .fsp-class-col says 7rem was just short for that combination, which is exactly what
     pushed the icon past this card's right border here. */
  .fsp-class-col { gap: .15rem; padding: .25rem .5rem; min-width: 8rem; flex-basis: 8rem; }
}

/* ============================================================================
   NAUTIKA · Passengers & Seats / Payment steps (public site)
   ----------------------------------------------------------------------------
   The booking flow's geometry, lifted from the same ferry-search-panel.css the
   ticket rules above come from, so /book/trip reads as the Agency and BackOffice
   New Booking screen rather than as a different product wearing the same colours.

   The flow it lays out is the portals' flow, in the portals' order: passenger
   details first, in their own card; the seat map and fare pane revealed only
   once those validate; then a Payment step that reviews the trips and the
   passengers beside the fare and the payment mode.

   Same discipline as above — only rules anchored to an fsp- class the public
   flow actually uses. The portals' tab bars, remarks, trade discount, agency
   commission and passenger manifest table are all deliberately left behind:
   this site has one ticket type, no agent and no discount.

   --fsp-topbar-h is the height of the site navbar, which is sticky on every page
   (see nautika.site.css): the rail, the fare pane and the seat-map head all pin
   *under* the bar rather than to the top of the viewport, or the bar would cover
   them. --fsp-rail-h is measured in nautika.booking-trip.js, as in the portals.
   ========================================================================== */

:root { --fsp-topbar-h: var(--site-navbar-h, 0rem); }

/* ---- Back-toolbar above a step ------------------------------------------- */
.fsp-results-toolbar { display: flex; align-items: center; gap: .6rem; margin-bottom: 1rem; }
/* Every "Back to …" in the funnel is one chip — the whole pill is the control, icon and words together,
   rather than an icon button with a caption beside it that looked clickable and was not. Secondary,
   in the seat-hold countdown's own pairing (secondary-500 on black), so it reads the same in both
   themes and stays clear of primary, which is the way forward on every step. */
.fsp-back-chip { display: inline-flex; align-items: center; gap: .35rem; padding: .4rem .85rem .4rem .6rem;
  border-radius: var(--nk-radius-pill); border: 1px solid var(--nk-secondary-200);
  background: var(--nk-secondary-500); color: #000; font: inherit; font-size: var(--nk-text-sm);
  font-weight: 600; line-height: 1.2; text-decoration: none; cursor: pointer;
  transition: filter var(--nk-dur-fast), box-shadow var(--nk-dur-fast); }
.fsp-back-chip .material-symbols-outlined { font-size: 1.1rem; }
.fsp-back-chip:hover { filter: brightness(.95); color: #000; text-decoration: none; }
.fsp-back-chip:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--nk-secondary-200); }
.fsp-step2-toolbar, .fsp-step3-toolbar { margin-bottom: 1.25rem; }

/* ---- Progress rail: steps + seat-hold countdown, pinned ------------------- */
.fsp-progress-rail { position: sticky; top: var(--fsp-topbar-h, 0rem); z-index: 40;
  background: var(--nk-surface); padding: .75rem 0 .6rem;
  box-shadow: 0 6px 12px -10px rgb(0 0 0 / .35); margin-bottom: 1.25rem; }
.fsp-steps { max-width: 520px; margin-inline: auto; }
@media (min-width: 768px) {
  .fsp-steps { max-width: none; width: 100%; }
  .fsp-steps .nk-step { white-space: nowrap; }
}
/* Centred in the rail rather than tucked against its left edge: the chip is a warning about the whole
   booking, not a label for whatever happens to sit under it, and the steps above it are centred too.
   fit-content + auto margins, so the pill still hugs its own text. */
.fsp-progress-rail > .fsp-hold-countdown { display: flex; width: fit-content; margin: .6rem auto 0; }
.fsp-hold-countdown { display: flex; align-items: center; gap: .35rem; margin: 0 0 .6rem;
  padding: .35rem .7rem; border-radius: var(--nk-radius-pill); background: var(--nk-secondary-500);
  color: #000; border: 1px solid var(--nk-secondary-200);
  font-size: var(--nk-text-xs); font-weight: 700; }
.fsp-hold-countdown .material-symbols-outlined { font-size: 1rem; }
.fsp-hold-countdown-expired { background: var(--nk-error-50, #fdecea); color: var(--nk-error); }
/* Expired, the chip is a sentence rather than a clock, and the portals' version carries no icon on it. */
.fsp-hold-countdown-expired .material-symbols-outlined { display: none; }

/* ---- Passenger details: first, and in its own card ------------------------ */
.fsp-passengers-pane { margin-bottom: 1rem; }
.fsp-passengers-card { border: 1px solid var(--nk-line); border-radius: var(--nk-radius); background: var(--nk-surface);
  box-shadow: var(--nk-shadow); padding: .75rem .9rem .9rem; }
.fsp-passengers-actions { display: flex; justify-content: flex-end; align-items: center; gap: 1rem; margin-top: .75rem; }
.fsp-passengers-actions-hint { font-size: var(--nk-text-sm); color: var(--nk-muted); margin-right: auto; }
.fsp-passengers-error { font-size: var(--nk-text-sm); color: var(--nk-error); margin: .6rem 0 0; }

/* ---- Seats: map (left) + fare pane (right) -------------------------------- */
.fsp-step2-inner { --fsp-seatmap-max: 42rem;
  display: flex; align-items: flex-start; gap: 1.25rem;
  border: 1px solid var(--nk-line); border-radius: var(--nk-radius); background: var(--nk-surface);
  box-shadow: var(--nk-shadow); padding: 1rem 1.1rem 1.1rem;
  scroll-margin-top: calc(var(--fsp-topbar-h, 0rem) + var(--fsp-rail-h, 0px) + 1rem); }
.fsp-seatmap-pane { flex: 1 1 60%; min-width: 0; display: flex; flex-direction: column; gap: 1.25rem; }
/* width:100% is what makes "cap it and centre it" mean that: as a column flex item with auto inline
   margins, the leg was sized to its own contents instead of stretching, so the cap never came into play
   and — now that the decks are laid out by the width they are given — a two-deck vessel could never find
   the room to put them side by side. */
.fsp-seatmap-leg { width: 100%; max-width: var(--fsp-seatmap-max, 42rem); margin-inline: auto; }
.fsp-fare-pane { flex: 0 0 15rem; position: sticky;
  top: calc(var(--fsp-topbar-h, 0rem) + var(--fsp-rail-h, 0px) + 1rem); }

/* ---- The fare bar, on narrower windows -------------------------------------
   The BackOffice New Booking screen's: once the seat card is 1100px or narrower the fare card leaves the
   deck plan's side and becomes a bar along the bottom of the screen, under a full-width map. Collapsed it
   is one row — caret, "N of M seats picked", a chip per fare, the total — with Review and Checkout beside
   it; tapping the row (.is-open) opens the per-trip blocks above it. The button markup is in Trip.cshtml,
   its summary is written by renderFareBar in nautika.booking-trip.js.

   Fixed to the bottom of the window, as theirs is, and lined up with the seat card by measureFareBar in
   nautika.booking-trip.js (the portals' NkFareBar, which lives in a framework script this site must not
   load), which writes --fsp-bar-left/--fsp-bar-width/--fsp-bar-h on the card; the card pads its foot by
   the bar's height so the last row of the deck can be scrolled clear of it. Not sticky: a sticky bar
   cannot rise above the top of the card it is in, so opened while the card was only just on screen, half
   of it sat below the fold.

   A container query on the seat card's own width, as theirs is, rather than on the window: the card's
   width follows the page container (nautika.site.css), and a window breakpoint worked out from one
   container width silently goes wrong the day that width changes. [data-trip-steps] is exactly as wide
   as the card, and a query can only ask about an ancestor of what it styles. */
[data-trip-steps] { container: fsp-trip / inline-size; }
.fsp-fare-bar { display: none; }
@container fsp-trip (max-width: 1100px) {
  .fsp-step2-inner { flex-direction: column; padding-bottom: calc(var(--fsp-bar-h, 4rem) + .75rem); }
  /* Stacked, the cross axis is horizontal — and .fsp-step2-inner's align-items:flex-start therefore
     sizes the panes to their CONTENT rather than stretching them. The seat map has to say width:100%,
     or the deck plan is drawn into whatever narrow box its own contents happen to want. */
  .fsp-seatmap-pane { width: 100%; }
  .fsp-fare-pane { flex: 0 0 auto; position: fixed; top: auto; bottom: 0; z-index: 60; margin: 0;
    left: var(--fsp-bar-left, 0px); width: var(--fsp-bar-width, 100%); }
  .fsp-fare-pane .fsp-fare-card { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem .9rem; padding: .5rem .9rem;
    border-radius: var(--nk-radius) var(--nk-radius) 0 0; border-bottom: none;
    box-shadow: 0 -8px 24px -12px rgb(0 0 0 / .25); background: var(--nk-surface); }
  .fsp-fare-bar { display: inline-flex; align-items: center; gap: .5rem; flex: 1 1 0; min-width: 0; order: 1;
    padding: .25rem 0; background: none; border: none; text-align: left; color: var(--nk-ink); cursor: pointer; font: inherit; }
  .fsp-fare-bar-caret { font-size: 1.3rem; color: var(--nk-muted); transition: transform var(--nk-dur); }
  .fsp-fare-pane.is-open .fsp-fare-bar-caret { transform: rotate(180deg); }
  .fsp-fare-bar-summary { display: flex; flex-wrap: wrap; align-items: center; gap: .25rem .6rem; font-size: var(--nk-text-sm); }
  .fsp-fare-bar-seats { color: var(--nk-warning-700); font-weight: 600; white-space: nowrap; }
  .fsp-fare-bar-seats.is-done { color: var(--nk-success-700); }
  .fsp-fare-bar-chip { display: inline-flex; align-items: baseline; gap: .3rem; white-space: nowrap; padding-left: .6rem; border-left: 1px solid var(--nk-line-strong); }
  .fsp-fare-bar-chip-label { color: var(--nk-ink-soft); }
  .fsp-fare-bar-chip-calc { font-size: var(--nk-text-xs); color: var(--nk-muted); font-variant-numeric: tabular-nums; }
  .fsp-fare-bar-chip strong { font-family: var(--nk-font-display); color: var(--nk-ink); }
  .fsp-fare-bar-total { color: var(--nk-ink-soft); white-space: nowrap; padding-left: .6rem; border-left: 1px solid var(--nk-line-strong); }
  .fsp-fare-bar-total strong { font-family: var(--nk-font-display); font-size: var(--nk-text-lg); color: var(--nk-primary-700); margin-left: .2rem; }
  /* Three selectors deep so it outranks Trip.cshtml's phone rule that widens every large button: on the
     bar the button sits beside the summary until the window is too narrow for both (below). */
  .fsp-step2-inner .fsp-fare-pane .fsp-fare-payment-btn { width: auto; margin-top: 0; order: 2; flex: 0 0 auto;
    font-size: var(--nk-text-sm); padding: .7em 1.2em; }
  .fsp-fare-pane .fsp-fare-legs, .fsp-fare-pane .fsp-fare-total-so-far { order: 0; flex: 1 1 100%; width: 100%; display: none; margin-bottom: 0; }
  /* The per-trip blocks are label/amount rows — capped, side by side, so an amount does not sit a metre
     from its label. Capped in height too, which the portals' is not: a round trip's three blocks opened
     on a phone would otherwise push the bar's own row off the top of the screen. */
  .fsp-fare-pane.is-open .fsp-fare-legs { display: flex; flex-direction: row; flex-wrap: wrap; gap: .75rem 2rem;
    padding: .25rem 0 .5rem; border-bottom: 1px dashed var(--nk-line-strong); max-height: 55vh; overflow-y: auto; }
  .fsp-fare-pane.is-open .fsp-fare-legs > .fsp-fare-leg-block { flex: 1 1 18rem; max-width: 26rem; }
  .fsp-fare-pane.is-open .fsp-fare-total-so-far:not([hidden]) { display: flex; margin: 0; }
}
@media (min-width: 1600px) {
  .fsp-step2-inner { --fsp-seatmap-max: 54rem; }
  .fsp-fare-pane { flex-basis: 19rem; }
}

/* A date field that cannot be used yet — a later leg's Return on a multi-leg round trip, which is
   shown but belongs to the first journey alone. flatpickr's visible field is a readonly text input,
   so the theme's own .form-control colours would otherwise leave it looking live. */
.nk-datepicker-alt.nk-datepicker-disabled { opacity: .5; cursor: not-allowed; }

/* Class picker and legend, above the deck plan — the portals' .fsp-seatmap-head. Not sticky any more:
   the trip tab bar is what stays in view while the deck scrolls (see its rule above). Both at once
   would stack four bars over the deck on a phone, and the one a passenger loses first on a long deck is
   which trip they are seating, not the class they chose for it. */
.fsp-seatmap-head { padding: .4rem 0 .35rem; margin-bottom: .35rem; }
/* The results ticket's own class row hugs a route line, behind a dashed divider; here it is the whole
   width of the pane and reads left to right. */
.fsp-step2-classes { border-left: none; padding-left: 0; justify-content: flex-start; margin-bottom: .5rem; }
.fsp-seatmap-legend:empty { display: none; }

/* The seat map's own legend, drawn by the shared seat map into [data-seatmap-legend]. The rule is the
   portals' (ferry-search-panel.css), which this site does not load — without it the swatches have no
   size and the entries run together as one word. Two entries here, never six: see PublicSeatMap. */
.nk-sm-legend { display: flex; flex-wrap: wrap; gap: .4rem .9rem; }
.nk-sm-legend .nk-sm-leg { display: inline-flex; align-items: center; gap: .35rem;
  font-size: var(--nk-text-xs); color: var(--nk-ink-soft); }
.nk-sm-legend i { width: .95rem; height: .95rem; border-radius: 4px; border: 1.5px solid; display: inline-block; }

/* The deck panels themselves, another rule the portals get from ferry-search-panel.css and this site
   does not load — without it .bsm-decks has no layout at all, so an "Any class" vessel's two decks were
   simply two blocks stacked one above the other however much room the pane had.

   The mount is a query container, so which way they go is decided by the pane rather than by the window:
   the seat map shares its row with the fare card, and the same window can therefore be wide with the
   decks squeezed. Stacked by default — a phone, and a tablet held upright, has room for one — and side
   by side the moment the pane can hold both. */
.tp-seatmap { container: nk-seatmap / inline-size; }
.bsm-decks { display: flex; flex-direction: column; gap: 1rem; align-items: stretch; }
.bsm-decks .nk-sm-deck { position: relative; flex: 0 0 auto; min-width: 0; border: 1px solid var(--nk-line);
  border-radius: var(--nk-radius); background: var(--nk-surface); padding: .6rem; }
.bsm-decks .nk-sm-deck svg { display: block; width: 100%; height: auto; }
.nk-sm-deck-title { display: flex; align-items: baseline; gap: .5rem; margin-bottom: .4rem;
  font-size: var(--nk-text-sm); font-weight: 700; color: var(--nk-ink); }
.nk-sm-deck-title small { font-weight: 400; color: var(--nk-muted); font-size: var(--nk-text-xs); }
@container nk-seatmap (min-width: 40rem) {
  .bsm-decks { flex-direction: row; align-items: flex-start; }
  /* flex-basis is the main axis: 0 shares the width across a row, and would have meant no height at
     all in the stacked case above. */
  .bsm-decks .nk-sm-deck { flex: 1 1 0; }
}
/* Two decks need more than the single-deck cap, or side by side just means two narrow columns. The
   portals relax the same cap for the same reason. */
.fsp-seatmap-leg:has(.bsm-decks-multi) { max-width: min(100%, 64rem); }

/* The deck plan's seats. The portals get these from ferry-search-panel.css, which this site does not
   load — without them a seat is a picture: the arrow cursor says nothing is clickable, and nothing
   answers the pointer until the click has already gone to the server.

   Keyed on the status CODE the engine stamps on every seat group, not on the label beside it: the
   label is prose an operator may reword, and a seat that cannot be picked must not offer a hand. On
   this site PublicSeatMap has already collapsed every unavailable reason onto one, so in practice this
   is two states — but the rule is written so it stays right if that ever stops being true. */
.nk-sm-deck svg g[data-seat-id] { cursor: not-allowed; }
.nk-sm-deck svg g[data-seat-id][data-seat-status="AVAILABLE"],
.nk-sm-deck svg g[data-seat-id][data-seat-status="SELECTED"] { cursor: pointer; }
/* Something has to answer the pointer before the click: the seat lifts slightly rather than changing
   colour, because colour here is status and a hover that borrows it would read as a state change. */
.nk-sm-deck svg g[data-seat-id][data-seat-status="AVAILABLE"]:hover,
.nk-sm-deck svg g[data-seat-id][data-seat-status="SELECTED"]:hover {
  filter: brightness(1.06) saturate(1.08) drop-shadow(0 1px 2px rgb(0 0 0 / .28)); }
@media (prefers-reduced-motion: reduce) {
  .nk-sm-deck svg g[data-seat-id]:hover { filter: brightness(1.06); }
}

/* The seat-class (i) and its panel, ported from the portals' ferry-search-panel.css — which this site
   does not load, so without these the icon is an unstyled button and the panel never appears. The
   markup and the feature copy behind it come from the shared booking.info-popover.js, added to these
   server-rendered class columns by NkInfoPopover.enhanceSeatClasses. */
/* ---- The seat-class (i) popover ------------------------------------------
   The panel is "portaled" to <body> on open (see ferry-search-panel.js openInfoPanel/positionInfoPanel)
   rather than absolutely-positioned inside .fsp-info-popover: every .fsp-class-col has
   position:relative + a non-auto z-index (so the selected column can be raised above its siblings),
   and that combination establishes a CSS stacking context, which traps a nested absolutely-positioned
   popover's own z-index for comparison only *within* that context — no z-index on the popover itself
   can then make it paint above a later, unrelated ticket card. Moving it to <body> with position:fixed
   sidesteps the whole ancestor-stacking-context problem, which is why its position here is `fixed` with
   plain pixel left/top set by JS, not a percentage/transform anchored to a small parent. */
.fsp-info-popover { position: relative; display: inline-flex; }
.fsp-info-btn { display: inline-flex; align-items: center; justify-content: center; width: 1.3rem; height: 1.3rem; border-radius: 50%; color: var(--nk-muted); }
.fsp-info-btn:hover { color: var(--nk-primary); background: var(--nk-primary-50); }
.fsp-info-btn .material-symbols-outlined { font-size: 1.05rem; }
.fsp-info-panel {
  display: none; position: fixed; z-index: 950; width: 19rem; max-width: 82vw; background: var(--nk-surface);
  border: 1px solid var(--nk-line); border-radius: var(--nk-radius); box-shadow: var(--nk-shadow-lg); padding: 1rem;
}
/* A plain fade rather than nk-fade-up's 24px slide: the panel is anchored to the icon that opened it,
   and something that slides into position under the pointer reads as a misplaced panel correcting
   itself. It appears where it stays. */
.fsp-info-panel.nk-open { display: block; animation: nk-fade var(--nk-dur-fast) var(--nk-ease-out); }
.fsp-info-title { font-family: var(--nk-font-display); font-weight: 700; margin-bottom: .8rem; text-align: center; }
.fsp-info-close {
  position: absolute; top: .5rem; right: .5rem; width: 1.6rem; height: 1.6rem; border-radius: 50%;
  display: flex; align-items: center; justify-content: center; color: var(--nk-muted);
}
.fsp-info-close:hover { background: var(--nk-surface-2); color: var(--nk-ink); }
.fsp-info-close .material-symbols-outlined { font-size: 1.1rem; }
/* Plain-text popover body — the PMB/Fuel Surcharge info icons (see infoPopoverHtml) use this instead of
   .fsp-feature-list, which is specific to the seat-class popover's tick/no-tick lines. */
.fsp-info-text { font-size: var(--nk-text-sm); color: var(--nk-ink-soft); line-height: 1.5; text-align: left; }

/* NkInfoPopover.rowsHtml — a label/value list inside a popover, with one row allowed to stand out
   (the cancellation tiers on the cancel dialog: which band applies, and what the others would cost).
   The applicable row is marked by weight and the primary accent, not by a warning colour: it names a
   charge the reader has not yet agreed to, and red there reads as something having gone wrong. */
.fsp-info-rows { display: flex; flex-direction: column; gap: .35rem; }
.fsp-info-lede { font-weight: 700; color: var(--nk-ink); margin-bottom: .2rem; }
.fsp-info-row { display: flex; justify-content: space-between; gap: 1rem; }
.fsp-info-row-on { color: var(--nk-primary); font-weight: 600; }

/* Below ~640px an anchored popover can't reliably stay on-screen (the trigger can be anywhere), so it
   becomes a fixed bottom sheet instead — positionInfoPanel() just adds/removes this class, the fixed
   positioning below does the rest regardless of the trigger's location. */
@media (max-width: 640px) {
  .fsp-info-panel.fsp-info-panel-sheet.nk-open {
    position: fixed; top: auto; right: 0; bottom: 0; left: 0; transform: none;
    width: auto; max-width: none; max-height: 75vh; overflow-y: auto;
    border-radius: var(--nk-radius-lg) var(--nk-radius-lg) 0 0; box-shadow: var(--nk-shadow-xl);
    animation: nk-fade-up var(--nk-dur) var(--nk-ease-out);
  }
}

/* The seat-class panel is a list of short lines, some of them things the class does NOT include (the
   legacy copy lists both). The tick and the muted bar carry that difference; the words alone would read
   as a benefit either way. */
.fsp-feature-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .5rem; }
.fsp-feature-item { display: flex; align-items: flex-start; gap: .5rem;
  font-size: var(--nk-text-sm); line-height: 1.35; color: var(--nk-ink-soft); text-align: left; }
.fsp-feature-item .material-symbols-outlined { font-size: 1.05rem; line-height: 1.25; flex: 0 0 auto; color: var(--nk-success); }
.fsp-feature-item-no { color: var(--nk-muted); }
.fsp-feature-item-no .material-symbols-outlined { color: var(--nk-faint); }


/* A column with its panel open is raised above its neighbours (the panel itself is portaled to <body>,
   but anything else about the column — a focus ring, a hover — has to stay above them too). */
.fsp-class-col.fsp-info-active { z-index: 2; }

/* ---- The fare card, on both steps ---------------------------------------- */
.fsp-fare-card { border: 1.5px solid var(--nk-primary-200); border-radius: var(--nk-radius); background: var(--nk-surface);
  box-shadow: var(--nk-shadow); padding: 1rem; }
.fsp-fare-legs { display: flex; flex-direction: column; gap: .85rem; margin-bottom: .85rem; }
.fsp-fare-leg-block { padding-top: .7rem; border-top: 1px solid var(--nk-line); }
.fsp-fare-leg-block:first-child { padding-top: 0; border-top: none; }
.fsp-fare-leg-vessel { display: flex; align-items: baseline; gap: .5rem; font-family: var(--nk-font-display);
  margin-bottom: .35rem; }
.fsp-fare-leg-vessel-name { font-weight: 700; font-size: var(--nk-text-sm); flex: 0 0 auto; }
.fsp-fare-leg-route { flex: 1 1 auto; min-width: 0; font-weight: 400; font-size: var(--nk-text-xs);
  color: var(--nk-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.fsp-fare-leg-surcharge { display: flex; justify-content: space-between; align-items: center;
  font-size: var(--nk-text-xs); color: var(--nk-ink-soft); margin-top: .25rem; }
/* A fare line's arithmetic — "\20B950 \D7 2" — under its label rather than beside it, so a long seat
   class name and its calculation never fight for the same line. */
.fsp-fare-leg-surcharge > span:first-child { display: flex; flex-direction: column; min-width: 0; }
/* The label and its "what is this?" (i) share the first of those lines. The icon is the seat classes'
   one at three-quarter size: on a charge nobody disputes it should read as a footnote, not a control. */
.fsp-fare-leg-label { display: inline-flex; align-items: center; gap: .15rem; min-width: 0; }
.fsp-fare-leg-surcharge .fsp-info-btn { width: 1.1rem; height: 1.1rem; }
.fsp-fare-leg-surcharge .fsp-info-btn .material-symbols-outlined { font-size: .9rem; }
.fsp-fare-leg-surcharge > span:last-child { flex: 0 0 auto; font-variant-numeric: tabular-nums; }
.fsp-fare-calc { font-size: var(--nk-text-xs); color: var(--nk-muted); font-weight: 400; font-variant-numeric: tabular-nums; }
/* A seat class's name is the line's heading, as on the portals' card; its amount stays the weight of
   the PMB and fuel figures beneath it, so the column of amounts reads as one column. */
.fsp-fare-class-line .fsp-fare-leg-label { font-weight: 600; }
.fsp-fare-leg-total { display: flex; justify-content: space-between; font-size: var(--nk-text-sm); font-weight: 700;
  margin-top: .35rem; padding-top: .35rem; border-top: 1px dashed var(--nk-line); }
.fsp-fare-leg-caption { font-size: var(--nk-text-xs); font-weight: 700; color: var(--nk-muted);
  text-transform: uppercase; letter-spacing: .02em; margin-bottom: .3rem; }
.fsp-fare-total-so-far { display: flex; justify-content: space-between; font-size: var(--nk-text-xs);
  font-weight: 700; color: var(--nk-ink-soft); background: var(--nk-surface-2);
  border-radius: var(--nk-radius-sm); padding: .45rem .6rem; margin: -.35rem 0 .85rem; }
.fsp-fare-total-block { display: flex; justify-content: space-between; align-items: baseline;
  margin-top: .5rem; padding-top: .6rem; border-top: 1px solid var(--nk-line); font-weight: 700;
  font-size: var(--nk-text-lg); }
.fsp-fare-total-amount { color: var(--nk-primary); font-size: var(--nk-text-lg); font-family: var(--nk-font-display); }
.fsp-fare-payment-btn { width: 100%; margin-top: 1rem; }
/* The fare card beside the deck plan is as narrow as 15rem, and a large button's 1.8em of padding a side
   plus an icon and "Review and Checkout" does not fit in that — the label ran out of the button. So the
   card is a size container, and the button's label scales with the card it is in (between 13px and the
   base size), its padding tightens, and as a last resort the label wraps rather than overflowing. The
   fare bar sets its own size and padding below, more specifically, and is unaffected. */
.fsp-fare-card { container: fsp-fare / inline-size; }
.fsp-fare-payment-btn { font-size: clamp(.8125rem, 5.6cqi, var(--nk-text-base)); padding-inline: 1em;
  white-space: normal; line-height: 1.2; text-align: center; }
/* Seats still to choose on a journey left on "Any class": a line that says so and no figure — see
   legFareGroups in nautika.booking-trip.js. The same amber as the fare bar's "N of M seats picked". */
.fsp-fare-awaiting .fsp-fare-leg-label { color: var(--nk-warning-700); }
@media (max-width: 639px) {
  /* The bar's button takes a row of its own under the summary once there is no room beside it. */
  .fsp-step2-inner .fsp-fare-pane .fsp-fare-payment-btn { flex: 1 1 100%; width: 100%; }
}

/* ---- Payment step: review (left) + fare and payment mode (right) ---------- */
.fsp-pay-inner { display: flex; align-items: flex-start; gap: 1.5rem; }
.fsp-pay-main { flex: 1 1 55%; min-width: 0; display: flex; flex-direction: column; gap: 1.25rem; }
.fsp-pay-main > :empty, .fsp-pay-main > [hidden] { display: none; }
.fsp-pay-side { flex: 1 1 45%; min-width: 0; max-width: 34rem; position: sticky;
  top: calc(var(--fsp-topbar-h, 0rem) + var(--fsp-rail-h, 0px) + 1rem); }
@media (max-width: 1023px) {
  .fsp-pay-inner { flex-direction: column; }
  .fsp-pay-main, .fsp-pay-side { flex: 1 1 auto; width: 100%; max-width: none; }
  .fsp-pay-side { position: static; }
}
.fsp-pay-side .fsp-fare-leg-vessel { display: none; }
.fsp-pay-side .fsp-fare-leg-caption { font-weight: 700; color: var(--nk-ink); margin-bottom: .35rem; }
.fsp-pay-side .fsp-fare-leg-surcharge { font-size: var(--nk-text-sm); color: var(--nk-ink); padding: .2rem 0; }
.fsp-pay-side .fsp-fare-leg-surcharge > span:last-child { font-weight: 700; font-variant-numeric: tabular-nums; }
.fsp-pay-side .fsp-fare-calc { color: var(--nk-ink-soft); }
.fsp-pay-side .fsp-fare-leg-total { font-size: var(--nk-text-base); color: var(--nk-ink); }
.fsp-pay-side .fsp-fare-leg-total > span:last-child { font-weight: 800; }
.fsp-pay-card { border: 1px solid var(--nk-line); border-radius: var(--nk-radius); background: var(--nk-surface);
  box-shadow: var(--nk-shadow); padding: .75rem .9rem .9rem; }
.fsp-pay-title { margin: 0 0 .6rem; font-family: var(--nk-font-display); }
.fsp-pay-trip { padding-top: .7rem; border-top: 1px solid var(--nk-line); }
.fsp-pay-trip:first-child { padding-top: 0; border-top: none; }
.fsp-pay-trip + .fsp-pay-trip { margin-top: .7rem; }
.fsp-pay-trip-meta { display: flex; align-items: center; flex-wrap: wrap; gap: .4rem .6rem; margin: 0 0 .4rem; }
.fsp-pay-trip-vessel { font-size: var(--nk-text-sm); color: var(--nk-ink-soft); }
.fsp-pay-pax-head { display: flex; align-items: center; gap: .6rem; margin-bottom: .6rem; }
.fsp-pay-pax-head .fsp-pay-title { margin: 0; flex: 1 1 auto; }
.fsp-pay-muted { color: var(--nk-muted); font-size: var(--nk-text-xs); }

/* The passenger manifest — one row per passenger, one column per trip with the seat class and seat
   number each holds on it. The BackOffice and Agency Payment step's table: those apps draw it with their
   design system's .nk-table, which this site's does not carry, so the same values are restated here
   under this table's own class rather than defining a global .nk-table that would one day meet a real
   one. The scroll box is what lets a round trip's four columns fit a phone without the page scrolling
   sideways. */
.fsp-pay-pax-scroll { overflow-x: auto; }
.fsp-pay-pax-table { width: 100%; border-collapse: collapse; font-size: var(--nk-text-sm); }
.fsp-pay-pax-table thead th { background: var(--nk-surface-2); text-align: left; font-family: var(--nk-font-display);
  font-weight: 700; color: var(--nk-ink-soft); padding: .65rem .9rem; white-space: nowrap;
  border-bottom: 2px solid var(--nk-line); font-size: var(--nk-text-xs); text-transform: uppercase; letter-spacing: .04em; }
.fsp-pay-pax-table tbody td { padding: .6rem .9rem; border-bottom: 1px solid var(--nk-line); color: var(--nk-ink); vertical-align: top; }
.fsp-pay-pax-table .fsp-pay-trip-title { display: block; }
/* The one departure from the portals' table: they name the sector by code ("PB → HL"), which fits on a
   line; this site's legs carry only the full island names, and held to one line those pushed a two-trip
   table into a scrollbar on a desktop. So the route wraps, and the column is as wide as its seats. */
.fsp-pay-pax-table .fsp-pay-trip-route { display: block; font-weight: 500; text-transform: none; letter-spacing: 0;
  color: var(--nk-muted); white-space: normal; min-width: 9rem; }
/* Room for a name and its Lead chip on one line, now the trip columns can give some of theirs up. */
.fsp-pay-pax-table tbody td:first-child { min-width: 11rem; }
.fsp-pay-pax-name { font-weight: 700; display: flex; align-items: center; gap: .4rem; flex-wrap: wrap; }
.fsp-pay-pax-facts { font-size: var(--nk-text-xs); color: var(--nk-muted); }
/* Seat class and seat number as a pair of badges, the class quiet and the number solid. Laid out as their
   own inline row with a gap — two abutting badges read as one blob — in a wrapper span rather than a
   flex <td>, which would take the cell out of the table's column alignment. */
.fsp-pay-seat-pair { display: inline-flex; align-items: center; flex-wrap: wrap; gap: .4rem; margin-right: .5rem; vertical-align: middle; }
.fsp-pay-seat-pair:last-child { margin-right: 0; }
.fsp-seat-badge { display: inline-flex; align-items: center; padding: .2rem .55rem; border-radius: var(--nk-radius-sm);
  border: 1px solid var(--nk-line); font-size: var(--nk-text-xs); font-weight: 700; font-family: var(--nk-font-display); }
.fsp-seat-badge-class { background: var(--nk-primary-50); border-color: var(--nk-primary-200); color: var(--nk-primary-700); }
.fsp-seat-badge-num { padding: .1rem .3rem; background: var(--nk-primary); border-color: var(--nk-primary); color: #fff; }
.fsp-pay-chip { display: inline-flex; align-items: center; padding: .05rem .45rem; border-radius: var(--nk-radius-pill);
  border: 1px solid var(--nk-line); background: var(--nk-surface-2); color: var(--nk-ink-soft);
  font-size: var(--nk-text-xs); font-weight: 700; }
.fsp-pay-chip-lead { background: var(--nk-primary-50); border-color: var(--nk-primary-200); color: var(--nk-primary-700); }
/* The live passenger form is MOVED here while it is being edited, never copied — so its own card
   chrome and its "Select seats" action, which mean nothing on this step, are hidden rather than
   removed: the node handed back to the seats step is exactly the one it lent out. */
.fsp-pay-pax-slot .fsp-passengers-pane { margin-bottom: 0; }
.fsp-pay-pax-slot .fsp-passengers-card { border: none; box-shadow: none; padding: 0; }
.fsp-editing-pax .fsp-passengers-actions { display: none; }
/* The pane arrives with its own "Passenger details" heading, into a card whose head already says exactly
   that — two identical titles, one above the other. The progress count beside it is worth keeping, so
   only the heading goes. */
.fsp-pay-pax-slot .fsp-passengers-title { display: none; }
.fsp-pay-pax-slot .fsp-passengers-toolbar { margin-bottom: .4rem; }
/* The required marker. The portals colour it from their own design system (.nk-label .nk-req); this
   site never had a rule for it at all, so every asterisk on the passenger card and here rendered in the
   label's own muted grey and said nothing. */
.nk-req { color: var(--nk-error); font-weight: 700; }

/* The checkout consent, directly above the button it is about. A checkbox and a paragraph rather than
   fine print: the tick is the record that it was accepted, so it has to be legible and unticked to
   begin with. align-items:flex-start keeps the box on the sentence's first line however many lines it
   wraps to, and the whole thing is a <label>, so the text is part of the hit area. */
.fsp-consent { display: flex; align-items: flex-start; gap: .55rem; margin: .9rem 0 .6rem;
  font-size: var(--nk-text-sm); line-height: 1.45; color: var(--nk-ink-soft); cursor: pointer; }
.fsp-consent input[type="checkbox"] { flex: 0 0 auto; width: 1.05rem; height: 1.05rem; margin-top: .12rem;
  accent-color: var(--nk-primary); cursor: pointer; }
.fsp-consent a { color: var(--nk-primary-600); text-decoration: underline; text-underline-offset: 2px; }
.fsp-consent a:hover { color: var(--nk-primary-700); }

.fsp-payment-mode-field { margin: .8rem 0 0; }
/* The dropdown fills its field the way a select would, rather than shrinking to its own label. */
.fsp-payment-mode-field .nk-dropdown { width: 100%; }
.fsp-payment-mode-field .nk-dropdown-toggle { width: 100%; justify-content: space-between; }

/* ============================================================================
   NAUTIKA · Passenger details (public site)
   ----------------------------------------------------------------------------
   The Agency/BackOffice New Booking passenger card, lifted from the same
   ferry-search-panel.css as everything above it: a roster row per passenger
   (number · name · facts · Lead chip · status) over a collapsible form.

   One substitution runs through the whole block. The portals build their
   passenger fields out of .bk-field, which in THEIR design system is a light
   field on a white card. In Nautika.Components — this site's copy — .bk-field
   is the dark hero search deck's field (white text on a translucent navy slab),
   because that is the only place the public site uses it. Reusing it here would
   paint a row of dark slabs across a white card, so the same field is spelled
   .fsp-field, defined below with the internal portals' values.
   ========================================================================== */

/* .nk-pax-field / .nk-pax-dd are the shared passenger card's field and dropdown (booking.passenger-card.js).
   The card is one piece of markup across all three booking apps now, so it names the role rather than
   any one app's class — which is what lets this site dress it without inheriting .bk-field, for exactly
   the reason set out above. Aliased onto .fsp-field rather than restated, so the two cannot drift. */
/* ---- The field itself: the internal portals' .bk-field, under a name this
        site's design system does not already spend on the dark deck. --------- */
.fsp-field, .nk-pax-field { display: flex; flex-direction: column; gap: .15rem; padding: .4rem .65rem;
  border-radius: var(--nk-radius); border: 1.5px solid var(--nk-line); background: var(--nk-surface);
  transition: border-color var(--nk-dur-fast), box-shadow var(--nk-dur-fast); min-width: 0; }
.fsp-field:focus-within, .nk-pax-field:focus-within { border-color: var(--nk-primary); box-shadow: 0 0 0 4px var(--nk-primary-50); }
/* A contact field the form will not accept as it stands — the lead passenger's phone or email while
   empty or malformed, anyone's while malformed (markContactFields in nautika.booking-trip.js). Red
   while the visitor is in it too: the ring tells them where they are, the border what is wrong. */
.nk-pax-field:has(.is-invalid) { border-color: var(--nk-error); }
.nk-pax-field:has(.is-invalid):focus-within { box-shadow: 0 0 0 4px var(--nk-error-50, #fdecea); }
.fsp-field > label, .nk-pax-field > label { font-size: .66rem; font-weight: 700; text-transform: uppercase; letter-spacing: .07em;
  color: var(--nk-muted); }
/* Payment Mode's label is error-coloured outright, not just its asterisk: it is the one thing on the
   payment step the visitor must set before anything can happen, sitting in a column of read-only
   figures where another quiet grey micro-label reads as one more of them. Directly after the muted
   rule it overrides, and for that reason — the two selectors weigh the same, so this is decided by
   which comes last and nothing else. */
.fsp-payment-mode-field > label { color: var(--nk-error); }
.fsp-field input, .nk-pax-field input,
.fsp-field textarea, .nk-pax-field textarea { border: none; outline: none; font-size: var(--nk-text-base); font-weight: 600;
  font-family: var(--nk-font-display); background: none; padding: 0; width: 100%; color: var(--nk-ink); }
/* A multi-line field is still a field — the portals' Remarks box is the reason (nautika.components.css);
   kept in step here so a textarea on this site never renders as a box inside a box either. */
.fsp-field textarea, .nk-pax-field textarea { resize: vertical; min-height: 3.4rem; line-height: 1.45; }
.fsp-field input::placeholder, .nk-pax-field input::placeholder,
.fsp-field textarea::placeholder, .nk-pax-field textarea::placeholder { font-weight: 400; color: var(--nk-faint); }
/* The passenger form is filled on a phone more than anywhere else, and its inputs sat just under
   the 16px at which iOS Safari stops zooming a focused field. Zooming mid-roster loses the page's
   place for every passenger after the first. */
@media (max-width: 820px) { .fsp-field input, .nk-pax-field input,
  .fsp-field textarea, .nk-pax-field textarea { font-size: max(16px, var(--nk-text-base)); } }
.fsp-dd, .nk-pax-dd { flex: 1; min-width: 0; }
.fsp-dd .nk-dropdown-toggle, .nk-pax-dd .nk-dropdown-toggle { border: none; background: none; padding: 0; min-width: 0; width: 100%;
  font-family: var(--nk-font-display); font-weight: 600; font-size: var(--nk-text-base); }
.fsp-dd .nk-dropdown-toggle:hover, .nk-pax-dd .nk-dropdown-toggle:hover { box-shadow: none; }
.fsp-dd .nk-dropdown-menu, .nk-pax-dd .nk-dropdown-menu { min-width: min(240px, calc(100vw - 2.5rem)); max-height: 16rem; overflow-y: auto; }
.fsp-dd .nk-dropdown-toggle [data-nk-dd-label], .nk-pax-dd .nk-dropdown-toggle [data-nk-dd-label] { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ---- Toolbar: title, how many are still outstanding, and the two shortcuts -- */
.fsp-passengers-toolbar { display: flex; align-items: center; flex-wrap: wrap; gap: .4rem 1rem; margin-bottom: .6rem; }
.fsp-passengers-toolbar-main { display: flex; align-items: baseline; gap: .6rem; flex: 1 1 auto; min-width: 0; }
.fsp-passengers-title { margin: 0; font-family: var(--nk-font-display); }
.fsp-passengers-progress { font-size: var(--nk-text-sm); color: var(--nk-muted); white-space: nowrap; }
.fsp-passengers-progress[data-state="ok"] { color: var(--nk-success-700); font-weight: 600; }
.fsp-passengers-tools { display: flex; align-items: center; flex-wrap: wrap; gap: .25rem; margin-left: auto; }
.fsp-passengers-tools > [hidden] { display: none; }

/* ---- Roster: one row per passenger, its form collapsing under it ------------
   overflow must stay visible — the gender / nationality / dial-code menus open
   past the card's edge — and the open card (or any with focus inside) is lifted
   above its siblings so a menu never ends up under the next row. */
.fsp-passengers-list { display: flex; flex-direction: column; gap: .45rem; }
.fsp-passengers-card, .fsp-passengers-list, .fsp-passenger-body { overflow: visible; }
.fsp-passenger-card { border: 1px solid var(--nk-line); border-radius: var(--nk-radius);
  background: var(--nk-surface); padding: 0; overflow: visible; position: relative; z-index: 1; }
.fsp-passenger-card.is-open { z-index: 2; border-color: var(--nk-primary-200); box-shadow: var(--nk-shadow-xs); }
.fsp-passenger-card:focus-within, .fsp-passenger-card:has(.nk-dropdown.nk-open) { z-index: 5; }
.fsp-passenger-card.has-error { border-color: var(--nk-error); }
.fsp-passenger-card-infant { border-color: var(--nk-secondary-200, var(--nk-line)); }
.fsp-passenger-card .nk-dropdown-menu { z-index: var(--nk-z-dropdown); }

.fsp-pax-row { display: flex; align-items: center; gap: .6rem; width: 100%; padding: .45rem .7rem;
  background: none; border: none; border-radius: var(--nk-radius) var(--nk-radius) 0 0;
  text-align: left; font: inherit; color: var(--nk-ink); cursor: pointer; }
.fsp-pax-row:hover { background: var(--nk-surface-2); }
.fsp-pax-row-num { flex: 0 0 1.6rem; height: 1.6rem; display: inline-flex; align-items: center; justify-content: center;
  border-radius: 50%; background: var(--nk-surface-2); border: 1px solid var(--nk-line);
  font-size: var(--nk-text-xs); font-weight: 700; font-family: var(--nk-font-display); color: var(--nk-ink-soft); }
.fsp-passenger-card.is-complete .fsp-pax-row-num { background: var(--nk-success); border-color: var(--nk-success); color: #fff; }
.fsp-pax-row-main { flex: 1 1 auto; min-width: 0; display: flex; align-items: baseline; gap: .6rem; flex-wrap: wrap; }
.fsp-pax-row-name { font-weight: 700; font-family: var(--nk-font-display); font-size: var(--nk-text-sm);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%; }
.fsp-pax-row-facts { font-size: var(--nk-text-xs); color: var(--nk-muted); white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.fsp-pax-row-lead { font-size: .65rem; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  padding: .12rem .45rem; border-radius: 999px; background: var(--nk-primary-50); color: var(--nk-primary-700); flex-shrink: 0; }
.fsp-pax-row-status { font-size: var(--nk-text-xs); font-weight: 600; padding: .15rem .55rem;
  border-radius: 999px; white-space: nowrap; flex-shrink: 0; }
.fsp-pax-row-status[data-state="empty"] { background: var(--nk-surface-2); color: var(--nk-muted); }
.fsp-pax-row-status[data-state="partial"] { background: var(--nk-warning-50); color: var(--nk-warning-700); }
.fsp-pax-row-status[data-state="ok"] { background: var(--nk-success-50); color: var(--nk-success-700); }
.fsp-pax-row-caret { font-size: 1.25rem; color: var(--nk-muted); transition: transform var(--nk-dur); flex-shrink: 0; }
.fsp-passenger-card.is-open .fsp-pax-row-caret { transform: rotate(180deg); }

.fsp-passenger-body { padding: .25rem .75rem .7rem; border-top: 1px dashed var(--nk-line); }
.fsp-passenger-head { display: flex; align-items: center; justify-content: space-between; gap: 1rem; margin-bottom: .35rem; }
.fsp-passenger-lead { display: inline-flex; align-items: center; gap: .4rem; font-size: var(--nk-text-sm);
  color: var(--nk-ink-soft); cursor: pointer; user-select: none; }
.fsp-passenger-infant-badge { display: inline-flex; align-items: center; font-size: var(--nk-text-xs);
  font-weight: 700; color: var(--nk-secondary-700, var(--nk-ink-soft));
  background: var(--nk-secondary-50, var(--nk-surface-2));
  border: 1px solid var(--nk-secondary-200, var(--nk-line)); border-radius: var(--nk-radius-pill); padding: .1rem .55rem; }
.fsp-pax-error { color: var(--nk-error); font-size: var(--nk-text-xs); margin: .4rem 0 0; }

/* ---- The fields: flex, not grid, so a narrowed field (Age) is followed by the
        next one rather than by the rest of a grid column. ------------------- */
/* The passenger card is a query CONTAINER, and the field layout below answers to its width rather than
   the window's. The same card is rendered at the full width of the passenger step and again, in the
   public site, inside the Payment step's narrow left column — the live form is MOVED there rather than
   copied. A window-width rule laid the widest one-row layout out inside a ~590px box and pushed Phone
   and Email clean out of the card. Inline-size containment does not clip, so the gender / nationality /
   dial-code menus still open past the card's edge as before. */
.fsp-passenger-card { container: nk-pax-card / inline-size; }

.fsp-passenger-grid { display: flex; flex-wrap: wrap; gap: .5rem .6rem; }
.fsp-passenger-grid > .nk-pax-field { flex: 1 1 11rem; min-width: 0; }
.fsp-passenger-grid > .nk-pax-field.fsp-pax-age { flex: 0 0 5.5rem; }
.fsp-passenger-grid > .nk-pax-field.fsp-pax-dob { flex: 0 0 9.5rem; }
.fsp-passenger-grid > .fsp-pax-contact { flex: 1 1 26rem; min-width: 0;
  display: flex; flex-wrap: wrap; gap: .5rem .6rem; }
.fsp-pax-contact > .nk-pax-field.fsp-pax-phone { flex: 0 0 15rem; min-width: 0; }
.fsp-pax-contact > .nk-pax-field:not(.fsp-pax-phone) { flex: 1 1 10rem; min-width: 0; }
/* .nk-pax-field's own column direction stretches children across the full width; align-self keeps this
   row hugging its (now narrow) content instead of re-introducing the dead space it was narrowed to remove. */
.fsp-phone-group { display: flex; align-items: center; align-self: flex-start; gap: .5rem; }
.fsp-phone-group .fsp-dialcode-dd { flex: 0 0 auto; width: auto; }
.fsp-phone-group .fsp-dialcode-dd .nk-dropdown-toggle { width: auto; display: inline-flex; align-items: center; gap: .15rem; }
.fsp-phone-group .fsp-dialcode-dd .nk-dropdown-toggle [data-nk-dd-label] { overflow: visible; }
.fsp-phone-group .fsp-dialcode-dd .nk-caret { margin-left: 0; }
.fsp-phone-group input[data-pax-role="phone"] { width: 100%; max-width: 7rem; }

@container nk-pax-card (max-width: 26rem) {
  /* Every field's 11rem basis already exceeds the row at this width, so Age's fixed narrow box buys
     nothing and just floats alone on its own row — it grows like the rest instead. */
  .fsp-passenger-grid > .nk-pax-field.fsp-pax-age { flex: 1 1 11rem; }
  .fsp-pax-contact { flex-direction: column; }
  /* The pair's flex-basis was written for a ROW, where it means width. Turning the strip on its side
     makes the main axis vertical, so 15rem and 10rem became field HEIGHTS — two enormous empty boxes
     on every phone. Stacked, each field is simply as tall as its own contents. Both selectors spelled
     out because the row rules they undo are themselves class-qualified, and a container query adds no
     specificity of its own. */
  .fsp-pax-contact > .nk-pax-field.fsp-pax-phone,
  .fsp-pax-contact > .nk-pax-field:not(.fsp-pax-phone) { flex: 0 0 auto; }
}
/* The roster row's summary is the card's own business, so it goes by the card's width; the toolbar
   above the list is not, and stays with the window. */
@container nk-pax-card (max-width: 34rem) {
  .fsp-pax-row-facts { display: none; }
}
@media (max-width: 639px) {
  .fsp-passengers-tools .nk-btn { padding-inline: .6em; }
}
/* A card wide enough for it: one row per passenger. Proportional shares with small minimums instead of
   fixed bases, so the row squeezes to fit rather than wrapping Phone + Email onto a second line. The
   minimums add up to ~59rem, which is where the threshold comes from. */
@container nk-pax-card (min-width: 60rem) {
  .fsp-passenger-grid { flex-wrap: nowrap; gap: .45rem; }
  .fsp-passenger-grid > .fsp-pax-contact { gap: .45rem; flex: 2.4 1 0; min-width: 23rem; flex-wrap: nowrap; }
  .fsp-passenger-grid > .nk-pax-field { flex: 1 1 0; min-width: 6rem; }
  .fsp-passenger-grid > .nk-pax-field.fsp-pax-age { flex: 0 0 5rem; min-width: 0; }
  .fsp-passenger-grid > .nk-pax-field.fsp-pax-gender { flex: 0 0 7rem; min-width: 0; }
  .fsp-passenger-grid > .nk-pax-field.fsp-pax-nationality { flex: 0 0 10rem; min-width: 0; }
  .fsp-pax-contact > .nk-pax-field.fsp-pax-phone { flex: 0 0 auto; }
  .fsp-pax-contact .fsp-phone-group input[data-pax-role="phone"] { width: 6.8rem; }
  .fsp-pax-contact > .nk-pax-field:not(.fsp-pax-phone) { flex: 1 1 0; min-width: 9rem; }
  /* A non-Indian nationality adds two more fields, and the one-row minimums stop fitting — the row
     goes back to wrapping rather than running off the edge of the card. */
  .fsp-passenger-grid:has([data-pax-natid]:not([hidden])) { flex-wrap: wrap; }
  .fsp-passenger-grid:has([data-pax-natid]:not([hidden])) > .nk-pax-field { flex: 1 1 11rem; }
  .fsp-passenger-grid:has([data-pax-natid]:not([hidden])) > .nk-pax-field.fsp-pax-age { flex: 0 0 5.5rem; }
  .fsp-passenger-grid:has([data-pax-natid]:not([hidden])) > .fsp-pax-contact { flex: 1 1 26rem; flex-wrap: wrap; }
}

/* ---- E-ticket ------------------------------------------------------------------------------------
   The ticket itself is no longer styled here. The Booking API renders it as one complete,
   self-contained document — fonts, sector colours and artwork inlined — and booking.eticket.js mounts
   that document in a sandboxed frame, so what a passenger sees on screen and what prints to PDF are
   the same document rather than two that have to be kept looking alike. What is left to style is the
   frame and the buttons around it.

   Isolation is the other half of the point: a travel document must not inherit whatever page it is
   embedded in — its resets, its design-system tokens, or its dark mode. -------------------------- */
.fsp-eticket { border: 1px solid var(--nk-line); border-radius: var(--nk-radius);
  background: var(--nk-surface); box-shadow: var(--nk-shadow-sm); overflow: hidden; }
/* A starting height, replaced by the measured one the moment the document loads. Without it the
   frame renders at the HTML default of 150px for as long as the layout takes, which reads as a
   broken ticket rather than a loading one. */
.fsp-eticket-frame { display: block; width: 100%; height: 58rem; border: 0; background: #fff; }
.fsp-eticket-actions { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: .6rem;
  margin-top: 1rem; }
.fsp-eticket-note { font-size: var(--nk-text-xs); color: var(--nk-warning-700); }
