/* travel_lonotv/assets/css/style.css */

/* This app diverges from the shared LonoTV red/pink gradient brand —
   a 60/30/10 palette instead (white / deep indigo / soft gold),
   solid colors only, no gradients or transparent backgrounds. Scoped
   to travel_lonotv only (shared_assets/tokens.css and the other 3
   apps keep the original look); overriding the tokens here means any
   future component that reads these variables picks up the new
   colors for free instead of needing a one-off override. */
:root {
    --accent-primary: #d4af37; /* soft gold — buttons, stars, active states */
    --accent-secondary: #d4af37;
    --accent-glow: rgba(212, 175, 55, 0.35);
    --text-primary: #0f1a34; /* deep indigo — headings, body text */
    /* Solid equivalent of tokens.css's rgba(0,0,0,0.1) border, so
       borders read the same on any background without relying on
       transparency (see the no-glass overrides below). */
    --border-color: #e5e5e5;
    /* System font stack instead of tokens.css's Google-hosted Inter
       (2026-09-06, optimizing for very slow connections) — every
       platform's own default UI font is already on the visitor's
       device, so this costs zero bytes and zero extra network round
       trips, versus 2 extra cross-origin origins (fonts.googleapis.com
       + fonts.gstatic.com) plus 3 font-weight files just to render
       text in a specific typeface. Ordered so each OS gets its native
       system font first (San Francisco on iOS/macOS, Segoe UI on
       Windows, Roboto on Android/Chrome OS) before falling back. */
    --font-main: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}

.btn-primary,
.btn-secondary {
    background: #d4af37;
    /* Gold is too light for white text to pass contrast — dark
       indigo text is both the readable choice and matches the
       "text uses the secondary color" part of the palette. */
    color: #0f1a34;
    border: none;
}

.btn-primary:hover,
.btn-secondary:hover {
    background: #d4af37;
    filter: brightness(0.92);
}

.btn-secondary:disabled,
.btn-primary:disabled {
    filter: none;
    opacity: 1;
    background: #e5e5e5;
    color: var(--text-secondary);
    cursor: not-allowed;
}

/* tokens.css washes the page with two large, low-opacity red/pink
   radial gradients (its original brand colors, not this app's blue) —
   dropped everywhere in this app, not just the hero-band pages. */
body {
    background-image: none;
}

/* Same "no transparency" pass as the glass/status overrides below:
   form inputs, amenity chips, and status pills all used a low-opacity
   black/color tint in tokens.css — solid equivalents here so nothing
   in a booking form or a route card reads as a faint see-through
   layer. */
.form-field input,
.form-field textarea,
.form-field select {
    background: #f5f5f5;
}

.status-pill.pending,
.status-pill.submitted {
    background: #fef3c7;
}

.status-pill.confirmed,
.status-pill.accepted {
    background: #dcfce7;
}

.status-pill.cancelled,
.status-pill.rejected {
    background: #fee2e2;
}

/* No glassmorphism in this app — solid backgrounds instead of
   tokens.css's translucent + backdrop-blur "glass" look (.category-tabs
   and .sticky-book-bar are this app's own rules, further down this
   file, and are solid there directly rather than overridden here).
   The border/shadow on each of these already does the job of
   separating it from whatever's behind it, so dropping the blur
   changes nothing structurally, just removes the see-through effect. */
.glass-nav,
.glass-card {
    background: #ffffff;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
}

/* tokens.css makes the navbar position:fixed (pinned across every
   page load) — this app scrolls it away with the rest of the page
   instead, so it's plain normal flow like everything else here.
   Background is the same deep forest green on *every* page, not just
   the hero-band ones — it used to be scoped to body.has-hero-band
   only, which meant a hotel/tour/route detail page (no hero band)
   still showed the old plain-white navbar, an inconsistency the user
   had to point at directly since it doesn't show up as a CSS error or
   layout bug, just a wrong color that's easy to overlook when testing
   from the code side. */
.navbar {
    position: static;
    background: #1b4332;
    border-bottom: none;
}

.text-accent {
    background: none;
    -webkit-background-clip: unset;
    -webkit-text-fill-color: unset;
    /* Bright brand gold — reads clearly since the navbar is always a
       dark background now (a lighter color against dark), everywhere,
       not just where a hero band happens to be. */
    color: #d4af37;
    font-weight: 700;
}

/* tokens.css's 80px padding-top assumes .main-container sits right
   under the fixed navbar — here .category-tabs sits between them and
   already provides its own clearance (see its margin-top below), so
   this app trims the shared value down to avoid stacking both. */
.main-container {
    padding-top: 1rem;
}

.travel-hero {
    padding: 2rem 5% 3rem;
    max-width: 800px;
    margin: 0 auto;
    text-align: center;
}

.travel-hero .hero-title {
    font-size: 2.25rem;
    font-weight: 700;
    line-height: 1.15;
    margin-bottom: 1rem;
    /* Balances line lengths instead of the browser default (which
       tends to leave one short word alone on the last line, e.g.
       "Book Your Next" / "Stay") — a no-op in unsupported browsers,
       just falls back to normal wrapping. */
    text-wrap: balance;
}

@media (max-width: 480px) {
    .travel-hero .hero-title {
        font-size: 1.75rem;
    }
}

.travel-hero .hero-subtitle {
    color: var(--text-secondary);
    font-size: 0.9rem;
}

/* Hero band — a solid-color backdrop spanning navbar + category-tabs +
   hero + search bar as one continuous area, on the homepage/tours/
   transport list pages only (body.has-hero-band) — the navbar and
   category-tabs are the same forest green on *every* page (see the
   base .navbar/.category-tabs/.category-tab rules above), but only
   these 3 list pages extend that same green down through a hero
   section and search bar too, since detail pages have no hero to
   extend it into. No hero photography exists for this app yet, so a
   flat brand color is the honest choice over a stock/placeholder
   image; swap in a real photo here later if one becomes available. */
body.has-hero-band {
    background-color: #1b4332;
    background-image: none;
}

body.has-hero-band .travel-hero .hero-title {
    color: #ffffff;
}

body.has-hero-band .travel-hero .hero-subtitle {
    color: #c9d9cf;
}

.hero-search {
    position: relative;
    /* text-align:center on .travel-hero only centers inline content —
       this is a block-level box with its own max-width, so it needs
       its own auto margins to actually center within that container. */
    margin: 1.25rem auto 0;
    max-width: 480px;
    text-align: left;
}

/* The direct-child selector matters here — .hero-search-btn (below)
   also contains an .icon-search, and it needs its own centering, not
   this absolute-positioned-against-the-input placement. */
.hero-search > .icon-search {
    position: absolute;
    left: 1.3rem;
    top: 50%;
    transform: translateY(-50%);
    width: 18px;
    height: 18px;
    color: var(--text-secondary);
    pointer-events: none;
}

.hero-search-input {
    width: 100%;
    background: #ffffff;
    border: none;
    border-radius: 50px;
    padding: 0.9rem 3.5rem 0.9rem 3rem;
    font-family: inherit;
    font-size: 1rem;
    color: var(--text-primary);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
}

.hero-search-input:focus {
    outline: 3px solid #f0e2a8;
}

.hero-search-input::placeholder {
    color: var(--text-secondary);
}

/* The action button living inside the search pill — icon-only at
   every width (the pill itself is narrow enough, max 480px, that a
   text label would feel cramped even on desktop) so there's no
   separate mobile-collapse rule needed. Click scrolls to the results,
   since the list below is already live-filtering per keystroke —
   this gives the button a real purpose without duplicating that. */
.hero-search-btn {
    position: absolute;
    right: 0.4rem;
    top: 50%;
    transform: translateY(-50%);
    width: 2.6rem;
    height: 2.6rem;
    display: flex;
    align-items: center;
    justify-content: center;
    background: #d4af37;
    color: #0f1a34;
    border: none;
    border-radius: 50%;
    cursor: pointer;
}

.hero-search-btn:hover {
    filter: brightness(0.92);
}

.hero-search-btn .icon-search {
    width: 18px;
    height: 18px;
}

/* The content grid resets to the normal white page below the hero
   band — rounded top corners read as a distinct "sheet" rather than a
   hard color cut. This only works cleanly because .hotels-section
   itself has no max-width (that's .section-inner's job, nested inside
   it) — a background-color here would otherwise only fill a centered
   1200px box and leave blue showing either side of it on a wide
   screen. (An earlier version tried to patch that with an oversized
   box-shadow instead of fixing the width — box-shadow spread pushes
   equally in *every* direction, not just sideways, so it also bled
   upward over the hero band above and whited it out. Don't reintroduce
   that trick.) */
body.has-hero-band .hotels-section {
    background: #ffffff;
    border-radius: 24px 24px 0 0;
    margin-top: 1.5rem;
    padding-top: 2rem;
}

/* Category tabs — Hotels / Tours / Transport. Real links (not JS tab
   switching) so each section is its own crawlable page once it exists;
   Tours/Transport are plain disabled spans until their pages ship.
   Plain normal flow (not sticky) — scrolls away with the page, same
   as the navbar above it (see .navbar override below). The old
   margin-top/sticky-top:64px existed only to clear the fixed navbar;
   with the navbar no longer fixed, nothing needs clearing. */
.category-tabs {
    display: flex;
    gap: 0.5rem;
    padding: 0.6rem 5%;
    background: #1b4332;
    border-bottom: none;
    overflow-x: auto;
}

.category-tab {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.5rem 1.1rem;
    border-radius: 50px;
    font-weight: 600;
    font-size: 0.9rem;
    text-decoration: none;
    /* Light sage on the dark green background — was var(--text-secondary)
       (a gray meant for a white background) back when this bar was
       still white on every page except the 3 hero-band ones. */
    color: #c9d9cf;
    border: 1px solid #3d6152;
    white-space: nowrap;
}

/* :not(.active) is explicit here on purpose — .category-tab.active
   (below) needs to keep its dark indigo text on hover too, for
   contrast against its own gold background, not turn white. */
.category-tab:not(.active):hover {
    color: #ffffff;
}

.icon-nav {
    width: 16px;
    height: 16px;
    flex-shrink: 0;
}

.category-tab.active {
    background: #d4af37;
    color: #0f1a34;
    border: none;
}

.category-tab small {
    font-size: 0.65rem;
    text-transform: uppercase;
    margin-left: 0.3rem;
}

.back-link {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    color: var(--text-secondary);
    text-decoration: none;
    font-weight: 600;
    font-size: 0.9rem;
    margin-bottom: 1rem;
}

.icon-chevron {
    width: 12px;
    height: 12px;
    flex-shrink: 0;
    vertical-align: -1px;
}

.icon-star {
    width: 14px;
    height: 14px;
    vertical-align: -2px;
}

.icon-search {
    display: block;
}

.back-link:hover {
    color: var(--text-primary);
}

.hotels-section {
    padding-bottom: 4rem;
}

.section-inner {
    max-width: 1200px;
    margin: 0 auto;
    padding: 0 5%;
}

/* Fixed column counts rather than auto-fit/minmax — the previous
   fluid version usually landed near 4 on a typical desktop width but
   wasn't guaranteed to, and did nothing to control mobile at all
   (it would fit as many 280px-min cards as the viewport allowed,
   which is 1 on most phones). 4 desktop / 2 mobile is a deliberate,
   consistent grid rhythm instead — same breakpoint tours/transport
   already share via this one grid class. */
.hotels-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 1.5rem;
}

@media (min-width: 900px) {
    .hotels-grid {
        grid-template-columns: repeat(4, 1fr);
    }
}

@media (max-width: 640px) {
    .hotels-grid {
        gap: 1rem;
    }
}

/* ---- Homepage service preview sections (index.php) — one row per
   service (Hotels/Tours/Transport), each capped to HOMEPAGE_PREVIEW_LIMIT
   cards server-side so it's actually one .hotels-grid row's worth, with
   a "View all" link into that service's own full list page. */
.service-section {
    margin-bottom: 3rem;
}

.service-section:last-child {
    margin-bottom: 0;
}

.service-section-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 1.25rem;
}

.service-section-header h2 {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    font-size: 1.4rem;
}

.service-section-header h2 .icon-nav {
    width: 22px;
    height: 22px;
    color: #d4af37;
}

.view-all-link {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    color: var(--text-primary);
    font-weight: 600;
    font-size: 0.9rem;
    text-decoration: none;
    white-space: nowrap;
}

.view-all-link:hover {
    color: #d4af37;
}

.view-all-link .icon-chevron {
    width: 10px;
    height: 10px;
}

/* Author CSS always wins over the browser's built-in [hidden]{display:none}
   regardless of specificity — so wireLiveSearch() setting .hidden=true on
   one of these (in app.js) did nothing visually, since this class's own
   `display: flex` below silently overrode it. The live search actually
   filtered correctly the whole time; nothing was ever hidden on screen.
   [hidden] here is more specific than the bare class, so it correctly
   wins back. Same fix applies to .route-card below, same reason. */
.hotel-card[hidden],
.route-card[hidden] {
    display: none;
}

.hotel-card {
    overflow: hidden;
    display: flex;
    flex-direction: column;
    text-decoration: none;
    color: inherit;
    transition: transform 0.2s ease, box-shadow 0.2s ease;
}

.hotel-card:hover {
    transform: translateY(-3px);
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.1);
}

.hotel-card .hotel-cover {
    width: 100%;
    height: 160px;
    object-fit: cover;
    background: #f5f5f5;
    display: block;
}

.hotel-card .hotel-body {
    padding: 1.25rem;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0.4rem;
}

.hotel-card h3 {
    font-size: 1.15rem;
}

.hotel-location {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    color: var(--text-secondary);
    font-size: 0.9rem;
}

.hotel-stars {
    color: #d4af37;
    font-size: 0.9rem;
}

.hotel-stars small {
    color: var(--text-secondary);
    font-weight: 400;
    margin-left: 0.3rem;
}

/* Block + full-width rather than left sized to its own text — every
   card in a row is already the same column width (see .hotels-grid's
   fixed column count), so stretching the button to fill that width
   keeps hotel/tour/route cards' buttons the same size regardless of
   label length, without needing to measure/match text widths. */
.hotel-card-cta {
    display: block;
    width: 100%;
    margin-top: 0.5rem;
    text-align: center;
    pointer-events: none;
}

/* Two labels in the markup (render_hotel_card()/render_tour_card()/
   render_route_card(), includes/api.php), one shown at a time by
   width — "View & Book" reads fine on a desktop-width card, but on a
   narrow phone (2-column grid, see .hotels-grid's breakpoint) that
   text plus the pill's own padding was tight enough to wrap. "View" is
   the accurate word for what this button actually does either way —
   it opens the detail page, not a booking itself; the real "Book"
   button lives on the room/departure/schedule row there. */
.cta-label-short {
    display: none;
}

@media (max-width: 640px) {
    .cta-label-full {
        display: none;
    }

    .cta-label-short {
        display: inline;
    }
}

/* ---- List toolbar (sort + filter chips), shared by all 3 list pages —
   reads/writes the same data-search/data-price/data-rating/data-mode
   attributes wireListControls() (app.js) already expects on each card. */
.list-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 1.5rem;
}

.list-toolbar-count {
    color: var(--text-secondary);
    font-size: 0.9rem;
    font-weight: 600;
}

.list-toolbar-controls {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.6rem;
}

.filter-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}

.filter-chip,
.sort-select {
    background: #ffffff;
    border: 1px solid var(--border-color);
    border-radius: 50px;
    padding: 0.4rem 0.9rem;
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--text-secondary);
    font-family: inherit;
    cursor: pointer;
}

.filter-chip:hover {
    border-color: #d4af37;
}

.filter-chip.is-active {
    background: #1b4332;
    border-color: #1b4332;
    color: #ffffff;
}

.sort-select {
    color: var(--text-primary);
    padding-right: 1.4rem;
}

/* ---- Card media wrapper — the image (or, for routes, the icon tile)
   plus whatever badges overlay it. Positioned relative so
   .featured-ribbon/.price-badge below can sit on top of it. */
.hotel-card-media {
    position: relative;
}

.featured-ribbon {
    position: absolute;
    top: 0.75rem;
    left: 0.75rem;
    background: #d4af37;
    color: #0f1a34;
    font-size: 0.7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    padding: 0.3rem 0.7rem;
    border-radius: 50px;
}

.price-badge {
    position: absolute;
    bottom: 0.75rem;
    left: 0.75rem;
    background: #ffffff;
    color: var(--text-primary);
    font-weight: 700;
    font-size: 0.85rem;
    padding: 0.35rem 0.75rem;
    border-radius: 8px;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.18);
}

.price-badge small {
    font-weight: 400;
    color: var(--text-secondary);
    font-size: 0.7rem;
    margin-left: 0.2rem;
}

/* No photo exists for a route (no cover_image column on
   transport_routes) — the price badge sits directly on the solid tile
   instead, so it needs to read against dark green rather than get a
   white-on-white box. */
.route-card-media .price-badge {
    position: static;
    margin-top: 0.75rem;
    background: rgba(255, 255, 255, 0.15);
    color: #ffffff;
    box-shadow: none;
}

.route-card-media .price-badge small {
    color: #c9d9cf;
}

/* ---- Amenity chips — list cards (compact) and detail page (roomier),
   built from the hotel's own real `amenities` array via icon_amenity(). */
.amenity-chip-row {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
}

.amenity-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    background: #f5f5f5;
    border: 1px solid var(--border-color);
    border-radius: 50px;
    padding: 0.25rem 0.65rem;
    font-size: 0.75rem;
    color: var(--text-secondary);
}

.amenity-chip .icon-inline {
    width: 13px;
    height: 13px;
}

.amenity-chip-more {
    font-weight: 600;
}

.amenity-chip-row-detail {
    margin-top: 0.75rem;
}

.amenity-chip-row-detail .amenity-chip {
    font-size: 0.8rem;
    padding: 0.35rem 0.8rem;
}

.amenity-chip-row-detail .amenity-chip .icon-inline {
    width: 15px;
    height: 15px;
}

.amenities-heading {
    margin-top: 1.25rem;
    font-size: 1rem;
}

/* ---- Quick facts row — detail-page info cards and tour/route list
   cards, a compact icon+text summary of fields already fetched. */
.quick-facts {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem 1rem;
    margin-top: 0.5rem;
}

.quick-fact {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    color: var(--text-secondary);
    font-size: 0.85rem;
}

/* Reused as a quick-fact chip (transport mode) — keep its own
   status-pill color instead of the gray every other quick-fact uses. */
.quick-fact.status-pill {
    color: var(--color-success);
}

.icon-inline {
    width: 15px;
    height: 15px;
    flex-shrink: 0;
    color: #d4af37;
    vertical-align: -3px;
}

/* ---- Transport route cards — the same grid-card shape hotels/tours
   use (see .hotels-grid, reused directly in transport.php's markup)
   instead of the old plain text row, since there's no reason routes
   should look visually thinner than the other two sections just
   because they have no photo. The media area is a solid tile with a
   centered icon in place of an <img> — same "no photo" visual
   language transport-route.php's own detail-page banner already uses. */
.route-card-media {
    height: 160px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    background: #1b4332;
    padding: 1rem;
}

.route-card-media .icon-nav {
    width: 40px;
    height: 40px;
    color: #d4af37;
}

.route-card-path {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.route-card-next {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    color: var(--text-secondary);
    font-size: 0.85rem;
    margin: 0;
}

.route-card-next .icon-inline {
    color: var(--text-secondary);
}

.route-arrow {
    color: var(--text-secondary);
}

/* Bigger than the default 12px chevron — this one sits inline in a
   large heading (route-card's title, or the h1 on the route detail
   page), where the default size would look disproportionately small. */
.route-arrow .icon-chevron {
    width: 18px;
    height: 18px;
    vertical-align: -3px;
}

.itinerary-heading {
    margin-top: 1.25rem;
    font-size: 1rem;
}

.itinerary-body {
    margin-top: 0.5rem;
}

/* Hotel detail page */
.hotel-detail-header {
    padding: 1.5rem 5% 0;
    max-width: 1000px;
    margin: 0 auto;
}

.hotel-detail-cover {
    width: 90%;
    max-width: 1000px;
    height: 260px;
    object-fit: cover;
    border-radius: var(--border-radius-lg);
    display: block;
    margin: 0.5rem auto 0;
}

/* Transport routes have no cover_image field at all (the schema never
   had one — a route isn't a single photographable place the way a
   hotel or tour is) — without this, the route detail page jumped
   straight from the back-link into the info card, visually much
   shorter up top than the hotel/tour pages that do have a photo
   there, reading as an inconsistent layout even though the structure
   below it is identical. Same size/position as .hotel-detail-cover so
   it fills the same visual role rather than pretending to be a real
   photo. */
.route-detail-banner {
    width: 90%;
    max-width: 1000px;
    height: 260px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.6rem;
    background: #1b4332;
    border-radius: var(--border-radius-lg);
    margin: 0.5rem auto 0;
}

.route-detail-banner .icon-nav {
    width: 60px;
    height: 60px;
    color: #d4af37;
}

/* The route path + mode overlaid directly on the banner (added
   alongside the pre-existing centered icon) — makes this "no photo"
   placeholder actually convey the route rather than just filling
   space, same idea as a hotel/tour's cover image having its name as
   an adjacent info card. Text is white against the banner's own solid
   green, not var(--text-primary) (dark indigo, meant for white pages). */
.route-detail-banner-path {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin: 0;
    color: #ffffff;
    font-weight: 700;
    font-size: 1.15rem;
}

.route-detail-banner .icon-chevron {
    color: #d4af37;
}

.hotel-detail-layout {
    max-width: 1000px;
    margin: 2rem auto 0;
    padding: 0 5% 4rem;
    display: grid;
    grid-template-columns: 1fr;
    gap: 2rem;
}

@media (min-width: 800px) {
    .hotel-detail-layout {
        grid-template-columns: 1fr 1.2fr;
        align-items: start;
    }
}

.hotel-detail-info {
    padding: 1.75rem;
}

.hotel-detail-name {
    font-size: 1.75rem;
    margin-bottom: 0.4rem;
}

.hotel-description {
    margin-top: 1rem;
    color: var(--text-secondary);
    font-size: 0.95rem;
    line-height: 1.7;
}

.results-heading {
    font-size: 1.3rem;
    margin-bottom: 1rem;
}

.hotel-rooms {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
}

.room-row {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: center;
    gap: 1rem;
    font-size: 0.9rem;
}

.hotel-rooms-detail .room-row {
    padding: 1rem 1.25rem;
}

.room-info {
    display: flex;
    flex: 1;
    flex-direction: column;
    gap: 0.2rem;
    /* Without this, a flex item won't shrink below its content's own
       max width (the "Presidential Suite" line, say) — on a narrow
       phone that pushed the Book button off the edge instead of
       wrapping, since body{overflow-x:hidden} just clips it rather
       than showing a scrollbar. min-width:0 lets it shrink/wrap
       properly; flex-wrap on .room-row above is the fallback if it
       still doesn't fit next to the button. */
    min-width: 0;
}

.room-meta {
    color: var(--text-secondary);
    font-size: 0.85rem;
}

.room-price {
    font-weight: 600;
}

/* A small icon identifying the row type (bed/calendar/clock) — purely
   decorative, sits to the left of .room-info. .room-info's own new
   flex:1 (above) is what keeps this from getting shoved around when a
   3rd flex child joins the row. */
.room-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    flex-shrink: 0;
    border-radius: 50%;
    background: #f5f5f5;
    color: #1b4332;
}

.room-icon .icon-inline {
    width: 16px;
    height: 16px;
    color: inherit;
}

/* Real, already-computed low-seat-count urgency (seats_available <= 3)
   — never a fabricated "X people are looking at this" style message,
   just a visual treatment of a number the page was already showing. */
.is-low-availability {
    color: #b45309;
    font-weight: 700;
}

/* Sticky bottom booking bar — the always-reachable CTA pattern used by
   every mobile booking flow, so a visitor never has to scroll back up
   to act. Padding respects the iOS home-indicator safe area. */
.sticky-book-bar {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: 950;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.85rem 5% calc(0.85rem + env(safe-area-inset-bottom));
    background: #ffffff;
    border-top: 1px solid var(--border-color);
}

.sticky-book-price {
    font-weight: 700;
    min-width: 0;
    overflow-wrap: break-word;
}

.sticky-book-price small {
    font-weight: 400;
    color: var(--text-secondary);
}

.main-container.has-sticky-bar {
    padding-bottom: calc(4rem + 64px + env(safe-area-inset-bottom));
}

/* Booking modal — centered dialog on desktop, bottom sheet on mobile */
.booking-modal {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.6);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 2000;
    padding: 1rem;
}

.booking-modal[hidden] {
    display: none;
}

.booking-modal-content {
    width: 100%;
    max-width: 420px;
    padding: 2rem;
    position: relative;
    max-height: 90vh;
    overflow-y: auto;
    background: #ffffff;
}

.booking-modal-close {
    position: absolute;
    top: 1rem;
    right: 1rem;
    padding: 0.3rem 0.9rem;
}

#booking-modal-title {
    margin-bottom: 1rem;
    padding-right: 5rem;
}

body.modal-open {
    overflow: hidden;
}

@media (max-width: 640px) {
    .booking-modal {
        align-items: flex-end;
        padding: 0;
    }

    .booking-modal-content {
        max-width: 100%;
        max-height: 85vh;
        border-radius: 20px 20px 0 0;
        padding: 1.5rem 1.5rem calc(1.5rem + env(safe-area-inset-bottom));
        animation: sheet-up 0.25s ease-out;
    }

    .sticky-book-bar {
        padding-left: 1.25rem;
        padding-right: 1.25rem;
    }

    /* The category tabs use their natural (desktop-sized) width at
       every screen size — on a narrow phone, 3 pills at that size
       don't fit the viewport, and .category-tabs's overflow-x:auto
       was papering over that with a horizontal scrollbar instead of
       actually fixing the fit. flex:1 forces the 3 tabs to share
       exactly the available width (no scrollbar needed, by
       construction) — smaller padding/font/icon here so "Transport"
       still fits its now-narrower share without wrapping. */
    .category-tabs {
        overflow-x: hidden;
    }

    .category-tab {
        flex: 1;
        flex-shrink: 1;
        min-width: 0;
        justify-content: center;
        padding: 0.55rem 0.35rem;
    }

    /* 4 tabs (Home/Hotels/Tours/Transport) sharing a narrow phone width
       no longer leaves room for "Transport" as a label next to its
       icon — rather than shrinking text until it barely fits (fragile,
       breaks again the moment a longer label is ever needed), tabs go
       icon-only here, same "compact bottom-nav" convention plenty of
       real booking apps use. Each icon is sized up a little since it's
       carrying the whole tab's meaning alone now, not sharing the job
       with a label. */
    .category-tab span {
        display: none;
    }

    .category-tab .icon-nav {
        width: 20px;
        height: 20px;
    }
}

@keyframes sheet-up {
    from { transform: translateY(100%); }
    to { transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
    .booking-modal-content {
        animation: none;
    }
}

/* tokens.css's footer padding (3rem top, 2rem bottom) plus the grid's
   own 2rem bottom margin add up to a lot of empty vertical space —
   noticeably so on a page that's otherwise fairly compact. Tightened
   here rather than in tokens.css, since that's shared by all 4 apps. */
.site-footer {
    padding: 2rem 5% 1.25rem;
}

.footer-grid {
    margin-bottom: 1.25rem;
}

@media (max-width: 640px) {
    .site-footer {
        padding: 1.5rem 5% 1rem;
    }

    .footer-grid {
        gap: 1.5rem;
        margin-bottom: 1rem;
    }
}
