/* ═══════════════════════════════════════════════════════════════════
   Tour page
   ═══════════════════════════════════════════════════════════════════

   The page this replaces was an event page wearing tour vocabulary. It
   opened on a 500px black rectangle where a banner would have been (no
   tour on this platform has one), then offered a row of icon buttons that
   collapsed the fifteen-day itinerary and the twelve inclusions behind a
   click. The single most valuable thing the agency had written was
   invisible on arrival, while "Featured Speakers", "Venue / Address" and
   a 0.00 star rating held the layout open.

   A tour answers different questions than an event. Where does it go, how
   long, what happens each day, what is included, what is the weather like
   then, what does it cost. This page is those questions in that order,
   and the itinerary is open because the itinerary is the product.

   No new visual identity: the vocabulary is the one destination pages and
   tour cards already use — --hub-* tokens, hairline cards, --hub-fill for
   state, and the --tp-rating season scale from theme.css.
   ═══════════════════════════════════════════════════════════════════ */

/* ── Shell ──────────────────────────────────────────────────────── */

.tour-page {
    background: var(--hub-bg);
    color: var(--hub-ink);
    /* Treść rysuje skrypt po pobraniu wycieczki. Do tego czasu pusty <main>
       wpuszczał stopkę na pierwszy ekran, a potem ją spychał: CLS 0,71
       (pomiar 2026-10-17). Ekran zarezerwowany z góry — stopka zaczyna
       pod nim i nie skacze. */
    min-height: 100vh;
}

.tour-wrap {
    width: min(1180px, 100% - 2.5rem);
    margin-inline: auto;
}

.tour-section {
    padding: clamp(2.25rem, 4.5vw, 3.5rem) 0;
    border-top: 1px solid var(--hub-hairline);
}

.tour-section:first-of-type { border-top: 0; }

.tour-section-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    margin-bottom: 1.5rem;
}

.tour-section-title {
    margin: 0;
    font-size: clamp(1.35rem, 2.4vw, 1.75rem);
    font-weight: 700;
    letter-spacing: -0.015em;
    text-wrap: balance;
}

.tour-section-sub {
    margin: 0;
    color: var(--hub-ink-muted);
    font-size: 0.95rem;
}

/* ── Hero ───────────────────────────────────────────────────────
   No tour on this platform carries a photograph, so the hero cannot be
   an image well — the old one rendered as an empty black box half a
   screen tall. What a tour does always have is a route and a shape, so
   that is what opens the page. */

.tour-hero {
    /* Jedna liczba na margines nagłówka: lewy odstęp tekstu i prawy odstęp
       zdjęcia liczą się z niej, więc nie da się ich rozjechać. Liczone w `%`,
       nie w `vw` — `vw` obejmuje pasek przewijania i nagłówek uciekłby o kilka
       pikseli względem sekcji niżej. */
    --tour-gutter: max(1.25rem, calc((100% - 1180px) / 2));
    position: relative;
    padding: clamp(1.5rem, 3vw, 2.5rem) 0 clamp(2rem, 4vw, 3rem);
    background:
        radial-gradient(120% 90% at 15% 0%, rgb(var(--hub-accent-rgb) / 0.14), transparent 60%),
        linear-gradient(168deg, var(--hub-bg-deep) 0%, var(--hub-bg) 62%, var(--hub-elev) 100%);
    overflow: hidden;
}

.tour-breadcrumb {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    align-items: center;
    font-size: 0.85rem;
    color: var(--hub-ink-muted);
    margin-bottom: 1.5rem;
}

.tour-breadcrumb a {
    color: var(--hub-ink-muted);
    text-decoration: none;
}

/* Okruszki to linki wyjścia ze strony, a miały 24 px wysokości — trafia się
   w nie dopiero za drugim razem. Napis zostaje tam, gdzie był; rośnie sam
   obszar dotyku, więc rząd okruszków wyższy jest o dwadzieścia pikseli. */
@media (hover: none) and (pointer: coarse) {
    .tour-breadcrumb a {
        display: inline-flex;
        align-items: center;
        min-height: 44px;
    }
}

.tour-breadcrumb a:hover {
    color: var(--hub-accent);
    text-decoration: underline;
}

.tour-breadcrumb .tour-crumb-now {
    color: var(--hub-ink);
    /* A fifteen-word tour title would push the whole trail off a phone. */
    max-width: min(46ch, 100%);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.tour-pills {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-bottom: 1rem;
}

.tour-pill {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.32rem 0.7rem;
    border: 1px solid var(--hub-hairline);
    border-radius: 999px;
    background: rgb(var(--hub-elev-rgb) / 0.7);
    font-size: 0.8rem;
    font-weight: 600;
    letter-spacing: 0.01em;
    color: var(--hub-ink-muted);
}

.tour-pill svg { width: 14px; height: 14px; }

.tour-pill-accent {
    border-color: rgb(var(--hub-accent-rgb) / 0.4);
    background: rgb(var(--hub-accent-rgb) / 0.1);
    color: var(--hub-accent-strong);
}

/* Two seats left is a fact worth carrying at the top, not only in the
   booking card the reader has to look sideways for. */
.tour-pill-scarce {
    border-color: rgb(var(--hub-warning-rgb, 200 120 20) / 0.45);
    background: rgb(var(--hub-warning-rgb, 200 120 20) / 0.12);
    color: var(--hub-warning);
}

.tour-title {
    margin: 0 0 0.75rem;
    font-size: clamp(1.9rem, 4.4vw, 3rem);
    line-height: 1.1;
    letter-spacing: -0.025em;
    font-weight: 800;
    text-wrap: balance;
    max-width: 22ch;
}

.tour-lede {
    margin: 0;
    max-width: 62ch;
    font-size: clamp(1rem, 1.5vw, 1.1rem);
    line-height: 1.65;
    color: var(--hub-ink-muted);
}

/* ── Facts strip ────────────────────────────────────────────────
   The four things a traveller checks before reading a word of the
   itinerary. Not tiles with borders — a tour has one identity, and
   boxing every figure separately reads as four unrelated objects. */

.tour-facts {
    display: grid;
    /* 210px, nie 150px: w zwężonej kolumnie obok zdjęcia cztery fakty po
       150px mieściły się we trzy, więc czwarty spadał do drugiego rzędu obok
       pustego pola. Przy 210px wychodzi równe 2×2, a na pełnej szerokości
       dalej jeden rząd. */
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 200px), 1fr));
    gap: 1px;
    margin-top: 1.35rem;
    background: var(--hub-hairline);
    border: 1px solid var(--hub-hairline);
    border-radius: var(--hub-radius);
    overflow: hidden;
}

/* Cztery fakty to podpis pod nagłówkiem, nie druga tabela cennikowa. Były
   wielkości akapitu — 1 rem padding, wartość 1.05 rem — i na telefonie zżerały
   247 px pod samym tytułem. Etykieta prowadzi, wartość jest mocna, ale obie
   o stopień mniejsze; dopisek schodzi do roli dopisku. */
.tour-fact {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    padding: 0.65rem 0.85rem;
    background: var(--hub-elev);
}

.tour-fact-label {
    font-size: 0.62rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    font-weight: 700;
    color: var(--hub-ink-muted);
}

.tour-fact-value {
    font-size: 0.92rem;
    font-weight: 700;
    line-height: 1.35;
}

.tour-fact-note {
    font-size: 0.72rem;
    line-height: 1.35;
    color: var(--hub-ink-muted);
}

/* ── Body grid ──────────────────────────────────────────────────
   Content left, booking rail right. The rail is sticky on desktop and
   becomes a fixed bar at the bottom on a phone, where a sidebar would
   simply be 900px of scrolling before the itinerary starts. */

.tour-body {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 340px;
    gap: clamp(1.5rem, 3vw, 3rem);
    align-items: start;
}

.tour-main { min-width: 0; }

.tour-rail {
    position: sticky;
    top: 92px;
    display: flex;
    flex-direction: column;
    gap: 1rem;
}

/* ── Route ──────────────────────────────────────────────────────
   Six stops over fifteen days, and which region each sits in — the
   thing a "Venue / Address" block could never say about a tour that
   moves every other day. Stops are matched against the destination
   catalogue, so each one links to a page that already exists. */

.tour-route {
    display: flex;
    flex-wrap: wrap;
    align-items: stretch;
    gap: 0.5rem;
    padding: 0;
    margin: 0;
    list-style: none;
}

.tour-stop {
    position: relative;
    display: flex;
    align-items: center;
    gap: 0.6rem;
}

.tour-stop-link {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    padding: 0.7rem 1rem;
    border: 1px solid var(--hub-hairline);
    border-radius: var(--hub-radius);
    background: var(--hub-elev);
    text-decoration: none;
    color: inherit;
    transition: border-color var(--hub-transition), background var(--hub-transition);
}

.tour-stop-link:hover {
    border-color: rgb(var(--hub-accent-rgb) / 0.5);
    background: rgb(var(--hub-accent-rgb) / 0.06);
}

.tour-stop-name {
    font-weight: 700;
    font-size: 0.95rem;
}

.tour-stop-meta {
    font-size: 0.78rem;
    color: var(--hub-ink-muted);
}

.tour-stop-arrow {
    /* Decoration between two labels, not text — faint is right here. */
    color: var(--hub-ink-faint);
    flex: none;
}

.tour-stop-arrow svg { width: 16px; height: 16px; display: block; }

/* The map is the one picture this tour has, so it gets real height
   rather than the sliver a location block used to allot. */
.tour-map-shell { position: relative; margin-top: 1.5rem; }

.tour-map {
    height: clamp(280px, 38vw, 420px);
    border: 1px solid var(--hub-hairline);
    border-radius: var(--hub-radius);
    overflow: hidden;
    background: var(--hub-surface);
}

/* Choosing a basemap. The same control as the tours map, so the two read
   as one product — and it sits over the map rather than above it, because
   the route below is what the section is about. */
.tour-map-layers {
    position: absolute;
    z-index: 500;
    top: 0.6rem; right: 0.6rem;
    display: flex;
    padding: 2px;
    border: 1px solid var(--hub-hairline);
    border-radius: 9px;
    background: rgb(var(--hub-elev-rgb) / 0.92);
    backdrop-filter: blur(6px);
    box-shadow: 0 2px 10px rgb(0 0 0 / 0.12);
}

.tour-map-layer {
    min-height: 28px;
    padding: 0 0.6rem;
    border: 0;
    border-radius: 7px;
    background: none;
    color: var(--hub-ink-muted);
    font: inherit; font-size: 0.78rem; font-weight: 700;
    cursor: pointer;
    white-space: nowrap;
}

.tour-map-layer.is-on { background: var(--hub-accent); color: var(--hub-on-accent); }
.tour-map-layer:not(.is-on):hover { color: var(--hub-accent-strong); }

@media (max-width: 560px) {
    .tour-map-layers { left: 0.6rem; right: 0.6rem; justify-content: space-between; }
    .tour-map-layer { flex: 1 1 0; padding: 0 0.25rem; text-align: center; }
}

@media (hover: none) and (pointer: coarse) {
    .tour-map-layer { min-height: 44px; }
}

.tour-map-note {
    margin: 0.65rem 0 0;
    font-size: 0.82rem;
    color: var(--hub-ink-muted);
}

/* ── Przejazdy na mapie ──────────────────────────────────────────────────
   Każdy przejazd rysowany osobno, w stylu swojego środka transportu. Wcześniej
   cała wycieczka była jedną łamaną przez przystanki, więc jazda samochodem
   przez góry wyglądała identycznie jak przelot — stąd wrażenie, że wszystko
   lata samolotem.

   Kolor idzie z CSS, nie z JS: Leaflet wpisuje `stroke` jako atrybut SVG, a
   właściwość CSS go pokrywa. Dzięki temu linie same przemalowują się przy
   zmianie motywu, tak jak reszta mapy. */
.tour-leg-line { fill: none; }

.tour-leg-road  { stroke: var(--hub-accent); }

/* Tory ciemniejsze od szosy: przy Huế → Đà Nẵng obie biegną obok siebie
   (kolej brzegiem, droga przez przełęcz) i muszą dać się rozróżnić. */
.tour-leg-rail  { stroke: var(--hub-ink); }

.tour-leg-air   { stroke: var(--hub-ink-muted); }
.tour-leg-water { stroke: #2E7D9A; }

/* Dojazd do dworca. Nie wiemy, którędy biegnie — i kropki mają to mówić. */
.tour-leg-transfer { stroke: var(--hub-ink-faint); }

.tour-map-legend {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem 0.9rem;
    margin-top: 0.4rem;
}

.tour-map-key {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    font-size: 0.76rem;
}

/* Próbka linii rysowana obramowaniem, nie SVG — ten sam wzór kreski co na
   mapie da się tu oddać samym `border-top`. */
.tour-map-key-line {
    width: 1.6rem;
    height: 0;
    border-top: 2px solid currentColor;
}

.tour-map-key-line.tour-leg-road  { border-top-color: var(--hub-accent); }
.tour-map-key-line.tour-leg-rail  { border-top-style: dashed; border-top-color: var(--hub-ink); }
.tour-map-key-line.tour-leg-air   { border-top-style: dashed; border-top-color: var(--hub-ink-muted); }
.tour-map-key-line.tour-leg-water { border-top-style: dotted; border-top-color: #2E7D9A; }

/* ── Itinerary ──────────────────────────────────────────────────
   Open on arrival. Fifteen days is a long read, so each day carries its
   heading and its text with a spine down the left that makes the trip
   legible as a sequence rather than fifteen separate cards. */

.tour-days {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 0;
    margin: 0;
    padding: 0;
    list-style: none;
}

.tour-day {
    position: relative;
    display: grid;
    grid-template-columns: 3.25rem minmax(0, 1fr);
    gap: 0 1.15rem;
    padding: 0 0 1.65rem;
}

/* The spine. Stops at the last day rather than trailing into nothing. */
.tour-day::before {
    content: '';
    position: absolute;
    left: 1.55rem;
    top: 2.4rem;
    bottom: 0;
    width: 2px;
    background: var(--hub-hairline);
}

.tour-day:last-child::before { display: none; }

.tour-day-marker {
    grid-row: 1 / span 2;
    position: relative;
    z-index: 1;
    width: 3.25rem;
    height: 3.25rem;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    border: 1px solid var(--hub-hairline);
    border-radius: 50%;
    background: var(--hub-elev);
    font-weight: 700;
    line-height: 1;
}

.tour-day-num {
    font-size: 1.1rem;
    font-variant-numeric: tabular-nums;
}

.tour-day-word {
    font-size: 0.58rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--hub-ink-muted);
    font-weight: 700;
}

.tour-day-title {
    margin: 0.55rem 0 0.35rem;
    font-size: 1.05rem;
    font-weight: 700;
    line-height: 1.35;
    text-wrap: balance;
}

.tour-day-text {
    margin: 0;
    color: var(--hub-ink-muted);
    line-height: 1.65;
    max-width: 68ch;
}

/* Gdzie klient tej nocy śpi. Program dnia nie mówił tego wcale, choć
   „gdzie będę spał" to jedno z trzech pytań, z którymi się go czyta. */
.tour-day-night {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.4rem;
    margin: 0.6rem 0 0;
    font-size: 0.88rem;
    color: rgb(var(--hub-ink-rgb) / 0.7);
}

.tour-day-night svg {
    width: 16px;
    height: 16px;
    flex: none;
    color: rgb(var(--hub-ink-rgb) / 0.45);
}

.tour-day-night-label {
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: rgb(var(--hub-ink-rgb) / 0.45);
}

.tour-day-stars { color: var(--hub-accent); letter-spacing: 0.04em; }

/* Punkt zbiórki i zakończenia — ten sam wiersz co nocleg, ale w kolorze
   akcentu: to jedyna rzecz w planie, której turysta bez przelotu MUSI
   dotrzymać, żeby wycieczka w ogóle się dla niego zaczęła. */
.tour-day-meet {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.4rem;
    margin: 0.6rem 0 0;
    padding: 0.5rem 0.7rem;
    font-size: 0.88rem;
    color: var(--hub-ink);
    background: rgb(var(--hub-accent-rgb) / 0.08);
    border-radius: 10px;
}
.tour-day-meet svg { width: 16px; height: 16px; flex: none; color: var(--hub-accent-strong); }
.tour-day-meet .tour-day-night-label { color: var(--hub-accent-strong); }
.tour-day-meet-nav {
    margin-left: auto;
    font-weight: 700;
    color: var(--hub-accent-strong);
    text-decoration: underline;
    text-underline-offset: 2px;
}

.tour-day-places {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem;
    margin-top: 0.6rem;
}

.tour-day-place {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    /* „Đà Nẵng" łamało się w środku pigułki i robiło z niej dwuwierszowy
       klocek wyższy od sąsiadów. Nazwa miejsca nie ma gdzie się złamać. */
    white-space: nowrap;
    padding: 0.15rem 0.5rem;
    border: 1px solid var(--hub-hairline);
    border-radius: 999px;
    font-size: 0.75rem;
    color: var(--hub-ink-muted);
    text-decoration: none;
}

.tour-day-place:hover {
    border-color: rgb(var(--hub-accent-rgb) / 0.5);
    color: var(--hub-accent-strong);
}

/* Pigułka miejsca to LINK do przewodnika po tej destynacji, a miała 26 px
   wysokości — poniżej tego, w co da się trafić kciukiem bez celowania.
   Jest ich piętnaście, po jednej na dzień, więc chybione trafienie zdarza
   się często. Wyższe pigułki dokładają do strony jakieś 270 px z 8900, co
   jest ceną, którą warto zapłacić. */
@media (hover: none) and (pointer: coarse) {
    .tour-day-place {
        min-height: 44px;
        /* „Huế" to pigułka szeroka na 27 px — wysoka na tyle, żeby w nią
           trafić, i wąska na tyle, żeby chybić w bok. */
        min-width: 44px;
        justify-content: center;
        padding-inline: 0.7rem;
    }
}

/* A tour that crosses from the north to the centre changes climate and
   character halfway through; the itinerary should say so where it
   happens rather than leaving the reader to notice. */
.tour-leg {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin: 0 0 1.5rem;
    padding-left: 4.4rem;
    font-size: 0.78rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.09em;
    color: var(--hub-ink-muted);
}

.tour-leg::after {
    content: '';
    flex: 1;
    height: 1px;
    background: var(--hub-hairline);
}

/* ── Inclusions ─────────────────────────────────────────────────
   All twelve of this tour's features are things the price covers, and
   every one arrived carrying the same generic sparkle emoji. A list of
   identical icons is noise; one consistent check mark down the left is
   the shape a "what's included" list actually has. */

.tour-incl {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: 0.15rem 2rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

.tour-incl-item {
    display: flex;
    align-items: flex-start;
    gap: 0.7rem;
    padding: 0.6rem 0;
    border-bottom: 1px solid var(--hub-hairline);
    line-height: 1.5;
}

.tour-incl-item svg {
    flex: none;
    width: 18px;
    height: 18px;
    margin-top: 0.15rem;
    color: var(--hub-accent);
}

.tour-incl-text { min-width: 0; }

.tour-incl-title { font-weight: 600; }

.tour-incl-desc {
    display: block;
    margin-top: 0.2rem;
    font-size: 0.85rem;
    color: var(--hub-ink-muted);
}

/* ── Weather ────────────────────────────────────────────────────
   The one thing a tour page can tell a buyer that a brochure cannot:
   what the sky actually does in the regions this trip crosses, in the
   month it runs. Climatological normals, already in the platform for
   the destination pages, coloured on the --tp-rating scale so the same
   green means the same thing here as it does there. */

.tour-wx {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: 1rem;
}

.tour-wx-card {
    display: flex;
    flex-direction: column;
    gap: 0.7rem;
    padding: 1.15rem 1.25rem;
    border: 1px solid var(--hub-hairline);
    border-left: 6px solid var(--tp-rating);
    border-radius: var(--hub-radius);
    background: var(--hub-elev);
}

.tour-wx-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
}

.tour-wx-where {
    font-weight: 700;
    font-size: 1rem;
}

.tour-wx-when {
    font-size: 0.78rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    font-weight: 700;
    color: var(--hub-ink-muted);
}

.tour-wx-figures {
    display: flex;
    align-items: center;
    gap: 1rem;
}

.tour-wx-icon {
    color: var(--tp-rating);
    flex: none;
}

.tour-wx-icon svg { display: block; }

.tour-wx-temp {
    font-size: 1.5rem;
    font-weight: 800;
    font-variant-numeric: tabular-nums;
    line-height: 1;
}

.tour-wx-low {
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--hub-ink-muted);
}

.tour-wx-rain {
    font-size: 0.85rem;
    color: var(--hub-ink-muted);
}

.tour-wx-verdict {
    font-weight: 700;
    color: var(--tp-rating);
    font-size: 0.9rem;
}

.tour-wx-note {
    margin: 0;
    font-size: 0.88rem;
    line-height: 1.55;
    color: var(--hub-ink-muted);
}

/* Numbered route pins. Styled here rather than inline in the map code so
   both themes reach them — accent-on-fill measured 2.76:1 in light. */
.tour-map-pin {
    width: 26px;
    height: 26px;
    display: grid;
    place-items: center;
    border-radius: 50%;
    background: var(--hub-fill);
    color: var(--hub-on-fill);
    border: 2px solid var(--hub-elev);
    box-shadow: 0 1px 4px rgb(0 0 0 / 0.3);
    font: 700 12px/1 system-ui, -apple-system, sans-serif;
    cursor: pointer;
}

/* Start trasy (punkt zbiórki) — „S", odróżniony od numerów atrakcji. */
.tour-map-pin.is-start { background: var(--hub-ink); color: var(--hub-bg); }

/* Przystanki programu (migracje 139–142): lista atrakcji pod mapą trasy
   miejskiej i w planie każdego dnia. Kliknięcie przybliża mapę. */
.tour-sights, .tour-day-stops { list-style: none; margin: 0.75rem 0 0; padding: 0; display: flex; flex-wrap: wrap; gap: 0.4rem; }
.tour-sights { margin: 0 0 1rem; }
.tour-day-stop {
    display: inline-flex; align-items: center; gap: 0.4rem; min-height: 2rem; padding: 0.2rem 0.7rem 0.2rem 0.25rem;
    border-radius: 999px; border: 1px solid var(--hub-hairline); background: var(--hub-elev);
    color: var(--hub-ink); font: inherit; font-size: 0.82rem; line-height: 1.25; text-align: left; cursor: pointer;
}
.tour-day-stop:hover { border-color: var(--hub-accent); }
.tour-day-stop-nr {
    flex: none; display: inline-grid; place-items: center; min-width: 1.5rem; height: 1.5rem; padding: 0 0.3rem;
    border-radius: 999px; background: var(--hub-fill); color: var(--hub-on-fill); font-size: 0.72rem; font-weight: 800;
}
.tour-day-stop-nr.is-start { background: var(--hub-ink); color: var(--hub-bg); }
/* Objazdówka: atrakcje bez numerów (numerami na mapie są miasta) — kropka jak na mapie. */
.tour-day-stop-nr.is-dot { min-width: 0.55rem; width: 0.55rem; height: 0.55rem; padding: 0; margin: 0 0.15rem 0 0.5rem;
    background: var(--hub-accent); }

/* ── Booking rail ───────────────────────────────────────────────── */

.tour-book {
    border: 1px solid var(--hub-hairline);
    border-radius: var(--hub-radius);
    background: var(--hub-elev);
    box-shadow: var(--hub-shadow);
    overflow: hidden;
}

.tour-book-top {
    padding: 1.25rem 1.35rem;
    border-bottom: 1px solid var(--hub-hairline);
}

.tour-price {
    display: flex;
    align-items: baseline;
    gap: 0.45rem;
    flex-wrap: wrap;
}

.tour-price-value {
    font-size: 2rem;
    font-weight: 800;
    letter-spacing: -0.02em;
    font-variant-numeric: tabular-nums;
    line-height: 1;
}

.tour-price-unit {
    font-size: 0.9rem;
    color: var(--hub-ink-muted);
}

.tour-price-note {
    margin: 0.5rem 0 0;
    font-size: 0.85rem;
    color: var(--hub-ink-muted);
}

/* Wybór terminu (migracja 109) — nad wierszami, bo od niego zależą wolne
   miejsca pokazane niżej. */
.tour-book-dep {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    padding: 1rem 1.35rem 0.4rem;
}
.tour-book-dep > span {
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: rgb(var(--hub-ink-rgb) / 0.55);
}
.tour-book-dep select {
    width: 100%;
    min-height: 44px;
    padding: 0.5rem 0.7rem;
    border: 1px solid var(--hub-hairline);
    border-radius: 12px;
    background: var(--hub-surface);
    color: var(--hub-ink);
    font: inherit;
    font-weight: 600;
}

.tour-book-rows {
    padding: 1rem 1.35rem;
    display: flex;
    flex-direction: column;
    gap: 0.65rem;
    border-bottom: 1px solid var(--hub-hairline);
}

.tour-book-row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    font-size: 0.9rem;
}

.tour-book-row dt { color: var(--hub-ink-muted); }
.tour-book-row dd { margin: 0; font-weight: 700; text-align: right; }

.tour-book-actions {
    padding: 1.25rem 1.35rem;
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
}

.tour-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    min-height: 48px;
    padding: 0.75rem 1.25rem;
    border: 1px solid var(--hub-hairline);
    border-radius: 999px;
    background: transparent;
    color: var(--hub-ink);
    font: inherit;
    font-weight: 700;
    cursor: pointer;
    text-decoration: none;
    transition: background var(--hub-transition), border-color var(--hub-transition),
                color var(--hub-transition);
}

.tour-btn:hover {
    border-color: rgb(var(--hub-accent-rgb) / 0.6);
    background: rgb(var(--hub-accent-rgb) / 0.08);
}

.tour-btn-primary {
    border-color: transparent;
    background: var(--hub-fill);
    color: var(--hub-on-fill);
}

.tour-btn-primary:hover {
    background: var(--hub-fill-deep);
    border-color: transparent;
    color: var(--hub-on-fill);
}

.tour-btn[disabled] {
    opacity: 0.55;
    cursor: not-allowed;
}

.tour-btn-pair {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0.6rem;
}

.tour-btn svg { width: 18px; height: 18px; }

.tour-book-foot {
    padding: 0 1.35rem 1.25rem;
    font-size: 0.82rem;
    color: var(--hub-ink-muted);
    line-height: 1.55;
}

.tour-organizer {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 1rem 1.35rem;
    border-top: 1px solid var(--hub-hairline);
}

.tour-organizer-avatar {
    flex: none;
    width: 40px;
    height: 40px;
    display: grid;
    place-items: center;
    border-radius: 50%;
    background: var(--hub-fill);
    color: var(--hub-on-fill);
    font-weight: 800;
    font-size: 0.85rem;
}

.tour-organizer-name { font-weight: 700; font-size: 0.92rem; }
.tour-organizer-role { font-size: 0.78rem; color: var(--hub-ink-muted); }

/* ── Mobile booking bar ─────────────────────────────────────────
   On a phone the rail falls below fifteen days of itinerary, so the
   price and the button follow the reader instead. Sits above the
   bottom navigation, which is 68px tall. */

.tour-bar {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 900;
    display: none;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.75rem 1rem calc(0.75rem + env(safe-area-inset-bottom));
    background: rgb(var(--hub-elev-rgb) / 0.97);
    border-top: 1px solid var(--hub-hairline);
    backdrop-filter: blur(10px);
}

.tour-bar-price { display: flex; flex-direction: column; gap: 0.1rem; }
.tour-bar-value { font-size: 1.15rem; font-weight: 800; line-height: 1; }
.tour-bar-note { font-size: 0.72rem; color: var(--hub-ink-muted); }
.tour-bar .tour-btn { flex: 1; max-width: 200px; }

/* ── Empty / error ──────────────────────────────────────────────── */

.tour-empty {
    padding: clamp(3rem, 10vw, 6rem) 0;
    text-align: center;
    color: var(--hub-ink-muted);
}

.tour-empty h1 { color: var(--hub-ink); margin-bottom: 0.5rem; }

/* ── Responsive ─────────────────────────────────────────────────── */

@media (max-width: 980px) {
    .tour-body { grid-template-columns: minmax(0, 1fr); }

    /* The rail moves under the facts strip and stops being sticky —
       a sticky card in normal flow on a phone just eats the screen. */
    .tour-rail { position: static; order: -1; }

    .tour-title { max-width: none; }
}

@media (max-width: 640px) {
    .tour-wrap { width: min(1180px, 100% - 1.75rem); }

    .tour-facts { grid-template-columns: repeat(2, minmax(0, 1fr)); }

    .tour-day {
        grid-template-columns: 2.5rem minmax(0, 1fr);
        gap: 0 0.85rem;
    }

    .tour-day::before { left: 1.2rem; top: 1.9rem; }

    .tour-day-marker { width: 2.5rem; height: 2.5rem; }

    /* Słowo „Dzień" schodziło do 8 px, żeby zmieścić się w kółku 40 px —
       a 8 px to nie jest mały napis, tylko napis nie do przeczytania.
       Kółko ma nieść NUMER; że to dzień, mówi nagłówek sekcji („Dzień po
       dniu"), tytuł każdej karty i czytnik ekranu (`sr-only` „Dzień N:”).
       Bez tego słowa numer ma wreszcie miejsce, żeby urosnąć. */
    .tour-day-word { display: none; }
    .tour-day-num { font-size: 1.2rem; }

    /* 9,9 px na etykiecie faktu („Terminy", „Trasa"). Wersaliki w tym
       rozmiarze czyta się przez domysł. */
    .tour-fact-label { font-size: 0.75rem; }
    .tour-fact-note  { font-size: 0.75rem; }
    .tour-bar-note   { font-size: 0.75rem; }

    /* Panel rezerwacji powtarzał CAŁĄ tabelkę faktów z nagłówka: wyjazd,
       długość, wielkość grupy, dostępność — co do wartości te same cztery
       rzeczy, na telefonie w odległości jednego ekranu od siebie. Na szerokim
       ekranie panel stoi z boku i powtórzenie ma sens (fakty są poza zasięgiem
       wzroku), na wąskim jest pod spodem i kosztuje 210 px za nic.
       Cena, przyciski i biuro zostają — to jedyne, czego w nagłówku nie ma. */
    .tour-book-rows { display: none; }

    .tour-leg { padding-left: 3.35rem; }

    /* The site's bottom navigation is 68px tall and also fixed, so the
       booking bar rides above it rather than on top of it. */
    .tour-bar { display: flex; bottom: 68px; }

    /* Clear both fixed bars. The padding goes on the body, not on
       .tour-page: the footer is its sibling, so padding on the main
       element left the last 72px of the footer under the booking bar. */
    body:has(.tour-page) { padding-bottom: 165px; }

    /* The rail's own button would be a second, identical call to action
       three centimetres from the one in the bar. */
    .tour-rail .tour-book-actions .tour-btn-primary { display: none; }
}

@media (prefers-reduced-motion: reduce) {
    .tour-btn, .tour-stop-link, .tour-day-place { transition: none; }
}

/* ── Currency switcher ──────────────────────────────────────────
   The operator bills in their own currency; this shows the same money
   in the reader's. The billed figure stays on screen underneath — a
   converted price is an indication at today's reference rate, not what
   will be charged. */

.tour-fx {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-top: 0.9rem;
    padding-top: 0.9rem;
    border-top: 1px solid var(--hub-hairline);
}

.tour-fx-label {
    font-size: 0.78rem;
    color: var(--hub-ink-muted);
    white-space: nowrap;
}

.tour-fx-select {
    flex: 1;
    min-height: 36px;
    padding: 0.3rem 0.5rem;
    border: 1px solid var(--hub-hairline);
    border-radius: 8px;
    background: var(--hub-surface);
    color: var(--hub-ink);
    font: inherit;
    font-size: 0.85rem;
    font-weight: 600;
    cursor: pointer;
}

.tour-fx-select:focus-visible {
    outline: 2px solid var(--hub-focus);
    outline-offset: 1px;
}

.tour-price-billed strong { color: var(--hub-ink); }

@media (hover: none) and (pointer: coarse) {
    .tour-fx-select { min-height: 44px; }
}

/* ── Zdjęcie wycieczki w nagłówku ────────────────────────────────────────
   Nasze zdjęcie, wgrane przez biuro. Do tej pory żyło wyłącznie na kafelku
   listy: biuro je wgrywało, widziało na liście i nie znajdowało tam, gdzie
   klient naprawdę czyta o wyjeździe.

   Prawa kolumna nagłówka stała pusta, a opis i tak zajmuje lewą. Poniżej
   1000 px wraca nad tekst, bo dwie kolumny na telefonie to dwa paski. */
/* Zwężamy kolumnę tekstu, ale nie przesuwamy jej do krawędzi ekranu:
   lewy margines liczy się tak samo jak przy wyśrodkowanym `.tour-wrap`,
   więc tytuł stoi w jednej linii z nagłówkiem i resztą strony. */
.tour-hero.has-photo > .tour-wrap {
    max-width: min(52%, 600px);
    margin-inline: var(--tour-gutter) 0;
}

/* Zdjęcie trzyma ten sam margines co tekst po drugiej stronie. Wcześniej
   dobiegało do krawędzi ekranu i nagłówek był niesymetryczny: z lewej szeroki
   odstęp, z prawej żaden. */
.tour-hero-photo {
    position: absolute;
    top: 50%;
    right: var(--tour-gutter);
    transform: translateY(-50%);
    width: min(42%, 520px);
    aspect-ratio: 4 / 3;
    max-height: calc(100% - clamp(3rem, 6vw, 5rem));
    border-radius: var(--hub-radius, 14px);
    overflow: hidden;
}

.tour-hero-photo img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

/* Ledwie muśnięcie tłem od strony tekstu, żeby krawędź nie wyglądała na
   doklejoną. Wcześniej ta powłoka sięgała 38% szerokości i pełnym kryciem —
   zasłaniała lewą trzecią część zdjęcia. */
.tour-hero-photo::after {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(to right, rgb(var(--hub-bg-rgb) / 0.16) 0%, rgb(var(--hub-bg-rgb) / 0) 18%);
}

@media (max-width: 1000px) {
    .tour-hero.has-photo > .tour-wrap { max-width: none; margin-inline: auto; }

    /* Zdjęcie siedzi teraz w kolumnie tekstu, więc marginesy ma już po
       rodzicu — własne dołożyłyby drugi odstęp. */
    .tour-hero-photo {
        position: relative;
        top: auto;
        right: auto;
        transform: none;
        width: auto;
        max-width: none;
        aspect-ratio: 16 / 10;
        max-height: none;
        height: auto;
        margin: 1.25rem 0 0;
    }

    .tour-hero-photo::after {
        background: linear-gradient(to top, rgb(var(--hub-bg-rgb) / 0.12) 0%, transparent 40%);
    }
}

/* ── Logo biura ──────────────────────────────────────────────────────────
   Na miejscu inicjałów. Inicjały zostają dla biur, które logo nie wgrały —
   pusty okrąg mówiłby mniej niż dwie litery. */
.tour-organizer-logo {
    flex: none;
    display: grid;
    place-items: center;
    width: 40px;
    height: 40px;
    border-radius: 10px;
    background: var(--hub-elev);
    border: 1px solid var(--hub-hairline);
    overflow: hidden;
}

.tour-organizer-logo img { width: 100%; height: 100%; object-fit: contain; padding: 3px; }

/* Logo, które się nie wczytało, zostawia pusty kwadrat — gorszy niż inicjały,
   więc znika razem ze swoją ramką. */
.tour-organizer-logo.is-broken { display: none; }

/* ── Zdjęcie dnia ────────────────────────────────────────────────────────
   Wgrywane w kompozytorze przy konkretnym dniu i zapisywane na klocku, więc
   ten sam dzień użyty w drugiej wycieczce przychodzi z tym samym zdjęciem.
   Stoi pod opisem, nie nad nim: najpierw czyta się, co się tego dnia dzieje. */
.tour-day-photo {
    /* Ograniczone, choć kolumna jest szeroka: przy 15 dniach zdjęcie na całą
       szerokość zamienia plan w album, a opis dnia to często dwa wiersze —
       obrazek trzy razy wyższy od tekstu, który ilustruje, kłamie o proporcji
       ważności. */
    max-width: min(100%, 420px);
    margin: 0.85rem 0 0;
    border-radius: var(--hub-radius, 14px);
    overflow: hidden;
    background: var(--hub-surface);
}

.tour-day-photo img {
    display: block;
    width: 100%;
    aspect-ratio: 16 / 9;
    object-fit: cover;
}

/* ── Zdjęcie obok opisu ──────────────────────────────────────────────────
   Drugi układ, wybierany przy dniu w kompozytorze. Ten sam plik, inne
   miejsce: dzień o dwóch zdaniach i mocnym zdjęciu czyta się lepiej w
   dwóch kolumnach niż jako podpis pod obrazem.

   Flex, nie grid, z jednego powodu: gdy zdjęcie nie wczyta się i skrypt
   usunie `figure`, siatka zostawiłaby po nim pustą kolumnę razem z odstępem.
   We flexie przerwa istnieje tylko między tym, co naprawdę stoi obok. */
.tour-day-body.is-aside {
    display: flex;
    align-items: flex-start;
    gap: 1.25rem;
}

.tour-day-body.is-aside .tour-day-copy {
    flex: 1 1 auto;
    min-width: 0;
}

.tour-day-body.is-aside .tour-day-photo {
    flex: 0 0 18rem;
    max-width: 18rem;
    /* Równo z pierwszym wierszem tytułu, nie z jego kratką liter. */
    margin: 0.3rem 0 0;
}

/* Poniżej tej szerokości kolumna tekstu robi się węższa od zdjęcia i dwie
   kolumny przestają cokolwiek dawać — wtedy zdjęcie wraca pod opis. */
@media (max-width: 760px) {
    .tour-day-body.is-aside { display: block; }

    .tour-day-body.is-aside .tour-day-photo {
        max-width: min(100%, 420px);
        margin: 0.85rem 0 0;
    }
}

/* ── Telefon ─────────────────────────────────────────────────────────────
   Poprawki z przeglądu wersji mobilnej (390 px). Każda z nich odpowiada
   czemuś, co dało się zmierzyć, a nie wrażeniu. */
@media (max-width: 640px) {
    /* Nazwa wycieczki stała w okruszkach i zaraz pod nimi w nagłówku —
       dwa razy to samo, a okruszki zajmowały przez to dwa wiersze. */
    .tour-crumb-now,
    .tour-breadcrumb span:has(+ .tour-crumb-now) { display: none; }

    /* Trzy plakietki po 33 px stawały jedna pod drugą, bo brakowało im
       kilku pikseli do pary. Ciaśniej — i mieszczą się po dwie. */
    .tour-pill { padding: 0.3rem 0.55rem; font-size: 0.72rem; }
    .tour-pill svg { width: 12px; height: 12px; }

    /* Przystanki trasy zawijały się tak, że strzałka zostawała na końcu
       wiersza i wskazywała na nic. Jeden rząd, przesuwany palcem. */
    .tour-route {
        flex-wrap: nowrap;
        overflow-x: auto;
        scroll-snap-type: x proximity;
        -webkit-overflow-scrolling: touch;
        padding-bottom: 0.35rem;
    }

    .tour-route::-webkit-scrollbar { height: 0; }
    .tour-stop { flex: 0 0 auto; scroll-snap-align: start; }

    /* Przełącznik podkładu mapy szedł przez całą szerokość i wchodził pod
       przyciski powiększania Leafletu — pierwsza zakładka była nieczytelna.
       Nad mapą, w jednym rzędzie, przesuwanym palcem. */
    .tour-map-layers {
        position: static;
        margin-bottom: 0.5rem;
        overflow-x: auto;
        backdrop-filter: none;
        box-shadow: none;
    }

    .tour-map-layers::-webkit-scrollbar { height: 0; }
}

/* Dalszy ciąg tego samego dnia (zbiórka i przejazd, dwa półdniowe):
   kółko bez numeru, mniejsze, żeby oś dni nie liczyła go drugi raz. */
.tour-day.is-same-day .tour-day-marker {
    width: 14px;
    height: 14px;
    justify-self: center;
    margin-top: 0.35rem;
}

/* ── Przedłużenia (migracja 110) ──────────────────────────────────────
   Karty w stylu przystanków trasy: kilka dni po wycieczce, z ceną „+"
   od osoby, bo dolicza się ją do ceny wycieczki. */
.tour-ext-list { display: flex; flex-direction: column; gap: 0.75rem; }
.tour-ext {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    gap: 0.9rem;
    align-items: center;
    padding: 0.8rem;
    border: 1px solid var(--hub-hairline);
    border-radius: var(--hub-radius);
    background: var(--hub-elev);
    color: inherit;
    text-decoration: none;
    transition: border-color var(--hub-transition);
}
.tour-ext:hover { border-color: var(--hub-accent); }
.tour-ext-photo { width: 5.5rem; height: 4rem; border-radius: 10px; overflow: hidden; display: block; }
.tour-ext-photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
.tour-ext-body { display: flex; flex-direction: column; gap: 0.2rem; min-width: 0; }
.tour-ext-title { color: var(--hub-ink); font-size: 1rem; }
.tour-ext-meta { font-size: 0.82rem; color: rgb(var(--hub-ink-rgb) / 0.6); }
.tour-ext-desc {
    font-size: 0.86rem; color: rgb(var(--hub-ink-rgb) / 0.75);
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.tour-ext-price { font-weight: 800; color: var(--hub-ink); text-align: right; white-space: nowrap; }
.tour-ext-price small { display: block; font-weight: 500; font-size: 0.75rem; color: rgb(var(--hub-ink-rgb) / 0.55); }
.tour-ext-parents { margin: 0; padding: 0 1.35rem 1.2rem 2.6rem; display: flex; flex-direction: column; gap: 0.35rem; }
.tour-ext-parents a { font-weight: 700; color: var(--hub-accent-strong); }

@media (max-width: 640px) {
    .tour-ext { grid-template-columns: minmax(0, 1fr) auto; }
    .tour-ext-photo { display: none; }
}
